Skip to content

fix(cli): wheels test preamble stops doubling _test for coreTestDataSourceName-only configs (#2489) - #2602

Merged
bpamiri merged 3 commits into
developfrom
claude/unruffled-margulis-3a4c9a
May 12, 2026
Merged

bpamiri merged 3 commits into
developfrom
claude/unruffled-margulis-3a4c9a

Conversation

@bpamiri

@bpamiri bpamiri commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Resolves #2489.

The reporter saw Running app tests (testappdb_test_test)... when their config/settings.cfm only declared set(coreTestDataSourceName="testappdb_test"). $resolveAppTestDataSource in cli/lucli/Module.cfc used dataSourceName\s*=\s*"([^"]*)" to scan settings.cfm — and because reFindNoCase is case-insensitive and the pattern had no anchors, it caught the trailing substring inside coreTestDataSourceName, then re-appended _test. The CLI was lying about which datasource the run would use against.

Fixes

  • $resolveAppTestDataSource (cli/lucli/Module.cfc):

    • Settings.cfm matcher now uses \bdataSourceName\b\s*=\s*"([^"]*)" and strips CFML/cfscript/tag-style comments first, matching the pattern info() already uses one screen up the file.
    • .env matcher is anchored to start-of-line so MY_DATASOURCE_NAME=foo or unrelated keys whose names happen to end in DATASOURCE_NAME don't false-match.
    • Defensive guard: if the resolved base already ends in _test, don't append again. Prevents future regressions if a user names their app datasource myapp_test.
    • Exposed as public (matching the $-prefix-for-internal convention used by $normalizeTestFilter) so the new regression specs can drive it directly.
  • Extracted TestDirectoryResolver from app-runner.cfm alongside the existing TestDbResolver, so the directory-scope rule (^tests(\.[a-zA-Z0-9_]+)*$) is unit-testable instead of HTTP-only. The reporter's second complaint — --filter=models still ignored on the latest snapshot — traces cleanly through the current CLI: $normalizeTestFilter("models") → "tests.specs.models" → ?directory=tests.specs.models → resolver accepts → TestBox scopes correctly. Verified end-to-end against a local server: curl ".../wheels/app/tests?directory=tests.specs.functional" runs only the one functional spec. The most likely explanation for the reporter's experience is a stale CLI install pre-fix(cli): normalize wheels test --filter so short names actually scope #2394; if --filter ever silently regresses, the new resolver specs will catch it before it ships.

Tests

  • 13 new specs in AppRunnerTestDirectorySpec.cfc covering: default fallback, accepted dotted paths, deep nesting, underscore/digit segments, whitespace trimming, rejection of bare short names, rejection of paths outside the tests.* namespace, rejection of slashes / hyphens / trailing dots.
  • 9 new specs in TestCommandSpec.cfc covering: (unknown) fallback, app-datasource resolution with _test suffix, useTestDB=false short-circuit, the coreTestDataSourceName collision case (regression for this issue), commented-out settings (line / block / tag style), no-doubling guard, .env precedence over settings.cfm.

Test plan

  • Framework core suite green locally on Lucee 7 + SQLite — 3452 pass / 0 fail / 0 error (198 bundles), including the 13 new AppRunnerTestDirectorySpec specs.
  • CI compat-matrix (Lucee 6/7, Adobe 2023/2025, BoxLang × SQLite/H2/MySQL/Postgres/SQL Server/CockroachDB/Oracle).
  • CLI test suite via the proper LuCLI-based runner (bash tools/test-cli-local.sh) — couldn't run locally (the wheels server in the worktree doesn't expose the modules.BaseModule mapping the CLI specs need), trusting CI.

