You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

fast-spec

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-spec - npm Package Compare versions

Comparing version
0.0.4
to
0.0.5
+24
lib/internal/union-graph.d.ts
export declare class UnionGraph {
/**
* Store the rootNode corresponding to a given node
*
* `{ [node]: rootNode }`
*/
private readonly parentNode;
/**
* Store all the nodes linked to a given rootNode (including itself)
*
* `{ [ rootNode ]: Set<nodes including rootNode> }`
*/
private readonly links;
/**
* Create a link between two nodes (must have different names)
*
* Unknown nodes will be created
*/
addLink(nodeA: string, nodeB: string): void;
/**
* Extract all the relationships declared so far
*/
values(): string[][];
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class UnionGraph {
constructor() {
/**
* Store the rootNode corresponding to a given node
*
* `{ [node]: rootNode }`
*/
this.parentNode = new Map();
/**
* Store all the nodes linked to a given rootNode (including itself)
*
* `{ [ rootNode ]: Set<nodes including rootNode> }`
*/
this.links = new Map();
}
/**
* Create a link between two nodes (must have different names)
*
* Unknown nodes will be created
*/
addLink(nodeA, nodeB) {
if (nodeA === nodeB) {
// stop: no need for a link
return;
}
const parentNodeA = this.parentNode.get(nodeA);
const parentNodeB = this.parentNode.get(nodeB);
if (parentNodeA && parentNodeB) {
if (parentNodeA === parentNodeB) {
// stop: there is already a link between nodeA and nodeB
// as they reference the same parent
return;
}
// merge A and B
const linksForParentA = this.links.get(parentNodeA);
const linksForParentB = this.links.get(parentNodeB);
for (const lnkB of linksForParentB)
linksForParentA.add(lnkB);
// update the parent for B and its brothers to be the same as the one for A
for (const lnkB of linksForParentB)
this.parentNode.set(lnkB, parentNodeA);
// remove B
this.links.delete(parentNodeB);
}
else if (parentNodeA) {
// append nodeB into already known this.links for nodeA
this.links.get(parentNodeA).add(nodeB);
// declare the parent for B to be the same as the one for A
this.parentNode.set(nodeB, parentNodeA);
}
else if (parentNodeB) {
// append nodeA into already known this.links for nodeB
this.links.get(parentNodeB).add(nodeA);
// declare the parent for A to be the same as the one for B
this.parentNode.set(nodeA, parentNodeB);
}
else {
// create a new equlity relation
this.links.set(nodeA, new Set([nodeA, nodeB]));
// declare the parent of A and B to be A
this.parentNode.set(nodeA, nodeA);
this.parentNode.set(nodeB, nodeA);
}
}
/**
* Extract all the relationships declared so far
*/
values() {
return Array.from(this.links.values()).map(vs => Array.from(vs));
}
}
exports.UnionGraph = UnionGraph;
//# sourceMappingURL=union-graph.js.map
{"version":3,"file":"union-graph.js","sourceRoot":"","sources":["../../src/internal/union-graph.ts"],"names":[],"mappings":";;AAAA,MAAa,UAAU;IAAvB;QACE;;;;WAIG;QACc,eAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;QAExD;;;;WAIG;QACc,UAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAuD1D,CAAC;IArDC;;;;OAIG;IACH,OAAO,CAAC,KAAa,EAAE,KAAa;QAClC,IAAI,KAAK,KAAK,KAAK,EAAE;YACnB,2BAA2B;YAC3B,OAAO;SACR;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,WAAW,IAAI,WAAW,EAAE;YAC9B,IAAI,WAAW,KAAK,WAAW,EAAE;gBAC/B,wDAAwD;gBACxD,0CAA0C;gBAC1C,OAAO;aACR;YACD,gBAAgB;YAChB,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC;YACrD,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC;YACrD,KAAK,MAAM,IAAI,IAAI,eAAe;gBAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9D,2EAA2E;YAC3E,KAAK,MAAM,IAAI,IAAI,eAAe;gBAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAC3E,WAAW;YACX,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;SAChC;aAAM,IAAI,WAAW,EAAE;YACtB,uDAAuD;YACvD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxC,2DAA2D;YAC3D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;SACzC;aAAM,IAAI,WAAW,EAAE;YACtB,uDAAuD;YACvD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxC,2DAA2D;YAC3D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;SACzC;aAAM;YACL,gCAAgC;YAChC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;YAC/C,wCAAwC;YACxC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;SACnC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;CACF;AApED,gCAoEC"}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const union_graph_1 = require("./union-graph");
test('should be able to declare an empty graph', () => {
// Arrange / Act
const union = new union_graph_1.UnionGraph();
// Act
expect(reorder(union.values())).toEqual([]);
});
test('should be able to declare a first link', () => {
// Arrange
const union = new union_graph_1.UnionGraph();
// Act
union.addLink('a', 'b');
// Assert
expect(reorder(union.values())).toEqual([['a', 'b']]);
});
test('should be able to add nodes without any of them from the tree', () => {
// Arrange
const union = new union_graph_1.UnionGraph();
// Act
union.addLink('a', 'b');
union.addLink('c', 'd');
// Assert
expect(reorder(union.values())).toEqual([['a', 'b'], ['c', 'd']]);
});
test('should be able to add a new node to an existing tree', () => {
// Arrange
const union = new union_graph_1.UnionGraph();
// Act
union.addLink('a', 'b');
union.addLink('a', 'c');
// Assert
expect(reorder(union.values())).toEqual([['a', 'b', 'c']]);
});
test('should be able to add a new node to an existing tree by referencing the other node', () => {
// Arrange
const union = new union_graph_1.UnionGraph();
// Act
union.addLink('a', 'b');
union.addLink('b', 'c');
// Assert
expect(reorder(union.values())).toEqual([['a', 'b', 'c']]);
});
test('should be able to merge two trees together', () => {
// Arrange
const union = new union_graph_1.UnionGraph();
// Act
union.addLink('a', 'b');
union.addLink('c', 'd');
union.addLink('b', 'd');
// Assert
expect(reorder(union.values())).toEqual([['a', 'b', 'c', 'd']]);
});
test('should be able to add new nodes on merged trees', () => {
// Arrange
const union = new union_graph_1.UnionGraph();
// Act
union.addLink('a', 'b');
union.addLink('c', 'd');
union.addLink('b', 'd');
union.addLink('b', 'e');
union.addLink('c', 'f');
// Assert
expect(reorder(union.values())).toEqual([['a', 'b', 'c', 'd', 'e', 'f']]);
});
// Helper
function reorder(values) {
return values.map(vs => vs.sort()).sort((vsA, vsB) => vsA[0].localeCompare(vsB[0]));
}
//# sourceMappingURL=union-graph.spec.js.map
{"version":3,"file":"union-graph.spec.js","sourceRoot":"","sources":["../../src/internal/union-graph.spec.ts"],"names":[],"mappings":"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"}
+10
-33

@@ -6,2 +6,3 @@ "use strict";

const fast_check_1 = require("fast-check");
const union_graph_1 = require("./internal/union-graph");
var SpecDefType;

@@ -134,28 +135,3 @@ (function (SpecDefType) {

.noShrink();
const equalities = new Map();
const addEquality = (specA, specB) => {
if (specA === specB) {
return;
}
const alreadyKnowA = equalities.has(specA);
const alreadyKnowB = equalities.has(specB);
if (alreadyKnowA && alreadyKnowB) {
// merge A and B
equalities.set(specA, new Set([...equalities.get(specA), ...equalities.get(specB)]));
// remove B
equalities.delete(specB);
}
else if (alreadyKnowA) {
// append specB into already known equalities for specA
equalities.get(specA).add(specB);
}
else if (alreadyKnowB) {
// append specA into already known equalities for specB
equalities.get(specB).add(specA);
}
else {
// create a new equlity relation
equalities.set(specA, new Set([specA, specB]));
}
};
const union = new union_graph_1.UnionGraph();
const previousSpecs = new Map();

@@ -178,5 +154,8 @@ for (const spec of fast_check_1.sample(specArb, settings && settings.numSamples)) {

// Combination only rely on constants
if (lodash_isequal_1.default(spec.build1([]), spec.build2([]))) {
addEquality(minSpecLabel, maxSpecLabel);
try {
if (lodash_isequal_1.default(spec.build1([]), spec.build2([]))) {
union.addLink(minSpecLabel, maxSpecLabel);
}
}
catch (_err) { }
}

@@ -187,12 +166,10 @@ else {

return lodash_isequal_1.default(spec.build1(t), spec.build2(t));
}), { numRuns: settings && settings.numFuzz });
}), { numRuns: settings && settings.numFuzz, endOnFailure: true });
if (!out.failed)
addEquality(minSpecLabel, maxSpecLabel);
union.addLink(minSpecLabel, maxSpecLabel);
}
}
return Array.from(equalities.values()).map(vs => Array.from(vs)
.sort()
.join(' == '));
return union.values().map(vs => vs.sort().join(' == '));
}
exports.findSpecs = findSpecs;
//# sourceMappingURL=fast-spec.js.map
{
"name": "fast-spec",
"version": "0.0.4",
"version": "0.0.5",
"description": "Discover laws in your code like with QuickSpec",

@@ -10,2 +10,4 @@ "main": "lib/fast-spec.js",

"build": "tsc",
"test": "jest",
"example": "ts-node examples/index.ts",
"format": "prettier --write \"**/*.{js,ts}\"",

@@ -35,7 +37,21 @@ "format:check": "prettier --list-different \"**/*.{js,ts}\""

"devDependencies": {
"@types/jest": "^24.0.19",
"@types/lodash.isequal": "^4.5.5",
"@types/node": "^12.11.1",
"jest": "^24.9.0",
"prettier": "^1.18.2",
"ts-jest": "^24.1.0",
"ts-node": "^8.4.1",
"typescript": "^3.6.4"
},
"jest": {
"globals": {
"ts-jest": {
"tsConfig": "tsconfig.json"
}
},
"transform": {
"^.+\\.ts$": "ts-jest"
}
}
}

