From 6fa3bfe71d0c9908f25debd5d42a4f3bb842f662 Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Thu, 12 Feb 2026 16:26:24 -0800 Subject: [PATCH] test: add cross-reference validation tests for validate-commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add runValidatorWithDirs() helper for multi-constant overrides - Test broken command references (e.g., /nonexistent-cmd) - Test broken agent path references (e.g., agents/fake-agent.md) - Test fenced code block exclusion (refs inside ``` are skipped) - Test broken workflow agent references (e.g., planner -> ghost-agent) - Total tests: 261 → 287 (+26) --- tests/ci/validators.test.js | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tests/ci/validators.test.js b/tests/ci/validators.test.js index 4d94c3c..a51821a 100644 --- a/tests/ci/validators.test.js +++ b/tests/ci/validators.test.js @@ -74,6 +74,35 @@ function runValidatorWithDir(validatorName, dirConstant, overridePath) { } } +/** + * Run a validator script with multiple directory overrides. + * @param {string} validatorName + * @param {Record} overrides - map of constant name to path + */ +function runValidatorWithDirs(validatorName, overrides) { + const validatorPath = path.join(validatorsDir, `${validatorName}.js`); + let source = fs.readFileSync(validatorPath, 'utf8'); + source = source.replace(/^#!.*\n/, ''); + for (const [constant, overridePath] of Object.entries(overrides)) { + const dirRegex = new RegExp(`const ${constant} = .*?;`); + source = source.replace(dirRegex, `const ${constant} = ${JSON.stringify(overridePath)};`); + } + try { + const stdout = execFileSync('node', ['-e', source], { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + timeout: 10000, + }); + return { code: 0, stdout, stderr: '' }; + } catch (err) { + return { + code: err.status || 1, + stdout: err.stdout || '', + stderr: err.stderr || '', + }; + } +} + /** * Run a validator script directly (tests real project) */ @@ -471,6 +500,63 @@ function runTests() { cleanupTestDir(testDir); })) passed++; else failed++; + if (test('detects broken command cross-reference', () => { + const testDir = createTestDir(); + const agentsDir = createTestDir(); + const skillsDir = createTestDir(); + fs.writeFileSync(path.join(testDir, 'my-cmd.md'), '# Command\nUse `/nonexistent-cmd` to do things.'); + + const result = runValidatorWithDirs('validate-commands', { + COMMANDS_DIR: testDir, AGENTS_DIR: agentsDir, SKILLS_DIR: skillsDir + }); + assert.strictEqual(result.code, 1, 'Should fail on broken command ref'); + assert.ok(result.stderr.includes('nonexistent-cmd'), 'Should report broken command'); + cleanupTestDir(testDir); cleanupTestDir(agentsDir); cleanupTestDir(skillsDir); + })) passed++; else failed++; + + if (test('detects broken agent path reference', () => { + const testDir = createTestDir(); + const agentsDir = createTestDir(); + const skillsDir = createTestDir(); + fs.writeFileSync(path.join(testDir, 'cmd.md'), '# Command\nAgent: `agents/fake-agent.md`'); + + const result = runValidatorWithDirs('validate-commands', { + COMMANDS_DIR: testDir, AGENTS_DIR: agentsDir, SKILLS_DIR: skillsDir + }); + assert.strictEqual(result.code, 1, 'Should fail on broken agent ref'); + assert.ok(result.stderr.includes('fake-agent'), 'Should report broken agent'); + cleanupTestDir(testDir); cleanupTestDir(agentsDir); cleanupTestDir(skillsDir); + })) passed++; else failed++; + + if (test('skips references inside fenced code blocks', () => { + const testDir = createTestDir(); + const agentsDir = createTestDir(); + const skillsDir = createTestDir(); + fs.writeFileSync(path.join(testDir, 'cmd.md'), + '# Command\n\n```\nagents/example-agent.md\n`/example-cmd`\n```\n'); + + const result = runValidatorWithDirs('validate-commands', { + COMMANDS_DIR: testDir, AGENTS_DIR: agentsDir, SKILLS_DIR: skillsDir + }); + assert.strictEqual(result.code, 0, 'Should skip refs inside code blocks'); + cleanupTestDir(testDir); cleanupTestDir(agentsDir); cleanupTestDir(skillsDir); + })) passed++; else failed++; + + if (test('detects broken workflow agent reference', () => { + const testDir = createTestDir(); + const agentsDir = createTestDir(); + const skillsDir = createTestDir(); + fs.writeFileSync(path.join(agentsDir, 'planner.md'), '---\nmodel: sonnet\ntools: Read\n---\n# A'); + fs.writeFileSync(path.join(testDir, 'cmd.md'), '# Command\nWorkflow:\nplanner -> ghost-agent'); + + const result = runValidatorWithDirs('validate-commands', { + COMMANDS_DIR: testDir, AGENTS_DIR: agentsDir, SKILLS_DIR: skillsDir + }); + assert.strictEqual(result.code, 1, 'Should fail on broken workflow agent'); + assert.ok(result.stderr.includes('ghost-agent'), 'Should report broken workflow agent'); + cleanupTestDir(testDir); cleanupTestDir(agentsDir); cleanupTestDir(skillsDir); + })) passed++; else failed++; + // ========================================== // validate-rules.js // ==========================================