Files
oh-my-pi/packages/coding-agent/test/tools/find-validate-paths.test.ts
T
oldschoola 96aad47eb6 fix(coding-agent): address PR #1388 review feedback
Refactor:
- session.ts: extract mapDebugpyMissingModule helper; replace the duplicated
  inline check in launch/attach catch blocks. Add jsdoc on DapStartRequestFailure.settled
  documenting per-call ownership and how throwPreferredDapStartError consumes it.
- path-utils.ts: replace the no-op keepOpaqueResourceUri branch with an
  OPAQUE_RESOURCE_SCHEMES Set so the structure carries the intent. Functionally
  equivalent; new opaque schemes become a one-line Set change.

Tests:
- dap-launch-failures: cover the debugpy stderr -> 'pip install debugpy'
  rewrite for launch and attach, plus a negative case (non-debugpy adapter
  with the substring in stderr is left untouched).
- dap-launch-failures: model the delayed-launch-failure case the new
  settled-race in throwPreferredDapStartError defends against. FakeDapClient
  gains optional launchErrorDelayMs/attachErrorDelayMs.
- dap-launch-failures (DebugTool): assert adapter:'debugpy' early-throw
  surfaces 'python not found in PATH' on both launch and attach when
  selectLaunchAdapter/selectAttachAdapter return null, and the unspecified-adapter
  path still falls back to the generic 'No debugger adapter' error.
- find.ts: export validateFindPathInputs and pin the new backslash-escape
  semantics (\, no longer trips the comma-joined heuristic) plus the
  existing brace-expansion and rejection paths.
- patch.ts: cover the post-write verification error message. The user-facing
  ToolError must contain the caller-supplied relative path and not the
  absolute resolvedPath (which still lives in the structured context for
  log correlation).
- split-internal-url-sel: reword two mcp:// test comments that described a
  'peeler refuses' guard that doesn't exist; rename the tests to reflect the
  actual opaque-scheme rule.
2026-05-26 01:54:09 -07:00

43 lines
1.9 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import { validateFindPathInputs } from "../../src/tools/find";
describe("validateFindPathInputs", () => {
it("accepts a normal array of glob entries", () => {
expect(() => validateFindPathInputs(["src/**/*.ts", "test/**/*.ts"])).not.toThrow();
});
it('rejects comma-joined entries (the `["a,b"]` shape)', () => {
expect(() => validateFindPathInputs(["a.py,b.py"])).toThrow(/paths is an array/);
});
it("allows commas inside brace expansion", () => {
expect(() => validateFindPathInputs(["src/{a,b}/*.ts"])).not.toThrow();
expect(() => validateFindPathInputs(["{foo,bar,baz}.md"])).not.toThrow();
});
it("allows backslash-escaped commas at top level (matches search.ts:containsTopLevelComma)", () => {
// Backslash-escapes a literal comma in a filename — must not trip the
// array-vs-string heuristic.
expect(() => validateFindPathInputs(["weird\\,name.txt"])).not.toThrow();
expect(() => validateFindPathInputs(["a\\,b\\,c"])).not.toThrow();
});
it("still rejects unescaped top-level commas mixed with escaped ones", () => {
// `a\,b,c` — the second comma is unescaped, so the heuristic should fire.
expect(() => validateFindPathInputs(["a\\,b,c"])).toThrow(/paths is an array/);
});
it("allows a trailing backslash without crashing", () => {
// `foo\\` is a backslash at end-of-string; the i+1<length guard must hold.
expect(() => validateFindPathInputs(["foo\\"])).not.toThrow();
});
it("treats `\\{a,b}` as an escaped brace, so the inner comma is still top-level", () => {
// Skip-next semantics: the backslash consumes the `{`, so braceDepth stays 0
// and the unescaped `,` between `a` and `b` rejects. This pins the literal
// behavior of the new escape-skip, which intentionally does NOT model glob
// brace semantics — it only mirrors search.ts's containsTopLevelComma.
expect(() => validateFindPathInputs(["\\{a,b}"])).toThrow(/paths is an array/);
});
});