UNPKG

@btc-vision/transaction

Version:

OPNet transaction library allows you to create and sign transactions for the OPNet network.

918 lines (729 loc) 28 kB
import { describe, expect, it, vi } from 'vitest'; import { FastBigIntMap } from './old/FastBigIntMap.js'; describe('FastBigIntMap - Comprehensive Tests', () => { describe('Constructor', () => { it('should create an empty map with no parameters', () => { const map = new FastBigIntMap(); expect(map.size).toBe(0); }); it('should create an empty map with null parameter', () => { const map = new FastBigIntMap(null); expect(map.size).toBe(0); }); it('should create an empty map with undefined parameter', () => { const map = new FastBigIntMap(undefined); expect(map.size).toBe(0); }); it('should create a map from an array of tuples', () => { const entries: ReadonlyArray<readonly [bigint, bigint]> = [ [1n, 100n], [2n, 200n], [3n, 300n], ]; const map = new FastBigIntMap(entries); expect(map.size).toBe(3); expect(map.get(1n)).toBe(100n); expect(map.get(2n)).toBe(200n); expect(map.get(3n)).toBe(300n); }); it('should create a map from an empty array', () => { const map = new FastBigIntMap([]); expect(map.size).toBe(0); }); it('should create a map from another FastBigIntMap instance', () => { const original = new FastBigIntMap([ [10n, 1000n], [20n, 2000n], ]); const copy = new FastBigIntMap(original); expect(copy.size).toBe(2); expect(copy.get(10n)).toBe(1000n); expect(copy.get(20n)).toBe(2000n); }); it('should create an independent copy when constructed from another FastBigIntMap', () => { const original = new FastBigIntMap([[1n, 100n]]); const copy = new FastBigIntMap(original); // Modify original original.set(1n, 999n); original.set(2n, 200n); // Copy should remain unchanged expect(copy.get(1n)).toBe(100n); expect(copy.has(2n)).toBe(false); expect(copy.size).toBe(1); }); it('should handle duplicate keys in initial array (last value wins)', () => { const entries: ReadonlyArray<readonly [bigint, bigint]> = [ [1n, 100n], [1n, 200n], [1n, 300n], ]; const map = new FastBigIntMap(entries); expect(map.size).toBe(1); expect(map.get(1n)).toBe(300n); }); }); describe('size property', () => { it('should return 0 for empty map', () => { const map = new FastBigIntMap(); expect(map.size).toBe(0); }); it('should return correct size after adding elements', () => { const map = new FastBigIntMap(); map.set(1n, 100n); expect(map.size).toBe(1); map.set(2n, 200n); expect(map.size).toBe(2); map.set(3n, 300n); expect(map.size).toBe(3); }); it('should not increase size when updating existing key', () => { const map = new FastBigIntMap(); map.set(1n, 100n); expect(map.size).toBe(1); map.set(1n, 200n); expect(map.size).toBe(1); }); it('should decrease size after deletion', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); expect(map.size).toBe(2); map.delete(1n); expect(map.size).toBe(1); }); it('should be 0 after clear', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); map.clear(); expect(map.size).toBe(0); }); }); describe('set method', () => { it('should add a new key-value pair', () => { const map = new FastBigIntMap(); map.set(1n, 100n); expect(map.has(1n)).toBe(true); expect(map.get(1n)).toBe(100n); }); it('should update an existing key', () => { const map = new FastBigIntMap(); map.set(1n, 100n); map.set(1n, 200n); expect(map.size).toBe(1); expect(map.get(1n)).toBe(200n); }); it('should return this for chaining', () => { const map = new FastBigIntMap(); const result = map.set(1n, 100n); expect(result).toBe(map); }); it('should allow method chaining', () => { const map = new FastBigIntMap(); map.set(1n, 100n).set(2n, 200n).set(3n, 300n); expect(map.size).toBe(3); expect(map.get(1n)).toBe(100n); expect(map.get(2n)).toBe(200n); expect(map.get(3n)).toBe(300n); }); it('should handle negative bigint keys', () => { const map = new FastBigIntMap(); map.set(-1n, 100n); map.set(-999999999999999999n, 200n); expect(map.get(-1n)).toBe(100n); expect(map.get(-999999999999999999n)).toBe(200n); }); it('should handle very large bigint keys', () => { const map = new FastBigIntMap(); const largeKey = 12345678901234567890123456789012345678901234567890n; map.set(largeKey, 100n); expect(map.has(largeKey)).toBe(true); expect(map.get(largeKey)).toBe(100n); }); it('should handle zero as key', () => { const map = new FastBigIntMap(); map.set(0n, 100n); expect(map.has(0n)).toBe(true); expect(map.get(0n)).toBe(100n); }); it('should handle negative values', () => { const map = new FastBigIntMap(); map.set(1n, -100n); expect(map.get(1n)).toBe(-100n); }); it('should handle zero as value', () => { const map = new FastBigIntMap(); map.set(1n, 0n); expect(map.get(1n)).toBe(0n); }); }); describe('get method', () => { it('should return the value for an existing key', () => { const map = new FastBigIntMap([[1n, 100n]]); expect(map.get(1n)).toBe(100n); }); it('should return undefined for a non-existing key', () => { const map = new FastBigIntMap(); expect(map.get(1n)).toBeUndefined(); }); it('should return undefined for key in empty map', () => { const map = new FastBigIntMap(); expect(map.get(999n)).toBeUndefined(); }); it('should return correct value after update', () => { const map = new FastBigIntMap(); map.set(1n, 100n); map.set(1n, 200n); expect(map.get(1n)).toBe(200n); }); it('should return undefined for deleted key', () => { const map = new FastBigIntMap([[1n, 100n]]); map.delete(1n); expect(map.get(1n)).toBeUndefined(); }); }); describe('has method', () => { it('should return true for existing key', () => { const map = new FastBigIntMap([[1n, 100n]]); expect(map.has(1n)).toBe(true); }); it('should return false for non-existing key', () => { const map = new FastBigIntMap(); expect(map.has(1n)).toBe(false); }); it('should return false after key is deleted', () => { const map = new FastBigIntMap([[1n, 100n]]); map.delete(1n); expect(map.has(1n)).toBe(false); }); it('should return false after clear', () => { const map = new FastBigIntMap([[1n, 100n]]); map.clear(); expect(map.has(1n)).toBe(false); }); it('should distinguish between different keys', () => { const map = new FastBigIntMap([[1n, 100n]]); expect(map.has(1n)).toBe(true); expect(map.has(2n)).toBe(false); expect(map.has(-1n)).toBe(false); }); }); describe('delete method', () => { it('should delete an existing key and return true', () => { const map = new FastBigIntMap([[1n, 100n]]); const result = map.delete(1n); expect(result).toBe(true); expect(map.has(1n)).toBe(false); expect(map.size).toBe(0); }); it('should return false for non-existing key', () => { const map = new FastBigIntMap(); const result = map.delete(1n); expect(result).toBe(false); }); it('should return false when deleting from empty map', () => { const map = new FastBigIntMap(); expect(map.delete(999n)).toBe(false); }); it('should only delete the specified key', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], [3n, 300n], ]); map.delete(2n); expect(map.has(1n)).toBe(true); expect(map.has(2n)).toBe(false); expect(map.has(3n)).toBe(true); expect(map.size).toBe(2); }); it('should maintain insertion order after deletion', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], [3n, 300n], ]); map.delete(2n); const keys = [...map.keys()]; expect(keys).toEqual([1n, 3n]); }); it('should return false when deleting already deleted key', () => { const map = new FastBigIntMap([[1n, 100n]]); map.delete(1n); expect(map.delete(1n)).toBe(false); }); }); describe('clear method', () => { it('should remove all entries', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], [3n, 300n], ]); map.clear(); expect(map.size).toBe(0); expect(map.has(1n)).toBe(false); expect(map.has(2n)).toBe(false); expect(map.has(3n)).toBe(false); }); it('should work on empty map', () => { const map = new FastBigIntMap(); map.clear(); expect(map.size).toBe(0); }); it('should allow adding entries after clear', () => { const map = new FastBigIntMap([[1n, 100n]]); map.clear(); map.set(2n, 200n); expect(map.size).toBe(1); expect(map.get(2n)).toBe(200n); }); }); describe('setAll method', () => { it('should copy all entries from another map', () => { const source = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const target = new FastBigIntMap(); target.setAll(source); expect(target.size).toBe(2); expect(target.get(1n)).toBe(100n); expect(target.get(2n)).toBe(200n); }); it('should replace all existing entries', () => { const source = new FastBigIntMap([[1n, 100n]]); const target = new FastBigIntMap([ [2n, 200n], [3n, 300n], ]); target.setAll(source); expect(target.size).toBe(1); expect(target.get(1n)).toBe(100n); expect(target.has(2n)).toBe(false); expect(target.has(3n)).toBe(false); }); it('should create independent copy (modifications to source do not affect target)', () => { const source = new FastBigIntMap([[1n, 100n]]); const target = new FastBigIntMap(); target.setAll(source); source.set(1n, 999n); source.set(2n, 200n); expect(target.get(1n)).toBe(100n); expect(target.has(2n)).toBe(false); }); it('should handle empty source map', () => { const source = new FastBigIntMap(); const target = new FastBigIntMap([[1n, 100n]]); target.setAll(source); expect(target.size).toBe(0); }); }); describe('addAll method', () => { it('should add all entries from another map', () => { const source = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const target = new FastBigIntMap(); target.addAll(source); expect(target.size).toBe(2); expect(target.get(1n)).toBe(100n); expect(target.get(2n)).toBe(200n); }); it('should merge with existing entries', () => { const source = new FastBigIntMap([ [2n, 200n], [3n, 300n], ]); const target = new FastBigIntMap([[1n, 100n]]); target.addAll(source); expect(target.size).toBe(3); expect(target.get(1n)).toBe(100n); expect(target.get(2n)).toBe(200n); expect(target.get(3n)).toBe(300n); }); it('should overwrite existing keys with values from source', () => { const source = new FastBigIntMap([[1n, 999n]]); const target = new FastBigIntMap([[1n, 100n]]); target.addAll(source); expect(target.size).toBe(1); expect(target.get(1n)).toBe(999n); }); it('should handle empty source map', () => { const source = new FastBigIntMap(); const target = new FastBigIntMap([[1n, 100n]]); target.addAll(source); expect(target.size).toBe(1); expect(target.get(1n)).toBe(100n); }); it('should preserve insertion order (existing keys first, then new keys)', () => { const source = new FastBigIntMap([ [2n, 200n], [3n, 300n], ]); const target = new FastBigIntMap([[1n, 100n]]); target.addAll(source); const keys = [...target.keys()]; expect(keys).toEqual([1n, 2n, 3n]); }); }); describe('entries method', () => { it('should return an iterator of [key, value] pairs', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const entries = [...map.entries()]; expect(entries).toEqual([ [1n, 100n], [2n, 200n], ]); }); it('should return empty iterator for empty map', () => { const map = new FastBigIntMap(); const entries = [...map.entries()]; expect(entries).toEqual([]); }); it('should iterate in insertion order', () => { const map = new FastBigIntMap(); map.set(3n, 300n); map.set(1n, 100n); map.set(2n, 200n); const entries = [...map.entries()]; expect(entries).toEqual([ [3n, 300n], [1n, 100n], [2n, 200n], ]); }); it('should be usable with for...of loop', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const collected: [bigint, bigint][] = []; for (const entry of map.entries()) { collected.push(entry); } expect(collected).toEqual([ [1n, 100n], [2n, 200n], ]); }); }); describe('keys method', () => { it('should return an iterator of keys', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], [3n, 300n], ]); const keys = [...map.keys()]; expect(keys).toEqual([1n, 2n, 3n]); }); it('should return empty iterator for empty map', () => { const map = new FastBigIntMap(); const keys = [...map.keys()]; expect(keys).toEqual([]); }); it('should iterate in insertion order', () => { const map = new FastBigIntMap(); map.set(5n, 500n); map.set(1n, 100n); map.set(3n, 300n); const keys = [...map.keys()]; expect(keys).toEqual([5n, 1n, 3n]); }); it('should be usable with for...of loop', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const collected: bigint[] = []; for (const key of map.keys()) { collected.push(key); } expect(collected).toEqual([1n, 2n]); }); }); describe('values method', () => { it('should return an iterator of values', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], [3n, 300n], ]); const values = [...map.values()]; expect(values).toEqual([100n, 200n, 300n]); }); it('should return empty iterator for empty map', () => { const map = new FastBigIntMap(); const values = [...map.values()]; expect(values).toEqual([]); }); it('should iterate in insertion order', () => { const map = new FastBigIntMap(); map.set(3n, 300n); map.set(1n, 100n); map.set(2n, 200n); const values = [...map.values()]; expect(values).toEqual([300n, 100n, 200n]); }); it('should be usable with for...of loop', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const collected: bigint[] = []; for (const value of map.values()) { collected.push(value); } expect(collected).toEqual([100n, 200n]); }); }); describe('forEach method', () => { it('should call callback for each entry', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const callback = vi.fn(); map.forEach(callback); expect(callback).toHaveBeenCalledTimes(2); expect(callback).toHaveBeenNthCalledWith(1, 100n, 1n, map); expect(callback).toHaveBeenNthCalledWith(2, 200n, 2n, map); }); it('should not call callback for empty map', () => { const map = new FastBigIntMap(); const callback = vi.fn(); map.forEach(callback); expect(callback).not.toHaveBeenCalled(); }); it('should iterate in insertion order', () => { const map = new FastBigIntMap(); map.set(3n, 300n); map.set(1n, 100n); map.set(2n, 200n); const order: bigint[] = []; map.forEach((_value: bigint, key: bigint) => { order.push(key); }); expect(order).toEqual([3n, 1n, 2n]); }); it('should use thisArg when provided', () => { const map = new FastBigIntMap([[1n, 100n]]); const context = { multiplier: 2n }; let result: bigint = 0n; map.forEach(function (this: { multiplier: bigint }, value: bigint) { result = value * this.multiplier; }, context); expect(result).toBe(200n); }); it('should work without thisArg', () => { const map = new FastBigIntMap([[1n, 100n]]); let sum = 0n; map.forEach((value: bigint) => { sum += value; }); expect(sum).toBe(100n); }); it('should pass map as third argument', () => { const map = new FastBigIntMap([[1n, 100n]]); let receivedMap: FastBigIntMap | null = null; map.forEach((_value: bigint, _key: bigint, m: FastBigIntMap) => { receivedMap = m; }); expect(receivedMap).toBe(map); }); }); describe('Symbol.iterator', () => { it('should make map iterable with for...of', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const collected: [bigint, bigint][] = []; for (const entry of map) { collected.push(entry); } expect(collected).toEqual([ [1n, 100n], [2n, 200n], ]); }); it('should return same iterator as entries()', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const fromIterator = [...map]; const fromEntries = [...map.entries()]; expect(fromIterator).toEqual(fromEntries); }); it('should work with spread operator', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const entries = [...map]; expect(entries).toEqual([ [1n, 100n], [2n, 200n], ]); }); it('should work with Array.from', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const entries = Array.from(map); expect(entries).toEqual([ [1n, 100n], [2n, 200n], ]); }); it('should work with destructuring', () => { const map = new FastBigIntMap([ [1n, 100n], [2n, 200n], ]); const [first, second] = map; expect(first).toEqual([1n, 100n]); expect(second).toEqual([2n, 200n]); }); it('should return empty iterator for empty map', () => { const map = new FastBigIntMap(); const entries = [...map]; expect(entries).toEqual([]); }); }); describe('Insertion order preservation', () => { it('should maintain insertion order across all iteration methods', () => { const map = new FastBigIntMap(); map.set(5n, 500n); map.set(1n, 100n); map.set(3n, 300n); map.set(2n, 200n); map.set(4n, 400n); const keysFromKeys = [...map.keys()]; const keysFromEntries = [...map.entries()].map(([k]) => k); const keysFromForEach: bigint[] = []; map.forEach((_: bigint, key: bigint) => keysFromForEach.push(key)); const keysFromIterator = [...map].map(([k]) => k); const expectedOrder = [5n, 1n, 3n, 2n, 4n]; expect(keysFromKeys).toEqual(expectedOrder); expect(keysFromEntries).toEqual(expectedOrder); expect(keysFromForEach).toEqual(expectedOrder); expect(keysFromIterator).toEqual(expectedOrder); }); it('should not change order when updating existing key', () => { const map = new FastBigIntMap(); map.set(1n, 100n); map.set(2n, 200n); map.set(3n, 300n); // Update middle key map.set(2n, 999n); const keys = [...map.keys()]; expect(keys).toEqual([1n, 2n, 3n]); expect(map.get(2n)).toBe(999n); }); }); describe('Edge cases', () => { it('should handle maximum safe bigint values', () => { const map = new FastBigIntMap(); const maxSafe = BigInt(Number.MAX_SAFE_INTEGER); const minSafe = BigInt(Number.MIN_SAFE_INTEGER); map.set(maxSafe, 1n); map.set(minSafe, 2n); expect(map.get(maxSafe)).toBe(1n); expect(map.get(minSafe)).toBe(2n); }); it('should handle extremely large bigints', () => { const map = new FastBigIntMap(); const hugeKey = 10n ** 100n; const hugeValue = 10n ** 200n; map.set(hugeKey, hugeValue); expect(map.get(hugeKey)).toBe(hugeValue); }); it('should handle many entries', () => { const map = new FastBigIntMap(); const count = 10000; for (let i = 0; i < count; i++) { map.set(BigInt(i), BigInt(i * 10)); } expect(map.size).toBe(count); expect(map.get(0n)).toBe(0n); expect(map.get(5000n)).toBe(50000n); expect(map.get(9999n)).toBe(99990n); }); it('should correctly handle 0n as both key and value', () => { const map = new FastBigIntMap(); map.set(0n, 0n); expect(map.has(0n)).toBe(true); expect(map.get(0n)).toBe(0n); expect(map.size).toBe(1); }); it('should handle negative zero (-0n is same as 0n in bigint)', () => { const map = new FastBigIntMap(); map.set(-0n, 100n); expect(map.get(0n)).toBe(100n); expect(map.has(-0n)).toBe(true); }); it('should handle operations in sequence', () => { const map = new FastBigIntMap(); // Add map.set(1n, 100n); map.set(2n, 200n); expect(map.size).toBe(2); // Update map.set(1n, 150n); expect(map.get(1n)).toBe(150n); expect(map.size).toBe(2); // Delete map.delete(1n); expect(map.size).toBe(1); expect(map.has(1n)).toBe(false); // Add back map.set(1n, 100n); expect(map.size).toBe(2); // Clear map.clear(); expect(map.size).toBe(0); // Add after clear map.set(3n, 300n); expect(map.size).toBe(1); expect(map.get(3n)).toBe(300n); }); }); describe('Type safety and method signatures', () => { it('set should accept bigint key and bigint value', () => { const map = new FastBigIntMap(); const result = map.set(1n, 100n); expect(result).toBeInstanceOf(FastBigIntMap); }); it('get should return bigint or undefined', () => { const map = new FastBigIntMap([[1n, 100n]]); const existing: bigint | undefined = map.get(1n); const nonExisting: bigint | undefined = map.get(999n); expect(typeof existing).toBe('bigint'); expect(nonExisting).toBeUndefined(); }); it('has should return boolean', () => { const map = new FastBigIntMap([[1n, 100n]]); expect(typeof map.has(1n)).toBe('boolean'); expect(typeof map.has(999n)).toBe('boolean'); }); it('delete should return boolean', () => { const map = new FastBigIntMap([[1n, 100n]]); expect(typeof map.delete(1n)).toBe('boolean'); expect(typeof map.delete(999n)).toBe('boolean'); }); it('size should return number', () => { const map = new FastBigIntMap([[1n, 100n]]); expect(typeof map.size).toBe('number'); }); }); });