Release Fixture Tools 0.2.0
Verify / verify (push) Canceled after 0s

This commit is contained in:
2026-09-02 13:00:37 +02:00
parent f5d018c64f
commit f1c41e7079
22 changed files with 1007 additions and 126 deletions
+102
View File
@@ -1,9 +1,11 @@
import { describe, expect, it } from "vitest";
import {
generateFixtures,
constraintCoverageMatrix,
modelJson,
parseFixtureModel,
serializeDataset,
topologicalTableOrder,
type GeneratedDataset,
} from "../../src/fixture/model";
@@ -175,4 +177,104 @@ describe("fixture model", () => {
}),
).toThrow(/100,000 field values/u);
});
it("imports and generates composite relational constraints topologically", () => {
const sql = `CREATE TABLE tenants (
region VARCHAR(8) NOT NULL,
tenant_id INTEGER NOT NULL,
PRIMARY KEY (region, tenant_id)
);
CREATE TABLE events (
region VARCHAR(8) NOT NULL,
tenant_id INTEGER NOT NULL,
sequence INTEGER NOT NULL,
UNIQUE (region, tenant_id, sequence),
FOREIGN KEY (region, tenant_id) REFERENCES tenants(region, tenant_id)
);`;
const model = parseFixtureModel(sql, "sql").model;
expect(model.tables[1]?.constraints).toEqual([
{ kind: "unique", fields: ["region", "tenant_id", "sequence"] },
{
kind: "foreignKey",
fields: ["region", "tenant_id"],
references: { table: "tenants", fields: ["region", "tenant_id"] },
},
]);
expect(topologicalTableOrder(model)).toEqual(["tenants", "events"]);
const dataset = generateFixtures(model, {
seed: "composite",
rows: 12,
boundaryPercent: 10,
invalidPercent: 0,
providerProfile: "auto",
});
const targets = new Set(
dataset.tables.tenants?.map((row) => `${row.region}:${row.tenant_id}`),
);
expect(
dataset.tables.events?.every((row) =>
targets.has(`${row.region}:${row.tenant_id}`),
),
).toBe(true);
expect(dataset.generationOrder).toEqual(["tenants", "events"]);
expect(
constraintCoverageMatrix(model, dataset).some(
(entry) =>
entry.table === "events" &&
entry.constraint.startsWith("foreignKey(region,tenant_id)"),
),
).toBe(true);
});
it("accepts scalar table-level primary and foreign-key constraints", () => {
const sql = `CREATE TABLE accounts (
account_id INTEGER NOT NULL,
PRIMARY KEY (account_id)
);
CREATE TABLE entries (
account_id INTEGER NOT NULL,
FOREIGN KEY (account_id) REFERENCES accounts(account_id)
);`;
const model = parseFixtureModel(sql, "sql").model;
expect(model.tables[0]?.constraints).toEqual([
{ kind: "unique", fields: ["account_id"] },
]);
expect(model.tables[1]?.constraints).toEqual([
{
kind: "foreignKey",
fields: ["account_id"],
references: { table: "accounts", fields: ["account_id"] },
},
]);
const dataset = generateFixtures(model, {
seed: "scalar-table-constraints",
rows: 8,
boundaryPercent: 0,
invalidPercent: 0,
});
const accounts = new Set(
dataset.tables.accounts?.map((row) => row.account_id),
);
expect(
dataset.tables.entries?.every((row) => accounts.has(row.account_id)),
).toBe(true);
});
it("supports deterministic built-in and custom provider profiles", () => {
const model = parseFixtureModel("display_name,host,sku\n", "csv").model;
const options = {
seed: "providers",
rows: 4,
boundaryPercent: 0,
invalidPercent: 0,
providerProfile: "auto",
};
const generated = generateFixtures(model, options);
expect(generated).toEqual(generateFixtures(model, options));
expect(generated.tables.records?.[0]).toMatchObject({
display_name: expect.stringMatching(/ /u),
host: expect.stringMatching(/\.example\.test$/u),
sku: "SKU-000001",
});
});
});