test(okr): vakt mot ekskluderte termer i sporede filer
Ny tests/domain-filter.test.mjs skanner innhold og sti i hver sporet fil
(git ls-files, med filsystem-fallback uten .git) mot en lokal, gitignored
termliste. Hver term må treffe sin egen kjent-positive prøve, og lista må
ha kjent-negative prøver som ikke treffer. Uten lista hoppes testen over
med en tydelig melding. Skanneren har også en syntetisk selvtest. Den
navngitte unntakslista er tom og har en vakt mot foreldede oppføringer.
RØD på 3c240af: 115 treff i 35 filer (139 filer skannet).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3c240af7ea
commit
d71de15d48
1 changed files with 117 additions and 0 deletions
117
tests/domain-filter.test.mjs
Normal file
117
tests/domain-filter.test.mjs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// domain-filter.test.mjs
|
||||
// Vakt: ingen sporet fil -- innhold ELLER sti -- skal treffe den lokale
|
||||
// ekskluderingslista.
|
||||
//
|
||||
// Termlista er med vilje IKKE sporet: den ligger i tests/.excluded-terms.local.md
|
||||
// (gitignored via *.local.md). Mangler fila, hoppes vakten over med en tydelig
|
||||
// melding -- da er ingenting maalt, og det skal ikke leses som null treff.
|
||||
// Hver term baerer en kjent-positiv proeve, og lista har kjent-negative proever,
|
||||
// saa et moenster som ikke kan finne noe aldri passerer som en null-maaling.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
||||
import { join, dirname, relative, sep } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const SELF = relative(ROOT, fileURLToPath(import.meta.url)).split(sep).join('/');
|
||||
const TERMFIL = join(ROOT, 'tests', '.excluded-terms.local.md');
|
||||
const MANGLER = `ekskluderingslista mangler (${relative(ROOT, TERMFIL)}) -- vakten er IKKE kjoert`;
|
||||
|
||||
// Navngitt unntaksliste: sti -> begrunnelse. Hver oppfoering maa finnes og
|
||||
// fortsatt treffe, ellers er den foreldet og testen feiler.
|
||||
const UNNTAK = new Map([]);
|
||||
|
||||
function lesTermer() {
|
||||
const termer = [];
|
||||
const negative = [];
|
||||
for (const raa of readFileSync(TERMFIL, 'utf8').split('\n')) {
|
||||
const linje = raa.trim();
|
||||
if (!linje || linje.startsWith('#')) continue;
|
||||
if (linje.startsWith('!')) {
|
||||
negative.push(linje.slice(1).trim());
|
||||
continue;
|
||||
}
|
||||
const [kilde, proeve] = linje.split(' => ');
|
||||
termer.push({ kilde: kilde.trim(), proeve: proeve === undefined ? undefined : proeve.trim() });
|
||||
}
|
||||
return { termer, negative };
|
||||
}
|
||||
|
||||
function sporedeFiler() {
|
||||
try {
|
||||
const ut = execFileSync('git', ['ls-files', '-z'], { cwd: ROOT, encoding: 'utf8' });
|
||||
const filer = ut.split('\0').filter(Boolean);
|
||||
if (filer.length > 0) return filer;
|
||||
} catch {
|
||||
// Ingen git (f.eks. installert plugin-kopi) -> gaa filtreet.
|
||||
}
|
||||
const ut = [];
|
||||
const gaa = (dir) => {
|
||||
for (const navn of readdirSync(join(ROOT, dir))) {
|
||||
if (navn === '.git' || navn === 'node_modules' || navn === '.claude') continue;
|
||||
if (navn.endsWith('.local.md')) continue;
|
||||
const rel = dir ? `${dir}/${navn}` : navn;
|
||||
if (statSync(join(ROOT, rel)).isDirectory()) gaa(rel);
|
||||
else ut.push(rel);
|
||||
}
|
||||
};
|
||||
gaa('');
|
||||
return ut;
|
||||
}
|
||||
|
||||
function finnTreff(filer, les, moenster) {
|
||||
const treff = [];
|
||||
for (const sti of filer) {
|
||||
if (moenster.test(sti)) treff.push(`${sti} (filnavn)`);
|
||||
les(sti).split('\n').forEach((linje, i) => {
|
||||
const m = linje.match(moenster);
|
||||
if (m) treff.push(`${sti}:${i + 1}: ${m[0]}`);
|
||||
});
|
||||
}
|
||||
return treff;
|
||||
}
|
||||
|
||||
const lesFil = (sti) => readFileSync(join(ROOT, sti)).toString('utf8');
|
||||
|
||||
test('finnTreff melder baade innhold og filnavn (syntetisk kjent-positiv)', () => {
|
||||
const syntetisk = { 'a/zz-forbudt-zz.md': 'ren tekst', 'b.md': 'linje\nher er zz-forbudt-zz' };
|
||||
const treff = finnTreff(Object.keys(syntetisk), (s) => syntetisk[s], /zz-forbudt-zz/iu);
|
||||
assert.equal(treff.length, 2);
|
||||
assert.match(treff[0], /\(filnavn\)$/);
|
||||
assert.match(treff[1], /^b\.md:2: /);
|
||||
});
|
||||
|
||||
test('ingen sporet fil treffer den lokale ekskluderingslista (innhold eller sti)', (t) => {
|
||||
if (!existsSync(TERMFIL)) {
|
||||
t.skip(MANGLER);
|
||||
return;
|
||||
}
|
||||
const { termer, negative } = lesTermer();
|
||||
assert.ok(termer.length > 0, 'ekskluderingslista har ingen termer');
|
||||
assert.ok(negative.length > 0, 'ekskluderingslista har ingen kjent-negative proever');
|
||||
|
||||
// Validering foer bruk: hver term treffer sin kjent-positive proeve.
|
||||
for (const { kilde, proeve } of termer) {
|
||||
assert.ok(proeve, `term uten kjent-positiv proeve: ${kilde}`);
|
||||
assert.match(proeve, new RegExp(kilde, 'iu'), `term treffer ikke sin egen proeve: ${kilde}`);
|
||||
}
|
||||
const moenster = new RegExp(termer.map((x) => x.kilde).join('|'), 'iu');
|
||||
for (const s of negative) assert.doesNotMatch(s, moenster, `kjent-negativ treffer: ${s}`);
|
||||
|
||||
// Nevneren: skanningen maa faktisk se repoet, inkl. seg selv og fixturene.
|
||||
const filer = sporedeFiler();
|
||||
assert.ok(filer.length > 100, `for faa filer skannet (${filer.length}) -- enumereringen er brukket`);
|
||||
assert.ok(filer.includes(SELF), 'testfila selv skal vaere med i skanningen');
|
||||
assert.ok(filer.some((f) => f.startsWith('tests/fixtures/')), 'fixturene skal vaere med i skanningen');
|
||||
assert.ok(!filer.some((f) => f.endsWith('.local.md')), 'en *.local.md-fil er sporet -- ekskluderingslista kan lekke');
|
||||
|
||||
for (const [sti, grunn] of UNNTAK) {
|
||||
assert.ok(filer.includes(sti), `unntak for ukjent fil: ${sti} (${grunn})`);
|
||||
assert.ok(finnTreff([sti], lesFil, moenster).length > 0, `foreldet unntak, treffer ikke lenger: ${sti}`);
|
||||
}
|
||||
const treff = finnTreff(filer.filter((f) => !UNNTAK.has(f)), lesFil, moenster);
|
||||
assert.deepEqual(treff, [], `${treff.length} treff:\n${treff.join('\n')}`);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue