Skip to content

Commit b44581a

Browse files
committed
Check CI shard coverage as a file set, not a path string
Subdirectory shards (src-a/b/c) can never equal the literal ./src filter string, so the gate now expands both sides to test files. Sorted-array equality still fails on a dropped file or a file covered twice.
1 parent 2880f9a commit b44581a

1 file changed

Lines changed: 36 additions & 11 deletions

File tree

tests/unit/check-gate.test.ts

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { readFileSync } from "node:fs";
2-
import { join } from "node:path";
1+
import { readdirSync, readFileSync, statSync } from "node:fs";
2+
import { join, relative } from "node:path";
33
import { describe, expect, test } from "bun:test";
44

55
// Guard against the gate drifting apart again (CL-7300): `bun run check` and
@@ -27,6 +27,25 @@ const GUARD_SCRIPT = "check:projects-dir-guard";
2727
const TEST_SUITE =
2828
"bun test ./src ./tests ./evals ./scripts --randomize --seed 424242";
2929

30+
function expandToTestFiles(filters: string[]): string[] {
31+
const files: string[] = [];
32+
const walk = (dir: string) => {
33+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
34+
const absolute = join(dir, entry.name);
35+
if (entry.isDirectory()) walk(absolute);
36+
else if (entry.name.endsWith(".test.ts"))
37+
files.push(relative(repoRoot, absolute).split("/").join("/"));
38+
}
39+
};
40+
for (const filter of filters) {
41+
const absolute = join(repoRoot, filter.replace(/^\.\//, ""));
42+
if (statSync(absolute).isFile())
43+
files.push(relative(repoRoot, absolute).split("/").join("/"));
44+
else walk(absolute);
45+
}
46+
return files.sort();
47+
}
48+
3049
describe("check gate", () => {
3150
test("`test` is the seeded, randomized one-process suite whose path union CI shards", () => {
3251
expect(pkg.scripts.test).toBe(TEST_SUITE);
@@ -67,14 +86,20 @@ describe("check gate", () => {
6786
});
6887

6988
test("CI test shards cover exactly the suite's paths", () => {
70-
// Sharding must never silently drop part of the suite: the union of the
71-
// matrix shards has to equal the unsharded `test` script's paths.
72-
const shardPaths = [...ci.matchAll(/^\s+paths: (.+)$/gm)]
73-
.flatMap((match) => match[1]?.trim().split(/\s+/) ?? [])
74-
.sort();
75-
const suitePaths = TEST_SUITE.split(" ")
76-
.filter((part) => part.startsWith("./"))
77-
.sort();
78-
expect(shardPaths).toEqual(suitePaths);
89+
// Sharding must never silently drop (or double-run) part of the suite:
90+
// expanding the matrix shards' filters to test files has to equal the
91+
// unsharded `test` script's paths expanded the same way. Subdirectory
92+
// shards (src-a/b/c) can never equal the literal ./src string, so this
93+
// compares sorted file sets; a file covered twice fails the equality
94+
// through the duplicate entry.
95+
const shardFilters = [...ci.matchAll(/^\s+paths: (.+)$/gm)].flatMap(
96+
(match) => match[1]?.trim().split(/\s+/) ?? [],
97+
);
98+
const suiteFilters = TEST_SUITE.split(" ").filter((part) =>
99+
part.startsWith("./"),
100+
);
101+
expect(expandToTestFiles(shardFilters)).toEqual(
102+
expandToTestFiles(suiteFilters),
103+
);
79104
});
80105
});

0 commit comments

Comments
 (0)