test(#1970): consolidate 61 install-suite regression tests into function suites
Fold 61 issue-named install/codex/runtime regression files into the canonical test file that owns each subject-under-test, preserving every assertion and its origin issue number as provenance (block-scoped describe wrappers, zero assertion loss — 652 subtests conserved 1:1). Routes: - codex-config.test.cjs +19 (codex config/toml/hooks/adapter/skill surface) - install.test.cjs +18 (node-runner norm, manifest, arg parse, finishInstall) - install-runtime-artifacts +13 (per-runtime conversion + emission) - install-minimal-hooks +6 (hook-event dialects + guards) - path-replacement +2 (opencode absolute pathPrefix) - install-write-confinement +2 (pristine dir writes) - install-regressions +1 (user-artifact preservation) Removes 61 tests/ files → 61 fewer CI processes. Regenerates the regression-name allowlist (271→222), ratchets the file-count allowlist (config 10→9, install 12→9), and makes 13 relocated allow-test-rule exemptions issue-ref-compliant (ADR-456; prunes 13 stale allowlist ids). Repoints ADR-0009's moved-test list. lint:ci green. Part of epic #1969. Closes #1970. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -206,3 +206,235 @@ describe('containsResolvedHomedir predicate (#3503)', () => {
|
||||
assert.strictEqual(containsResolvedHomedir('$HOME/.claude/', '$HOME'), false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// Folded from tests/bug-2376-opencode-windows-home-path.test.cjs — consolidation epic #1969 (B1 #1970)
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
{
|
||||
const { describe: __foldDescribe } = require('node:test');
|
||||
__foldDescribe("folded:bug-2376-opencode-windows-home-path (consolidation epic #1969 B1 #1970)", () => {
|
||||
/**
|
||||
* Regression test for #2376: @$HOME not correctly mapped in OpenCode on Windows.
|
||||
*
|
||||
* On Windows, $HOME is not expanded by PowerShell/cmd.exe, so OpenCode cannot
|
||||
* resolve @$HOME/... file references in installed command files.
|
||||
*
|
||||
* Fix: install.js must use the absolute path (not $HOME-relative) when installing
|
||||
* for OpenCode. (Generalized to all platforms in #2831 — OpenCode `@file`
|
||||
* references are not shell-expanded on any platform.)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { describe, test, before, after } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
let computePathPrefix;
|
||||
|
||||
before(() => {
|
||||
process.env.GSD_TEST_MODE = '1';
|
||||
// Re-require fresh in case other tests already loaded it.
|
||||
delete require.cache[require.resolve('../bin/install.js')];
|
||||
({ computePathPrefix } = require('../bin/install.js'));
|
||||
});
|
||||
|
||||
after(() => {
|
||||
delete process.env.GSD_TEST_MODE;
|
||||
});
|
||||
|
||||
describe('bug-2376: OpenCode on Windows must use absolute path, not $HOME', () => {
|
||||
test('computePathPrefix is exported by install.js', () => {
|
||||
assert.equal(typeof computePathPrefix, 'function');
|
||||
});
|
||||
|
||||
test('OpenCode on Windows: pathPrefix is absolute (no $HOME substitution)', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: true,
|
||||
isWindowsHost: true,
|
||||
resolvedTarget: 'C:/Users/user/.config/opencode',
|
||||
homeDir: 'C:/Users/user',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, 'C:/Users/user/.config/opencode/');
|
||||
assert.ok(!pathPrefix.includes('$HOME'));
|
||||
});
|
||||
|
||||
test('Claude Code on Windows: pathPrefix still uses $HOME (unaffected)', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: false,
|
||||
isWindowsHost: true,
|
||||
resolvedTarget: 'C:/Users/user/.claude',
|
||||
homeDir: 'C:/Users/user',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, '$HOME/.claude/');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// Folded from tests/bug-2831-opencode-home-path-prefix.test.cjs — consolidation epic #1969 (B1 #1970)
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
{
|
||||
const { describe: __foldDescribe } = require('node:test');
|
||||
__foldDescribe("folded:bug-2831-opencode-home-path-prefix (consolidation epic #1969 B1 #1970)", () => {
|
||||
// allow-test-rule: source-text-is-the-product (see #2831)
|
||||
// Workflow .md / agent .md / command .md / reference .md files — their text
|
||||
// IS what the runtime loads. Testing text content tests the deployed contract.
|
||||
// Per CONTRIBUTING.md exception matrix.
|
||||
|
||||
/**
|
||||
* Regression test for #2831: OpenCode @file references contain literal `$HOME`
|
||||
* which OpenCode does not expand — `@$HOME/.config/opencode/...` is resolved
|
||||
* as a path relative to the config command/ dir, producing
|
||||
* `command/$HOME/.config/opencode/...` (file not found).
|
||||
*
|
||||
* Root cause: install.js pathPrefix used `$HOME`-relative paths for OpenCode on
|
||||
* non-Windows hosts (only Windows was guarded by #2376). OpenCode's `@file`
|
||||
* include syntax does NOT shell-expand `$HOME` on any platform.
|
||||
*
|
||||
* Fix: pathPrefix must use the absolute path for OpenCode on all platforms.
|
||||
*
|
||||
* Tests exercise install.js's exported `computePathPrefix` directly (no source
|
||||
* grepping) and additionally simulate the `copyFlattenedCommands` substitution
|
||||
* pipeline on a temp tree to verify no `$HOME` literal leaks into emitted files.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { describe, test, before, after } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const { cleanup } = require('./helpers.cjs');
|
||||
|
||||
let computePathPrefix;
|
||||
|
||||
before(() => {
|
||||
process.env.GSD_TEST_MODE = '1';
|
||||
delete require.cache[require.resolve('../bin/install.js')];
|
||||
({ computePathPrefix } = require('../bin/install.js'));
|
||||
});
|
||||
|
||||
after(() => {
|
||||
delete process.env.GSD_TEST_MODE;
|
||||
});
|
||||
|
||||
describe('bug-2831: OpenCode pathPrefix uses absolute path on all platforms', () => {
|
||||
test('computePathPrefix is exported by install.js', () => {
|
||||
assert.equal(typeof computePathPrefix, 'function');
|
||||
});
|
||||
|
||||
test('OpenCode on macOS: pathPrefix is absolute (no $HOME)', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: true,
|
||||
isWindowsHost: false,
|
||||
homeDir: '/Users/alice',
|
||||
resolvedTarget: '/Users/alice/.config/opencode',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, '/Users/alice/.config/opencode/');
|
||||
assert.ok(!pathPrefix.includes('$HOME'));
|
||||
});
|
||||
|
||||
test('OpenCode on Linux: pathPrefix is absolute (no $HOME)', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: true,
|
||||
isWindowsHost: false,
|
||||
homeDir: '/home/bob',
|
||||
resolvedTarget: '/home/bob/.config/opencode',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, '/home/bob/.config/opencode/');
|
||||
assert.ok(!pathPrefix.includes('$HOME'));
|
||||
});
|
||||
|
||||
test('OpenCode on Windows: pathPrefix is absolute (preserves #2376)', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: true,
|
||||
isWindowsHost: true,
|
||||
homeDir: 'C:/Users/carol',
|
||||
resolvedTarget: 'C:/Users/carol/.config/opencode',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, 'C:/Users/carol/.config/opencode/');
|
||||
});
|
||||
|
||||
test('Claude Code on macOS: pathPrefix still uses $HOME (unaffected)', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: false,
|
||||
isWindowsHost: false,
|
||||
homeDir: '/Users/alice',
|
||||
resolvedTarget: '/Users/alice/.claude',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, '$HOME/.claude/');
|
||||
});
|
||||
|
||||
test('Local install (non-global): pathPrefix uses absolute path regardless of runtime', () => {
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: false,
|
||||
isOpencode: false,
|
||||
isWindowsHost: false,
|
||||
homeDir: '/Users/alice',
|
||||
resolvedTarget: '/Users/alice/projects/foo/.claude',
|
||||
});
|
||||
assert.strictEqual(pathPrefix, '/Users/alice/projects/foo/.claude/');
|
||||
});
|
||||
|
||||
test('Substitution pipeline simulation: OpenCode emits no @$HOME literal', () => {
|
||||
// This validates the same regex substitution pipeline used by
|
||||
// copyFlattenedCommands when writing OpenCode command files. We invoke the
|
||||
// real exported computePathPrefix; the regex passes mirror the install.js
|
||||
// call sites (globalClaudeRegex / globalClaudeHomeRegex).
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-2831-'));
|
||||
try {
|
||||
const srcRoot = path.join(tmp, 'src');
|
||||
const targetRoot = path.join(tmp, 'home', '.config', 'opencode');
|
||||
const srcCmdDir = path.join(srcRoot, 'commands', 'gsd');
|
||||
fs.mkdirSync(srcCmdDir, { recursive: true });
|
||||
fs.mkdirSync(targetRoot, { recursive: true });
|
||||
|
||||
const srcFile = path.join(srcCmdDir, 'autonomous.md');
|
||||
fs.writeFileSync(
|
||||
srcFile,
|
||||
'---\nname: autonomous\n---\n<execution_context>\n@~/.claude/gsd-core/workflows/autonomous.md\n@$HOME/.claude/gsd-core/references/ui-brand.md\n</execution_context>\n'
|
||||
);
|
||||
|
||||
const homeDir = path.join(tmp, 'home').replace(/\\/g, '/');
|
||||
const resolvedTarget = targetRoot.replace(/\\/g, '/');
|
||||
const pathPrefix = computePathPrefix({
|
||||
isGlobal: true,
|
||||
isOpencode: true,
|
||||
isWindowsHost: false,
|
||||
homeDir,
|
||||
resolvedTarget,
|
||||
});
|
||||
|
||||
let content = fs.readFileSync(srcFile, 'utf8');
|
||||
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
||||
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
||||
|
||||
assert.ok(
|
||||
!/@\$HOME\b/.test(content),
|
||||
`output must not contain @$HOME literal; got:\n${content}`
|
||||
);
|
||||
assert.ok(
|
||||
!/\$HOME\b/.test(content),
|
||||
`output must not contain $HOME literal; got:\n${content}`
|
||||
);
|
||||
assert.ok(
|
||||
content.includes(`@${resolvedTarget}/`),
|
||||
`output should include absolute path with @ prefix; got:\n${content}`
|
||||
);
|
||||
} finally {
|
||||
cleanup(tmp);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user