Skip to content

Commit 69fa10a

Browse files
committed
test(cli): assert source on every resolvePlatformBinary tier, and add the missing match-mode refusal
platform-binary.test.ts's candidate-order suite already pins PATH's tie-break ordering but never read .source, so a resolver that always reported "platform-package" (the pinned-binary claim callers gate on) would have passed. Add source assertions to the two PATH-tier tests and a new case for the node_modules/.bin tier; platform-package and undefined are already covered in engine-version-consistency.test.ts. engine-dispatch.test.ts's REFUSALS table covers every other reason a runtime capture is refused but had no case for an unimplemented match: value, even though "must not be coerced to anchor" is asMatchMode's central claim. Add that case. Coverage only, no production changes.
1 parent 2d088fa commit 69fa10a

2 files changed

Lines changed: 68 additions & 4 deletions

File tree

‎packages/cli/test/engine-dispatch.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,19 @@ describe("engine dispatch by directory", () => {
434434
RUNTIME_CAPTURE.replace("id: logs-abc12345\n", ""),
435435
/no string `id`/,
436436
],
437+
[
438+
// asMatchMode's central claim: an unimplemented `match:` is refused, not
439+
// coerced to `anchor`. `anchor` and `broad` scan differently — `anchor`
440+
// is a syntactic narrow, `broad` a whole-language enumerator — so
441+
// silently falling back would run the capture as a narrow, match a
442+
// fraction of what it was written for, and report the shortfall as a
443+
// clean pass. The `it.each` above already asserts the capture is
444+
// dropped from discovery; this asserts `verify` explains why, which is
445+
// what REFUSALS exists to cover for every other reason.
446+
"unimplemented match mode",
447+
RUNTIME_CAPTURE.replace("match: anchor", "match: whole-repo"),
448+
/match: "whole-repo", which this build does not implement/,
449+
],
437450
];
438451

439452
it.each(REFUSALS)(

‎packages/cli/test/platform-binary.test.ts‎

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
chmodSync,
3+
mkdirSync,
34
mkdtempSync,
45
readFileSync,
56
rmSync,
@@ -167,7 +168,14 @@ describe("candidate order", () => {
167168
const originalPath = process.env.PATH;
168169
process.env.PATH = directory;
169170
try {
170-
expect(resolvePlatformBinary(FAKE).path).toBe(join(directory, "sg"));
171+
const resolution = resolvePlatformBinary(FAKE);
172+
expect(resolution.path).toBe(join(directory, "sg"));
173+
// The tier that answered, not just the path: a resolver that always
174+
// reported "platform-package" would still pass every assertion above,
175+
// since FAKE's platform-package tier is deliberately unresolvable and
176+
// the path itself only proves *a* file was found, not which search tier
177+
// found it.
178+
expect(resolution.source).toBe("PATH");
171179
} finally {
172180
process.env.PATH = originalPath;
173181
}
@@ -178,14 +186,57 @@ describe("candidate order", () => {
178186
const originalPath = process.env.PATH;
179187
process.env.PATH = directory;
180188
try {
181-
expect(resolvePlatformBinary(FAKE).path).toBe(
182-
join(directory, "ast-grep")
183-
);
189+
const resolution = resolvePlatformBinary(FAKE);
190+
expect(resolution.path).toBe(join(directory, "ast-grep"));
191+
expect(resolution.source).toBe("PATH");
184192
} finally {
185193
process.env.PATH = originalPath;
186194
}
187195
});
188196

197+
/**
198+
* The tier `resolvePlatformBinary` searches between the pinned platform
199+
* package and PATH: a binary linked into the CLI's own `node_modules/.bin`.
200+
*
201+
* `platform-package` and `undefined` are already pinned in
202+
* `engine-version-consistency.test.ts`, and `PATH` above. Every closed-set
203+
* value `source` can take needs its own case — a resolver that collapsed
204+
* this tier's result to `"PATH"` (they are searched by the same loop, over
205+
* the same candidate list) would pass every other test in this file.
206+
*/
207+
onUnix(
208+
"reports node_modules/.bin as the source when that tier answers",
209+
() => {
210+
// Mirrors the computation `resolvePlatformBinary` uses internally
211+
// (relative to the compiled module's own directory) — this is the exact
212+
// location that tier searches, not a stand-in for it.
213+
const localBin = join(
214+
import.meta.dirname,
215+
"..",
216+
"src",
217+
"node_modules",
218+
".bin"
219+
);
220+
mkdirSync(localBin, { recursive: true });
221+
workspaces.push(join(import.meta.dirname, "..", "src", "node_modules"));
222+
const binaryPath = join(localBin, "sg");
223+
writeFileSync(binaryPath, "#!/bin/sh\necho 'fake-tool 1.0.0'\n");
224+
chmodSync(binaryPath, 0o755);
225+
226+
// Keep PATH from also containing a match, so only the .bin tier can
227+
// answer.
228+
const originalPath = process.env.PATH;
229+
process.env.PATH = "";
230+
try {
231+
const resolution = resolvePlatformBinary(FAKE);
232+
expect(resolution.path).toBe(binaryPath);
233+
expect(resolution.source).toBe("node_modules/.bin");
234+
} finally {
235+
process.env.PATH = originalPath;
236+
}
237+
}
238+
);
239+
189240
it("names each searched location once, however many spellings it tried", () => {
190241
// The platform package is probed under one name, and a tier searched under
191242
// two spellings is still one place to look; repeating a label makes

0 commit comments

Comments
 (0)