import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { resolve, dirname, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; import { isFixturePath, FIXTURE_DIR_NAMES, runAllScanners } from '../../scanners/scan-orchestrator.mjs'; const __dirname = dirname(fileURLToPath(import.meta.url)); const PLUGIN_ROOT = resolve(__dirname, '../..'); const FIXTURES = resolve(__dirname, '../fixtures'); // ======================================== // isFixturePath // ======================================== describe('isFixturePath', () => { const target = '/repo'; it('matches tests/ subdirectory relative to target', () => { assert.strictEqual(isFixturePath({ file: '/repo/tests/fixtures/CLAUDE.md' }, target), true); }); it('matches examples/ subdirectory relative to target', () => { assert.strictEqual(isFixturePath({ file: '/repo/examples/demo/settings.json' }, target), true); }); it('matches __tests__/ subdirectory', () => { assert.strictEqual(isFixturePath({ file: '/repo/__tests__/config/CLAUDE.md' }, target), true); }); it('does not match production paths', () => { assert.strictEqual(isFixturePath({ file: '/repo/CLAUDE.md' }, target), false); assert.strictEqual(isFixturePath({ file: '/repo/plugins/config-audit/CLAUDE.md' }, target), false); }); it('does not filter when target IS a fixture directory', () => { // If we're scanning tests/fixtures/broken-project directly, its files should NOT be filtered const fixtureTarget = '/repo/tests/fixtures/broken-project'; assert.strictEqual( isFixturePath({ file: '/repo/tests/fixtures/broken-project/CLAUDE.md' }, fixtureTarget), false, 'Files at the root of the scanned target should not be filtered' ); }); it('falls back to path field', () => { assert.strictEqual(isFixturePath({ path: '/repo/tests/broken/hooks.json' }, target), true); }); it('falls back to location field', () => { assert.strictEqual(isFixturePath({ location: '/repo/examples/bad.md' }, target), true); }); it('returns false when file is null (GAP findings)', () => { assert.strictEqual(isFixturePath({ file: null }, target), false); }); it('returns false for empty finding (no file/path/location)', () => { assert.strictEqual(isFixturePath({}, target), false); }); it('returns false when file is outside target path', () => { assert.strictEqual(isFixturePath({ file: '/other/tests/foo.md' }, target), false); }); it('uses platform-native separator (path.sep)', () => { // On macOS/Linux sep='/', on Windows sep='\\' // This test verifies the function works with the native separator const nativePath = `${target}${sep}tests${sep}fixtures${sep}CLAUDE.md`; assert.strictEqual(isFixturePath({ file: nativePath }, target), true); }); }); // ======================================== // FIXTURE_DIR_NAMES // ======================================== describe('FIXTURE_DIR_NAMES', () => { it('contains expected directory names', () => { assert.ok(FIXTURE_DIR_NAMES.includes('tests')); assert.ok(FIXTURE_DIR_NAMES.includes('examples')); assert.ok(FIXTURE_DIR_NAMES.includes('__tests__')); }); }); // ======================================== // runAllScanners — fixture filtering // ======================================== describe('runAllScanners — fixture filtering', () => { it('excludes fixture findings by default when scanning plugin root', async () => { const env = await runAllScanners(PLUGIN_ROOT); // The plugin has test fixtures in tests/fixtures/ — those should be filtered out const allFindingFiles = env.scanners.flatMap(s => s.findings.map(f => f.file)).filter(Boolean); const fixtureInResults = allFindingFiles.filter(f => f.includes('/tests/')); assert.strictEqual(fixtureInResults.length, 0, 'No fixture findings should appear in scanner results'); }); it('stores excluded findings in env.fixture_findings', async () => { const env = await runAllScanners(PLUGIN_ROOT); // Plugin has intentionally broken fixtures — at least some findings should be excluded if (env.fixture_findings) { assert.ok(Array.isArray(env.fixture_findings)); assert.ok(env.fixture_findings.length > 0, 'Expected fixture findings to be captured'); // All fixture findings should have test/example paths for (const f of env.fixture_findings) { const p = f.file || f.path || f.location || ''; assert.ok( p.includes('/tests/') || p.includes('/examples/'), `Fixture finding path should contain /tests/ or /examples/: ${p}` ); } } // Note: if no fixture findings exist (unlikely but possible), test still passes }); it('includes fixture findings when filterFixtures is false', async () => { const env = await runAllScanners(PLUGIN_ROOT, { filterFixtures: false }); assert.strictEqual(env.fixture_findings, undefined, 'No fixture_findings field when filtering disabled'); // Some findings should have test fixture paths const allFindingFiles = env.scanners.flatMap(s => s.findings.map(f => f.file)).filter(Boolean); const fixtureInResults = allFindingFiles.filter(f => f.includes('/tests/')); assert.ok(fixtureInResults.length > 0, 'Fixture findings should be present when filtering disabled'); }); it('does not filter GAP findings (file is null)', async () => { const env = await runAllScanners(PLUGIN_ROOT); const gapScanner = env.scanners.find(s => s.scanner === 'GAP'); assert.ok(gapScanner, 'GAP scanner should be present'); // GAP findings have file: null — they should never be filtered for (const f of gapScanner.findings) { assert.strictEqual(f.file, null, 'GAP findings have null file and should not be filtered'); } }); it('recalculates scanner counts after fixture filtering', async () => { const env = await runAllScanners(PLUGIN_ROOT); for (const scanner of env.scanners) { // Verify counts match actual findings const expected = { critical: 0, high: 0, medium: 0, low: 0, info: 0 }; for (const f of scanner.findings) { if (expected[f.severity] !== undefined) expected[f.severity]++; } assert.deepStrictEqual(scanner.counts, expected, `Scanner ${scanner.scanner}: counts should match actual findings after filtering`); } }); it('total_findings in aggregate excludes fixtures', async () => { const withFilter = await runAllScanners(PLUGIN_ROOT, { filterFixtures: true }); const withoutFilter = await runAllScanners(PLUGIN_ROOT, { filterFixtures: false }); // With filter should have fewer or equal findings assert.ok( withFilter.aggregate.total_findings <= withoutFilter.aggregate.total_findings, `Filtered total (${withFilter.aggregate.total_findings}) should be <= unfiltered (${withoutFilter.aggregate.total_findings})` ); }); it('fixture filtering and suppression are independent', async () => { // Both enabled (default) const both = await runAllScanners(PLUGIN_ROOT, { filterFixtures: true, suppress: true }); // Only fixtures const fixturesOnly = await runAllScanners(PLUGIN_ROOT, { filterFixtures: true, suppress: false }); // Only suppression const suppressOnly = await runAllScanners(PLUGIN_ROOT, { filterFixtures: false, suppress: true }); // fixture_findings should be present in both fixture-filtered runs if (both.fixture_findings) { assert.ok(fixturesOnly.fixture_findings, 'fixture_findings should be present regardless of suppress flag'); } // suppressed_findings should be present in both suppression-enabled runs (if any suppressions exist) if (both.suppressed_findings) { assert.ok(suppressOnly.suppressed_findings, 'suppressed_findings should be present regardless of filterFixtures flag'); } }); });