From 8b0294ee4158f60cd01880eb25b1b8b242346dfd Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 14 Jan 2022 12:50:25 -0300 Subject: [PATCH] better description of coin test selection and using c8 for coverage runtime --- packages/taler-wallet-core/.gitignore | 1 + packages/taler-wallet-core/package.json | 5 +- .../src/operations/withdraw.test.ts | 3 -- .../src/util/coinSelection.test.ts | 51 +++++++++++-------- pnpm-lock.yaml | 36 ++++++++++++- 5 files changed, 69 insertions(+), 27 deletions(-) diff --git a/packages/taler-wallet-core/.gitignore b/packages/taler-wallet-core/.gitignore index 502167fa0..cb5a51ac5 100644 --- a/packages/taler-wallet-core/.gitignore +++ b/packages/taler-wallet-core/.gitignore @@ -1 +1,2 @@ /lib +/coverage diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json index 223aa05e4..76180e159 100644 --- a/packages/taler-wallet-core/package.json +++ b/packages/taler-wallet-core/package.json @@ -16,7 +16,8 @@ "compile": "tsc && rollup -c", "pretty": "prettier --write src", "test": "tsc && ava", - "coverage": "tsc && nyc ava", + "coverage": "tsc && c8 --src src --all ava", + "coverage:html": "tsc && c8 -r html --src src --all ava", "clean": "rimraf dist lib tsconfig.tsbuildinfo" }, "files": [ @@ -42,6 +43,7 @@ "@typescript-eslint/eslint-plugin": "^5.9.0", "@typescript-eslint/parser": "^5.9.0", "ava": "^4.0.0", + "c8": "^7.11.0", "eslint": "^8.6.0", "eslint-config-airbnb-typescript": "^16.1.0", "eslint-plugin-import": "^2.25.4", @@ -49,7 +51,6 @@ "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", "jed": "^1.1.1", - "nyc": "^15.1.0", "po2json": "^0.4.5", "prettier": "^2.5.1", "rimraf": "^3.0.2", diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts b/packages/taler-wallet-core/src/operations/withdraw.test.ts index 179852966..2c890a121 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.test.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts @@ -357,9 +357,6 @@ test("withdrawal selection bug repro", (t) => { const res = selectWithdrawalDenominations(amount, denoms); - console.error("cost", Amounts.stringify(res.totalWithdrawCost)); - console.error("withdraw amount", Amounts.stringify(amount)); - t.assert(Amounts.cmp(res.totalWithdrawCost, amount) <= 0); t.pass(); }); diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts index b4dc2a18b..49f8d1635 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -42,11 +42,12 @@ function fakeAci(current: string, feeDeposit: string): AvailableCoinInfo { }; } -test("coin selection 1", (t) => { +test("it should be able to pay if merchant takes the fees", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.1"), fakeAci("EUR:1.0", "EUR:0.0"), ]; + acis.forEach((x, i) => x.coinPub = String(i)); const res = selectPayCoins({ candidates: { @@ -63,17 +64,18 @@ test("coin selection 1", (t) => { t.fail(); return; } - t.true(res.coinPubs.length === 2); + t.deepEqual(res.coinPubs, ["1", "0"]); t.pass(); }); -test("coin selection 2", (t) => { +test("it should take the last two coins if it pays less fees", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.5"), fakeAci("EUR:1.0", "EUR:0.0"), // Merchant covers the fee, this one shouldn't be used fakeAci("EUR:1.0", "EUR:0.0"), ]; + acis.forEach((x, i) => x.coinPub = String(i)); const res = selectPayCoins({ candidates: { @@ -90,17 +92,18 @@ test("coin selection 2", (t) => { t.fail(); return; } - t.true(res.coinPubs.length === 2); + t.deepEqual(res.coinPubs, ["1", "2"]); t.pass(); }); -test("coin selection 3", (t) => { +test("it should take the last coins if the merchant doest not take all the fee", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.5"), fakeAci("EUR:1.0", "EUR:0.5"), // this coin should be selected instead of previous one with fee fakeAci("EUR:1.0", "EUR:0.0"), - ]; + ] + acis.forEach((x, i) => x.coinPub = String(i)); const res = selectPayCoins({ candidates: { @@ -117,15 +120,15 @@ test("coin selection 3", (t) => { t.fail(); return; } - t.true(res.coinPubs.length === 2); + t.deepEqual(res.coinPubs, ["2", "0"]); t.pass(); }); -test("coin selection 4", (t) => { +test("it should use 3 coins to cover fees and payment", (t) => { const acis: AvailableCoinInfo[] = [ - fakeAci("EUR:1.0", "EUR:0.5"), - fakeAci("EUR:1.0", "EUR:0.5"), - fakeAci("EUR:1.0", "EUR:0.5"), + fakeAci("EUR:1.0", "EUR:0.5"), //contributed value 1 (fee by the merchant) + fakeAci("EUR:1.0", "EUR:0.5"), //contributed value .5 + fakeAci("EUR:1.0", "EUR:0.5"), //contributed value .5 ]; const res = selectPayCoins({ @@ -147,7 +150,7 @@ test("coin selection 4", (t) => { t.pass(); }); -test("coin selection 5", (t) => { +test("it should return undefined if there is not enough coins", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.5"), fakeAci("EUR:1.0", "EUR:0.5"), @@ -169,7 +172,7 @@ test("coin selection 5", (t) => { t.pass(); }); -test("coin selection 6", (t) => { +test("it should return undefined if there is not enough coins (taking into account fees)", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.5"), fakeAci("EUR:1.0", "EUR:0.5"), @@ -188,7 +191,7 @@ test("coin selection 6", (t) => { t.pass(); }); -test("coin selection 7", (t) => { +test("it should not count into customer fee if merchant can afford it", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.1"), fakeAci("EUR:1.0", "EUR:0.1"), @@ -211,13 +214,15 @@ test("coin selection 7", (t) => { t.pass(); }); -test("coin selection 8", (t) => { +test("it should use the coins that spent less relative fee", (t) => { const acis: AvailableCoinInfo[] = [ fakeAci("EUR:1.0", "EUR:0.2"), fakeAci("EUR:0.1", "EUR:0.2"), fakeAci("EUR:0.05", "EUR:0.05"), fakeAci("EUR:0.05", "EUR:0.05"), ]; + acis.forEach((x, i) => x.coinPub = String(i)); + const res = selectPayCoins({ candidates: { candidateCoins: acis, @@ -228,8 +233,11 @@ test("coin selection 8", (t) => { wireFeeLimit: a("EUR:0"), wireFeeAmortization: 1, }); - t.truthy(res); - t.true(res!.coinContributions.length === 3); + if (!res) { + t.fail(); + return; + } + t.deepEqual(res.coinPubs, ["0", "2", "3"]); t.pass(); }); @@ -248,10 +256,13 @@ test("coin selection 9", (t) => { wireFeeLimit: a("EUR:0"), wireFeeAmortization: 1, }); - t.truthy(res); - t.true(res!.coinContributions.length === 2); + if (!res) { + t.fail(); + return; + } + t.true(res.coinContributions.length === 2); t.true( - Amounts.cmp(Amounts.sum(res!.coinContributions).amount, "EUR:1.2") === 0, + Amounts.cmp(Amounts.sum(res.coinContributions).amount, "EUR:1.2") === 0, ); t.pass(); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d662f139c..33b57d498 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -230,6 +230,7 @@ importers: ava: ^4.0.0 axios: ^0.24.0 big-integer: ^1.6.51 + c8: ^7.11.0 eslint: ^8.6.0 eslint-config-airbnb-typescript: ^16.1.0 eslint-plugin-import: ^2.25.4 @@ -238,7 +239,6 @@ importers: eslint-plugin-react-hooks: ^4.3.0 fflate: ^0.7.2 jed: ^1.1.1 - nyc: ^15.1.0 po2json: ^0.4.5 prettier: ^2.5.1 rimraf: ^3.0.2 @@ -264,6 +264,7 @@ importers: '@typescript-eslint/eslint-plugin': 5.9.0_bd2fd93dbcc607ad2f21b784bccfe0c8 '@typescript-eslint/parser': 5.9.0_eslint@8.6.0+typescript@4.5.4 ava: 4.0.0_@ava+typescript@3.0.1 + c8: 7.11.0 eslint: 8.6.0 eslint-config-airbnb-typescript: 16.1.0_f58c50c65f5161471396f16cd51518fd eslint-plugin-import: 2.25.4_eslint@8.6.0 @@ -271,7 +272,6 @@ importers: eslint-plugin-react: 7.28.0_eslint@8.6.0 eslint-plugin-react-hooks: 4.3.0_eslint@8.6.0 jed: 1.1.1 - nyc: 15.1.0 po2json: 0.4.5 prettier: 2.5.1 rimraf: 3.0.2 @@ -5289,6 +5289,10 @@ packages: resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} dev: true + /@bcoe/v8-coverage/0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + /@cnakazawa/watch/1.0.4: resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==} engines: {node: '>=0.1.95'} @@ -11930,6 +11934,25 @@ packages: engines: {node: '>= 0.8'} dev: true + /c8/7.11.0: + resolution: {integrity: sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==} + engines: {node: '>=10.12.0'} + hasBin: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@istanbuljs/schema': 0.1.3 + find-up: 5.0.0 + foreground-child: 2.0.0 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-report: 3.0.0 + istanbul-reports: 3.1.3 + rimraf: 3.0.2 + test-exclude: 6.0.0 + v8-to-istanbul: 8.1.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + dev: true + /cacache/12.0.4: resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==} dependencies: @@ -23670,6 +23693,15 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true + /v8-to-istanbul/8.1.1: + resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} + engines: {node: '>=10.12.0'} + dependencies: + '@types/istanbul-lib-coverage': 2.0.3 + convert-source-map: 1.8.0 + source-map: 0.7.3 + dev: true + /validate-npm-package-license/3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: