Skip to content

Commit 9ccde39

Browse files
committed
import golden tests without fs, use Integer instead of BigInt
1 parent 3a22a98 commit 9ccde39

19 files changed

+536
-57
lines changed

packages/firestore/src/remote/bloom_filter.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
import { Md5 } from '@firebase/webchannel-wrapper';
17+
import { Md5, Integer } from '@firebase/webchannel-wrapper';
1818

1919
import { debugAssert } from '../util/assert';
2020

@@ -26,10 +26,10 @@ export class BloomFilter {
2626
padding: number,
2727
private readonly hashCount: number
2828
) {
29-
debugAssert(padding >= 0, 'Padding is negative or undefined.');
29+
debugAssert(padding >= 0, 'Padding is negative.');
3030
this.bitSize = this.bitmap.length * 8 - padding;
3131
debugAssert(this.bitSize >= 0, 'Bitmap size is negative.');
32-
debugAssert(this.hashCount >= 0, 'Hash count is negative or undefined.');
32+
debugAssert(this.hashCount >= 0, 'Hash count is negative.');
3333
}
3434

3535
getBitSize(): number {
@@ -54,16 +54,22 @@ export class BloomFilter {
5454
// Interpret the hashed value as two 64-bit chunks as unsigned integers, encoded using 2’s
5555
// complement using little endian.
5656
const dataView = new DataView(encodedBytes.buffer);
57-
const hash1 = dataView.getBigUint64(0, /* littleEndian= */ true);
58-
const hash2 = dataView.getBigUint64(8, /* littleEndian= */ true);
57+
const firstUint32 = dataView.getUint32(0, /* littleEndian= */ true);
58+
const secondUint32 = dataView.getUint32(4, /* littleEndian= */ true);
59+
const thirdUint32 = dataView.getUint32(8, /* littleEndian= */ true);
60+
const fourthUint32 = dataView.getUint32(12, /* littleEndian= */ true);
61+
const hash1 = new Integer([firstUint32, secondUint32], 0);
62+
const hash2 = new Integer([thirdUint32, fourthUint32], 0);
5963

6064
for (let i = 0; i < this.hashCount; i++) {
6165
// Calculate hashed value h(i) = h1 + (i * h2), wrap if hash value overflow
62-
let combinedHash = hash1 + BigInt(i) * hash2;
63-
combinedHash = BigInt.asUintN(64, combinedHash);
66+
let combinedHash = hash1.add(hash2.multiply(Integer.fromNumber(i)));
67+
combinedHash = combinedHash.modulo(Integer.fromNumber(Math.pow(2, 64)));
6468

6569
// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))).
66-
const module = Number(combinedHash % BigInt(this.bitSize));
70+
const module = Number(
71+
combinedHash.modulo(Integer.fromNumber(this.bitSize))
72+
);
6773
const byte = this.bitmap[Math.floor(module / 8)];
6874

6975
if (!(byte & (0x01 << module % 8))) {

packages/firestore/test/unit/core/webchannel_wrapper.test.ts

Lines changed: 246 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
// These tests are mostly to ensure that the exported classes correctly map to
2020
// underlying functionality from google-closure-library.
2121

22-
import { Md5 } from '@firebase/webchannel-wrapper';
22+
import { Md5, Integer } from '@firebase/webchannel-wrapper';
2323
import { expect } from 'chai';
2424

2525
describe('Md5', () => {
@@ -83,3 +83,248 @@ describe('Md5', () => {
8383
expect(md5.digest()).to.deep.equal(DIGEST_OF_DEF);
8484
});
8585
});
86+
87+
describe('Integer', () => {
88+
it('constructor should create distinct instances', () => {
89+
const instance1 = new Integer([1], 0);
90+
const instance2 = new Integer([1], 0);
91+
expect(instance1).is.instanceof(Integer);
92+
expect(instance2).is.instanceof(Integer);
93+
expect(instance1).is.not.equal(instance2);
94+
});
95+
96+
it('constructor should construct 1 and -1, 2 and -2', () => {
97+
const positiveOne = new Integer([1], 0);
98+
expect(positiveOne.toNumber()).equals(1);
99+
const negativeOne = new Integer([-1], -1);
100+
expect(negativeOne.toNumber()).equals(-1);
101+
const positiveTwo = new Integer([2], 0);
102+
expect(positiveTwo.toNumber()).equals(2);
103+
const negativeTwo = new Integer([-2], -1);
104+
expect(negativeTwo.toNumber()).equals(-2);
105+
});
106+
107+
it('constructor should construct big positive values', () => {
108+
expect(new Integer([0xff], 0).toNumber()).equals(255);
109+
expect(new Integer([0xffff], 0).toNumber()).equals(65535);
110+
expect(new Integer([0xffffff], 0).toNumber()).equals(16777215);
111+
expect(new Integer([0xffffffff], 0).toNumber()).equals(4294967295);
112+
expect(new Integer([0, 1], 0).toNumber()).equals(4294967296);
113+
expect(new Integer([1, 1], 0).toNumber()).equals(4294967297);
114+
expect(new Integer([0xfffffffe, 1], 0).toNumber()).equals(8589934590);
115+
expect(new Integer([0xffffffff, 1], 0).toNumber()).equals(8589934591);
116+
expect(new Integer([0, 2], 0).toNumber()).equals(8589934592);
117+
expect(new Integer([1, 2], 0).toNumber()).equals(8589934593);
118+
expect(
119+
new Integer(
120+
[0x992ce530, 0xbc1f3bbb, 0x2080e2ee, 0xe53c0595],
121+
0
122+
).toString()
123+
).equals('304704862073361391914321619654827369776');
124+
});
125+
126+
it('constructor should construct big negative values', () => {
127+
expect(new Integer([0xffffffff], -1).toNumber()).equals(-1);
128+
expect(new Integer([0xfffffffe], -1).toNumber()).equals(-2);
129+
expect(new Integer([0xfffffffd], -1).toNumber()).equals(-3);
130+
expect(new Integer([0xfffffff0], -1).toNumber()).equals(-16);
131+
expect(new Integer([0xffffff00], -1).toNumber()).equals(-256);
132+
expect(new Integer([0xfffff000], -1).toNumber()).equals(-4096);
133+
expect(new Integer([0xffff0000], -1).toNumber()).equals(-65536);
134+
expect(new Integer([0xfff00000], -1).toNumber()).equals(-1048576);
135+
expect(new Integer([0xff000000], -1).toNumber()).equals(-16777216);
136+
expect(new Integer([0xf0000000], -1).toNumber()).equals(-268435456);
137+
expect(new Integer([0x00000001], -1).toNumber()).equals(-4294967295);
138+
expect(new Integer([0x00000000], -1).toNumber()).equals(-4294967296);
139+
expect(new Integer([0x00000000, 0xffffffff], -1).toNumber()).equals(
140+
-4294967296
141+
);
142+
expect(new Integer([0xffffffff, 0xfffffffe], -1).toNumber()).equals(
143+
-4294967297
144+
);
145+
expect(new Integer([0xfffffffe, 0xfffffffe], -1).toNumber()).equals(
146+
-4294967298
147+
);
148+
});
149+
150+
it('add() should produce the sum of the two numbers', () => {
151+
expect(Integer.fromNumber(0).add(Integer.fromNumber(0)).toNumber()).equals(
152+
0
153+
);
154+
expect(Integer.fromNumber(1).add(Integer.fromNumber(1)).toNumber()).equals(
155+
2
156+
);
157+
expect(
158+
Integer.fromNumber(0xffffffff).add(Integer.fromNumber(1)).toNumber()
159+
).equals(4294967296);
160+
expect(
161+
Integer.fromString('304704862073361391914321619654827369776')
162+
.add(Integer.fromString('77393247566944052149773810817307943505'))
163+
.toString()
164+
).equals('382098109640305444064095430472135313281');
165+
expect(Integer.fromNumber(0).add(Integer.fromNumber(-1)).toNumber()).equals(
166+
-1
167+
);
168+
});
169+
170+
it('multiply() should produce the product of the two numbers', () => {
171+
expect(
172+
Integer.fromNumber(0).multiply(Integer.fromNumber(0)).toNumber()
173+
).equals(0);
174+
expect(
175+
Integer.fromNumber(1).multiply(Integer.fromNumber(0)).toNumber()
176+
).equals(0);
177+
expect(
178+
Integer.fromNumber(1).multiply(Integer.fromNumber(1)).toNumber()
179+
).equals(1);
180+
expect(
181+
Integer.fromNumber(9).multiply(Integer.fromNumber(3)).toNumber()
182+
).equals(27);
183+
expect(
184+
Integer.fromNumber(0xffffffff)
185+
.multiply(Integer.fromNumber(0xca11ba11))
186+
.toString()
187+
).equals('14560623649052575215');
188+
expect(
189+
Integer.fromString('304704862073361391914321619654827369776')
190+
.multiply(Integer.fromString('77393247566944052149773810817307943505'))
191+
.toString()
192+
).equals(
193+
'23582098825295199538298333106941184620809785262540690532878112097410752504880'
194+
);
195+
expect(
196+
Integer.fromNumber(5).multiply(Integer.fromNumber(-1)).toNumber()
197+
).equals(-5);
198+
});
199+
200+
it('modulo() should produce the division remainder of the two numbers', () => {
201+
expect(() => Integer.fromNumber(0).modulo(Integer.fromNumber(0))).to.throw(
202+
'division by zero'
203+
);
204+
expect(() => Integer.fromNumber(42).modulo(Integer.fromNumber(0))).to.throw(
205+
'division by zero'
206+
);
207+
expect(
208+
Integer.fromNumber(20).modulo(Integer.fromNumber(1)).toNumber()
209+
).equals(0);
210+
expect(
211+
Integer.fromNumber(2).modulo(Integer.fromNumber(2)).toNumber()
212+
).equals(0);
213+
expect(
214+
Integer.fromNumber(3).modulo(Integer.fromNumber(2)).toNumber()
215+
).equals(1);
216+
expect(
217+
Integer.fromNumber(4).modulo(Integer.fromNumber(2)).toNumber()
218+
).equals(0);
219+
expect(
220+
Integer.fromNumber(0xffffffff)
221+
.modulo(Integer.fromNumber(0xca11ba11))
222+
.toNumber()
223+
).equals(904807918);
224+
expect(
225+
Integer.fromString('304704862073361391914321619654827369776')
226+
.modulo(Integer.fromString('77393247566944052149773810817307943505'))
227+
.toString()
228+
).equals('72525119372529235465000187202903539261');
229+
expect(
230+
Integer.fromString('304704862073361391914321619654827369776')
231+
.modulo(Integer.fromNumber(313))
232+
.toNumber()
233+
).equals(167);
234+
});
235+
236+
it('compare() should correctly compare two numbers for order', () => {
237+
const numbers = Object.freeze([
238+
Integer.fromNumber(-4294967298),
239+
Integer.fromNumber(-2),
240+
Integer.fromNumber(-1),
241+
Integer.fromNumber(0),
242+
Integer.fromNumber(1),
243+
Integer.fromNumber(2),
244+
Integer.fromNumber(0xffffffff),
245+
Integer.fromString('77393247566944052149773810817307943505'),
246+
Integer.fromString('304704862073361391914321619654827369776')
247+
]);
248+
for (let i1 = 0; i1 < numbers.length; i1++) {
249+
for (let i2 = 0; i2 < numbers.length; i2++) {
250+
const num1 = numbers[i1];
251+
const num2 = numbers[i2];
252+
const expected = i1 === i2 ? 0 : i1 < i2 ? -1 : 1;
253+
expect(num1.compare(num2)).equals(expected);
254+
}
255+
}
256+
});
257+
258+
it('toNumber() should return the correct number', () => {
259+
const one = Integer.fromNumber(1);
260+
const two = Integer.fromNumber(2);
261+
expect(Integer.fromNumber(0).toNumber()).equals(0);
262+
expect(Integer.fromNumber(1).toNumber()).equals(1);
263+
expect(Integer.fromNumber(-1).toNumber()).equals(-1);
264+
expect(Integer.fromNumber(Number.MAX_SAFE_INTEGER).toNumber()).equals(
265+
Number.MAX_SAFE_INTEGER
266+
);
267+
expect(Integer.fromNumber(Number.MIN_SAFE_INTEGER).toNumber()).equals(
268+
Number.MIN_SAFE_INTEGER
269+
);
270+
expect(
271+
Integer.fromNumber(Number.MAX_SAFE_INTEGER).add(one).toNumber()
272+
).equals(Number.MAX_SAFE_INTEGER + 1);
273+
expect(
274+
Integer.fromNumber(Number.MAX_SAFE_INTEGER).add(two).toNumber()
275+
).equals(Number.MAX_SAFE_INTEGER + 1);
276+
});
277+
278+
it('toString() should return the correct number', () => {
279+
const one = Integer.fromNumber(1);
280+
const two = Integer.fromNumber(2);
281+
expect(Integer.fromNumber(0).toString()).equals('0');
282+
expect(Integer.fromNumber(1).toString()).equals('1');
283+
expect(Integer.fromNumber(-1).toString()).equals('-1');
284+
expect(Integer.fromNumber(Number.MAX_SAFE_INTEGER).toString()).equals(
285+
'9007199254740991'
286+
);
287+
expect(Integer.fromNumber(Number.MIN_SAFE_INTEGER).toString()).equals(
288+
'-9007199254740991'
289+
);
290+
expect(
291+
Integer.fromNumber(Number.MAX_SAFE_INTEGER).add(one).toString()
292+
).equals('9007199254740992');
293+
expect(
294+
Integer.fromNumber(Number.MAX_SAFE_INTEGER).add(two).toString()
295+
).equals('9007199254740993');
296+
expect(
297+
Integer.fromString('304704862073361391914321619654827369776').toString()
298+
).equals('304704862073361391914321619654827369776');
299+
300+
expect(Integer.fromNumber(0).toString(2)).equals('0');
301+
expect(Integer.fromNumber(43981).toString(2)).equals('1010101111001101');
302+
expect(Integer.fromNumber(43981).toString(8)).equals('125715');
303+
expect(Integer.fromNumber(43981).toString(10)).equals('43981');
304+
expect(Integer.fromNumber(43981).toString(16)).equals('abcd');
305+
});
306+
307+
it('fromNumber() create a new Integer with the given value', () => {
308+
// The tests for toString() and toNumber() cover this method.
309+
});
310+
311+
it('fromString() create a new Integer with the given value', () => {
312+
expect(Integer.fromString('0').toNumber()).equals(0);
313+
expect(Integer.fromString('1').toNumber()).equals(1);
314+
expect(Integer.fromString('-1').toNumber()).equals(-1);
315+
expect(Integer.fromString('42').toNumber()).equals(42);
316+
expect(Integer.fromString('9007199254740991').toNumber()).equals(
317+
Number.MAX_SAFE_INTEGER
318+
);
319+
expect(Integer.fromString('-9007199254740991').toNumber()).equals(
320+
Number.MIN_SAFE_INTEGER
321+
);
322+
expect(
323+
Integer.fromString('304704862073361391914321619654827369776').toString()
324+
).equals('304704862073361391914321619654827369776');
325+
326+
expect(Integer.fromString('abcd', 16).toNumber()).equals(43981);
327+
expect(Integer.fromString('125715', 8).toNumber()).equals(43981);
328+
expect(Integer.fromString('1010101111001101', 2).toNumber()).equals(43981);
329+
});
330+
});

0 commit comments

Comments
 (0)