BMAD-METHOD/test/test-file-refs-csv.js

134 lines
5.1 KiB
JavaScript

/**
* CSV File Reference Extraction Test Runner
*
* Tests extractCsvRefs() from validate-file-refs.js against fixtures.
* Verifies correct extraction of workflow-file references from CSV files.
*
* Usage: node test/test-file-refs-csv.js
* Exit codes: 0 = all tests pass, 1 = test failures
*/
const fs = require('node:fs');
const path = require('node:path');
const { extractCsvRefs } = require('../tools/validate-file-refs.js');
// ANSI color codes
const colors = {
reset: '\u001B[0m',
green: '\u001B[32m',
red: '\u001B[31m',
cyan: '\u001B[36m',
dim: '\u001B[2m',
};
const FIXTURES = path.join(__dirname, 'fixtures/file-refs-csv');
let totalTests = 0;
let passedTests = 0;
const failures = [];
function test(name, fn) {
totalTests++;
try {
fn();
passedTests++;
console.log(` ${colors.green}\u2713${colors.reset} ${name}`);
} catch (error) {
console.log(` ${colors.red}\u2717${colors.reset} ${name} ${colors.red}${error.message}${colors.reset}`);
failures.push({ name, message: error.message });
}
}
function assert(condition, message) {
if (!condition) throw new Error(message);
}
function loadFixture(relativePath) {
const fullPath = path.join(FIXTURES, relativePath);
const content = fs.readFileSync(fullPath, 'utf-8');
return { fullPath, content };
}
// --- Valid fixtures ---
console.log(`\n${colors.cyan}CSV File Reference Extraction Tests${colors.reset}\n`);
console.log(`${colors.cyan}Valid fixtures${colors.reset}`);
test('bmm-style.csv: extracts workflow-file refs with trailing commas', () => {
const { fullPath, content } = loadFixture('valid/bmm-style.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 2, `Expected 2 refs, got ${refs.length}`);
assert(refs[0].raw === '_bmad/bmm/workflows/document-project/workflow.md', `Wrong raw[0]: ${refs[0].raw}`);
assert(refs[1].raw === '_bmad/core/workflows/brainstorming/workflow.md', `Wrong raw[1]: ${refs[1].raw}`);
assert(refs[0].type === 'project-root', `Wrong type: ${refs[0].type}`);
assert(refs[0].line === 2, `Wrong line for row 0: ${refs[0].line}`);
assert(refs[1].line === 3, `Wrong line for row 1: ${refs[1].line}`);
assert(refs[0].file === fullPath, 'Wrong file path');
});
test('core-style.csv: extracts refs from core module-help format', () => {
const { fullPath, content } = loadFixture('valid/core-style.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 2, `Expected 2 refs, got ${refs.length}`);
assert(refs[0].raw === '_bmad/core/workflows/brainstorming/workflow.md', `Wrong raw[0]: ${refs[0].raw}`);
assert(refs[1].raw === '_bmad/core/workflows/party-mode/workflow.md', `Wrong raw[1]: ${refs[1].raw}`);
});
test('minimal.csv: extracts refs from minimal 3-column CSV', () => {
const { fullPath, content } = loadFixture('valid/minimal.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 1, `Expected 1 ref, got ${refs.length}`);
assert(refs[0].raw === '_bmad/core/tasks/help.md', `Wrong raw: ${refs[0].raw}`);
assert(refs[0].line === 2, `Wrong line: ${refs[0].line}`);
});
// --- Invalid fixtures ---
console.log(`\n${colors.cyan}Invalid fixtures (expect 0 refs)${colors.reset}`);
test('no-workflow-column.csv: returns 0 refs when workflow-file column missing', () => {
const { fullPath, content } = loadFixture('invalid/no-workflow-column.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 0, `Expected 0 refs, got ${refs.length}`);
});
test('empty-data.csv: returns 0 refs when CSV has header only', () => {
const { fullPath, content } = loadFixture('invalid/empty-data.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 0, `Expected 0 refs, got ${refs.length}`);
});
test('all-empty-workflow.csv: returns 0 refs when all workflow-file cells empty', () => {
const { fullPath, content } = loadFixture('invalid/all-empty-workflow.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 0, `Expected 0 refs, got ${refs.length}`);
});
test('unresolvable-vars.csv: filters out template variables, keeps normal refs', () => {
const { fullPath, content } = loadFixture('invalid/unresolvable-vars.csv');
const refs = extractCsvRefs(fullPath, content);
assert(refs.length === 1, `Expected 1 ref, got ${refs.length}`);
assert(refs[0].raw === '_bmad/core/tasks/help.md', `Wrong raw: ${refs[0].raw}`);
});
// --- Summary ---
console.log(`\n${colors.cyan}${'═'.repeat(55)}${colors.reset}`);
console.log(`${colors.cyan}Test Results:${colors.reset}`);
console.log(` Total: ${totalTests}`);
console.log(` Passed: ${colors.green}${passedTests}${colors.reset}`);
console.log(` Failed: ${passedTests === totalTests ? colors.green : colors.red}${totalTests - passedTests}${colors.reset}`);
console.log(`${colors.cyan}${'═'.repeat(55)}${colors.reset}\n`);
if (failures.length > 0) {
console.log(`${colors.red}FAILED TESTS:${colors.reset}\n`);
for (const failure of failures) {
console.log(`${colors.red}\u2717${colors.reset} ${failure.name}`);
console.log(` ${failure.message}\n`);
}
process.exit(1);
}
console.log(`${colors.green}All tests passed!${colors.reset}\n`);
process.exit(0);