blob: 76af14eabc0503052fa6a9b726485f79c614441e [file] [log] [blame]
/**
* @fileoverview Tests for Int64.
*/
goog.module('protobuf.Int64Test');
goog.setTestOnly();
const Int64 = goog.require('protobuf.Int64');
const Long = goog.require('goog.math.Long');
describe('Int64', () => {
it('can be constructed from bits', () => {
const int64 = Int64.fromBits(0, 1);
expect(int64.getLowBits()).toEqual(0);
expect(int64.getHighBits()).toEqual(1);
});
it('zero is defined', () => {
const int64 = Int64.getZero();
expect(int64.getLowBits()).toEqual(0);
expect(int64.getHighBits()).toEqual(0);
});
it('max value is defined', () => {
const int64 = Int64.getMaxValue();
expect(int64).toEqual(Int64.fromBits(0xFFFFFFFF, 0x7FFFFFFF));
expect(int64.asLong()).toEqual(Long.getMaxValue());
});
it('min value is defined', () => {
const int64 = Int64.getMinValue();
expect(int64).toEqual(Int64.fromBits(0, 0x80000000));
expect(int64.asLong()).toEqual(Long.getMinValue());
});
it('Can be converted to long', () => {
const int64 = Int64.fromInt(1);
expect(int64.asLong()).toEqual(Long.fromInt(1));
});
it('Negative value can be converted to long', () => {
const int64 = Int64.fromInt(-1);
expect(int64.getLowBits()).toEqual(0xFFFFFFFF | 0);
expect(int64.getHighBits()).toEqual(0xFFFFFFFF | 0);
expect(int64.asLong()).toEqual(Long.fromInt(-1));
});
it('Can be converted to number', () => {
const int64 = Int64.fromInt(1);
expect(int64.asNumber()).toEqual(1);
});
it('Can convert negative value to number', () => {
const int64 = Int64.fromInt(-1);
expect(int64.asNumber()).toEqual(-1);
});
it('MAX_SAFE_INTEGER can be used.', () => {
const int64 = Int64.fromNumber(Number.MAX_SAFE_INTEGER);
expect(int64.getLowBitsUnsigned()).toEqual(0xFFFFFFFF);
expect(int64.getHighBits()).toEqual(0x1FFFFF);
expect(int64.asNumber()).toEqual(Number.MAX_SAFE_INTEGER);
});
it('MIN_SAFE_INTEGER can be used.', () => {
const int64 = Int64.fromNumber(Number.MIN_SAFE_INTEGER);
expect(int64.asNumber()).toEqual(Number.MIN_SAFE_INTEGER);
});
it('constructs fromInt', () => {
const int64 = Int64.fromInt(1);
expect(int64.getLowBits()).toEqual(1);
expect(int64.getHighBits()).toEqual(0);
});
it('constructs fromLong', () => {
const int64 = Int64.fromLong(Long.fromInt(1));
expect(int64.getLowBits()).toEqual(1);
expect(int64.getHighBits()).toEqual(0);
});
// TODO: Use our own checking system here.
if (goog.DEBUG) {
it('asNumber throws for MAX_SAFE_INTEGER + 1', () => {
expect(() => Int64.fromNumber(Number.MAX_SAFE_INTEGER + 1).asNumber())
.toThrow();
});
it('fromInt(MAX_SAFE_INTEGER) throws', () => {
expect(() => Int64.fromInt(Number.MAX_SAFE_INTEGER)).toThrow();
});
it('fromInt(1.5) throws', () => {
expect(() => Int64.fromInt(1.5)).toThrow();
});
}
const decimalHexPairs = {
'0x0000000000000000': {signed: '0'},
'0x0000000000000001': {signed: '1'},
'0x00000000ffffffff': {signed: '4294967295'},
'0x0000000100000000': {signed: '4294967296'},
'0xffffffffffffffff': {signed: '-1', unsigned: '18446744073709551615'},
'0x8000000000000000':
{signed: '-9223372036854775808', unsigned: '9223372036854775808'},
'0x8000000080000000':
{signed: '-9223372034707292160', unsigned: '9223372039002259456'},
'0x01b69b4bacd05f15': {signed: '123456789123456789'},
'0xfe4964b4532fa0eb':
{signed: '-123456789123456789', unsigned: '18323287284586094827'},
'0xa5a5a5a5a5a5a5a5':
{signed: '-6510615555426900571', unsigned: '11936128518282651045'},
'0x5a5a5a5a5a5a5a5a': {signed: '6510615555426900570'},
'0xffffffff00000000':
{signed: '-4294967296', unsigned: '18446744069414584320'},
};
it('serializes to signed decimal strings', () => {
for (const [hex, decimals] of Object.entries(decimalHexPairs)) {
const int64 = hexToInt64(hex);
expect(int64.toSignedDecimalString()).toEqual(decimals.signed);
}
});
it('serializes to unsigned decimal strings', () => {
for (const [hex, decimals] of Object.entries(decimalHexPairs)) {
const int64 = hexToInt64(hex);
expect(int64.toUnsignedDecimalString())
.toEqual(decimals.unsigned || decimals.signed);
}
});
it('serializes to unsigned hex strings', () => {
for (const [hex, decimals] of Object.entries(decimalHexPairs)) {
const int64 = hexToInt64(hex);
let shortHex = hex.replace(/0x0*/, '0x');
if (shortHex == '0x') {
shortHex = '0x0';
}
expect(int64.toHexString()).toEqual(shortHex);
}
});
it('parses decimal strings', () => {
for (const [hex, decimals] of Object.entries(decimalHexPairs)) {
const signed = Int64.fromDecimalString(decimals.signed);
expect(int64ToHex(signed)).toEqual(hex);
if (decimals.unsigned) {
const unsigned = Int64.fromDecimalString(decimals.unsigned);
expect(int64ToHex(unsigned)).toEqual(hex);
}
}
});
it('parses hex strings', () => {
for (const [hex, decimals] of Object.entries(decimalHexPairs)) {
expect(int64ToHex(Int64.fromHexString(hex))).toEqual(hex);
}
expect(int64ToHex(Int64.fromHexString('-0x1')))
.toEqual('0xffffffffffffffff');
});
// TODO: Use our own checking system here.
if (goog.DEBUG) {
it('throws when parsing empty string', () => {
expect(() => Int64.fromDecimalString('')).toThrow();
});
it('throws when parsing float string', () => {
expect(() => Int64.fromDecimalString('1.5')).toThrow();
});
it('throws when parsing non-numeric string', () => {
expect(() => Int64.fromDecimalString('0xa')).toThrow();
});
}
it('checks if equal', () => {
const low = Int64.fromInt(1);
const high = Int64.getMaxValue();
expect(low.equals(Int64.fromInt(1))).toEqual(true);
expect(low.equals(high)).toEqual(false);
expect(high.equals(Int64.getMaxValue())).toEqual(true);
});
it('returns unique hashcode', () => {
expect(Int64.fromInt(1).hashCode()).toEqual(Int64.fromInt(1).hashCode());
expect(Int64.fromInt(1).hashCode())
.not.toEqual(Int64.fromInt(2).hashCode());
});
});
/**
* @param {string} hexString
* @return {!Int64}
*/
function hexToInt64(hexString) {
const high = hexString.slice(2, 10);
const low = hexString.slice(10);
return Int64.fromBits(parseInt(low, 16), parseInt(high, 16));
}
/**
* @param {!Int64} int64
* @return {string}
*/
function int64ToHex(int64) {
const ZEROS_32_BIT = '00000000';
const highPartialHex = int64.getHighBitsUnsigned().toString(16);
const lowPartialHex = int64.getLowBitsUnsigned().toString(16);
const highHex = ZEROS_32_BIT.slice(highPartialHex.length) + highPartialHex;
const lowHex = ZEROS_32_BIT.slice(lowPartialHex.length) + lowPartialHex;
return `0x${highHex}${lowHex}`;
}