From 53aaeb6f99605dcbf74c092344f87377ed34f207 Mon Sep 17 00:00:00 2001 From: Alejo Acosta <alejoacos@gmail.com> Date: Wed, 27 Nov 2024 17:02:37 -0300 Subject: [PATCH] update qiwallet aggregation unit test to use mock provider --- .../unit/qihdwallet-aggregate.unit.test.ts | 140 +++++------------- testcases/qi-wallet-aggregate.json.gz | Bin 604 -> 551 bytes 2 files changed, 39 insertions(+), 101 deletions(-) diff --git a/src/_tests/unit/qihdwallet-aggregate.unit.test.ts b/src/_tests/unit/qihdwallet-aggregate.unit.test.ts index 72233e71..01510da5 100644 --- a/src/_tests/unit/qihdwallet-aggregate.unit.test.ts +++ b/src/_tests/unit/qihdwallet-aggregate.unit.test.ts @@ -3,21 +3,9 @@ import { loadTests } from '../utils.js'; import { QiHDWallet } from '../../wallet/qi-hdwallet.js'; import { Mnemonic } from '../../wallet/mnemonic.js'; import { Zone } from '../../constants/zones.js'; -import { UTXO } from '../../quais.js'; - -// Custom error class for controlled exit -class TestCompletionError extends Error { - constructor(public readonly capturedArgs: any[]) { - super('Test completed successfully'); - this.name = 'TestCompletionError'; - } -} - -function sortByDenomination(inputs: UTXO[], order: 'asc' | 'desc' = 'asc') { - return inputs.sort((a, b) => - order === 'asc' ? (a.denomination || 0) - (b.denomination || 0) : (b.denomination || 0) - (a.denomination || 0), - ); -} +import { QiTransactionResponse } from '../../quais.js'; +import { MockProvider } from './mockProvider.js'; +import { TxInput, TxOutput } from '../../transaction/utxo.js'; interface AggregateTestCase { mnemonic: string; @@ -39,39 +27,37 @@ interface AggregateTestCase { }>; fee: number; expected: { - selection: { - inputs: Array<{ - txhash: string; - index: number; - address: string; - denomination: number; - }>; - spendOutputs: Array<{ - denomination: number; - }>; - changeOutputs: Array<{ - denomination: number; - }>; - }; - inputPubKeys: string[]; - sendAddresses: string[]; - changeAddresses: string[]; + txInputs: Array<TxInput>; + txOutputs: Array<TxOutput>; }; } +// helper method to sort txInputs by txhash +const sortTxInputs = (txInputs: Array<TxInput> | undefined) => { + return (txInputs || []).sort((a, b) => a.txhash.localeCompare(b.txhash)); +}; + +// helper method to sort txOutputs by address and filtering out 'lock' +const sortTxOutputs = (txOutputs: Array<TxOutput> | undefined) => { + return (txOutputs || []) + .map((txOutput) => ({ + address: txOutput.address.toLowerCase(), + denomination: txOutput.denomination, + })) + .sort((a, b) => a.address.localeCompare(b.address)); +}; + describe('QiHDWallet.aggregate', () => { const testCases = loadTests<AggregateTestCase>('qi-wallet-aggregate'); testCases.forEach((testCase) => { - it(`should correctly aggregate UTXOs for wallet with mnemonic`, async () => { - // Create wallet from mnemonic + it(`should correctly aggregate UTXOs for QiHDWallet`, async () => { const mnemonic = Mnemonic.fromPhrase(testCase.mnemonic); const wallet = QiHDWallet.fromMnemonic(mnemonic); - // Mock provider with minimal implementation - wallet.connect({ - getNetwork: async () => ({ chainId: BigInt(1) }), - } as any); + const mockProvider = new MockProvider({ network: BigInt(1) }); + + wallet.connect(mockProvider); // Add addresses to wallet before importing outpoints for (const addressToAdd of testCase.addressesToAdd) { @@ -81,72 +67,24 @@ describe('QiHDWallet.aggregate', () => { // Import test outpoints wallet.importOutpoints(testCase.outpointInfos); - // Spy on prepareTransaction and throw custom error to exit early - wallet['prepareTransaction'] = async (...args) => { - throw new TestCompletionError(args); - }; - - try { - await wallet.aggregate(testCase.zone as any); - assert.fail('Expected TestCompletionError to be thrown'); - } catch (error) { - if (error instanceof TestCompletionError) { - const [selection, inputPubKeys, sendAddresses, changeAddresses] = error.capturedArgs; - - const sortedInputs = sortByDenomination(selection.inputs, 'desc'); - const sortedExpectedInputs = sortByDenomination( - testCase.expected.selection.inputs as UTXO[], - 'desc', - ); + const txResponse = (await wallet.aggregate(testCase.zone)) as QiTransactionResponse; - // Verify selection with complete input properties - assert.deepStrictEqual( - sortedInputs.map((input: UTXO) => ({ - txhash: input.txhash, - index: input.index, - address: input.address, - denomination: input.denomination, - })), - sortedExpectedInputs, - `inputs: expected: ${JSON.stringify(sortedExpectedInputs, null, 2)}, \nactual: ${JSON.stringify(sortedInputs, null, 2)}`, - ); + // assert txResponse is not null or undefined + assert(txResponse !== null && txResponse !== undefined, 'txResponse is null or undefined'); - // Verify spendOutputs - assert.deepStrictEqual( - selection.spendOutputs.map((output: UTXO) => ({ denomination: output.denomination })), - testCase.expected.selection.spendOutputs, - `spendOutputs: expected: ${JSON.stringify(testCase.expected.selection.spendOutputs, null, 2)}, \nactual: ${JSON.stringify(selection.spendOutputs, null, 2)}`, - ); + // assert expected txInputs are equal to captured txInputs + assert.deepStrictEqual( + sortTxInputs(txResponse.txInputs), + sortTxInputs(testCase.expected.txInputs), + `txInputs: expected: ${JSON.stringify(testCase.expected.txInputs, null, 2)}, \nactual: ${JSON.stringify(txResponse.txInputs, null, 2)}`, + ); - // Verify changeOutputs - assert.deepStrictEqual( - selection.changeOutputs.map((output: UTXO) => ({ denomination: output.denomination })), - testCase.expected.selection.changeOutputs, - `changeOutputs: expected: ${JSON.stringify(testCase.expected.selection.changeOutputs, null, 2)}, \nactual: ${JSON.stringify(selection.changeOutputs, null, 2)}`, - ); - - // Verify input public keys - assert.deepStrictEqual( - inputPubKeys, - testCase.expected.inputPubKeys, - `inputPubKeys: expected: ${JSON.stringify(testCase.expected.inputPubKeys, null, 2)}, \nactual: ${JSON.stringify(inputPubKeys, null, 2)}`, - ); - - // Verify addresses - assert.deepStrictEqual( - sendAddresses, - testCase.expected.sendAddresses, - `sendAddresses: expected: ${JSON.stringify(testCase.expected.sendAddresses, null, 2)}, \nactual: ${JSON.stringify(sendAddresses, null, 2)}`, - ); - assert.deepStrictEqual( - changeAddresses, - testCase.expected.changeAddresses, - `changeAddresses: expected: ${JSON.stringify(testCase.expected.changeAddresses, null, 2)}, \nactual: ${JSON.stringify(changeAddresses, null, 2)}`, - ); - } else { - throw error; - } - } + // assert expected txOutputs are equal to captured txOutputs + assert.deepStrictEqual( + sortTxOutputs(txResponse.txOutputs), + sortTxOutputs(testCase.expected.txOutputs), + `txOutputs: expected: ${JSON.stringify(testCase.expected.txOutputs, null, 2)}, \nactual: ${JSON.stringify(txResponse.txOutputs, null, 2)}`, + ); }); }); }); diff --git a/testcases/qi-wallet-aggregate.json.gz b/testcases/qi-wallet-aggregate.json.gz index af0bab08fac376f85e263908dd98f96c2e56891d..5e53107e72c0ba0dc91c3c6b6fa84a3fbc761dd4 100644 GIT binary patch delta 534 zcmV+x0_pwS1g8WCABzYGp>{`+2OfV-kDD+MJ(FKyaoz*in2+AFn?}m1m)@!z3?76P z<3YhBq}BfS8WOfyb`O=R-AYmBfbm#<Z{D*sv-q*_el0xDuMN~_RN;RiKGY2!VNVLg z9XTk}%8*)Vt<aDoq9*nT`T#_k0}iXZ21KF}7KrF<g?mzqx)z$WLR+%O)9`;=se{AJ z)!tSF^{H-DL7>i2o=62+Bgp|u(ss%c)uJB2YSn`z7J5tC2Ce@vRQeMQ3{?hw5S%mE z*#?!d8&hKIj+`cMRCRUc(&vol+rAQQH9`DSgku2%s4^0IhZ#%>2?lHBJaMjF=QS3) zVLxu4&skqcxrer$YRbxxM?8O{Oz>qGaJm#>OxGz-f#w<IY0RD^TV1%{8ZrPD1$LwA zk?73xDVET?CG%i+OXd;XEtv<uTQZOMuPurHuO;rY9Y@iH3EJ<tlyWwUu5P_9Y;#e^ zQvMpQgn>GAR*YNd8z?Nu7q^|+8`E_5W$H~_A2jCPK7{8tUA}|Ug@=FU5Tps^f)`M7 zkwPBjB~5Zx1`tWg<2YszMFr(DPa#VJE=qR}z$h&lOC$dbdwIDJQA2M^4ZA5d(M_r0 zH>D>2d^O{;eVBUPH#cqGZ+5c|pO*PjBuPdegLRgzSCX%y=#hObN{A(YDruN77W~mO Yn<n8a`l%&9FSfq{Mk@wy2QLi(0IRh05C8xG delta 587 zcmV-R0<`_71l$A%ABzYG>EJz)2OfVtZ`&{so$X&iXzn19qAX=|;u;7#v_rST10|j+ zA{0-sC|hok|6b}Vv7HPBf+T?91N6Zo`0n1j18@FoKKnbL&Aie;iAH7K4e_9?a1UFO zAwH0uLahubmDUOk*&}LV_n>z`l-XhTb;p26G{OQAjV*9XN>P?VlUis?ws?Q&eham8 zn5o*@f}lQ>mC6W|Dar#WKx-r^Ku+pLS)yvx9ayPaki<f3NnN4!zI2)XK?7Zue(U># z2OC?VGWOo&Si3F9Y1Xqk+H>x~GxKa)h`N{{-ef_aKnJRfgw|pDlS6{RQaMeWYR7(! z*+aMPmyd(j6H;!WuBV)mJm7yJPbd?78TgzoMG(<-%wwQwLU|mqJIPjK?3aRcfLVr3 z&$<sZ#Q6|O=v9()V^>MeExbx{Zu~0AxkdjiN%XmrxYwp1MPnqWf8tWgvsrX>>NK(Y zksXWqDO?U+=)g(QFQKg<vmht6y&AN03=)h%l&Ko~GzF*F?=<#a7Uq9#V!zVsgMX~# zyRe}b#fDuJoA9F8@QY#-eH@!;WYd2(<K<abVB~i<fL_1v&LD!<AhJT3-*AMnd7f~? zP5Prrzro=dzhgsF@Z$yLf@hF(5knfLIbEbI_aT&&M^VHe3^U4Q8bh-1xyao<0HZW# zES{SBiuD;-^QZc|@o78ca+=sDCHCVyU5dpbp|}1zN!BaLS7CU|zGgW@lHcVtSTN=v ZgAKiO0@roZ<9zO(%|C@Rh~;Sy00008A^`vZ