…ourceName-only configs (#2489)

`$resolveAppTestDataSource` in `cli/lucli/Module.cfc` matched
`config/settings.cfm` with `dataSourceName\s*=\s*"([^"]*)"`. The
case-insensitive matcher caught the trailing substring inside
`set(coreTestDataSourceName="testappdb_test")` and re-appended
`_test`, surfacing `testappdb_test_test` in the `Running app
tests (...)` preamble. The matcher now uses `\bdataSourceName\b`
and strips CFML comments first (matching the pattern already
used by `info()`), and guards against re-appending `_test` if
the resolved base already ends in `_test`. .env lookup is also
anchored to start-of-line so an unrelated key whose name happens
to end in `DATASOURCE_NAME` can't match by accident.

Issue thread also reported `--filter` still being ignored on the
latest snapshot. The CLI's `$normalizeTestFilter` + URL build
trace correctly through `app-runner.cfm`'s `?directory=` regex
(verified end-to-end against a local server: `--filter=models`
correctly scopes to `tests.specs.models`). Most likely the user
hit a stale CLI install pre-#2394. Extracted the app-runner's
`?directory=` regex into `TestDirectoryResolver` alongside
`TestDbResolver` so the silent-fallback path (bare
`?directory=models` collapsing to `tests.specs`) is unit-testable
instead of HTTP-only — if the regex ever regresses, a unit test
will catch it before it ships.

Also exposes `$resolveAppTestDataSource` as `public` (matching the
`$`-prefix-for-internal convention used by `$normalizeTestFilter`)
so the new regression specs can drive it directly.

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot — Reviewer A

TL;DR: This PR correctly diagnoses and fixes the coreTestDataSourceName-leaks-into-dataSourceName regex match (issue #2489). The three-part fix — word-boundary anchoring, .env start-of-line anchoring, and the no-double-suffix guard — is technically sound, and the TestDirectoryResolver extraction follows the established TestDbResolver precedent cleanly. One stated fix (the .env start-of-line anchor) lacks a regression test, and the CLI specs are explicitly unverified locally. Everything else looks good. Comment (no blocking issues, one coverage gap to address before merge).


Correctness

The core logic is correct on all three axes:

Word-boundary fix (cli/lucli/Module.cfc line 5082):

var settingsMatch = reFindNoCase('\bdataSourceName\b\s*=\s*"([^"]*)"', settingsContent, 1, true);

Java's \b correctly prohibits a match inside coreTestDataSourceName because the character preceding the D is t (a word character), so there is no word boundary. Verified against the Java Pattern spec.

_test doubling guard (line 5100):

return reFindNoCase("_test$", base) ? base : base & "_test";

Sound. Correctly handles a user who names their app datasource myapp_test.

stripCfmlComments reuse (line 5081): Reuses the existing private helper already called by info() at line 951. Consistent and correct.


Tests

Coverage gap — the .env start-of-line anchor fix has no regression test.

The PR body explicitly claims: ".env matcher is anchored to start-of-line so MY_DATASOURCE_NAME=foo or unrelated keys whose names happen to end in DATASOURCE_NAME don't false-match." This is one of the three stated fixes. Looking at the 9 new specs in TestCommandSpec.cfc, the closest coverage is the precedence test (spec 9), which only confirms that .env wins over settings.cfm — it does not exercise the left-anchor behaviour at all.

Suggested addition alongside the existing describe block in cli/lucli/tests/specs/commands/TestCommandSpec.cfc:

it("does NOT match a .env key whose name ends in DATASOURCE_NAME", () => {
    // Pre-fix, reFindNoCase("DATASOURCE_NAME=...", content) matched
    // MY_DATASOURCE_NAME=foo because there was no start-of-line anchor.
    var sandbox = $scaffold(envBody = "MY_DATASOURCE_NAME=wrongkey");
    var localMod = new cli.lucli.Module(cwd = sandbox);
    expect(localMod.$resolveAppTestDataSource(true)).toBe("(unknown)");
    $tearDown(sandbox);
});

CLI specs untested locally: The PR test plan has [ ] CLI test suite explicitly unchecked. The 9 new specs in TestCommandSpec.cfc use per-test new cli.lucli.Module(cwd = sandbox) via a fresh $scaffold helper rather than the suite-level fixture in beforeAll(). Whether Module.init() completes cleanly against a directory containing only config/settings.cfm and an empty vendor/wheels/ is untested outside CI. Not a blocker, but worth flagging.

AppRunnerTestDirectorySpec.cfc coverage is solid: All 13 specs in vendor/wheels/tests/specs/dispatch/ are clean WheelsTest BDD syntax, no legacy RocketUnit patterns, no # in string literals, no closure local-variable gotchas, and the specs run without network or database dependencies.


Conventions

public access on $resolveAppTestDataSource (cli/lucli/Module.cfc line 5064): Changing from private to public for testability is consistent with the $ + public pattern already used by $normalizeTestFilter at line 491. No issue.


Cross-engine

No cross-engine concerns in the framework code or AppRunnerTestDirectorySpec.cfc. TestDirectoryResolver.cfc is clean: StructKeyExists, Trim, Len, ReFindNoCase — all standard CFML with no closure gotchas and no client/application scope.

The $scaffold helper in TestCommandSpec.cfc calls directoryCreate(path, true, true) — two extra arguments. Per the cross-engine guide and issue #2567, this is Lucee-only. However, TestCommandSpec.cfc runs exclusively on the Lucee-backed LuCLI runtime, not Adobe CF, and the same three-argument form already appears in the existing beforeAll() at line 12. Not a new issue, not a blocker.


Docs

CHANGELOG entry is present in the correct [Unreleased] -> Fixed position. The entry is verbose but accurately covers all three fix dimensions.


Commits

Single commit fix(cli): wheels test preamble stops doubling _test for coreTestDataSourceName-only configs (#2489) — type fix, scope cli, subject 88 characters, not ALL-CAPS. Conforms to commitlint.config.js.


Action items before merge:

  1. Add the missing .env start-of-line anchor regression test (see suggested it() above).
  2. Verify CI green on TestCommandSpec.cfc CLI specs — the unchecked test plan item is the main open gate.

@wheels-bot

wheels-bot Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Wheels Bot — Reviewer B (round 1)

A's review is technically sound and well-evidenced. The one coverage gap A flagged (missing regression test for the .env start-of-line anchor fix) is real and verifiable. No sycophancy, no false positives, and no missed issues on re-scan of the diff. Aligning with A's COMMENT verdict and the single action item.

Sycophancy

None detected. A takes a clear position with evidence for every claim and does not issue an unconditional LGTM.

False positives

None detected.

  • Word-boundary claim: A says Java's \b blocks a match inside coreTestDataSourceName because the character before D is t (a word character). Verified against the diff — the updated pattern at cli/lucli/Module.cfc line 5082 is \bdataSourceName\b and the Java regex spec confirms \b requires a word/non-word boundary transition. The claim is accurate.
  • _test doubling guard: A calls the reFindNoCase("_test$", base) ternary sound. Correct — spec 8 (does not double-append) exercises it directly.
  • stripCfmlComments reuse: A says it is an existing private helper already used by info(). The PR body confirms this and the diff shows the call replacing a bare fileRead. No issue.
  • directoryCreate(path, true, true) engine concern: A flags it as Lucee-only per issue 2567 but correctly limits the concern to a pre-existing pattern not new in this PR, and correctly calls it a non-blocker because CLI specs run exclusively on the Lucee-backed LuCLI runtime. Accurate scoping.
  • .env anchor correctness: A does not assert the (?:^|\n) alternative is wrong — only that its failure mode (a key ending in DATASOURCE_NAME) lacks a dedicated test. The implementation is correct: without the multiline flag, ^ matches only at string start and \n triggers on each subsequent line break, so MY_DATASOURCE_NAME=wrongkey with no preceding newline cannot match. A's concern is about missing test coverage, not a defect in the logic.

Missed issues

None detected.

Re-scanning the diff:

  • Cross-engine: TestDirectoryResolver.cfc uses only StructKeyExists, Trim, Len, and ReFindNoCase — portable across all engines. The AppRunnerTestDirectorySpec.cfc specs are clean WheelsTest BDD with no closure local-var captures or engine-specific API calls.
  • Commit: fix(cli): wheels test preamble stops doubling _test for coreTestDataSourceName-only configs — type fix, scope cli, subject 88 chars, not ALL-CAPS. Conforms to commitlint.config.js.
  • .ai/wheels/ updates: This is an internal CLI regression fix with no user-facing API or behavior change. No documentation update required.
  • Test spec structure: The $scaffold and $tearDown helpers are defined as component-level methods and called from within it() closures. In Lucee, closures created inside a component method capture the component variables scope, so the bare calls resolve correctly. Not a concern for CLI-only specs.
  • app-runner.cfm delegation: Passing the raw url scope struct to resolveDirectory() is correct — the resolver calls StructKeyExists(arguments.url, "directory"), which works identically whether url is the built-in URL scope or a plain struct passed in tests.

A's observation that the CLI test plan item is unchecked is correctly labeled "worth flagging" but not blocking — CI is the authoritative gate for LuCLI-hosted specs.

Verdict alignment

A issues COMMENT with two concrete action items (add the missing .env anchor test; confirm CI green). That is consistent with finding a genuine coverage gap and an unverified test run — neither alone is a merge blocker, but together they warrant a pre-merge check. Verdict is proportionate.

Convergence

Aligned. A correctly identified the one substantive gap: the .env start-of-line anchor is one of the three stated fixes in the PR description, but no spec exercises the MY_DATASOURCE_NAME= false-match case. A's suggested it() is directly actionable. The joint recommendation is: add that one spec to cli/lucli/tests/specs/commands/TestCommandSpec.cfc inside the existing describe("$resolveAppTestDataSource") block, then let CI verify the full CLI suite. No other changes needed.

bpamiri and others added 2 commits May 11, 2026 20:16
- Add regression spec for the `.env` start-of-line anchor in
  $resolveAppTestDataSource (cli/lucli/Module.cfc:5072): confirms a
  key whose name ends in DATASOURCE_NAME (`MY_DATASOURCE_NAME=...`)
  does not false-match against the DATASOURCE_NAME extraction.
  cli/lucli/tests/specs/commands/TestCommandSpec.cfc.

Closes A's one coverage-gap action item; B aligned in round 1.

Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
@wheels-bot

wheels-bot Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Wheels Bot — Address Review (round 1)

Applied consensus findings from Reviewer A and Reviewer B's convergence (round 1):

  • Added regression spec for the .env start-of-line anchor fix. New it("does NOT match a .env key whose name ends in DATASOURCE_NAME", …) in cli/lucli/tests/specs/commands/TestCommandSpec.cfc (inside the existing describe("$resolveAppTestDataSource …") block). Scaffolds a sandbox containing only MY_DATASOURCE_NAME=wrongkey in .env and asserts $resolveAppTestDataSource(true) returns "(unknown)". Pre-fix the unanchored DATASOURCE_NAME\s*=\s*… pattern would have matched the trailing substring; the (?:^|\n)\s*DATASOURCE_NAME anchor at cli/lucli/Module.cfc:5072 now prevents that.

Both of A's action items now have either a test or a CI gate:

A's action item Resolution
Add .env start-of-line anchor regression test Added in this commit
Verify CI green on TestCommandSpec.cfc Deferred to CI — tools/test-cli-local.sh requires interactive approval in this environment, and the PR body already documented that the LuCLI server in the worktree can't host CLI specs locally

Reviewer B's round-1 critique surfaced no missed issues and no false positives, so no findings were intentionally skipped.

The new commit will trigger a fresh Reviewer A run on the updated SHA. Convergence loop continues until reviewers align on approve or the outer-loop cap (5 rounds) is reached.

wheels-bot[bot]
wheels-bot Bot previously approved these changes May 12, 2026

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot -- Reviewer A

TL;DR: This PR resolves the coreTestDataSourceName-leaks-into-dataSourceName regex match (issue #2489) via three coordinated fixes: word-boundary anchoring, .env start-of-line anchoring, and a no-double-suffix guard. The previous Reviewer A cycle flagged one coverage gap (no regression spec for the .env anchor fix); commit ae98e145 closes it exactly. All three fix dimensions now have direct regression tests. Approve -- no blocking issues.


Correctness

All three fix axes hold up under scrutiny:

Word-boundary fix (cli/lucli/Module.cfc, $resolveAppTestDataSource):

Java word boundary correctly rejects a match inside coreTestDataSourceName because the character before d is t (a word character) -- no word boundary. Confirmed against the Java Pattern spec.

.env anchor fix (same function):

Pattern (?:^|\n)\s*DATASOURCE_NAME\s*=\s*([^\r\n]+) -- verified edge cases: MY_DATASOURCE_NAME=foo at start of file fails because after the start anchor, \s* cannot consume MY_ (no whitespace). A key on a subsequent line fails because after \n, \s* will not skip MY_. The capture group ([^\r\n]+) replacing the old (.+) also eliminates the trailing carriage-return edge case on Windows line-endings.

No-double-suffix guard: reFindNoCase("_test$", base) ? base : base & "_test" is clean and handles the myapp_test datasource naming case without ambiguity.

stripCfmlComments reuse: The settings-file path now pre-strips comments before matching, consistent with the pattern info() already uses.


Tests

The coverage gap from the previous review cycle has been addressed. Commit ae98e145 adds a spec that passes envBody = "MY_DATASOURCE_NAME=wrongkey" to $scaffold, instantiates a fresh new cli.lucli.Module(cwd=sandbox), calls $resolveAppTestDataSource(true), and asserts the result is (unknown). This directly exercises the start-of-line anchor behaviour and will catch any future regression that strips or weakens it. Logic is correct: an env file containing only MY_DATASOURCE_NAME=wrongkey leaves base empty and returns (unknown).

AppRunnerTestDirectorySpec.cfc (13 specs in vendor/wheels/tests/specs/dispatch/): BDD syntax throughout, no legacy assert() / test_ patterns, no unescaped hash characters in string literals that could crash the suite, no closure gotchas. Covers default fallback, accepted dotted paths, whitespace trimming, and all rejection cases (bare short names, namespace escapes, slashes, hyphens, trailing dots, double-dots).


Cross-engine

No cross-engine concerns in the framework-side changes. TestDirectoryResolver.cfc uses only StructKeyExists, Trim, Len, ReFindNoCase -- all standard CFML with no engine-specific gotchas.

TestCommandSpec.cfc calls directoryCreate(path, true, true) (three-argument form) in $scaffold(). Per the cross-engine guide this form is Lucee-only; however, TestCommandSpec.cfc runs exclusively on the Lucee-backed LuCLI runtime, and the same three-argument form already existed in the suite beforeAll() before this PR. Not a new issue.


Commits

The original commit (967281846) uses type fix, scope cli, 100 chars at the limit but valid. The follow-up bot commit (ae98e145) carries the required DCO trailer (Signed-off-by: claude[bot]). Minor style nit on the follow-up: type test would be more precise for a pure test addition, and the subject names the review process rather than the change -- neither is a commitlint violation.


Docs

CHANGELOG [Unreleased] -> Fixed entry is present and accurately covers all three fix dimensions.


No action items remain from the previous review cycle. The CI gate (compat-matrix and CLI suite) is the last open procedural item, expected per the test plan.

@wheels-bot
wheels-bot Bot dismissed their stale review May 12, 2026 03:31

Auto-dismissed by Reviewer A guard: body is shorter than 200 characters or missing the canonical wheels-bot:review-a marker. See #2558 for context.

@wheels-bot

wheels-bot Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Wheels Bot — Reviewer A guard

Detected and dismissed 1 bogus Reviewer A review(s) on commit ae98e14. Cause: review body shorter than 200 characters or missing the canonical wheels-bot:review-a marker. See wheels-dev/wheels#2558 for context.

@wheels-bot

wheels-bot Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Wheels Bot — Reviewer B (round 1)

Review 4268917363 — the review ID passed to this invocation — has body "test" (3 characters), state DISMISSED, and was already handled by the guard comment. The canonical Reviewer A review for the current head SHA is 4268918438; that is the one critiqued below.

A's review is clean. The coverage gap flagged in round 1 (no regression spec for the .env start-of-line anchor fix) was closed exactly as A recommended, and A correctly verifies the closure. No sycophancy, no false positives, no missed issues.

Sycophancy

None detected. A approves with specific evidence: names the new spec, explains why it closes the prior gap, and verifies the anchor logic against concrete edge cases. Not an unconditional LGTM.

False positives

None detected.

  • Word-boundary claim: A says the character before d in coreTestDataSourceName is t (a word character), blocking the \b assertion. Verified: coreTest ends in t; both t and D (case-insensitive) are word characters so no boundary fires. Accurate.
  • .env anchor logic: A explains that MY_DATASOURCE_NAME=foo at start-of-file fails because after (?:^|\n) matches ^, \s* cannot skip the leading MY_. Verified against the pattern in cli/lucli/Module.cfc: (?:^|\n)\s*DATASOURCE_NAME\s*=\s*([^\r\n]+). \s* matches only whitespace; M terminates the attempt immediately. A key on a subsequent line with \n preceding it likewise fails because MY_ is not whitespace. Accurate.
  • New regression spec correctness: A says the spec scaffolds MY_DATASOURCE_NAME=wrongkey in .env, instantiates Module(cwd=sandbox), and asserts (unknown). Verified in the diff: the spec does exactly that, and the logic is sound — no DATASOURCE_NAME (unqualified) key exists in the file so base stays empty and the function returns (unknown). Accurate.
  • directoryCreate(path, true, true) cross-engine concern: A correctly limits this to a pre-existing CLI-only pattern that predates this PR. Not a new issue; not a blocker. Accurate.

Missed issues

None detected.

Re-scan of the diff:

  • TestDirectoryResolver.cfc uses only StructKeyExists, Trim, Len, ReFindNoCase — all portable, no engine-specific surface.
  • AppRunnerTestDirectorySpec.cfc: 13 specs, clean BDD syntax, no unescaped # in string literals (spec uses chr(34) for quotes and chr(10) for newlines throughout), no closure local-variable captures.
  • The .env pattern uses ([^\r\n]+) rather than (.+), which correctly strips trailing \r on Windows line endings. A does not call this out explicitly, but it is correct behavior and not a missed issue.
  • Commit ae98e145: subject fix(cli): address Reviewer A/B consensus findings (round 1) — 72 chars, valid type, valid scope, not ALL-CAPS. DCO trailer present: Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>. A's minor style nit (test type would be more precise for a pure test addition) is accurate but not a violation — leaving it as a nit is proportionate.
  • No .ai/wheels/ documentation updates needed; this is an internal CLI regex regression fix with no user-facing API change.

Verdict alignment

A's APPROVE is consistent with the findings: the one action item from round 1 was addressed directly, no new issues were introduced, and the only remaining open item is CI (procedural, expected per the test plan).

Convergence

Aligned. A correctly identified and verified the closure of the sole coverage gap. No outstanding disputes, no unaddressed findings. Joint recommendation: approve and merge once the CI compat-matrix and CLI suite are green.

@bpamiri
bpamiri merged commit 1723dd5 into develop May 12, 2026
8 checks passed
@bpamiri
bpamiri deleted the claude/unruffled-margulis-3a4c9a branch May 12, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wheels test ignores --filter and --db arguments

1 participant