UNPKG

@bsv/wallet-toolbox

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

413 lines 17.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const src_1 = require("../../../../../src"); const TestUtilsWalletStorage_1 = require("../../../../../test/utils/TestUtilsWalletStorage"); const EntityOutput_1 = require("../EntityOutput"); describe('Output class method tests', () => { jest.setTimeout(99999999); const env = TestUtilsWalletStorage_1.TestUtilsWalletStorage.getEnv('test'); const ctxs = []; const ctxs2 = []; beforeAll(async () => { if (env.runMySQL) { ctxs.push(await TestUtilsWalletStorage_1.TestUtilsWalletStorage.createLegacyWalletMySQLCopy('OutputTests')); ctxs2.push(await TestUtilsWalletStorage_1.TestUtilsWalletStorage.createLegacyWalletMySQLCopy('OutputTests2')); } ctxs.push(await TestUtilsWalletStorage_1.TestUtilsWalletStorage.createLegacyWalletSQLiteCopy('OutputBTests')); ctxs2.push(await TestUtilsWalletStorage_1.TestUtilsWalletStorage.createLegacyWalletSQLiteCopy('OutputTests2')); }); afterAll(async () => { for (const ctx of ctxs) { await ctx.storage.destroy(); } for (const ctx of ctxs2) { await ctx.storage.destroy(); } }); // Test: equals identifies matching entities with and without SyncMap test('0_equals identifies matching entities with and without SyncMap', async () => { const ctx = ctxs[0]; // Insert initial record into the database const initialData = { outputId: 601, created_at: new Date('2023-01-01'), updated_at: new Date('2023-01-02'), userId: 1, transactionId: 100, basketId: 1, spendable: true, change: false, satoshis: 1000, outputDescription: 'Test Output', vout: 40, type: 'p2pkh', providedBy: 'you', purpose: 'testing', txid: 'txid123', spendingDescription: 'Test Spending', derivationPrefix: 'm/44', derivationSuffix: '/0/0', senderIdentityKey: 'key123', customInstructions: 'none', lockingScript: [1, 2, 3], scriptLength: 10, scriptOffset: 0 }; await ctx.activeStorage.insertOutput(initialData); // Create two Output entities from the same data const entity1 = new EntityOutput_1.EntityOutput(initialData); const entity2 = new EntityOutput_1.EntityOutput(initialData); const syncMap = (0, src_1.createSyncMap)(); syncMap.transaction.idMap[100] = 100; syncMap.outputBasket.idMap[1] = 1; // Verify equals with and without SyncMap expect(entity1.equals(entity2.toApi())).toBe(true); expect(entity1.equals(entity2.toApi(), syncMap)).toBe(true); }); // Test: equals identifies non-matching entities test('1_equals identifies non-matching entities', async () => { const ctx = ctxs[0]; // Insert initial record into the database const initialData = { outputId: 602, created_at: new Date('2023-01-01'), updated_at: new Date('2023-01-02'), userId: 1, transactionId: 101, basketId: 2, spendable: true, change: false, satoshis: 1000, outputDescription: 'Test Output', vout: 41, type: 'p2pkh', providedBy: 'you', purpose: 'testing', txid: 'txid124', spendingDescription: 'Test Spending', derivationPrefix: 'm/44', derivationSuffix: '/0/0', senderIdentityKey: 'key124', customInstructions: 'none', lockingScript: [1, 2, 3], scriptLength: 10, scriptOffset: 0 }; await ctx.activeStorage.insertOutput(initialData); // Create two Output entities with differing data const entity1 = new EntityOutput_1.EntityOutput(initialData); const entity2 = new EntityOutput_1.EntityOutput({ ...initialData, satoshis: 2000 }); // Verify equals returns false for different entities expect(entity1.equals(entity2.toApi())).toBe(false); }); // Test: equals identifies non-matching entities with optional fields and arrays test('2_equals handles optional fields and arrays', async () => { const ctx = ctxs[0]; // Insert initial record into the database const initialData = { outputId: 603, created_at: new Date('2023-01-01'), updated_at: new Date('2023-01-02'), userId: 1, transactionId: 102, basketId: 3, spendable: true, change: false, satoshis: 1000, outputDescription: 'Test Output', vout: 42, type: 'p2pkh', providedBy: 'you', purpose: 'testing', txid: 'txid125', spendingDescription: 'Test Spending', derivationPrefix: 'm/44', derivationSuffix: '/0/0', senderIdentityKey: 'key125', customInstructions: 'none', lockingScript: [1, 2, 3], scriptLength: 10, scriptOffset: 0 }; await ctx.activeStorage.insertOutput(initialData); // Create two Output entities with differing array data const entity1 = new EntityOutput_1.EntityOutput(initialData); const entity2 = new EntityOutput_1.EntityOutput({ ...initialData, lockingScript: [1, 2, 4] }); // Verify equals returns false for different arrays expect(entity1.equals(entity2.toApi())).toBe(false); }); // Test: mergeExisting updates entity and database when ei.updated_at > this.updated_at test('3_mergeExisting updates entity and database when ei.updated_at > this.updated_at', async () => { const ctx = ctxs[0]; // Insert initial Output record const initialData = { outputId: 701, created_at: new Date('2023-01-01'), updated_at: new Date('2023-01-02'), userId: 1, transactionId: 103, basketId: 1, spendable: true, change: false, satoshis: 1000, outputDescription: 'Initial Output', vout: 50, type: 'p2pkh', providedBy: 'you', purpose: 'initial', txid: 'txid201', spendingDescription: 'Initial Spending', derivationPrefix: 'm/44', derivationSuffix: '/0/0', senderIdentityKey: 'key201', customInstructions: 'none', lockingScript: [1, 2, 3], scriptLength: 10, scriptOffset: 0, spentBy: undefined }; await ctx.activeStorage.insertOutput(initialData); // Create an Output entity from the initial data const entity = new EntityOutput_1.EntityOutput(initialData); // Simulate the `ei` argument with a later `updated_at` const updatedData = { ...initialData, updated_at: new Date('2023-01-03'), // Later timestamp spendable: false, change: true, type: 'p2sh', providedBy: 'storage', purpose: 'updated', outputDescription: 'Updated Output', spendingDescription: 'Updated Spending', senderIdentityKey: 'key202', customInstructions: 'new instructions', scriptLength: 15, scriptOffset: 5, lockingScript: [4, 5, 6], spentBy: 105 }; const syncMap = (0, src_1.createSyncMap)(); syncMap.transaction.idMap = { 103: 103, 105: 105 }; syncMap.outputBasket.idMap[1] = 1; // Call mergeExisting const wasMergedRaw = await entity.mergeExisting(ctx.activeStorage, undefined, // `since` is not used in this method updatedData, syncMap, undefined // `trx` is not used ); const wasMerged = Boolean(wasMergedRaw); // Verify that wasMerged is true expect(wasMerged).toBe(true); // Verify that the entity is updated expect(entity.spentBy).toBe(105); expect(entity.spendable).toBe(false); expect(entity.change).toBe(true); expect(entity.type).toBe('p2sh'); expect(entity.providedBy).toBe('storage'); expect(entity.purpose).toBe('updated'); expect(entity.outputDescription).toBe('Updated Output'); expect(entity.spendingDescription).toBe('Updated Spending'); expect(entity.senderIdentityKey).toBe('key202'); expect(entity.customInstructions).toBe('new instructions'); expect(entity.scriptLength).toBe(15); expect(entity.scriptOffset).toBe(5); // Convert Buffer to array for comparison if (entity.lockingScript instanceof Buffer) { expect([...entity.lockingScript]).toEqual([4, 5, 6]); } else { expect(entity.lockingScript).toEqual([4, 5, 6]); } // Verify that the database is updated const updatedRecord = await ctx.activeStorage.findOutputs({ partial: { outputId: 701 } }); expect(updatedRecord.length).toBe(1); expect(updatedRecord[0]).toBeDefined(); expect(updatedRecord[0].spendable).toBe(false); expect(updatedRecord[0].type).toBe('p2sh'); // Handle undefined lockingScript gracefully if (updatedRecord[0].lockingScript) { expect(Buffer.from(updatedRecord[0].lockingScript).toJSON().data).toEqual([4, 5, 6]); } else { throw new Error('lockingScript is undefined'); } }); // Test: mergeExisting does not update when ei.updated_at <= this.updated_at test('4_mergeExisting does not update when ei.updated_at <= this.updated_at', async () => { const ctx = ctxs[0]; // Use the same initialData as before const initialData = { outputId: 702, created_at: new Date('2023-01-01'), updated_at: new Date('2023-01-02'), userId: 1, transactionId: 104, basketId: 1, spendable: true, change: false, satoshis: 1000, outputDescription: 'Initial Output', vout: 50, type: 'p2pkh', providedBy: 'you', purpose: 'initial', txid: 'txid202', spendingDescription: 'Initial Spending', derivationPrefix: 'm/44', derivationSuffix: '/0/0', senderIdentityKey: 'key202', customInstructions: 'none', lockingScript: [1, 2, 3], scriptLength: 10, scriptOffset: 0, spentBy: undefined }; await ctx.activeStorage.insertOutput(initialData); // Create an Output entity from the initial data const entity = new EntityOutput_1.EntityOutput(initialData); // Simulate the `ei` argument with an earlier `updated_at` const earlierData = { ...initialData, updated_at: new Date('2023-01-01'), // Earlier timestamp spendable: false }; const syncMap = (0, src_1.createSyncMap)(); syncMap.transaction.idMap = { 104: 104 }; syncMap.outputBasket.idMap[1] = 1; // Call mergeExisting const wasMergedRaw = await entity.mergeExisting(ctx.activeStorage, undefined, earlierData, syncMap, undefined); const wasMerged = Boolean(wasMergedRaw); // Verify that wasMerged is false expect(wasMerged).toBe(false); // Verify that the entity is not updated expect(entity.spendable).toBe(true); // Verify that the database is not updated const unchangedRecord = await ctx.activeStorage.findOutputs({ partial: { outputId: 702 } }); expect(unchangedRecord.length).toBe(1); expect(unchangedRecord[0].spendable).toBe(true); }); // Test: Output entity getters and setters test('Output entity getters and setters', async () => { const now = new Date(); // Initial test data const initialData = { outputId: 701, created_at: now, updated_at: now, userId: 1, transactionId: 103, basketId: 1, spendable: true, change: false, satoshis: 1000, outputDescription: 'Initial Output', vout: 50, type: 'p2pkh', providedBy: 'you', purpose: 'initial', txid: 'txid201', spendingDescription: 'Initial Spending', derivationPrefix: 'm/44', derivationSuffix: '/0/0', senderIdentityKey: 'key201', customInstructions: 'none', lockingScript: [1, 2, 3], scriptLength: 10, scriptOffset: 0, spentBy: 200 }; // Create the Output entity const entity = new EntityOutput_1.EntityOutput(initialData); // Validate getters expect(entity.outputId).toBe(initialData.outputId); expect(entity.created_at).toEqual(initialData.created_at); expect(entity.updated_at).toEqual(initialData.updated_at); expect(entity.userId).toBe(initialData.userId); expect(entity.transactionId).toBe(initialData.transactionId); expect(entity.basketId).toBe(initialData.basketId); expect(entity.spentBy).toBe(initialData.spentBy); expect(entity.vout).toBe(initialData.vout); expect(entity.satoshis).toBe(initialData.satoshis); expect(entity.outputDescription).toBe(initialData.outputDescription); expect(entity.spendable).toBe(initialData.spendable); expect(entity.change).toBe(initialData.change); expect(entity.txid).toBe(initialData.txid); expect(entity.type).toBe(initialData.type); expect(entity.providedBy).toBe(initialData.providedBy); expect(entity.purpose).toBe(initialData.purpose); expect(entity.spendingDescription).toBe(initialData.spendingDescription); expect(entity.derivationPrefix).toBe(initialData.derivationPrefix); expect(entity.derivationSuffix).toBe(initialData.derivationSuffix); expect(entity.senderIdentityKey).toBe(initialData.senderIdentityKey); expect(entity.customInstructions).toBe(initialData.customInstructions); expect(entity.lockingScript).toEqual(initialData.lockingScript); expect(entity.scriptLength).toBe(initialData.scriptLength); expect(entity.scriptOffset).toBe(initialData.scriptOffset); // Validate setters entity.outputId = 800; entity.created_at = new Date('2024-01-01'); entity.updated_at = new Date('2024-01-02'); entity.userId = 2; entity.transactionId = 104; entity.basketId = 2; entity.spentBy = 300; entity.vout = 60; entity.satoshis = 2000; entity.outputDescription = 'Updated Output'; entity.spendable = false; entity.change = true; entity.txid = 'txid202'; entity.type = 'p2sh'; entity.providedBy = 'storage'; entity.purpose = 'updated'; entity.spendingDescription = 'Updated Spending'; entity.derivationPrefix = 'm/45'; entity.derivationSuffix = '/1/0'; entity.senderIdentityKey = 'key202'; entity.customInstructions = 'new instructions'; entity.lockingScript = [4, 5, 6]; entity.scriptLength = 15; entity.scriptOffset = 5; expect(entity.outputId).toBe(800); expect(entity.created_at).toEqual(new Date('2024-01-01')); expect(entity.updated_at).toEqual(new Date('2024-01-02')); expect(entity.userId).toBe(2); expect(entity.transactionId).toBe(104); expect(entity.basketId).toBe(2); expect(entity.spentBy).toBe(300); expect(entity.vout).toBe(60); expect(entity.satoshis).toBe(2000); expect(entity.outputDescription).toBe('Updated Output'); expect(entity.spendable).toBe(false); expect(entity.change).toBe(true); expect(entity.txid).toBe('txid202'); expect(entity.type).toBe('p2sh'); expect(entity.providedBy).toBe('storage'); expect(entity.purpose).toBe('updated'); expect(entity.spendingDescription).toBe('Updated Spending'); expect(entity.derivationPrefix).toBe('m/45'); expect(entity.derivationSuffix).toBe('/1/0'); expect(entity.senderIdentityKey).toBe('key202'); expect(entity.customInstructions).toBe('new instructions'); expect(entity.lockingScript).toEqual([4, 5, 6]); expect(entity.scriptLength).toBe(15); expect(entity.scriptOffset).toBe(5); // Validate `id` setter and getter entity.id = 900; expect(entity.id).toBe(900); expect(entity.outputId).toBe(900); // Validate `entityName` and `entityTable` expect(entity.entityName).toBe('output'); expect(entity.entityTable).toBe('outputs'); }); }); //# sourceMappingURL=OutputTests.test.js.map