@@ -49,2 +49,2 @@ # fast-spec

*Live example available at https://runkit.com/dubzzz/hello-world-fast-spec*
*Live example available at https://runkit.com/dubzzz/hello-world-fast-spec-v2*
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fc = tslib_1.__importStar(require("fast-check"));
const fast_spec_1 = require("./fast-spec");
console.log(fast_spec_1.findSpecs([
fast_spec_1.funcDef("concat", 2, (a, b) => [...a, ...b]),
fast_spec_1.funcDef("reverse", 1, (a) => [...a].reverse()),
fast_spec_1.instDef("[]", []),
fast_spec_1.varDef("x", fc.array(fc.char()))
]));
console.log(fast_spec_1.findSpecs([
fast_spec_1.funcDef("concat", 2, (a, b) => [...a, ...b]),
fast_spec_1.funcDef("reverse", 1, (a) => [...a].reverse()),
fast_spec_1.funcDef("length", 1, (a) => a.length),
fast_spec_1.funcDef("map", 1, (a) => a.map(s => s + s)),
fast_spec_1.instDef("[]", []),
fast_spec_1.varDef("x", fc.array(fc.char()))
]));
console.log(fast_spec_1.findSpecs([
fast_spec_1.funcDef("concat", 2, (a, b) => [...a, ...b]),
fast_spec_1.instDef("[]", []),
fast_spec_1.varDef("x", fc.array(fc.char()))
]));
console.log(fast_spec_1.findSpecs([
fast_spec_1.funcDef("mul", 2, (a, b) => a * b),
fast_spec_1.funcDef("div", 2, (a, b) => a / b),
fast_spec_1.funcDef("plus", 2, (a, b) => a + b),
fast_spec_1.funcDef("minus", 2, (a, b) => a - b),
fast_spec_1.instDef("1", 1),
fast_spec_1.instDef("0", 0),
fast_spec_1.varDef("x", fc.integer())
]));
//# sourceMappingURL=tryit.js.map
{"version":3,"file":"tryit.js","sourceRoot":"","sources":["../src/tryit.ts"],"names":[],"mappings":";;;AAAA,uDAAiC;AACjC,2CAAkE;AAElE,OAAO,CAAC,GAAG,CACT,qBAAS,CAAC;IACR,mBAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,CAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,mBAAO,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACrD,mBAAO,CAAC,IAAI,EAAE,EAAE,CAAC;IACjB,kBAAM,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;CACjC,CAAC,CACH,CAAC;AAEF,OAAO,CAAC,GAAG,CACT,qBAAS,CAAC;IACR,mBAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,CAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,mBAAO,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACrD,mBAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5C,mBAAO,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,mBAAO,CAAC,IAAI,EAAE,EAAE,CAAC;IACjB,kBAAM,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;CACjC,CAAC,CACH,CAAC;AAEF,OAAO,CAAC,GAAG,CACT,qBAAS,CAAC;IACR,mBAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAQ,EAAE,CAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,mBAAO,CAAC,IAAI,EAAE,EAAE,CAAC;IACjB,kBAAM,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;CACjC,CAAC,CACH,CAAC;AAEF,OAAO,CAAC,GAAG,CACT,qBAAS,CAAC;IACR,mBAAO,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAClD,mBAAO,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAClD,mBAAO,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACnD,mBAAO,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,mBAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACf,mBAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACf,kBAAM,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC;CAC1B,CAAC,CACH,CAAC"}

