Files
msd-core/tests/feat-3210-fallow-schema-enum.test.cjs
Tom Boucher 75d5ca5875 feat(code-review): integrate fallow structural pre-pass for /gsd-code-review (#3424)
* feat(code-review): add optional fallow structural pre-pass

* fix(ci): sync lockfile for fallow optional binaries

* fix(test): make fallow integration tests cross-platform

* fix(review): require executable fallow binary paths

* docs(review): clarify structural findings usage and size guard

* fix(fallow): preserve line:0, prefer node_modules/.bin, sync SDK twin (H1, M2, N1 from #3424 review)

* fix(workflow): harden fallow pre-pass — exit check, timeout, atomic write, size-guard order (B1, H2-H4, M1, M3 from #3424 review)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(deps): pin fallow floor to ^2.70.0 matching lockfile (H7 from #3424 review)

* fix(config): enum-validate fallow.scope/profile + group code_quality.* contiguously (H5, N3 from #3424 review)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(fallow): label mcp gate reserved, version-pin install, expand context schema (B3, H8, M4, M8, L1 from #3424 review)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(fallow): replace source-grep with behavioral tests, expand fixtures, fail-loud tmpdir (B4, H6, L2, L3, M5, M6, N2 from #3424 review)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(workflow): escape closing structural_findings tag in JSON payload (CR #3424 inline finding)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:19:47 -04:00

176 lines
5.2 KiB
JavaScript

'use strict';
/**
* Enum validation for code_quality.fallow.scope and code_quality.fallow.profile.
*
* Fixes H5 from #3424 review: config-set silently accepted invalid enum values
* (e.g. scope=fullrepo) and fell through to default behavior. This test asserts
* that invalid values are rejected with a helpful error, and valid values pass.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs');
describe('feat-3210 / H5: enum validation for code_quality.fallow.scope and .profile', () => {
// --- code_quality.fallow.scope ---
test('config-set code_quality.fallow.scope=fullrepo is REJECTED with helpful error', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.scope', 'fullrepo'],
tmpDir
);
assert.ok(
!result.success,
'config-set code_quality.fallow.scope=fullrepo must fail, but it succeeded'
);
const combined = (result.output || '') + (result.error || '');
assert.ok(
combined.includes('phase') && combined.includes('repo'),
`Error message must mention valid values "phase" and "repo", got: ${combined}`
);
});
test('config-set code_quality.fallow.scope=phase is ACCEPTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.scope', 'phase'],
tmpDir
);
assert.ok(
result.success,
[
'config-set code_quality.fallow.scope=phase must succeed,',
'stdout: ' + result.output,
'stderr: ' + result.error,
].join('\n')
);
});
test('config-set code_quality.fallow.scope=repo is ACCEPTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.scope', 'repo'],
tmpDir
);
assert.ok(
result.success,
[
'config-set code_quality.fallow.scope=repo must succeed,',
'stdout: ' + result.output,
'stderr: ' + result.error,
].join('\n')
);
});
test('config-set code_quality.fallow.scope=PHASE (wrong case) is REJECTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.scope', 'PHASE'],
tmpDir
);
assert.ok(
!result.success,
'config-set code_quality.fallow.scope=PHASE must fail (values are case-sensitive)'
);
});
// --- code_quality.fallow.profile ---
test('config-set code_quality.fallow.profile=aggressive is REJECTED with helpful error', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.profile', 'aggressive'],
tmpDir
);
assert.ok(
!result.success,
'config-set code_quality.fallow.profile=aggressive must fail, but it succeeded'
);
const combined = (result.output || '') + (result.error || '');
assert.ok(
combined.includes('minimal') && combined.includes('standard') && combined.includes('strict'),
`Error message must mention valid values "minimal", "standard", "strict", got: ${combined}`
);
});
test('config-set code_quality.fallow.profile=minimal is ACCEPTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.profile', 'minimal'],
tmpDir
);
assert.ok(
result.success,
[
'config-set code_quality.fallow.profile=minimal must succeed,',
'stdout: ' + result.output,
'stderr: ' + result.error,
].join('\n')
);
});
test('config-set code_quality.fallow.profile=standard is ACCEPTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.profile', 'standard'],
tmpDir
);
assert.ok(
result.success,
[
'config-set code_quality.fallow.profile=standard must succeed,',
'stdout: ' + result.output,
'stderr: ' + result.error,
].join('\n')
);
});
test('config-set code_quality.fallow.profile=strict is ACCEPTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.profile', 'strict'],
tmpDir
);
assert.ok(
result.success,
[
'config-set code_quality.fallow.profile=strict must succeed,',
'stdout: ' + result.output,
'stderr: ' + result.error,
].join('\n')
);
});
test('config-set code_quality.fallow.profile=unknown is REJECTED', (t) => {
const tmpDir = createTempProject();
t.after(() => cleanup(tmpDir));
const result = runGsdTools(
['config-set', 'code_quality.fallow.profile', 'unknown'],
tmpDir
);
assert.ok(
!result.success,
'config-set code_quality.fallow.profile=unknown must fail'
);
});
});