Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(pass-style): Make @fast-check/ava a devDependency #2645

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/marshal/test/encodePassable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import test from '@endo/ses-ava/prepare-endo.js';

import { fc } from '@fast-check/ava';
import { Remotable } from '@endo/pass-style';
import { arbPassable } from '@endo/pass-style/tools.js';
import { makeArbitraries } from '@endo/pass-style/tools.js';
import { assert, Fail, q, b } from '@endo/errors';

import {
Expand All @@ -15,6 +15,8 @@ import {
import { compareRank, makeFullOrderComparatorKit } from '../src/rankOrder.js';
import { unsortedSample } from './_marshal-test-data.js';

const { arbPassable } = makeArbitraries(fc);

const statelessEncodePassableLegacy = makeEncodePassable();

const makeSimplePassableKit = ({ statelessSuffix } = {}) => {
Expand Down
4 changes: 3 additions & 1 deletion packages/marshal/test/rankOrder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import test from '@endo/ses-ava/prepare-endo.js';
// eslint-disable-next-line import/no-extraneous-dependencies
import { fc } from '@fast-check/ava';
import { makeTagged } from '@endo/pass-style';
import { arbPassable } from '@endo/pass-style/tools.js';
import { makeArbitraries } from '@endo/pass-style/tools.js';

import { q } from '@endo/errors';
import {
Expand All @@ -18,6 +18,8 @@ import {
} from '../src/rankOrder.js';
import { unsortedSample, sortedSample } from './_marshal-test-data.js';

const { arbPassable } = makeArbitraries(fc);

test('compareRank is reflexive', async t => {
await fc.assert(
fc.property(arbPassable, x => {
Expand Down
4 changes: 2 additions & 2 deletions packages/pass-style/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
"@endo/env-options": "workspace:^",
"@endo/errors": "workspace:^",
"@endo/eventual-send": "workspace:^",
"@endo/promise-kit": "workspace:^",
"@fast-check/ava": "^1.1.5"
"@endo/promise-kit": "workspace:^"
},
"devDependencies": {
"@endo/init": "workspace:^",
"@endo/ses-ava": "workspace:^",
"@fast-check/ava": "^1.1.5",
"ava": "^6.1.3",
"babel-eslint": "^10.1.0",
"eslint": "^8.57.0",
Expand Down
8 changes: 2 additions & 6 deletions packages/pass-style/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
// including testing done by other packages. Code dependent only on this
// package from production purposes, such as production code in importing
// packages, should avoid importing tools.
// Note that locally, the depenencies of tools are still listed as
// Note that locally, the dependencies of tools are still listed as
// `dependencies` rather than `devDependencies`.

export {
exampleAlice,
exampleBob,
exampleCarol,
arbString,
arbKeyLeaf,
arbLeaf,
arbKey,
arbPassable,
makeArbitraries,
} from './tools/arb-passable.js';
251 changes: 132 additions & 119 deletions packages/pass-style/tools/arb-passable.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// @ts-check
import '../src/types.js';
import { fc } from '@fast-check/ava';
import { Far } from '../src/make-far.js';
import { makeTagged } from '../src/makeTagged.js';

Expand All @@ -12,130 +11,144 @@ export const exampleAlice = Far('alice', {});
export const exampleBob = Far('bob', {});
export const exampleCarol = Far('carol', {});

export const arbString = fc.oneof(fc.string(), fc.fullUnicodeString());
/** @param {typeof import('@fast-check/ava').fc} fc */
export const makeArbitraries = fc => {
const arbString = fc.oneof(fc.string(), fc.fullUnicodeString());

const keyableLeaves = [
fc.constantFrom(null, undefined, false, true),
arbString,
arbString.map(s => Symbol.for(s)),
// primordial symbols and registered lookalikes
fc.constantFrom(
...Object.getOwnPropertyNames(Symbol).flatMap(k => {
const v = Symbol[k];
if (typeof v !== 'symbol') return [];
return [v, Symbol.for(k), Symbol.for(`@@${k}`)];
}),
),
fc.bigInt(),
fc.integer(),
fc.constantFrom(-0, NaN, Infinity, -Infinity),
fc.record({}),
fc.constantFrom(exampleAlice, exampleBob, exampleCarol),
];
const keyableLeaves = [
fc.constantFrom(null, undefined, false, true),
arbString,
arbString.map(s => Symbol.for(s)),
// primordial symbols and registered lookalikes
fc.constantFrom(
...Object.getOwnPropertyNames(Symbol).flatMap(k => {
const v = Symbol[k];
if (typeof v !== 'symbol') return [];
return [v, Symbol.for(k), Symbol.for(`@@${k}`)];
}),
),
fc.bigInt(),
fc.integer(),
fc.constantFrom(-0, NaN, Infinity, -Infinity),
fc.record({}),
fc.constantFrom(exampleAlice, exampleBob, exampleCarol),
];

export const arbKeyLeaf = fc.oneof(...keyableLeaves);
const arbKeyLeaf = fc.oneof(...keyableLeaves);

export const arbLeaf = fc.oneof(
...keyableLeaves,
arbString.map(s => Error(s)),
// unresolved promise
fc.constant(new Promise(() => {})),
);
const arbLeaf = fc.oneof(
...keyableLeaves,
arbString.map(s => Error(s)),
// unresolved promise
fc.constant(new Promise(() => {})),
);

const { keyDag } = fc.letrec(tie => {
return {
keyDag: fc.oneof(
{ withCrossShrink: true },
arbKeyLeaf,
fc.array(tie('keyDag')),
fc.dictionary(
arbString.filter(s => s !== 'then'),
tie('keyDag'),
const { keyDag } = fc.letrec(tie => {
return {
keyDag: fc.oneof(
{ withCrossShrink: true },
arbKeyLeaf,
fc.array(tie('keyDag')),
fc.dictionary(
arbString.filter(s => s !== 'then'),
tie('keyDag'),
),
),
),
};
});
};
});

const { arbDag } = fc.letrec(tie => {
return {
arbDag: fc.oneof(
{ withCrossShrink: true },
arbLeaf,
fc.array(tie('arbDag')),
fc.dictionary(
arbString.filter(s => s !== 'then'),
tie('arbDag'),
),
// A promise for a passable.
tie('arbDag').map(v => Promise.resolve(v)),
// A tagged value, either of arbitrary type with arbitrary payload
// or of known type with arbitrary or explicitly valid payload.
// Ordered by increasing complexity.
fc
.oneof(
fc.record({ type: arbString, payload: tie('arbDag') }),
fc.record({
type: fc.constantFrom('copySet'),
payload: fc.oneof(
tie('arbDag'),
// copySet valid payload is an array of unique passables.
// TODO: A valid copySet payload must be a reverse sorted array,
// so we should generate some of those as well.
fc.uniqueArray(tie('arbDag')),
),
}),
fc.record({
type: fc.constantFrom('copyBag'),
payload: fc.oneof(
tie('arbDag'),
// copyBag valid payload is an array of [passable, count] tuples
// in which each passable is unique.
// TODO: A valid copyBag payload must be a reverse sorted array,
// so we should generate some of those as well.
fc.uniqueArray(fc.tuple(tie('arbDag'), fc.bigInt()), {
selector: entry => entry[0],
}),
),
}),
fc.record({
type: fc.constantFrom('copyMap'),
payload: fc.oneof(
tie('arbDag'),
// copyMap valid payload is a
// `{ keys: Passable[], values: Passable[]}`
// record in which keys are unique and both arrays have the
// same length.
// TODO: In a valid copyMap payload, the keys must be a
// reverse sorted array, so we should generate some of
// those as well.
fc
.uniqueArray(
fc.record({ key: tie('arbDag'), value: tie('arbDag') }),
{ selector: entry => entry.key },
)
.map(entries => ({
keys: entries.map(({ key }) => key),
values: entries.map(({ value }) => value),
})),
),
}),
)
.map(({ type, payload }) =>
makeTagged(
type,
/** @type {import('../src/types.js').Passable} */ (payload),
),
const { arbDag } = fc.letrec(tie => {
return {
arbDag: fc.oneof(
{ withCrossShrink: true },
arbLeaf,
fc.array(tie('arbDag')),
fc.dictionary(
arbString.filter(s => s !== 'then'),
tie('arbDag'),
),
),
};
});
// A promise for a passable.
tie('arbDag').map(v => Promise.resolve(v)),
// A tagged value, either of arbitrary type with arbitrary payload
// or of known type with arbitrary or explicitly valid payload.
// Ordered by increasing complexity.
fc
.oneof(
fc.record({ type: arbString, payload: tie('arbDag') }),
fc.record({
type: fc.constantFrom('copySet'),
payload: fc.oneof(
tie('arbDag'),
// copySet valid payload is an array of unique passables.
// TODO: A valid copySet payload must be a reverse sorted array,
// so we should generate some of those as well.
fc.uniqueArray(tie('arbDag')),
),
}),
fc.record({
type: fc.constantFrom('copyBag'),
payload: fc.oneof(
tie('arbDag'),
// copyBag valid payload is an array of [passable, count] tuples
// in which each passable is unique.
// TODO: A valid copyBag payload must be a reverse sorted array,
// so we should generate some of those as well.
fc.uniqueArray(fc.tuple(tie('arbDag'), fc.bigInt()), {
selector: entry => entry[0],
}),
),
}),
fc.record({
type: fc.constantFrom('copyMap'),
payload: fc.oneof(
tie('arbDag'),
// copyMap valid payload is a
// `{ keys: Passable[], values: Passable[]}`
// record in which keys are unique and both arrays have the
// same length.
// TODO: In a valid copyMap payload, the keys must be a
// reverse sorted array, so we should generate some of
// those as well.
fc
.uniqueArray(
fc.record({ key: tie('arbDag'), value: tie('arbDag') }),
{ selector: entry => entry.key },
)
.map(entries => ({
keys: entries.map(({ key }) => key),
values: entries.map(({ value }) => value),
})),
),
}),
)
.map(({ type, payload }) => {
const passable = /** @type {import('../src/types.js').Passable} */ (
payload
);
return makeTagged(type, passable);
}),
),
};
});

/**
* A factory for arbitrary keys.
*/
export const arbKey = keyDag.map(x => harden(x));
/**
* A factory for arbitrary keys.
*/
const arbKey = keyDag.map(x => harden(x));

/**
* A factory for arbitrary passables.
*/
export const arbPassable = arbDag.map(x => harden(x));
/**
* A factory for arbitrary passables.
*/
const arbPassable = arbDag.map(x => harden(x));

return {
exampleAlice,
exampleBob,
exampleCarol,
arbString,
arbKeyLeaf,
arbLeaf,
arbKey,
arbPassable,
};
};
9 changes: 3 additions & 6 deletions packages/patterns/test/copySet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ import test from '@endo/ses-ava/prepare-endo.js';

import { fc } from '@fast-check/ava';
import { makeTagged, getTag, passStyleOf } from '@endo/marshal';
import {
arbKey,
exampleAlice,
exampleBob,
exampleCarol,
} from '@endo/pass-style/tools.js';
import { makeArbitraries } from '@endo/pass-style/tools.js';
import { Fail, q } from '@endo/errors';
import {
isCopySet,
Expand All @@ -28,6 +23,8 @@ import { M, matches } from '../src/patterns/patternMatchers.js';

import '../src/types.js';

const { arbKey, exampleAlice, exampleBob, exampleCarol } = makeArbitraries(fc);

/** @import { Key } from '../src/types.js'; */

const assertIsCopySet = (t, s) => {
Expand Down
Loading