feat: publish Regex Tools 0.2.0
This commit is contained in:
110
scripts/pcre2-codegen-golden.test.ts
Normal file
110
scripts/pcre2-codegen-golden.test.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
generatePcre2C,
|
||||
type Pcre2CGenerationRequest,
|
||||
} from "../src/regex/codegen/pcre2-c";
|
||||
|
||||
function request(operation: "match" | "replace"): Pcre2CGenerationRequest {
|
||||
return {
|
||||
flavour: "pcre2",
|
||||
flavourVersion: "PCRE2 10.47 8-bit WebAssembly",
|
||||
operation,
|
||||
pattern: String.raw`(?<word>\p{L}+)-(\d+)`,
|
||||
flags: ["g"],
|
||||
options: {
|
||||
matchLimit: 1_000_000,
|
||||
depthLimit: 1_000,
|
||||
heapLimitKib: 32_768,
|
||||
},
|
||||
subject: "x Grüße-42 y alpha-7",
|
||||
scanAll: true,
|
||||
...(operation === "replace" ? { replacement: "$2:$<word>" } : {}),
|
||||
maximumMatches: 100,
|
||||
maximumCaptureRows: 1_000,
|
||||
maximumOutputBytes: 4_096,
|
||||
};
|
||||
}
|
||||
|
||||
function sha256(value: string): string {
|
||||
return createHash("sha256").update(value).digest("hex");
|
||||
}
|
||||
|
||||
const exactToolchainPrefix = process.env.PCRE2_CODEGEN_PREFIX;
|
||||
const compileWithExactPcre2 = exactToolchainPrefix ? it : it.skip;
|
||||
|
||||
describe("PCRE2 C code-generation golden", () => {
|
||||
it("retains a reviewed deterministic source identity", () => {
|
||||
expect(sha256(generatePcre2C(request("match")).source)).toBe(
|
||||
"22b91d578a449b0ed5c30e6eadad30f19a2bcb26ac9db355c8ec7a69328675da",
|
||||
);
|
||||
expect(sha256(generatePcre2C(request("replace")).source)).toBe(
|
||||
"ab90a0d9831ea7b7145aa0072ac352b42baf9a795319d81f531b0f341b04a636",
|
||||
);
|
||||
});
|
||||
|
||||
compileWithExactPcre2(
|
||||
"compiles and executes against the explicitly supplied PCRE2 10.47 C toolchain",
|
||||
async () => {
|
||||
if (!exactToolchainPrefix) return;
|
||||
const header = path.join(exactToolchainPrefix, "include", "pcre2.h");
|
||||
const library =
|
||||
process.env.PCRE2_CODEGEN_LIBRARY ??
|
||||
path.join(exactToolchainPrefix, "lib64", "libpcre2-8.a");
|
||||
await expect(readFile(header)).resolves.toBeInstanceOf(Buffer);
|
||||
await expect(readFile(library)).resolves.toBeInstanceOf(Buffer);
|
||||
const directory = await mkdtemp(
|
||||
path.join(tmpdir(), "regex-tools-codegen-"),
|
||||
);
|
||||
try {
|
||||
for (const operation of ["match", "replace"] as const) {
|
||||
const generated = generatePcre2C(request(operation));
|
||||
const source = path.join(directory, generated.fileName);
|
||||
const executable = path.join(directory, `pcre2-${operation}`);
|
||||
await writeFile(source, generated.source);
|
||||
const compiled = spawnSync(
|
||||
process.env.CC ?? "cc",
|
||||
[
|
||||
"-std=c17",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
`-I${path.join(exactToolchainPrefix, "include")}`,
|
||||
source,
|
||||
library,
|
||||
"-o",
|
||||
executable,
|
||||
],
|
||||
{ encoding: "utf8" },
|
||||
);
|
||||
expect(
|
||||
`${compiled.stdout}${compiled.stderr}`,
|
||||
`${operation} fixture did not compile`,
|
||||
).toBe("");
|
||||
expect(compiled.status).toBe(0);
|
||||
const executed = spawnSync(executable, [], { encoding: "utf8" });
|
||||
expect(
|
||||
executed.status,
|
||||
`${operation} fixture failed: ${executed.stdout}${executed.stderr}`,
|
||||
).toBe(0);
|
||||
if (operation === "match") {
|
||||
expect(executed.stdout).toContain("match 1: UTF-8 bytes 2..12");
|
||||
expect(executed.stdout).toContain("group 1 / word");
|
||||
expect(executed.stdout).toContain(
|
||||
"completed: 2 match(es), 4 capture row(s)",
|
||||
);
|
||||
} else {
|
||||
expect(executed.stdout).toBe("x 42:Grüße y 7:alpha");
|
||||
expect(executed.stderr).toContain("completed: 2 substitution(s)");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user