build(expr): pin the runner commit and runtime of gen/runner, require RunnerSrc (GO-005)
env.mjs asserts the clone's HEAD (runner-commit.txt), that src/Sdk is clean and that a 9.0.x runtime is installed; TestRunnerCommit checks that the recorded data, runner-commit.txt and PORTING.md agree. No global.json: only SDK 10 is installed here and 'latestPatch' on 9.0.x cannot build, so the runtime is asserted instead.
- commit
- 736f11edddc5fbe930923e104415b18030134e2e
- author
- brice · · 2026-10-12 18:32 UTC
- committer
- brice · · 2026-10-18 14:59 UTC
- parent
- cf6b697
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
11 files · +118 -34
M expr/gen/runner/README.md +20 -2
| @@ -8,8 +8,26 @@ the stubs in `Stubs.cs`. `Program.cs` reads | |||
| 8 | 8 | per case: `{"k": kind, "s": string form, "j": toJSON of the result}`, or | |
| 9 | 9 | `{"err": {"t": "parse"|"eval", "m": message}}`. | |
| 10 | 10 | ||
| 11 | - | dotnet build -c Release expr/gen/runner -p:RunnerSrc=/path/to/runner/src/Sdk | |
| 12 | - | dotnet expr/gen/runner/bin/Release/net9.0/runner.dll input.json | |
| 11 | + | Requirements (checked, not assumed): | |
| 12 | + | ||
| 13 | + | - a clone of https://github.com/actions/runner at the commit in | |
| 14 | + | `runner-commit.txt` (`5f0b3ddcc6ee9fe9441e00d55e85b94ea4aad798`), clean in | |
| 15 | + | `src/Sdk`. `RunnerSrc` has no default: the build fails without it. | |
| 16 | + | - the .NET SDK (the project targets `net9.0`) and a **9.0.x runtime** | |
| 17 | + | (`dotnet --list-runtimes`): number formatting and case folding come from the | |
| 18 | + | runtime, and `env.mjs` refuses to run on another line. No `global.json` pins | |
| 19 | + | the SDK because any SDK that can build `net9.0` works (the author's machine | |
| 20 | + | has SDK 10 with the 9.0 runtime); the runtime is what matters and is asserted. | |
| 21 | + | ||
| 22 | + | Build and run: | |
| 23 | + | ||
| 24 | + | dotnet build -c Release expr/gen/runner -p:RunnerSrc=$RUNNER_CLONE/src/Sdk | |
| 25 | + | RUNNER_CLONE=<clone> node expr/gen/runner/answers.mjs | gzip -9 -n > expr/testdata/runner.json.gz | |
| 26 | + | ||
| 27 | + | The other scripts (`goldens.mjs`, `ordinal_cases.mjs`, `number_cases.mjs`, | |
| 28 | + | `fromjson_cases.mjs`) use the same environment (`env.mjs`); `runner.dll | |
| 29 | + | input.json` can also be run by hand. `TestRunnerCommit` checks that the | |
| 30 | + | recorded data, `runner-commit.txt` and `PORTING.md` name the same commit. | |
| 13 | 31 | ||
| 14 | 32 | It is how the C# column of `expr/PORTING.md` was established: the 34 765 | |
| 15 | 33 | expressions of `testdata/oracle.json.gz` were run through it and compared with | |
| @@ -8,8 +8,26 @@ the stubs in `Stubs.cs`. `Program.cs` reads | |||||
| 8 | per case: `{"k": kind, "s": string form, "j": toJSON of the result}`, or | 8 | per case: `{"k": kind, "s": string form, "j": toJSON of the result}`, or | ||
| 9 | `{"err": {"t": "parse"|"eval", "m": message}}`. | 9 | `{"err": {"t": "parse"|"eval", "m": message}}`. | ||
| 10 | 10 | ||||
| 11 | - | dotnet build -c Release expr/gen/runner -p:RunnerSrc=/path/to/runner/src/Sdk | 11 | + | Requirements (checked, not assumed): |
| 12 | - | dotnet expr/gen/runner/bin/Release/net9.0/runner.dll input.json | 12 | + | |
| 13 | + | - a clone of https://github.com/actions/runner at the commit in | |||
| 14 | + | `runner-commit.txt` (`5f0b3ddcc6ee9fe9441e00d55e85b94ea4aad798`), clean in | |||
| 15 | + | `src/Sdk`. `RunnerSrc` has no default: the build fails without it. | |||
| 16 | + | - the .NET SDK (the project targets `net9.0`) and a **9.0.x runtime** | |||
| 17 | + | (`dotnet --list-runtimes`): number formatting and case folding come from the | |||
| 18 | + | runtime, and `env.mjs` refuses to run on another line. No `global.json` pins | |||
| 19 | + | the SDK because any SDK that can build `net9.0` works (the author's machine | |||
| 20 | + | has SDK 10 with the 9.0 runtime); the runtime is what matters and is asserted. | |||
| 21 | + | ||||
| 22 | + | Build and run: | |||
| 23 | + | ||||
| 24 | + | dotnet build -c Release expr/gen/runner -p:RunnerSrc=$RUNNER_CLONE/src/Sdk | |||
| 25 | + | RUNNER_CLONE=<clone> node expr/gen/runner/answers.mjs | gzip -9 -n > expr/testdata/runner.json.gz | |||
| 26 | + | ||||
| 27 | + | The other scripts (`goldens.mjs`, `ordinal_cases.mjs`, `number_cases.mjs`, | |||
| 28 | + | `fromjson_cases.mjs`) use the same environment (`env.mjs`); `runner.dll | |||
| 29 | + | input.json` can also be run by hand. `TestRunnerCommit` checks that the | |||
| 30 | + | recorded data, `runner-commit.txt` and `PORTING.md` name the same commit. | |||
| 13 | 31 | ||||
| 14 | It is how the C# column of `expr/PORTING.md` was established: the 34 765 | 32 | It is how the C# column of `expr/PORTING.md` was established: the 34 765 | ||
| 15 | expressions of `testdata/oracle.json.gz` were run through it and compared with | 33 | expressions of `testdata/oracle.json.gz` were run through it and compared with | ||
M expr/gen/runner/answers.mjs +6 -11
| @@ -5,32 +5,27 @@ | |||
| 5 | 5 | // testdata/oracle.json.gz. Needs the .NET SDK and a clone of actions/runner: | |
| 6 | 6 | // | |
| 7 | 7 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | |
| 8 | - | // node expr/gen/runner/answers.mjs <runner clone> | gzip -9 -n > expr/testdata/runner.json.gz | |
| 8 | + | // RUNNER_CLONE=<runner clone> node expr/gen/runner/answers.mjs | gzip -9 -n > expr/testdata/runner.json.gz | |
| 9 | 9 | ||
| 10 | - | import { execFileSync } from "node:child_process"; | |
| 11 | 10 | import { readFileSync, writeFileSync, mkdtempSync } from "node:fs"; | |
| 12 | 11 | import { tmpdir } from "node:os"; | |
| 13 | - | import { join, dirname } from "node:path"; | |
| 14 | - | import { fileURLToPath } from "node:url"; | |
| 12 | + | import { join } from "node:path"; | |
| 13 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; | |
| 15 | 14 | import { gunzipSync } from "node:zlib"; | |
| 16 | 15 | ||
| 17 | - | const here = dirname(fileURLToPath(import.meta.url)); | |
| 18 | - | const runnerClone = process.argv[2]; | |
| 19 | - | if (!runnerClone) throw new Error("usage: answers.mjs <actions/runner clone>"); | |
| 16 | + | const env = checkEnvironment(process.argv[2]); | |
| 20 | 17 | ||
| 21 | 18 | const oracle = JSON.parse(gunzipSync(readFileSync(join(here, "../../testdata/oracle.json.gz")))); | |
| 22 | 19 | const dir = mkdtempSync(join(tmpdir(), "runner-answers-")); | |
| 23 | 20 | const input = join(dir, "in.json"); | |
| 24 | 21 | writeFileSync(input, JSON.stringify({ contexts: oracle.contexts, cases: oracle.cases.map(c => ({ e: c.e })) })); | |
| 25 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), input], { maxBuffer: 1 << 30 }).toString("utf8").split("\n").filter(Boolean); | |
| 22 | + | const out = runDriver([input]).split("\n").filter(Boolean); | |
| 26 | 23 | if (out.length !== oracle.cases.length) throw new Error(`got ${out.length} answers for ${oracle.cases.length} cases`); | |
| 27 | - | const git = (...a) => execFileSync("git", ["-C", runnerClone, ...a]).toString().trim(); | |
| 28 | - | const dotnet = execFileSync("dotnet", ["--list-runtimes"]).toString().split("\n").find(l => l.includes("Microsoft.NETCore.App 9")) ?? ""; | |
| 29 | 24 | const cases = out.map((l, i) => { | |
| 30 | 25 | const r = JSON.parse(l); | |
| 31 | 26 | return { e: oracle.cases[i].e, ...r }; | |
| 32 | 27 | }); | |
| 33 | 28 | process.stdout.write(JSON.stringify({ | |
| 34 | - | reference: { source: "actions/runner src/Sdk/DTExpressions2 (Expressions2)", commit: git("rev-parse", "HEAD"), runtime: dotnet.trim() }, | |
| 29 | + | reference: { source: "actions/runner src/Sdk/DTExpressions2 (Expressions2)", commit: env.commit, runtime: env.runtime }, | |
| 35 | 30 | cases, | |
| 36 | 31 | })); | |
| @@ -5,32 +5,27 @@ | |||||
| 5 | // testdata/oracle.json.gz. Needs the .NET SDK and a clone of actions/runner: | 5 | // testdata/oracle.json.gz. Needs the .NET SDK and a clone of actions/runner: | ||
| 6 | // | 6 | // | ||
| 7 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | 7 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | ||
| 8 | - | // node expr/gen/runner/answers.mjs <runner clone> | gzip -9 -n > expr/testdata/runner.json.gz | 8 | + | // RUNNER_CLONE=<runner clone> node expr/gen/runner/answers.mjs | gzip -9 -n > expr/testdata/runner.json.gz |
| 9 | 9 | ||||
| 10 | - | import { execFileSync } from "node:child_process"; | |||
| 11 | import { readFileSync, writeFileSync, mkdtempSync } from "node:fs"; | 10 | import { readFileSync, writeFileSync, mkdtempSync } from "node:fs"; | ||
| 12 | import { tmpdir } from "node:os"; | 11 | import { tmpdir } from "node:os"; | ||
| 13 | - | import { join, dirname } from "node:path"; | 12 | + | import { join } from "node:path"; |
| 14 | - | import { fileURLToPath } from "node:url"; | 13 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; |
| 15 | import { gunzipSync } from "node:zlib"; | 14 | import { gunzipSync } from "node:zlib"; | ||
| 16 | 15 | ||||
| 17 | - | const here = dirname(fileURLToPath(import.meta.url)); | 16 | + | const env = checkEnvironment(process.argv[2]); |
| 18 | - | const runnerClone = process.argv[2]; | |||
| 19 | - | if (!runnerClone) throw new Error("usage: answers.mjs <actions/runner clone>"); | |||
| 20 | 17 | ||||
| 21 | const oracle = JSON.parse(gunzipSync(readFileSync(join(here, "../../testdata/oracle.json.gz")))); | 18 | const oracle = JSON.parse(gunzipSync(readFileSync(join(here, "../../testdata/oracle.json.gz")))); | ||
| 22 | const dir = mkdtempSync(join(tmpdir(), "runner-answers-")); | 19 | const dir = mkdtempSync(join(tmpdir(), "runner-answers-")); | ||
| 23 | const input = join(dir, "in.json"); | 20 | const input = join(dir, "in.json"); | ||
| 24 | writeFileSync(input, JSON.stringify({ contexts: oracle.contexts, cases: oracle.cases.map(c => ({ e: c.e })) })); | 21 | writeFileSync(input, JSON.stringify({ contexts: oracle.contexts, cases: oracle.cases.map(c => ({ e: c.e })) })); | ||
| 25 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), input], { maxBuffer: 1 << 30 }).toString("utf8").split("\n").filter(Boolean); | 22 | + | const out = runDriver([input]).split("\n").filter(Boolean); |
| 26 | if (out.length !== oracle.cases.length) throw new Error(`got ${out.length} answers for ${oracle.cases.length} cases`); | 23 | if (out.length !== oracle.cases.length) throw new Error(`got ${out.length} answers for ${oracle.cases.length} cases`); | ||
| 27 | - | const git = (...a) => execFileSync("git", ["-C", runnerClone, ...a]).toString().trim(); | |||
| 28 | - | const dotnet = execFileSync("dotnet", ["--list-runtimes"]).toString().split("\n").find(l => l.includes("Microsoft.NETCore.App 9")) ?? ""; | |||
| 29 | const cases = out.map((l, i) => { | 24 | const cases = out.map((l, i) => { | ||
| 30 | const r = JSON.parse(l); | 25 | const r = JSON.parse(l); | ||
| 31 | return { e: oracle.cases[i].e, ...r }; | 26 | return { e: oracle.cases[i].e, ...r }; | ||
| 32 | }); | 27 | }); | ||
| 33 | process.stdout.write(JSON.stringify({ | 28 | process.stdout.write(JSON.stringify({ | ||
| 34 | - | reference: { source: "actions/runner src/Sdk/DTExpressions2 (Expressions2)", commit: git("rev-parse", "HEAD"), runtime: dotnet.trim() }, | 29 | + | reference: { source: "actions/runner src/Sdk/DTExpressions2 (Expressions2)", commit: env.commit, runtime: env.runtime }, |
| 35 | cases, | 30 | cases, | ||
| 36 | })); | 31 | })); | ||
A expr/gen/runner/env.mjs +45 -0
| @@ -0,0 +1,45 @@ | |||
| 1 | + | // SPDX-License-Identifier: MIT | |
| 2 | + | // | |
| 3 | + | // Shared by the scripts of this directory: finds the runner driver, and checks | |
| 4 | + | // that the clone it was built from is the one the recorded data is about and | |
| 5 | + | // that the .NET runtime is the 9.0 line (number formatting and case folding come | |
| 6 | + | // from the runtime, not from the SDK). | |
| 7 | + | // | |
| 8 | + | // RUNNER_CLONE=/path/to/actions/runner node expr/gen/runner/<script>.mjs | |
| 9 | + | ||
| 10 | + | import { execFileSync } from "node:child_process"; | |
| 11 | + | import { readFileSync } from "node:fs"; | |
| 12 | + | import { join, dirname } from "node:path"; | |
| 13 | + | import { fileURLToPath } from "node:url"; | |
| 14 | + | ||
| 15 | + | export const here = dirname(fileURLToPath(import.meta.url)); | |
| 16 | + | ||
| 17 | + | /** The commit of actions/runner the data in testdata/ is about (runner-commit.txt). */ | |
| 18 | + | export const runnerCommit = readFileSync(join(here, "runner-commit.txt"), "utf8").trim(); | |
| 19 | + | ||
| 20 | + | /** The driver built by `dotnet build -c Release expr/gen/runner -p:RunnerSrc=<clone>/src/Sdk`. */ | |
| 21 | + | export const driver = join(here, "bin/Release/net9.0/runner.dll"); | |
| 22 | + | ||
| 23 | + | /** | |
| 24 | + | * Checks the environment and returns { clone, commit, runtime }. The clone is | |
| 25 | + | * $RUNNER_CLONE (or the first argument); its HEAD must be runner-commit.txt and | |
| 26 | + | * its tree clean in src/Sdk, and `dotnet --list-runtimes` must list a | |
| 27 | + | * Microsoft.NETCore.App 9.0.x. | |
| 28 | + | */ | |
| 29 | + | export function checkEnvironment(arg) { | |
| 30 | + | const clone = process.env.RUNNER_CLONE || arg; | |
| 31 | + | if (!clone) throw new Error("set RUNNER_CLONE to a clone of https://github.com/actions/runner"); | |
| 32 | + | const git = (...a) => execFileSync("git", ["-C", clone, ...a]).toString().trim(); | |
| 33 | + | const commit = git("rev-parse", "HEAD"); | |
| 34 | + | if (commit !== runnerCommit) throw new Error(`the clone is at ${commit}, the data is about ${runnerCommit} (runner-commit.txt)`); | |
| 35 | + | if (git("status", "--porcelain", "--", "src/Sdk") !== "") throw new Error("the clone has local changes in src/Sdk"); | |
| 36 | + | const rt = execFileSync("dotnet", ["--list-runtimes"]).toString().split("\n").filter(l => /^Microsoft\.NETCore\.App 9\.0\.\d+ /.test(l)); | |
| 37 | + | if (rt.length === 0) throw new Error("no Microsoft.NETCore.App 9.0.x runtime installed (dotnet --list-runtimes)"); | |
| 38 | + | return { clone, commit, runtime: rt[rt.length - 1].replace(/ \[.*$/, "") }; | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | /** Runs the driver with args; the environment is checked first. */ | |
| 42 | + | export function runDriver(args, opts = {}) { | |
| 43 | + | checkEnvironment(); | |
| 44 | + | return execFileSync("dotnet", [driver, ...args], { maxBuffer: 1 << 30, ...opts }).toString("utf8"); | |
| 45 | + | } | |
| @@ -0,0 +1,45 @@ | |||||
| 1 | + | // SPDX-License-Identifier: MIT | |||
| 2 | + | // | |||
| 3 | + | // Shared by the scripts of this directory: finds the runner driver, and checks | |||
| 4 | + | // that the clone it was built from is the one the recorded data is about and | |||
| 5 | + | // that the .NET runtime is the 9.0 line (number formatting and case folding come | |||
| 6 | + | // from the runtime, not from the SDK). | |||
| 7 | + | // | |||
| 8 | + | // RUNNER_CLONE=/path/to/actions/runner node expr/gen/runner/<script>.mjs | |||
| 9 | + | ||||
| 10 | + | import { execFileSync } from "node:child_process"; | |||
| 11 | + | import { readFileSync } from "node:fs"; | |||
| 12 | + | import { join, dirname } from "node:path"; | |||
| 13 | + | import { fileURLToPath } from "node:url"; | |||
| 14 | + | ||||
| 15 | + | export const here = dirname(fileURLToPath(import.meta.url)); | |||
| 16 | + | ||||
| 17 | + | /** The commit of actions/runner the data in testdata/ is about (runner-commit.txt). */ | |||
| 18 | + | export const runnerCommit = readFileSync(join(here, "runner-commit.txt"), "utf8").trim(); | |||
| 19 | + | ||||
| 20 | + | /** The driver built by `dotnet build -c Release expr/gen/runner -p:RunnerSrc=<clone>/src/Sdk`. */ | |||
| 21 | + | export const driver = join(here, "bin/Release/net9.0/runner.dll"); | |||
| 22 | + | ||||
| 23 | + | /** | |||
| 24 | + | * Checks the environment and returns { clone, commit, runtime }. The clone is | |||
| 25 | + | * $RUNNER_CLONE (or the first argument); its HEAD must be runner-commit.txt and | |||
| 26 | + | * its tree clean in src/Sdk, and `dotnet --list-runtimes` must list a | |||
| 27 | + | * Microsoft.NETCore.App 9.0.x. | |||
| 28 | + | */ | |||
| 29 | + | export function checkEnvironment(arg) { | |||
| 30 | + | const clone = process.env.RUNNER_CLONE || arg; | |||
| 31 | + | if (!clone) throw new Error("set RUNNER_CLONE to a clone of https://github.com/actions/runner"); | |||
| 32 | + | const git = (...a) => execFileSync("git", ["-C", clone, ...a]).toString().trim(); | |||
| 33 | + | const commit = git("rev-parse", "HEAD"); | |||
| 34 | + | if (commit !== runnerCommit) throw new Error(`the clone is at ${commit}, the data is about ${runnerCommit} (runner-commit.txt)`); | |||
| 35 | + | if (git("status", "--porcelain", "--", "src/Sdk") !== "") throw new Error("the clone has local changes in src/Sdk"); | |||
| 36 | + | const rt = execFileSync("dotnet", ["--list-runtimes"]).toString().split("\n").filter(l => /^Microsoft\.NETCore\.App 9\.0\.\d+ /.test(l)); | |||
| 37 | + | if (rt.length === 0) throw new Error("no Microsoft.NETCore.App 9.0.x runtime installed (dotnet --list-runtimes)"); | |||
| 38 | + | return { clone, commit, runtime: rt[rt.length - 1].replace(/ \[.*$/, "") }; | |||
| 39 | + | } | |||
| 40 | + | ||||
| 41 | + | /** Runs the driver with args; the environment is checked first. */ | |||
| 42 | + | export function runDriver(args, opts = {}) { | |||
| 43 | + | checkEnvironment(); | |||
| 44 | + | return execFileSync("dotnet", [driver, ...args], { maxBuffer: 1 << 30, ...opts }).toString("utf8"); | |||
| 45 | + | } | |||
M expr/gen/runner/fromjson_cases.mjs +3 -5
| @@ -9,13 +9,11 @@ | |||
| 9 | 9 | // | |
| 10 | 10 | // Needs the built driver, see README.md. | |
| 11 | 11 | ||
| 12 | - | import { execFileSync } from "node:child_process"; | |
| 13 | 12 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | |
| 14 | 13 | import { tmpdir } from "node:os"; | |
| 15 | - | import { join, dirname } from "node:path"; | |
| 16 | - | import { fileURLToPath } from "node:url"; | |
| 14 | + | import { join } from "node:path"; | |
| 15 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; | |
| 17 | 16 | ||
| 18 | - | const here = dirname(fileURLToPath(import.meta.url)); | |
| 19 | 17 | const seeds = [ | |
| 20 | 18 | "null", "true", "false", "NaN", "Infinity", "-Infinity", "undefined", "0", "-0", "010", "08", "0x1F", "1.5e3", ".5", "5.", "12345678901234567890", | |
| 21 | 19 | '"a"', "'a'", '"\\u00e9\\ud83d\\ude00"', '"\\ud800"', "[]", "{}", "[1,2,3]", "[1,]", "[,1]", "[1,,2]", '{"a":1}', '{"a":1,"A":2}', "{a:1}", "{'a':'b'}", | |
| @@ -44,7 +42,7 @@ const lit = s => "'" + s.replaceAll("'", "''") + "'"; | |||
| 44 | 42 | const cases = inputs.map(s => ({ e: `toJSON(fromJSON(${lit(s)}))` })); | |
| 45 | 43 | const tmp = mkdtempSync(join(tmpdir(), "fj-")); | |
| 46 | 44 | writeFileSync(join(tmp, "in.json"), JSON.stringify({ contexts: {}, cases })); | |
| 47 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), join(tmp, "in.json")], { maxBuffer: 1 << 28 }).toString("utf8").split("\n").filter(Boolean); | |
| 45 | + | const out = runDriver([join(tmp, "in.json")]).split("\n").filter(Boolean); | |
| 48 | 46 | rmSync(tmp, { recursive: true }); | |
| 49 | 47 | if (out.length !== inputs.length) throw new Error("answer count"); | |
| 50 | 48 | const res = inputs.map((s, i) => { | |
| @@ -9,13 +9,11 @@ | |||||
| 9 | // | 9 | // | ||
| 10 | // Needs the built driver, see README.md. | 10 | // Needs the built driver, see README.md. | ||
| 11 | 11 | ||||
| 12 | - | import { execFileSync } from "node:child_process"; | |||
| 13 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | 12 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | ||
| 14 | import { tmpdir } from "node:os"; | 13 | import { tmpdir } from "node:os"; | ||
| 15 | - | import { join, dirname } from "node:path"; | 14 | + | import { join } from "node:path"; |
| 16 | - | import { fileURLToPath } from "node:url"; | 15 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; |
| 17 | 16 | ||||
| 18 | - | const here = dirname(fileURLToPath(import.meta.url)); | |||
| 19 | const seeds = [ | 17 | const seeds = [ | ||
| 20 | "null", "true", "false", "NaN", "Infinity", "-Infinity", "undefined", "0", "-0", "010", "08", "0x1F", "1.5e3", ".5", "5.", "12345678901234567890", | 18 | "null", "true", "false", "NaN", "Infinity", "-Infinity", "undefined", "0", "-0", "010", "08", "0x1F", "1.5e3", ".5", "5.", "12345678901234567890", | ||
| 21 | '"a"', "'a'", '"\\u00e9\\ud83d\\ude00"', '"\\ud800"', "[]", "{}", "[1,2,3]", "[1,]", "[,1]", "[1,,2]", '{"a":1}', '{"a":1,"A":2}', "{a:1}", "{'a':'b'}", | 19 | '"a"', "'a'", '"\\u00e9\\ud83d\\ude00"', '"\\ud800"', "[]", "{}", "[1,2,3]", "[1,]", "[,1]", "[1,,2]", '{"a":1}', '{"a":1,"A":2}', "{a:1}", "{'a':'b'}", | ||
| @@ -44,7 +42,7 @@ const lit = s => "'" + s.replaceAll("'", "''") + "'"; | |||||
| 44 | const cases = inputs.map(s => ({ e: `toJSON(fromJSON(${lit(s)}))` })); | 42 | const cases = inputs.map(s => ({ e: `toJSON(fromJSON(${lit(s)}))` })); | ||
| 45 | const tmp = mkdtempSync(join(tmpdir(), "fj-")); | 43 | const tmp = mkdtempSync(join(tmpdir(), "fj-")); | ||
| 46 | writeFileSync(join(tmp, "in.json"), JSON.stringify({ contexts: {}, cases })); | 44 | writeFileSync(join(tmp, "in.json"), JSON.stringify({ contexts: {}, cases })); | ||
| 47 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), join(tmp, "in.json")], { maxBuffer: 1 << 28 }).toString("utf8").split("\n").filter(Boolean); | 45 | + | const out = runDriver([join(tmp, "in.json")]).split("\n").filter(Boolean); |
| 48 | rmSync(tmp, { recursive: true }); | 46 | rmSync(tmp, { recursive: true }); | ||
| 49 | if (out.length !== inputs.length) throw new Error("answer count"); | 47 | if (out.length !== inputs.length) throw new Error("answer count"); | ||
| 50 | const res = inputs.map((s, i) => { | 48 | const res = inputs.map((s, i) => { | ||
M expr/gen/runner/goldens.mjs +3 -5
| @@ -7,19 +7,17 @@ | |||
| 7 | 7 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | |
| 8 | 8 | // node expr/gen/runner/goldens.mjs | |
| 9 | 9 | ||
| 10 | - | import { execFileSync } from "node:child_process"; | |
| 11 | 10 | import { readFileSync, readdirSync, writeFileSync, mkdtempSync, rmSync } from "node:fs"; | |
| 12 | 11 | import { tmpdir } from "node:os"; | |
| 13 | - | import { join, dirname } from "node:path"; | |
| 14 | - | import { fileURLToPath } from "node:url"; | |
| 12 | + | import { join } from "node:path"; | |
| 13 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; | |
| 15 | 14 | ||
| 16 | - | const here = dirname(fileURLToPath(import.meta.url)); | |
| 17 | 15 | const dir = join(here, "../../testdata/tojson"); | |
| 18 | 16 | const names = readdirSync(dir).filter(f => f.endsWith(".json")).map(f => f.slice(0, -5)).sort(); | |
| 19 | 17 | const cases = names.map(n => ({ e: `toJSON(fromJSON('${readFileSync(join(dir, n + ".json"), "utf8").replaceAll("'", "''")}'))` })); | |
| 20 | 18 | const tmp = mkdtempSync(join(tmpdir(), "goldens-")); | |
| 21 | 19 | writeFileSync(join(tmp, "in.json"), JSON.stringify({ contexts: {}, cases })); | |
| 22 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), join(tmp, "in.json")], { maxBuffer: 1 << 28 }).toString("utf8").split("\n").filter(Boolean); | |
| 20 | + | const out = runDriver([join(tmp, "in.json")]).split("\n").filter(Boolean); | |
| 23 | 21 | rmSync(tmp, { recursive: true }); | |
| 24 | 22 | names.forEach((n, i) => { | |
| 25 | 23 | const r = JSON.parse(out[i]); | |
| @@ -7,19 +7,17 @@ | |||||
| 7 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | 7 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | ||
| 8 | // node expr/gen/runner/goldens.mjs | 8 | // node expr/gen/runner/goldens.mjs | ||
| 9 | 9 | ||||
| 10 | - | import { execFileSync } from "node:child_process"; | |||
| 11 | import { readFileSync, readdirSync, writeFileSync, mkdtempSync, rmSync } from "node:fs"; | 10 | import { readFileSync, readdirSync, writeFileSync, mkdtempSync, rmSync } from "node:fs"; | ||
| 12 | import { tmpdir } from "node:os"; | 11 | import { tmpdir } from "node:os"; | ||
| 13 | - | import { join, dirname } from "node:path"; | 12 | + | import { join } from "node:path"; |
| 14 | - | import { fileURLToPath } from "node:url"; | 13 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; |
| 15 | 14 | ||||
| 16 | - | const here = dirname(fileURLToPath(import.meta.url)); | |||
| 17 | const dir = join(here, "../../testdata/tojson"); | 15 | const dir = join(here, "../../testdata/tojson"); | ||
| 18 | const names = readdirSync(dir).filter(f => f.endsWith(".json")).map(f => f.slice(0, -5)).sort(); | 16 | const names = readdirSync(dir).filter(f => f.endsWith(".json")).map(f => f.slice(0, -5)).sort(); | ||
| 19 | const cases = names.map(n => ({ e: `toJSON(fromJSON('${readFileSync(join(dir, n + ".json"), "utf8").replaceAll("'", "''")}'))` })); | 17 | const cases = names.map(n => ({ e: `toJSON(fromJSON('${readFileSync(join(dir, n + ".json"), "utf8").replaceAll("'", "''")}'))` })); | ||
| 20 | const tmp = mkdtempSync(join(tmpdir(), "goldens-")); | 18 | const tmp = mkdtempSync(join(tmpdir(), "goldens-")); | ||
| 21 | writeFileSync(join(tmp, "in.json"), JSON.stringify({ contexts: {}, cases })); | 19 | writeFileSync(join(tmp, "in.json"), JSON.stringify({ contexts: {}, cases })); | ||
| 22 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), join(tmp, "in.json")], { maxBuffer: 1 << 28 }).toString("utf8").split("\n").filter(Boolean); | 20 | + | const out = runDriver([join(tmp, "in.json")]).split("\n").filter(Boolean); |
| 23 | rmSync(tmp, { recursive: true }); | 21 | rmSync(tmp, { recursive: true }); | ||
| 24 | names.forEach((n, i) => { | 22 | names.forEach((n, i) => { | ||
| 25 | const r = JSON.parse(out[i]); | 23 | const r = JSON.parse(out[i]); | ||
M expr/gen/runner/number_cases.mjs +3 -5
| @@ -8,13 +8,11 @@ | |||
| 8 | 8 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | |
| 9 | 9 | // node expr/gen/runner/number_cases.mjs > expr/testdata/number_cases.txt | |
| 10 | 10 | ||
| 11 | - | import { execFileSync } from "node:child_process"; | |
| 12 | 11 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | |
| 13 | 12 | import { tmpdir } from "node:os"; | |
| 14 | - | import { join, dirname } from "node:path"; | |
| 15 | - | import { fileURLToPath } from "node:url"; | |
| 13 | + | import { join } from "node:path"; | |
| 14 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; | |
| 16 | 15 | ||
| 17 | - | const here = dirname(fileURLToPath(import.meta.url)); | |
| 18 | 16 | const set = new Set(); | |
| 19 | 17 | const add = s => set.add(s); | |
| 20 | 18 | const base = ["", " ", "0", "00", "-0", "+0", "1", "-1", "+1", "12", "007", "1.5", "-1.5", "1.", ".5", "-.5", "+.5", ".", "-.", "+.", "..", "1..2", "1.2.3", | |
| @@ -36,7 +34,7 @@ const hex = s => s.length ? [...s].flatMap(c => { const n = c.codePointAt(0); re | |||
| 36 | 34 | const all = [...set]; | |
| 37 | 35 | const tmp = mkdtempSync(join(tmpdir(), "num-")); | |
| 38 | 36 | writeFileSync(join(tmp, "in.txt"), all.map(hex).join("\n") + "\n"); | |
| 39 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), "--num", join(tmp, "in.txt")], { maxBuffer: 1 << 28 }).toString().split("\n").filter(Boolean); | |
| 37 | + | const out = runDriver(["--num", join(tmp, "in.txt")]).split("\n").filter(Boolean); | |
| 40 | 38 | rmSync(tmp, { recursive: true }); | |
| 41 | 39 | if (out.length !== all.length) throw new Error("answer count"); | |
| 42 | 40 | process.stdout.write(all.map((s, i) => `${hex(s)} ${out[i]}`).join("\n") + "\n"); | |
| @@ -8,13 +8,11 @@ | |||||
| 8 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | 8 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | ||
| 9 | // node expr/gen/runner/number_cases.mjs > expr/testdata/number_cases.txt | 9 | // node expr/gen/runner/number_cases.mjs > expr/testdata/number_cases.txt | ||
| 10 | 10 | ||||
| 11 | - | import { execFileSync } from "node:child_process"; | |||
| 12 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | 11 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | ||
| 13 | import { tmpdir } from "node:os"; | 12 | import { tmpdir } from "node:os"; | ||
| 14 | - | import { join, dirname } from "node:path"; | 13 | + | import { join } from "node:path"; |
| 15 | - | import { fileURLToPath } from "node:url"; | 14 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; |
| 16 | 15 | ||||
| 17 | - | const here = dirname(fileURLToPath(import.meta.url)); | |||
| 18 | const set = new Set(); | 16 | const set = new Set(); | ||
| 19 | const add = s => set.add(s); | 17 | const add = s => set.add(s); | ||
| 20 | const base = ["", " ", "0", "00", "-0", "+0", "1", "-1", "+1", "12", "007", "1.5", "-1.5", "1.", ".5", "-.5", "+.5", ".", "-.", "+.", "..", "1..2", "1.2.3", | 18 | const base = ["", " ", "0", "00", "-0", "+0", "1", "-1", "+1", "12", "007", "1.5", "-1.5", "1.", ".5", "-.5", "+.5", ".", "-.", "+.", "..", "1..2", "1.2.3", | ||
| @@ -36,7 +34,7 @@ const hex = s => s.length ? [...s].flatMap(c => { const n = c.codePointAt(0); re | |||||
| 36 | const all = [...set]; | 34 | const all = [...set]; | ||
| 37 | const tmp = mkdtempSync(join(tmpdir(), "num-")); | 35 | const tmp = mkdtempSync(join(tmpdir(), "num-")); | ||
| 38 | writeFileSync(join(tmp, "in.txt"), all.map(hex).join("\n") + "\n"); | 36 | writeFileSync(join(tmp, "in.txt"), all.map(hex).join("\n") + "\n"); | ||
| 39 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), "--num", join(tmp, "in.txt")], { maxBuffer: 1 << 28 }).toString().split("\n").filter(Boolean); | 37 | + | const out = runDriver(["--num", join(tmp, "in.txt")]).split("\n").filter(Boolean); |
| 40 | rmSync(tmp, { recursive: true }); | 38 | rmSync(tmp, { recursive: true }); | ||
| 41 | if (out.length !== all.length) throw new Error("answer count"); | 39 | if (out.length !== all.length) throw new Error("answer count"); | ||
| 42 | process.stdout.write(all.map((s, i) => `${hex(s)} ${out[i]}`).join("\n") + "\n"); | 40 | process.stdout.write(all.map((s, i) => `${hex(s)} ${out[i]}`).join("\n") + "\n"); | ||
M expr/gen/runner/ordinal_cases.mjs +3 -5
| @@ -8,13 +8,11 @@ | |||
| 8 | 8 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | |
| 9 | 9 | // node expr/gen/runner/ordinal_cases.mjs > expr/testdata/ordinal_cases.txt | |
| 10 | 10 | ||
| 11 | - | import { execFileSync } from "node:child_process"; | |
| 12 | 11 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | |
| 13 | 12 | import { tmpdir } from "node:os"; | |
| 14 | - | import { join, dirname } from "node:path"; | |
| 15 | - | import { fileURLToPath } from "node:url"; | |
| 13 | + | import { join } from "node:path"; | |
| 14 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; | |
| 16 | 15 | ||
| 17 | - | const here = dirname(fileURLToPath(import.meta.url)); | |
| 18 | 16 | const words = [ | |
| 19 | 17 | "", "a", "A", "ab", "AB", "abc", "ABC", "Hello", "hELLO", "hello world", "true", "TRUE", "null", | |
| 20 | 18 | "ß", "SS", "ss", "ẞ", "ʼn", "ʼN", "ffi", "FFI", "ffi", "ı", "I", "i", "İ", "ſ", "s", "S", | |
| @@ -29,7 +27,7 @@ const lines = []; | |||
| 29 | 27 | for (const a of words) for (const b of words) lines.push(`${hex(a)} ${hex(b)}`); | |
| 30 | 28 | const tmp = mkdtempSync(join(tmpdir(), "ordinal-")); | |
| 31 | 29 | writeFileSync(join(tmp, "in.txt"), lines.join("\n") + "\n"); | |
| 32 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), "--cmp", join(tmp, "in.txt")], { maxBuffer: 1 << 28 }).toString().split("\n").filter(Boolean); | |
| 30 | + | const out = runDriver(["--cmp", join(tmp, "in.txt")]).split("\n").filter(Boolean); | |
| 33 | 31 | rmSync(tmp, { recursive: true }); | |
| 34 | 32 | if (out.length !== lines.length) throw new Error("answer count"); | |
| 35 | 33 | // Keep every pair that is interesting (some predicate true) and a sample of the rest, to bound the file. | |
| @@ -8,13 +8,11 @@ | |||||
| 8 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | 8 | // dotnet build -c Release expr/gen/runner -p:RunnerSrc=<runner>/src/Sdk | ||
| 9 | // node expr/gen/runner/ordinal_cases.mjs > expr/testdata/ordinal_cases.txt | 9 | // node expr/gen/runner/ordinal_cases.mjs > expr/testdata/ordinal_cases.txt | ||
| 10 | 10 | ||||
| 11 | - | import { execFileSync } from "node:child_process"; | |||
| 12 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | 11 | import { writeFileSync, mkdtempSync, rmSync } from "node:fs"; | ||
| 13 | import { tmpdir } from "node:os"; | 12 | import { tmpdir } from "node:os"; | ||
| 14 | - | import { join, dirname } from "node:path"; | 13 | + | import { join } from "node:path"; |
| 15 | - | import { fileURLToPath } from "node:url"; | 14 | + | import { runDriver, here, checkEnvironment } from "./env.mjs"; |
| 16 | 15 | ||||
| 17 | - | const here = dirname(fileURLToPath(import.meta.url)); | |||
| 18 | const words = [ | 16 | const words = [ | ||
| 19 | "", "a", "A", "ab", "AB", "abc", "ABC", "Hello", "hELLO", "hello world", "true", "TRUE", "null", | 17 | "", "a", "A", "ab", "AB", "abc", "ABC", "Hello", "hELLO", "hello world", "true", "TRUE", "null", | ||
| 20 | "ß", "SS", "ss", "ẞ", "ʼn", "ʼN", "ffi", "FFI", "ffi", "ı", "I", "i", "İ", "ſ", "s", "S", | 18 | "ß", "SS", "ss", "ẞ", "ʼn", "ʼN", "ffi", "FFI", "ffi", "ı", "I", "i", "İ", "ſ", "s", "S", | ||
| @@ -29,7 +27,7 @@ const lines = []; | |||||
| 29 | for (const a of words) for (const b of words) lines.push(`${hex(a)} ${hex(b)}`); | 27 | for (const a of words) for (const b of words) lines.push(`${hex(a)} ${hex(b)}`); | ||
| 30 | const tmp = mkdtempSync(join(tmpdir(), "ordinal-")); | 28 | const tmp = mkdtempSync(join(tmpdir(), "ordinal-")); | ||
| 31 | writeFileSync(join(tmp, "in.txt"), lines.join("\n") + "\n"); | 29 | writeFileSync(join(tmp, "in.txt"), lines.join("\n") + "\n"); | ||
| 32 | - | const out = execFileSync("dotnet", [join(here, "bin/Release/net9.0/runner.dll"), "--cmp", join(tmp, "in.txt")], { maxBuffer: 1 << 28 }).toString().split("\n").filter(Boolean); | 30 | + | const out = runDriver(["--cmp", join(tmp, "in.txt")]).split("\n").filter(Boolean); |
| 33 | rmSync(tmp, { recursive: true }); | 31 | rmSync(tmp, { recursive: true }); | ||
| 34 | if (out.length !== lines.length) throw new Error("answer count"); | 32 | if (out.length !== lines.length) throw new Error("answer count"); | ||
| 35 | // Keep every pair that is interesting (some predicate true) and a sample of the rest, to bound the file. | 33 | // Keep every pair that is interesting (some predicate true) and a sample of the rest, to bound the file. | ||
A expr/gen/runner/runner-commit.txt +1 -0
| @@ -0,0 +1,1 @@ | |||
| 1 | + | 5f0b3ddcc6ee9fe9441e00d55e85b94ea4aad798 | |
| @@ -0,0 +1,1 @@ | |||||
| 1 | + | 5f0b3ddcc6ee9fe9441e00d55e85b94ea4aad798 | |||
M expr/gen/runner/runner.csproj +4 -1
| @@ -10,8 +10,11 @@ | |||
| 10 | 10 | <NoWarn>NU1701;CS8632;CS0108;CS0114;CS1591;CS0618;SYSLIB0050</NoWarn> | |
| 11 | 11 | <EnableDefaultCompileItems>false</EnableDefaultCompileItems> | |
| 12 | 12 | <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |
| 13 | - | <RunnerSrc Condition="'$(RunnerSrc)' == ''">$(HOME)/dev/clones/runner/src/Sdk</RunnerSrc> | |
| 14 | 13 | </PropertyGroup> | |
| 14 | + | <Target Name="RequireRunnerSrc" BeforeTargets="BeforeBuild;CoreCompile"> | |
| 15 | + | <Error Condition="'$(RunnerSrc)' == '' Or !Exists('$(RunnerSrc)/DTExpressions2')" Text="Set RunnerSrc to the src/Sdk directory of a clone of actions/runner at the commit in runner-commit.txt: dotnet build -c Release expr/gen/runner -p:RunnerSrc=<clone>/src/Sdk" /> | |
| 16 | + | </Target> | |
| 17 | + | ||
| 15 | 18 | <ItemGroup> | |
| 16 | 19 | <Compile Include="$(RunnerSrc)/DTExpressions2/**/*.cs" /> | |
| 17 | 20 | <Compile Include="$(RunnerSrc)/DTLogging/**/*.cs" /> | |
| @@ -10,8 +10,11 @@ | |||||
| 10 | <NoWarn>NU1701;CS8632;CS0108;CS0114;CS1591;CS0618;SYSLIB0050</NoWarn> | 10 | <NoWarn>NU1701;CS8632;CS0108;CS0114;CS1591;CS0618;SYSLIB0050</NoWarn> | ||
| 11 | <EnableDefaultCompileItems>false</EnableDefaultCompileItems> | 11 | <EnableDefaultCompileItems>false</EnableDefaultCompileItems> | ||
| 12 | <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | 12 | <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
| 13 | - | <RunnerSrc Condition="'$(RunnerSrc)' == ''">$(HOME)/dev/clones/runner/src/Sdk</RunnerSrc> | |||
| 14 | </PropertyGroup> | 13 | </PropertyGroup> | ||
| 14 | + | <Target Name="RequireRunnerSrc" BeforeTargets="BeforeBuild;CoreCompile"> | |||
| 15 | + | <Error Condition="'$(RunnerSrc)' == '' Or !Exists('$(RunnerSrc)/DTExpressions2')" Text="Set RunnerSrc to the src/Sdk directory of a clone of actions/runner at the commit in runner-commit.txt: dotnet build -c Release expr/gen/runner -p:RunnerSrc=<clone>/src/Sdk" /> | |||
| 16 | + | </Target> | |||
| 17 | + | ||||
| 15 | <ItemGroup> | 18 | <ItemGroup> | ||
| 16 | <Compile Include="$(RunnerSrc)/DTExpressions2/**/*.cs" /> | 19 | <Compile Include="$(RunnerSrc)/DTExpressions2/**/*.cs" /> | ||
| 17 | <Compile Include="$(RunnerSrc)/DTLogging/**/*.cs" /> | 20 | <Compile Include="$(RunnerSrc)/DTLogging/**/*.cs" /> | ||
M expr/runner_oracle_test.go +30 -0
| @@ -20,6 +20,12 @@ import ( | |||
| 20 | 20 | // and this package follows it (see PORTING.md). TestOracle excuses a mismatch | |
| 21 | 21 | // with the JavaScript only if this package gives the runner's answer there. | |
| 22 | 22 | ||
| 23 | + | // runnerCommit is the commit of actions/runner that every file recorded from the | |
| 24 | + | // runner is about. gen/runner/runner-commit.txt holds the same value and the | |
| 25 | + | // generator scripts refuse a clone at another commit; TestRunnerCommit checks | |
| 26 | + | // that the two agree and that runner.json.gz was made from it. | |
| 27 | + | const runnerCommit = "5f0b3ddcc6ee9fe9441e00d55e85b94ea4aad798" | |
| 28 | + | ||
| 23 | 29 | type runnerFile struct { | |
| 24 | 30 | Reference struct { | |
| 25 | 31 | Source string `json:"source"` | |
| @@ -179,3 +185,27 @@ func TestSameAnswerFromJSON(t *testing.T) { | |||
| 179 | 185 | } | |
| 180 | 186 | } | |
| 181 | 187 | } | |
| 188 | + | ||
| 189 | + | func TestRunnerCommit(t *testing.T) { | |
| 190 | + | txt, err := os.ReadFile("gen/runner/runner-commit.txt") | |
| 191 | + | if err != nil { | |
| 192 | + | t.Fatal(err) | |
| 193 | + | } | |
| 194 | + | if got := strings.TrimSpace(string(txt)); got != runnerCommit { | |
| 195 | + | t.Errorf("gen/runner/runner-commit.txt = %q, runnerCommit = %q", got, runnerCommit) | |
| 196 | + | } | |
| 197 | + | rf := loadRunner(t) | |
| 198 | + | if rf.Reference.Commit != runnerCommit { | |
| 199 | + | t.Errorf("testdata/runner.json.gz was recorded at %s, want %s", rf.Reference.Commit, runnerCommit) | |
| 200 | + | } | |
| 201 | + | if !strings.HasPrefix(rf.Reference.Runtime, "Microsoft.NETCore.App 9.0.") { | |
| 202 | + | t.Errorf("runtime %q, want Microsoft.NETCore.App 9.0.x", rf.Reference.Runtime) | |
| 203 | + | } | |
| 204 | + | doc, err := os.ReadFile("PORTING.md") | |
| 205 | + | if err != nil { | |
| 206 | + | t.Fatal(err) | |
| 207 | + | } | |
| 208 | + | if !strings.Contains(string(doc), runnerCommit) { | |
| 209 | + | t.Errorf("PORTING.md does not mention the runner commit %s", runnerCommit) | |
| 210 | + | } | |
| 211 | + | } | |
| @@ -20,6 +20,12 @@ import ( | |||||
| 20 | // and this package follows it (see PORTING.md). TestOracle excuses a mismatch | 20 | // and this package follows it (see PORTING.md). TestOracle excuses a mismatch | ||
| 21 | // with the JavaScript only if this package gives the runner's answer there. | 21 | // with the JavaScript only if this package gives the runner's answer there. | ||
| 22 | 22 | ||||
| 23 | + | // runnerCommit is the commit of actions/runner that every file recorded from the | |||
| 24 | + | // runner is about. gen/runner/runner-commit.txt holds the same value and the | |||
| 25 | + | // generator scripts refuse a clone at another commit; TestRunnerCommit checks | |||
| 26 | + | // that the two agree and that runner.json.gz was made from it. | |||
| 27 | + | const runnerCommit = "5f0b3ddcc6ee9fe9441e00d55e85b94ea4aad798" | |||
| 28 | + | ||||
| 23 | type runnerFile struct { | 29 | type runnerFile struct { | ||
| 24 | Reference struct { | 30 | Reference struct { | ||
| 25 | Source string `json:"source"` | 31 | Source string `json:"source"` | ||
| @@ -179,3 +185,27 @@ func TestSameAnswerFromJSON(t *testing.T) { | |||||
| 179 | } | 185 | } | ||
| 180 | } | 186 | } | ||
| 181 | } | 187 | } | ||
| 188 | + | ||||
| 189 | + | func TestRunnerCommit(t *testing.T) { | |||
| 190 | + | txt, err := os.ReadFile("gen/runner/runner-commit.txt") | |||
| 191 | + | if err != nil { | |||
| 192 | + | t.Fatal(err) | |||
| 193 | + | } | |||
| 194 | + | if got := strings.TrimSpace(string(txt)); got != runnerCommit { | |||
| 195 | + | t.Errorf("gen/runner/runner-commit.txt = %q, runnerCommit = %q", got, runnerCommit) | |||
| 196 | + | } | |||
| 197 | + | rf := loadRunner(t) | |||
| 198 | + | if rf.Reference.Commit != runnerCommit { | |||
| 199 | + | t.Errorf("testdata/runner.json.gz was recorded at %s, want %s", rf.Reference.Commit, runnerCommit) | |||
| 200 | + | } | |||
| 201 | + | if !strings.HasPrefix(rf.Reference.Runtime, "Microsoft.NETCore.App 9.0.") { | |||
| 202 | + | t.Errorf("runtime %q, want Microsoft.NETCore.App 9.0.x", rf.Reference.Runtime) | |||
| 203 | + | } | |||
| 204 | + | doc, err := os.ReadFile("PORTING.md") | |||
| 205 | + | if err != nil { | |||
| 206 | + | t.Fatal(err) | |||
| 207 | + | } | |||
| 208 | + | if !strings.Contains(string(doc), runnerCommit) { | |||
| 209 | + | t.Errorf("PORTING.md does not mention the runner commit %s", runnerCommit) | |||
| 210 | + | } | |||
| 211 | + | } | |||
M expr/testdata/runner.json.gz +0 -0 binary file: no text diff
binary file: no text diff