• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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