takt/src/__tests__/repertoire-ref-integrity.test.ts

121 lines
4.8 KiB
TypeScript

/**
* Unit tests for repertoire reference integrity scanner.
*
* Target: src/features/repertoire/remove.ts (findScopeReferences)
*
* Scanner searches for @scope package references in:
* - {root}/pieces/**\/*.yaml
* - {root}/preferences/piece-categories.yaml
* - {root}/.takt/pieces/**\/*.yaml (project-level)
*
* Detection criteria:
* - Matches "@{owner}/{repo}" substring in file contents
* - Plain names without "@" are NOT detected
* - References to a different @scope are NOT detected
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { findScopeReferences } from '../features/repertoire/remove.js';
import { makeScanConfig } from './helpers/repertoire-test-helpers.js';
describe('repertoire reference integrity: detection', () => {
let tempDir: string;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), 'takt-ref-integrity-'));
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
// U29: ~/.takt/pieces/ の @scope 参照を検出
// Given: {root}/pieces/my-review.yaml に
// persona: "@nrslib/takt-ensemble-fixture/expert-coder" を含む
// When: findScopeReferences("@nrslib/takt-ensemble-fixture", config)
// Then: my-review.yaml が検出される
it('should detect @scope reference in global pieces YAML', () => {
const piecesDir = join(tempDir, 'pieces');
mkdirSync(piecesDir, { recursive: true });
const pieceFile = join(piecesDir, 'my-review.yaml');
writeFileSync(pieceFile, 'persona: "@nrslib/takt-ensemble-fixture/expert-coder"');
const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir));
expect(refs.some((r) => r.filePath === pieceFile)).toBe(true);
});
// U30: {root}/preferences/piece-categories.yaml の @scope 参照を検出
// Given: piece-categories.yaml に @nrslib/takt-ensemble-fixture/expert を含む
// When: findScopeReferences("@nrslib/takt-ensemble-fixture", config)
// Then: piece-categories.yaml が検出される
it('should detect @scope reference in global piece-categories.yaml', () => {
const prefsDir = join(tempDir, 'preferences');
mkdirSync(prefsDir, { recursive: true });
const categoriesFile = join(prefsDir, 'piece-categories.yaml');
writeFileSync(categoriesFile, 'categories:\n - "@nrslib/takt-ensemble-fixture/expert"');
const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir));
expect(refs.some((r) => r.filePath === categoriesFile)).toBe(true);
});
// U31: {root}/.takt/pieces/ の @scope 参照を検出
// Given: プロジェクト {root}/.takt/pieces/proj.yaml に @scope 参照
// When: findScopeReferences("@nrslib/takt-ensemble-fixture", config)
// Then: proj.yaml が検出される
it('should detect @scope reference in project-level pieces YAML', () => {
const projectPiecesDir = join(tempDir, '.takt', 'pieces');
mkdirSync(projectPiecesDir, { recursive: true });
const projFile = join(projectPiecesDir, 'proj.yaml');
writeFileSync(projFile, 'persona: "@nrslib/takt-ensemble-fixture/expert-coder"');
const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir));
expect(refs.some((r) => r.filePath === projFile)).toBe(true);
});
});
describe('repertoire reference integrity: non-detection', () => {
let tempDir: string;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), 'takt-ref-nodetect-'));
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
// U32: @scope なし参照は検出しない
// Given: persona: "coder" のみ(@scope なし)
// When: findScopeReferences("@nrslib/takt-ensemble-fixture", config)
// Then: 結果が空配列
it('should not detect plain name references without @scope prefix', () => {
const piecesDir = join(tempDir, 'pieces');
mkdirSync(piecesDir, { recursive: true });
writeFileSync(join(piecesDir, 'plain.yaml'), 'persona: "coder"');
const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir));
expect(refs).toHaveLength(0);
});
// U33: 別スコープは検出しない
// Given: persona: "@other/package/name"
// When: findScopeReferences("@nrslib/takt-ensemble-fixture", config)
// Then: 結果が空配列
it('should not detect references to a different @scope package', () => {
const piecesDir = join(tempDir, 'pieces');
mkdirSync(piecesDir, { recursive: true });
writeFileSync(join(piecesDir, 'other.yaml'), 'persona: "@other/package/name"');
const refs = findScopeReferences('@nrslib/takt-ensemble-fixture', makeScanConfig(tempDir));
expect(refs).toHaveLength(0);
});
});