1/** 2 * @fileoverview Tests for Int64. 3 */ 4goog.module('protobuf.Int64Test'); 5goog.setTestOnly(); 6 7const Int64 = goog.require('protobuf.Int64'); 8const Long = goog.require('goog.math.Long'); 9 10describe('Int64', () => { 11 it('can be constructed from bits', () => { 12 const int64 = Int64.fromBits(0, 1); 13 expect(int64.getLowBits()).toEqual(0); 14 expect(int64.getHighBits()).toEqual(1); 15 }); 16 17 it('zero is defined', () => { 18 const int64 = Int64.getZero(); 19 expect(int64.getLowBits()).toEqual(0); 20 expect(int64.getHighBits()).toEqual(0); 21 }); 22 23 it('max value is defined', () => { 24 const int64 = Int64.getMaxValue(); 25 expect(int64).toEqual(Int64.fromBits(0xFFFFFFFF, 0x7FFFFFFF)); 26 expect(int64.asLong()).toEqual(Long.getMaxValue()); 27 }); 28 29 it('min value is defined', () => { 30 const int64 = Int64.getMinValue(); 31 expect(int64).toEqual(Int64.fromBits(0, 0x80000000)); 32 expect(int64.asLong()).toEqual(Long.getMinValue()); 33 }); 34 35 it('Can be converted to long', () => { 36 const int64 = Int64.fromInt(1); 37 expect(int64.asLong()).toEqual(Long.fromInt(1)); 38 }); 39 40 it('Negative value can be converted to long', () => { 41 const int64 = Int64.fromInt(-1); 42 expect(int64.getLowBits()).toEqual(0xFFFFFFFF | 0); 43 expect(int64.getHighBits()).toEqual(0xFFFFFFFF | 0); 44 expect(int64.asLong()).toEqual(Long.fromInt(-1)); 45 }); 46 47 it('Can be converted to number', () => { 48 const int64 = Int64.fromInt(1); 49 expect(int64.asNumber()).toEqual(1); 50 }); 51 52 it('Can convert negative value to number', () => { 53 const int64 = Int64.fromInt(-1); 54 expect(int64.asNumber()).toEqual(-1); 55 }); 56 57 it('MAX_SAFE_INTEGER can be used.', () => { 58 const int64 = Int64.fromNumber(Number.MAX_SAFE_INTEGER); 59 expect(int64.getLowBitsUnsigned()).toEqual(0xFFFFFFFF); 60 expect(int64.getHighBits()).toEqual(0x1FFFFF); 61 expect(int64.asNumber()).toEqual(Number.MAX_SAFE_INTEGER); 62 }); 63 64 it('MIN_SAFE_INTEGER can be used.', () => { 65 const int64 = Int64.fromNumber(Number.MIN_SAFE_INTEGER); 66 expect(int64.asNumber()).toEqual(Number.MIN_SAFE_INTEGER); 67 }); 68 69 it('constructs fromInt', () => { 70 const int64 = Int64.fromInt(1); 71 expect(int64.getLowBits()).toEqual(1); 72 expect(int64.getHighBits()).toEqual(0); 73 }); 74 75 it('constructs fromLong', () => { 76 const int64 = Int64.fromLong(Long.fromInt(1)); 77 expect(int64.getLowBits()).toEqual(1); 78 expect(int64.getHighBits()).toEqual(0); 79 }); 80 81 // TODO: Use our own checking system here. 82 if (goog.DEBUG) { 83 it('asNumber throws for MAX_SAFE_INTEGER + 1', () => { 84 expect(() => Int64.fromNumber(Number.MAX_SAFE_INTEGER + 1).asNumber()) 85 .toThrow(); 86 }); 87 88 it('fromInt(MAX_SAFE_INTEGER) throws', () => { 89 expect(() => Int64.fromInt(Number.MAX_SAFE_INTEGER)).toThrow(); 90 }); 91 92 it('fromInt(1.5) throws', () => { 93 expect(() => Int64.fromInt(1.5)).toThrow(); 94 }); 95 } 96 97 const decimalHexPairs = { 98 '0x0000000000000000': {signed: '0'}, 99 '0x0000000000000001': {signed: '1'}, 100 '0x00000000ffffffff': {signed: '4294967295'}, 101 '0x0000000100000000': {signed: '4294967296'}, 102 '0xffffffffffffffff': {signed: '-1', unsigned: '18446744073709551615'}, 103 '0x8000000000000000': 104 {signed: '-9223372036854775808', unsigned: '9223372036854775808'}, 105 '0x8000000080000000': 106 {signed: '-9223372034707292160', unsigned: '9223372039002259456'}, 107 '0x01b69b4bacd05f15': {signed: '123456789123456789'}, 108 '0xfe4964b4532fa0eb': 109 {signed: '-123456789123456789', unsigned: '18323287284586094827'}, 110 '0xa5a5a5a5a5a5a5a5': 111 {signed: '-6510615555426900571', unsigned: '11936128518282651045'}, 112 '0x5a5a5a5a5a5a5a5a': {signed: '6510615555426900570'}, 113 '0xffffffff00000000': 114 {signed: '-4294967296', unsigned: '18446744069414584320'}, 115 }; 116 117 it('serializes to signed decimal strings', () => { 118 for (const [hex, decimals] of Object.entries(decimalHexPairs)) { 119 const int64 = hexToInt64(hex); 120 expect(int64.toSignedDecimalString()).toEqual(decimals.signed); 121 } 122 }); 123 124 it('serializes to unsigned decimal strings', () => { 125 for (const [hex, decimals] of Object.entries(decimalHexPairs)) { 126 const int64 = hexToInt64(hex); 127 expect(int64.toUnsignedDecimalString()) 128 .toEqual(decimals.unsigned || decimals.signed); 129 } 130 }); 131 132 it('serializes to unsigned hex strings', () => { 133 for (const [hex, decimals] of Object.entries(decimalHexPairs)) { 134 const int64 = hexToInt64(hex); 135 let shortHex = hex.replace(/0x0*/, '0x'); 136 if (shortHex == '0x') { 137 shortHex = '0x0'; 138 } 139 expect(int64.toHexString()).toEqual(shortHex); 140 } 141 }); 142 143 it('parses decimal strings', () => { 144 for (const [hex, decimals] of Object.entries(decimalHexPairs)) { 145 const signed = Int64.fromDecimalString(decimals.signed); 146 expect(int64ToHex(signed)).toEqual(hex); 147 if (decimals.unsigned) { 148 const unsigned = Int64.fromDecimalString(decimals.unsigned); 149 expect(int64ToHex(unsigned)).toEqual(hex); 150 } 151 } 152 }); 153 154 it('parses hex strings', () => { 155 for (const [hex, decimals] of Object.entries(decimalHexPairs)) { 156 expect(int64ToHex(Int64.fromHexString(hex))).toEqual(hex); 157 } 158 expect(int64ToHex(Int64.fromHexString('-0x1'))) 159 .toEqual('0xffffffffffffffff'); 160 }); 161 162 // TODO: Use our own checking system here. 163 if (goog.DEBUG) { 164 it('throws when parsing empty string', () => { 165 expect(() => Int64.fromDecimalString('')).toThrow(); 166 }); 167 168 it('throws when parsing float string', () => { 169 expect(() => Int64.fromDecimalString('1.5')).toThrow(); 170 }); 171 172 it('throws when parsing non-numeric string', () => { 173 expect(() => Int64.fromDecimalString('0xa')).toThrow(); 174 }); 175 } 176 177 it('checks if equal', () => { 178 const low = Int64.fromInt(1); 179 const high = Int64.getMaxValue(); 180 expect(low.equals(Int64.fromInt(1))).toEqual(true); 181 expect(low.equals(high)).toEqual(false); 182 expect(high.equals(Int64.getMaxValue())).toEqual(true); 183 }); 184 185 it('returns unique hashcode', () => { 186 expect(Int64.fromInt(1).hashCode()).toEqual(Int64.fromInt(1).hashCode()); 187 expect(Int64.fromInt(1).hashCode()) 188 .not.toEqual(Int64.fromInt(2).hashCode()); 189 }); 190}); 191 192/** 193 * @param {string} hexString 194 * @return {!Int64} 195 */ 196function hexToInt64(hexString) { 197 const high = hexString.slice(2, 10); 198 const low = hexString.slice(10); 199 return Int64.fromBits(parseInt(low, 16), parseInt(high, 16)); 200} 201 202/** 203 * @param {!Int64} int64 204 * @return {string} 205 */ 206function int64ToHex(int64) { 207 const ZEROS_32_BIT = '00000000'; 208 const highPartialHex = int64.getHighBitsUnsigned().toString(16); 209 const lowPartialHex = int64.getLowBitsUnsigned().toString(16); 210 const highHex = ZEROS_32_BIT.slice(highPartialHex.length) + highPartialHex; 211 const lowHex = ZEROS_32_BIT.slice(lowPartialHex.length) + lowPartialHex; 212 return `0x${highHex}${lowHex}`; 213} 214