Sorry, the diff of this file is not supported yet

import isEqual from 'lodash.isequal';
import {
array,
memo,
constant,
constantFrom,
genericTuple,
shuffledSubarray,
oneof,
tuple,
sample,
check,
property,
Arbitrary
} from 'fast-check';
export enum SpecDefType {
Function = 'function',
Instance = 'instance',
Variable = 'variable'
}
export type SpecDefFunction = {
type: SpecDefType.Function;
name: string;
numParameters: number;
value: (...args: any[]) => any;
};
export function funcDef(name: string, numParameters: number, value: (...args: any[]) => any): SpecDefFunction {
return { name, type: SpecDefType.Function, value, numParameters };
}
export type SpecDefInstance = {
type: SpecDefType.Instance;
name: string;
value: any;
};
export function instDef(name: string, value: any): SpecDefInstance {
return { name, type: SpecDefType.Instance, value };
}
export type SpecDefVariable = {
type: SpecDefType.Variable;
name: string;
value: Arbitrary<any>;
};
export function varDef(name: string, value: Arbitrary<any>): SpecDefVariable {
return { name, type: SpecDefType.Variable, value };
}
export type FindSpecElement = SpecDefFunction | SpecDefInstance | SpecDefVariable;
export type FindSpecSettings = {
/**
* Number of combinations to try - default: 100
*/
numSamples?: number;
/**
* Complexity of the combinations - default: 2
*
* Higher complexity will produce combinations with more nested calls.
*/
complexity?: number;
/**
* Number of inputs to try to confirm a combination - default: 100
*/
numFuzz?: number;
};
type FindSpecsInternal = {
numArbs: number;
build: (ins: any[], offset: number) => { value: any; nextOffset: number };
repr: (ins: string[], offset: number) => { value: string; nextOffset: number };
};
type FindSpecsInternalBuilder = (n?: number) => Arbitrary<FindSpecsInternal>;
export function findSpecs(def: FindSpecElement[], settings?: FindSpecSettings): string[] {
const baseArbs: { name: string; arb: Arbitrary<any> }[] = [];
const specTermArbBuilder: FindSpecsInternalBuilder[] = [];
for (const el of def) {
switch (el.type) {
case SpecDefType.Variable: {
baseArbs.push({ name: el.name, arb: el.value });
specTermArbBuilder.push(
memo(() =>
constant({
numArbs: 1,
build: (vs: any[], offset: number) => {
return { value: vs[offset], nextOffset: offset + 1 };
},
repr: (xn: string[], offset: number) => {
return { value: xn[offset], nextOffset: offset + 1 };
}
})
)
);
break;
}
case SpecDefType.Instance: {
specTermArbBuilder.push(
memo(() =>
constant({
numArbs: 0,
build: (vs: any[], offset: number) => {
return { value: el.value, nextOffset: offset };
},
repr: (xn: string[], offset: number) => {
return { value: el.name, nextOffset: offset };
}
})
)
);
break;
}
case SpecDefType.Function: {
const elArb = memo(n =>
n <= 1 || el.numParameters === 0
? constant({
numArbs: el.numParameters,
build: (vs: any[], offset: number) => {
const nextOffset = offset + el.numParameters;
return {
value: el.value(...vs.slice(offset, nextOffset)),
nextOffset
};
},
repr: (xn: string[], offset: number) => {
const nextOffset = offset + el.numParameters;
return {
value: `${el.name}(${xn.slice(offset, nextOffset).join(', ')})`,
nextOffset
};
}
})
: genericTuple([...Array(el.numParameters)].map(() => oneof(...specTermArbBuilder.map(a => a())))).map(
t => {
return {
numArbs: t.reduce((acc, cur) => acc + cur.numArbs, 0),
build: (ins: any[], offset: number) => {
let nextOffset = offset;
const vs: any = [];
for (let idx = 0; idx !== el.numParameters; ++idx) {
const tmp = t[idx].build(ins, nextOffset);
nextOffset = tmp.nextOffset;
vs.push(tmp.value);
}
return {
value: el.value(...vs),
nextOffset
};
},
repr: (xn: string[], offset: number) => {
let nextOffset = offset;
const vs: string[] = [];
for (let idx = 0; idx !== el.numParameters; ++idx) {
const tmp = t[idx].repr(xn, nextOffset);
nextOffset = tmp.nextOffset;
vs.push(tmp.value);
}
return {
value: `${el.name}(${vs.join(', ')})`,
nextOffset
};
}
};
}
)
);
specTermArbBuilder.push(elArb);
break;
}
}
}
const maxDepth = settings && settings.complexity !== undefined ? settings.complexity : 2;
const specTermArb = oneof(...specTermArbBuilder.map(a => a(maxDepth)));
const specArb = tuple(specTermArb, specTermArb)
.chain(([t1, t2]) => {
const numArbs = t1.numArbs > t2.numArbs ? t1.numArbs : t2.numArbs;
const variableIndexes = [...Array(numArbs)].map((_, i) => i);
return tuple(
oneof(constant(variableIndexes), shuffledSubarray(variableIndexes, numArbs, numArbs)),
numArbs > 0
? array(constantFrom(...baseArbs), numArbs, numArbs) // throw if no baseArbs
: constant([])
).map(([reindex, inputsDef]) => {
const applyReindex = (ins: any[]) => {
return reindex.map(ri => ins[ri]);
};
const variableNames = inputsDef.map((inputDef, i) => `${inputDef.name}${i}`);
return {
inputArbs: inputsDef.map(inputDef => inputDef.arb),
build1: (ins: any[]) => t1.build(ins, 0).value,
build2: (ins: any[]) => t2.build(applyReindex(ins), 0).value,
spec1: `${t1.repr(variableNames, 0).value}`,
spec2: `${t2.repr(applyReindex(variableNames), 0).value}`
};
});
})
.filter(d => d.spec1 !== d.spec2)
.noShrink();
const equalities = new Map<string, Set<string>>();
const addEquality = (specA: string, specB: string) => {
if (specA === specB) {
return;
}
const alreadyKnowA = equalities.has(specA);
const alreadyKnowB = equalities.has(specB);
if (alreadyKnowA && alreadyKnowB) {
// merge A and B
equalities.set(specA, new Set([...equalities.get(specA)!, ...equalities.get(specB)!]));
// remove B
equalities.delete(specB);
} else if (alreadyKnowA) {
// append specB into already known equalities for specA
equalities.get(specA)!.add(specB);
} else if (alreadyKnowB) {
// append specA into already known equalities for specB
equalities.get(specB)!.add(specA);
} else {
// create a new equlity relation
equalities.set(specA, new Set([specA, specB]));
}
};
const previousSpecs = new Map<string, Set<string>>();
for (const spec of sample(specArb, settings && settings.numSamples)) {
// Sort labels of specs to have a consistent way to store
// the already investigated combinations
const minSpecLabel = spec.spec1 < spec.spec2 ? spec.spec1 : spec.spec2;
const maxSpecLabel = spec.spec1 < spec.spec2 ? spec.spec2 : spec.spec1;
// Skip already covered combinations
if (previousSpecs.has(minSpecLabel) && previousSpecs.get(minSpecLabel)!.has(maxSpecLabel)) {
continue;
}
// Add combination to the list of covered ones
if (!previousSpecs.has(minSpecLabel)) {
previousSpecs.set(minSpecLabel, new Set());
}
previousSpecs.get(minSpecLabel)!.add(maxSpecLabel);
if (spec.inputArbs.length === 0) {
// Combination only rely on constants
if (isEqual(spec.build1([]), spec.build2([]))) {
addEquality(minSpecLabel, maxSpecLabel);
}
} else {
// Combination rely on non-constant values
const out = check(
property(genericTuple(spec.inputArbs), t => {
return isEqual(spec.build1(t), spec.build2(t));
}),
{ numRuns: settings && settings.numFuzz }
);
if (!out.failed) addEquality(minSpecLabel, maxSpecLabel);
}
}
return Array.from(equalities.values()).map(vs =>
Array.from(vs)
.sort()
.join(' == ')
);
}
import * as fc from "fast-check";
import { funcDef, instDef, varDef, findSpecs } from "./fast-spec";
console.log(
findSpecs([
funcDef("concat", 2, (a: any[], b: any[]) => [...a, ...b]),
funcDef("reverse", 1, (a: any[]) => [...a].reverse()),
instDef("[]", []),
varDef("x", fc.array(fc.char()))
])
);
console.log(
findSpecs([
funcDef("concat", 2, (a: any[], b: any[]) => [...a, ...b]),
funcDef("reverse", 1, (a: any[]) => [...a].reverse()),
funcDef("length", 1, (a: any[]) => a.length),
funcDef("map", 1, (a: any[]) => a.map(s => s + s)),
instDef("[]", []),
varDef("x", fc.array(fc.char()))
])
);
console.log(
findSpecs([
funcDef("concat", 2, (a: any[], b: any[]) => [...a, ...b]),
instDef("[]", []),
varDef("x", fc.array(fc.char()))
])
);
console.log(
findSpecs([
funcDef("mul", 2, (a: number, b: number) => a * b),
funcDef("div", 2, (a: number, b: number) => a / b),
funcDef("plus", 2, (a: number, b: number) => a + b),
funcDef("minus", 2, (a: number, b: number) => a - b),
instDef("1", 1),
instDef("0", 0),
varDef("x", fc.integer())
])
);

Sorry, the diff of this file is not supported yet