- eslint.config.js (NEU): Flat-Config fuer ESLint 9 - Globals explizit definiert (console, process, Buffer, etc.) - TypeScript-Parser + Plugin - Rules: no-unused-vars, no-explicit-any (warn) - Tests haben relaxed rules (no-explicit-any off, fuer Mocks) - .eslintrc.cjs -> .eslintrc.cjs.bak (Deprecation-Warnung weg) - package.json scripts.lint: USE_FLAT_CONFIG-Flag entfernt (default flat) - Tests: 2 tote Variablen entfernt - tests/tfidf.test.ts: jaccardSim (ungenutzt, nur Kommentar-Vergleich noetig) - tests/webapp/manifest.test.ts: indexHtmlPath (ungenutzt) Verifiziert: - 117/117 Tests gruen - ESLint exit 0 (ohne Deprecation-Warnung) - Tool-Build OK, Webapp-Build OK
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
// Tests fuer 2.5-erweitert (TF-IDF Cosinus-Aehnlichkeit)
|
|
// Phase 2.5-erweitert
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { tfIdfCosineSimilarity, extractWords, jaccardSimilarity } from '../src/ingest.js';
|
|
|
|
describe('extractWords', () => {
|
|
it('lowercase + >= 4 Zeichen', () => {
|
|
expect(extractWords('Kaffee und ich')).toEqual(['kaffee']);
|
|
});
|
|
|
|
it('Satzzeichen werden entfernt', () => {
|
|
expect(extractWords('Kaffee, Milch! Zucker.')).toEqual(['kaffee', 'milch', 'zucker']);
|
|
});
|
|
|
|
it('Unicode bleibt erhalten', () => {
|
|
expect(extractWords('Größere Übung mit Äpfeln')).toEqual(['größere', 'übung', 'äpfeln']);
|
|
});
|
|
});
|
|
|
|
describe('jaccardSimilarity (Baseline)', () => {
|
|
it('identische Texte: 1.0', () => {
|
|
expect(jaccardSimilarity('Kaffee und Kuchen', 'Kaffee und Kuchen')).toBe(1.0);
|
|
});
|
|
|
|
it('verschiedene Texte: 0.0', () => {
|
|
expect(jaccardSimilarity('Kaffee trinken', 'Auto fahren')).toBe(0.0);
|
|
});
|
|
|
|
it('Teilweise Überlappung: zwischen 0 und 1', () => {
|
|
const sim = jaccardSimilarity('Kaffee am Morgen mit Milch', 'Kaffee am Abend mit Zucker');
|
|
expect(sim).toBeGreaterThan(0);
|
|
expect(sim).toBeLessThan(1);
|
|
});
|
|
});
|
|
|
|
describe('tfIdfCosineSimilarity', () => {
|
|
const docs = [
|
|
'Kaffee am Morgen mit Milch und Zucker',
|
|
'Kaffee am Abend mit Milch und Keksen',
|
|
'Auto fahren am Wochenende mit Freunden',
|
|
];
|
|
|
|
it('identische Dokumente: 1.0', () => {
|
|
expect(tfIdfCosineSimilarity(docs, docs[0], docs[0])).toBe(1.0);
|
|
});
|
|
|
|
it('Thematisch aehnliche Dokumente (Kaffee) > thematisch ungleiche (Kaffee vs Auto)', () => {
|
|
const similar = tfIdfCosineSimilarity(docs, docs[0], docs[1]);
|
|
const different = tfIdfCosineSimilarity(docs, docs[0], docs[2]);
|
|
expect(similar).toBeGreaterThan(different);
|
|
});
|
|
|
|
it('0.0 wenn eines der Dokumente nicht im Korpus', () => {
|
|
expect(tfIdfCosineSimilarity(docs, 'nicht im Korpus', docs[0])).toBe(0);
|
|
expect(tfIdfCosineSimilarity(docs, docs[0], 'auch nicht')).toBe(0);
|
|
});
|
|
|
|
it('Cosinus ist symmetrisch: sim(a, b) === sim(b, a)', () => {
|
|
const ab = tfIdfCosineSimilarity(docs, docs[0], docs[1]);
|
|
const ba = tfIdfCosineSimilarity(docs, docs[1], docs[0]);
|
|
expect(ab).toBeCloseTo(ba, 10);
|
|
});
|
|
|
|
it('TF-IDF bevorzugt seltene Wörter (bessere Diskriminierung als Jaccard)', () => {
|
|
// Beide Dokumente haben 'Kaffee' und 'Milch' gemeinsam, aber unterschiedliche andere
|
|
const d1 = 'Kaffee Milch am Morgen';
|
|
const d2 = 'Kaffee Milch am Abend';
|
|
// TF-IDF sollte unterscheiden, weil 'Kaffee' und 'Milch' im Gesamtkorpus haeufiger sind
|
|
const tfidfSim = tfIdfCosineSimilarity([d1, d2, 'Eine ganz andere Notiz ueber Sport'], d1, d2);
|
|
// Beide positiv, aber konzeptuell aehnlich -> TF-IDF ist tendenziell niedriger
|
|
expect(tfidfSim).toBeGreaterThan(0);
|
|
expect(tfidfSim).toBeLessThanOrEqual(1);
|
|
});
|
|
});
|