Skip to content
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
34 changes: 34 additions & 0 deletions test/helpers/benchmark-artifact.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* oxlint-disable no-bitwise */
import {
CORPUS_INTERVAL_METHOD,
DECISION_CONFIG_VERSION,
DECISION_INTERVAL_METHOD,
PRECISION_METHOD,
Expand All @@ -26,6 +27,39 @@ export const SYNTHETIC_DECISION_CONFIG = {
intervalMethod: DECISION_INTERVAL_METHOD,
};

export const CORPUS_DECISION_CONFIG = {
...SYNTHETIC_DECISION_CONFIG,
warmupMinimum: 0,
warmupMaximum: 0,
measuredBatchCount: 6,
intervalMethod: CORPUS_INTERVAL_METHOD,
replicates: 20,
batches: 6,
calibrationOrderBalanced: true,
};

const CORPUS_CATEGORIES = [
'accepted',
'both-failed',
'known-divergence',
'malformed-input',
'parser-rejected',
'reference-rejected',
'unexpected-divergence',
];

/** Correctness block for a corpus artifact with two accepted inputs. */
export function corpusCorrectness() {
return {
accepted: 2,
counts: Object.fromEntries(
CORPUS_CATEGORIES.map((c) => [c, c === 'accepted' ? 2 : 0])
),
categoryHashes: Object.fromEntries(CORPUS_CATEGORIES.map((c) => [c, c])),
inputHash: 'inputs',
};
}

/**
* Build a parser artifact from already-generated observations. `rows` contains
* one complete independent block per item, with baseline and candidate arrays
Expand Down
6 changes: 6 additions & 0 deletions test/helpers/numeric.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Read a number out of serialized CSS such as `calc(1.5)` or `-2`.
export const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
export const numeric = (text) => Number.parseFloat(scalarText(text));
9 changes: 9 additions & 0 deletions test/helpers/parse-source.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Parse CSS source over its full token range with the production parser.
import { tokenize } from '@csstools/css-tokenizer';
import { indexBlocks } from '../../src/lib/block-index.js';
import { parse } from '../../src/lib/parser.js';

export const parseSource = (css) => {
const tokens = tokenize({ css });
return parse(tokens, 0, tokens.length, indexBlocks(tokens));
};
21 changes: 21 additions & 0 deletions test/helpers/testValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,24 @@ export function testValue(fixture, expected, opts = {}) {
assert.strictEqual(result.css, expected);
};
}

export function testCss(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.strictEqual(result.css, expected);
};
}

export function testCssDoesNotThrow(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.strictEqual(result.css, expected);
assert.strictEqual(result.warnings().length, 0);
};
}
33 changes: 5 additions & 28 deletions test/index-cases.test.cjs
Original file line number Diff line number Diff line change
@@ -1,34 +1,11 @@
'use strict';

const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const postcss = require('postcss');
const reduceCalc = (opts = {}) => require('../src/index.js')(opts);
const { testValue } = require('./helpers/testValue.js');

const postcssOpts = { from: undefined };

function testCss(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.strictEqual(result.css, expected);
};
}

function testCssDoesNotThrow(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.strictEqual(result.css, expected);
const warnings = result.warnings();
assert.strictEqual(warnings.length, 0);
};
}
const {
testValue,
testCss,
testCssDoesNotThrow,
} = require('./helpers/testValue.js');

describe('CSS custom properties', () => {
test(
Expand Down
20 changes: 2 additions & 18 deletions test/index-edge-cases.test.cjs
Original file line number Diff line number Diff line change
@@ -1,24 +1,8 @@
'use strict';

const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const postcss = require('postcss');
const reduceCalc = (opts = {}) => require('../src/index.js')(opts);
const { testValue } = require('./helpers/testValue.js');

const postcssOpts = { from: undefined };

function testCssDoesNotThrow(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.strictEqual(result.css, expected);
const warnings = result.warnings();
assert.strictEqual(warnings.length, 0);
};
}
const { testValue, testCssDoesNotThrow } = require('./helpers/testValue.js');

describe('Throw', () => {
test(
'should not throw an exception when unknow function exist in calc',
Expand Down
17 changes: 1 addition & 16 deletions test/index-options.test.cjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
'use strict';

const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const postcss = require('postcss');
const reduceCalc = (opts = {}) => require('../src/index.js')(opts);
const { testValue } = require('./helpers/testValue.js');

const postcssOpts = { from: undefined };

function testCss(fixture, expected, opts = {}) {
return async () => {
const result = await postcss(reduceCalc(opts)).process(
fixture,
postcssOpts
);
assert.strictEqual(result.css, expected);
};
}
const { testValue, testCss } = require('./helpers/testValue.js');

describe('Discard zero values', () => {
test(
Expand Down
6 changes: 1 addition & 5 deletions test/property/algebraic-exponential.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ import { describe, test } from 'node:test';
import fc from 'fast-check';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
import { numeric } from '../helpers/numeric.js';
import { call, num } from '../../src/lib/node.js';

const NUM_RUNS = 500;

const out = (n) => serialize(simplify(n), { precision: 10 });
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));

// --- pow / sqrt / log / exp / hypot laws (§10.5) ----------------------
test('law: pow(x, 1) ≡ x for finite x', () => {
Expand Down
6 changes: 1 addition & 5 deletions test/property/algebraic-mod-rem.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ import { describe, test } from 'node:test';
import fc from 'fast-check';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
import { numeric } from '../helpers/numeric.js';
import { call, num, ident } from '../../src/lib/node.js';

const NUM_RUNS = 500;

const out = (n) => serialize(simplify(n), { precision: 10 });
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));

// Finite, non-zero numeric leaf — domain for most laws.
const finiteNum = fc.integer({ min: -1000, max: 1000 }).map(num);
Expand Down
6 changes: 1 addition & 5 deletions test/property/algebraic-round.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ import { describe, test } from 'node:test';
import fc from 'fast-check';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
import { numeric } from '../helpers/numeric.js';
import { call, num, ident } from '../../src/lib/node.js';

const NUM_RUNS = 500;

const out = (n) => serialize(simplify(n), { precision: 10 });
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));

// Finite, non-zero numeric leaf — domain for most laws.
const finiteNum = fc.integer({ min: -1000, max: 1000 }).map(num);
Expand Down
6 changes: 1 addition & 5 deletions test/property/algebraic-sign.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ import { describe, test } from 'node:test';
import fc from 'fast-check';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
import { numeric, scalarText } from '../helpers/numeric.js';
import { call, num, dim } from '../../src/lib/node.js';

const NUM_RUNS = 500;

const out = (n) => serialize(simplify(n), { precision: 10 });
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));

// Finite, non-zero numeric leaf — domain for most laws.
const finiteNum = fc.integer({ min: -1000, max: 1000 }).map(num);
Expand Down
6 changes: 1 addition & 5 deletions test/property/algebraic-trigonometry.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ import { describe, test } from 'node:test';
import fc from 'fast-check';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
import { numeric } from '../helpers/numeric.js';
import { call, num } from '../../src/lib/node.js';

const NUM_RUNS = 500;

const out = (n) => serialize(simplify(n), { precision: 10 });
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));

// --- trig laws (§10.4) ---------------------------------------------------
//
Expand Down
20 changes: 3 additions & 17 deletions test/property/naive-exponential.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,9 @@
// random gen to roll them.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { tokenize } from '@csstools/css-tokenizer';
import { indexBlocks } from '../../src/lib/block-index.js';
import { parse } from '../../src/lib/parser.js';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
const out = (s) => {
const tokens = tokenize({ css: s });
return serialize(
simplify(parse(tokens, 0, tokens.length, indexBlocks(tokens))),
{ precision: 10 }
);
};
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));
import { out as pipeline } from '../helpers/out.js';
import { numeric } from '../helpers/numeric.js';
const out = (s) => pipeline(s, { precision: 10 });
// --- §10.5 oracle rows for pow / sqrt / exp / log / hypot --------------
const POW_INPUTS = [
[2, 3],
Expand Down
59 changes: 17 additions & 42 deletions test/property/naive-stepped.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,20 @@
// random gen to roll them.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { tokenize } from '@csstools/css-tokenizer';
import { indexBlocks } from '../../src/lib/block-index.js';
import { parse } from '../../src/lib/parser.js';
import { simplify } from '../../src/lib/simplify.js';
import { serialize } from '../../src/lib/serialize.js';
const out = (s) => {
const tokens = tokenize({ css: s });
return serialize(
simplify(parse(tokens, 0, tokens.length, indexBlocks(tokens))),
{ precision: 10 }
);
};
const scalarText = (text) =>
text.startsWith('calc(') && text.endsWith(')')
? text.slice('calc('.length, -1)
: text;
const numeric = (text) => Number.parseFloat(scalarText(text));
import { out as pipeline } from '../helpers/out.js';
import { numeric } from '../helpers/numeric.js';
const out = (s) => pipeline(s, { precision: 10 });
// NaN must match NaN; otherwise allow tiny FP drift between algorithm shapes.
function assertAgrees(expected, got) {
if (Number.isNaN(expected)) {
assert.ok(Number.isNaN(got), `expected NaN, got ${got}`);
} else {
assert.ok(
Math.abs(expected - got) < 1e-9,
`naive=${expected}, prod=${got}`
);
}
}
// --- Naive reference impls ----------------------------------------------
//
// These use a *different* algorithmic shape from `simplify.ts`:
Expand Down Expand Up @@ -134,15 +131,7 @@ for (const row of rows) {
const expected = naiveRound(strategy, row.a, row.b);
const got = numeric(out(`round(${strategy}, ${row.a}, ${row.b})`));
// NaN === NaN check via Object.is.
if (Number.isNaN(expected)) {
assert.ok(Number.isNaN(got), `expected NaN, got ${got}`);
} else {
// Allow tiny FP drift between algorithm shapes.
assert.ok(
Math.abs(expected - got) < 1e-9,
`naive=${expected}, prod=${got}`
);
}
assertAgrees(expected, got);
});
}
}
Expand All @@ -153,26 +142,12 @@ for (const row of rows) {
test(`oracle: mod(${row.a}, ${row.b}) [${row.desc}]`, () => {
const expected = naiveMod(row.a, row.b);
const got = numeric(out(`mod(${row.a}, ${row.b})`));
if (Number.isNaN(expected)) {
assert.ok(Number.isNaN(got), `expected NaN, got ${got}`);
} else {
assert.ok(
Math.abs(expected - got) < 1e-9,
`naive=${expected}, prod=${got}`
);
}
assertAgrees(expected, got);
});
test(`oracle: rem(${row.a}, ${row.b}) [${row.desc}]`, () => {
const expected = naiveRem(row.a, row.b);
const got = numeric(out(`rem(${row.a}, ${row.b})`));
if (Number.isNaN(expected)) {
assert.ok(Number.isNaN(got), `expected NaN, got ${got}`);
} else {
assert.ok(
Math.abs(expected - got) < 1e-9,
`naive=${expected}, prod=${got}`
);
}
assertAgrees(expected, got);
});
}
// --- abs / sign — small but covers signed zero -------------------------
Expand Down
Loading
Loading