From 4e96088d9bdff9d5440034059c78668ae0a018ea Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Mon, 9 Jan 2023 19:08:25 -0800 Subject: [PATCH] chore(ERTP): AmountMath compare should be same as Key compare' --- packages/ERTP/package.json | 4 +-- .../mathHelpers/test-copyBagMathHelpers.js | 2 +- .../mathHelpers/test-copySetMathHelpers.js | 2 +- .../mathHelpers/test-natMathHelpers.js | 2 +- .../mathHelpers/test-setMathHelpers.js | 2 +- .../mathHelpers/test-strSetMathHelpers.js | 2 +- .../test/unitTests/test-amount-key-arith.js | 22 ++++++++++++++++ .../test/unitTests/test-amountProperties.js | 24 ++--------------- packages/ERTP/tools/arb-amount.js | 26 +++++++++++++++++++ .../mathHelpers => tools}/mockBrand.js | 4 +-- 10 files changed, 59 insertions(+), 31 deletions(-) create mode 100644 packages/ERTP/test/unitTests/test-amount-key-arith.js create mode 100644 packages/ERTP/tools/arb-amount.js rename packages/ERTP/{test/unitTests/mathHelpers => tools}/mockBrand.js (74%) diff --git a/packages/ERTP/package.json b/packages/ERTP/package.json index 4b6fbab2cbfe..f235ba7274e8 100644 --- a/packages/ERTP/package.json +++ b/packages/ERTP/package.json @@ -48,11 +48,11 @@ "@endo/eventual-send": "^0.16.8", "@endo/far": "^0.2.14", "@endo/marshal": "^0.8.1", - "@endo/promise-kit": "^0.2.52" + "@endo/promise-kit": "^0.2.52", + "@fast-check/ava": "^1.1.3" }, "devDependencies": { "@endo/bundle-source": "^2.4.2", - "@fast-check/ava": "^1.1.3", "ava": "^5.1.0", "tsd": "^0.25.0" }, diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js index 0a7a5b56f4a3..262c6d310a0d 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-copyBagMathHelpers.js @@ -6,7 +6,7 @@ import { } from '@agoric/store'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockBrand } from '../../../tools/mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js index f3a5504eef4d..8822190fd7a8 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-copySetMathHelpers.js @@ -2,7 +2,7 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { getCopySetKeys, makeCopySet } from '@agoric/store'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockBrand } from '../../../tools/mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js index 102af4db0de5..778a3d555bb1 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-natMathHelpers.js @@ -4,7 +4,7 @@ import { M } from '@agoric/store'; import { Far } from '@endo/marshal'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockBrand } from '../../../tools/mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js index 7d972568bc70..52dfe25c5471 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-setMathHelpers.js @@ -4,7 +4,7 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { Far } from '@endo/marshal'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockBrand } from '../../../tools/mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js b/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js index b268a5d0644c..3b3c91a5566b 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js +++ b/packages/ERTP/test/unitTests/mathHelpers/test-strSetMathHelpers.js @@ -2,7 +2,7 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; import { AmountMath as m, AssetKind } from '../../../src/index.js'; -import { mockBrand } from './mockBrand.js'; +import { mockBrand } from '../../../tools/mockBrand.js'; // The "unit tests" for MathHelpers actually make the calls through // AmountMath so that we can test that any duplication is handled diff --git a/packages/ERTP/test/unitTests/test-amount-key-arith.js b/packages/ERTP/test/unitTests/test-amount-key-arith.js new file mode 100644 index 000000000000..f0e086d55fc5 --- /dev/null +++ b/packages/ERTP/test/unitTests/test-amount-key-arith.js @@ -0,0 +1,22 @@ +import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; +import { fc } from '@fast-check/ava'; +import { keyEQ, keyGTE } from '@agoric/store'; + +import { AmountMath as m } from '../../src/index.js'; +import { arbAmount } from '../../tools/arb-amount.js'; + +test('amount equality iff key equality', async t => { + await fc.assert( + fc.property(fc.record({ x: arbAmount, y: arbAmount }), ({ x, y }) => { + return t.true(m.isEqual(x, y) === keyEQ(x, y)); + }), + ); +}); + +test('amount >= iff key >=', async t => { + await fc.assert( + fc.property(fc.record({ x: arbAmount, y: arbAmount }), ({ x, y }) => { + return t.true(m.isGTE(x, y) === keyGTE(x, y)); + }), + ); +}); diff --git a/packages/ERTP/test/unitTests/test-amountProperties.js b/packages/ERTP/test/unitTests/test-amountProperties.js index 6bfa2d718785..ba167c7b0469 100644 --- a/packages/ERTP/test/unitTests/test-amountProperties.js +++ b/packages/ERTP/test/unitTests/test-amountProperties.js @@ -1,29 +1,9 @@ import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js'; -import { makeCopyBag } from '@agoric/store'; import { fc } from '@fast-check/ava'; import { AmountMath as m, AssetKind } from '../../src/index.js'; -import { mockBrand } from './mathHelpers/mockBrand.js'; - -// Perhaps makeCopyBag should coalesce duplicate labels, but for now, it does -// not. -const distinctLabels = pairs => - new Set(pairs.map(([label, _qty]) => label)).size === pairs.length; -const positiveCounts = pairs => - pairs.filter(([_l, qty]) => qty > 0n).length === pairs.length; -const arbBagContents = fc - .nat(7) - .chain(size => - fc.array( - fc.tuple(fc.string(), fc.bigUint({ max: 1_000_000_000_000_000n })), - { minLength: size, maxLength: size }, - ), - ) - .filter(pairs => distinctLabels(pairs) && positiveCounts(pairs)); - -const arbAmount = arbBagContents.map(contents => - m.make(mockBrand, harden(makeCopyBag(contents))), -); +import { mockBrand } from '../../tools/mockBrand.js'; +import { arbAmount } from '../../tools/arb-amount.js'; // Note: we write P => Q as !P || Q since JS has no logical => operator const implies = (p, q) => !p || q; diff --git a/packages/ERTP/tools/arb-amount.js b/packages/ERTP/tools/arb-amount.js new file mode 100644 index 000000000000..154211aca46d --- /dev/null +++ b/packages/ERTP/tools/arb-amount.js @@ -0,0 +1,26 @@ +import { makeCopyBag } from '@agoric/store'; +import { fc } from '@fast-check/ava'; + +import { AmountMath as m } from '../src/index.js'; +import { mockBrand } from './mockBrand.js'; + +// Perhaps makeCopyBag should coalesce duplicate labels, but for now, it does +// not. +const distinctLabels = pairs => + new Set(pairs.map(([label, _qty]) => label)).size === pairs.length; +const positiveCounts = pairs => + pairs.filter(([_l, qty]) => qty > 0n).length === pairs.length; +const arbBagContents = fc + .nat(7) + .chain(size => + fc.array( + fc.tuple(fc.string(), fc.bigUint({ max: 1_000_000_000_000_000n })), + { minLength: size, maxLength: size }, + ), + ) + .filter(pairs => distinctLabels(pairs) && positiveCounts(pairs)); + +// TODO: should include many non-bag amounts too +export const arbAmount = arbBagContents.map(contents => + m.make(mockBrand, harden(makeCopyBag(contents))), +); diff --git a/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js b/packages/ERTP/tools/mockBrand.js similarity index 74% rename from packages/ERTP/test/unitTests/mathHelpers/mockBrand.js rename to packages/ERTP/tools/mockBrand.js index 3b0dd05597f0..e7424e29a803 100644 --- a/packages/ERTP/test/unitTests/mathHelpers/mockBrand.js +++ b/packages/ERTP/tools/mockBrand.js @@ -1,10 +1,10 @@ import { Far } from '@endo/marshal'; -import { AssetKind } from '../../../src/index.js'; +import { AssetKind } from '../src/index.js'; /** @type {Brand} */ export const mockBrand = Far('brand', { // eslint-disable-next-line no-unused-vars - isMyIssuer: async allegedIssuer => false, + isMyIssuer: async _allegedIssuer => false, getAllegedName: () => 'mock', getAmountShape: () => {}, getDisplayInfo: () => ({