Files
ocr_scanner/test/session.test.js
T
vchuserandClaude Opus 5 1ec3ca4054 Ersetze deutsche Bezeichner durch englische im Quelltext
Projektvorgabe: Kommentare und Oberflaechentexte deutsch, Bezeichner im Code
englisch. Betroffen: src/barcode.js (vorbereitungsPromise -> readyPromise,
inkl. Verweis-Kommentar in ocr.js), sowie lokale Variablen in
test/spec-match.test.js, test/session.test.js und test/pipeline.test.js
(u.a. ocrAufgerufen -> ocrCalled, gefunden bei vollstaendigem Durchgang
aller Test-Dateien). Testbeschreibungen (Prosa) und Kommentare bleiben
unangetastet - nur echte Bezeichner wurden umbenannt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 18:24:30 +02:00

177 lines
7.3 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { emptySpec } from '../src/spec.js';
import {
createSession, proposeAssignment, commitAssignment,
undoLast, moveEntry, removeEntry,
} from '../src/session.js';
const s64 = () => ({ ...emptySpec(), capacityGb: 64, formFactor: 'LRDIMM', rank: '4DRx4', speed: 'PC4-2400', partNumber: 'M386A8K40BM1-CRC4Y' });
const s32 = () => ({ ...emptySpec(), capacityGb: 32, formFactor: 'RDIMM', rank: '2Rx4', speed: 'PC4-2666', partNumber: 'M393A4K40BB1-CTD' });
function scan(session, spec, source = 'barcode') {
const plan = proposeAssignment(session, spec);
return commitAssignment(session, spec, source, plan.stackId);
}
test('erster Scan legt Stapel A an', () => {
const session = createSession();
const plan = proposeAssignment(session, s64());
assert.equal(plan.kind, 'new');
assert.equal(plan.stackId, 'A');
});
test('gleiches Modul landet auf demselben Stapel', () => {
const session = createSession();
scan(session, s64());
const plan = proposeAssignment(session, s64());
assert.equal(plan.kind, 'match');
assert.equal(plan.stackId, 'A');
});
test('anderes Modul legt Stapel B an', () => {
const session = createSession();
scan(session, s64());
const plan = proposeAssignment(session, s32());
assert.equal(plan.kind, 'new');
assert.equal(plan.stackId, 'B');
});
test('eine Verwechslung erzeugt keinen Fast-Duplikat-Stapel', () => {
const session = createSession();
scan(session, s64());
const noisy = { ...s64(), partNumber: 'M386A8K4OBM1-CRC4Y' };
const plan = proposeAssignment(session, noisy);
assert.equal(plan.kind, 'match');
assert.equal(plan.stackId, 'A');
});
test('Scan ohne Teilenummer bei zwei passenden Stapeln ist mehrdeutig', () => {
const session = createSession();
scan(session, { ...s64(), partNumber: 'M386A8K40BM1-CRC4Y' });
scan(session, { ...s64(), partNumber: 'HMAA8GL7AMR4N-UH' });
const withoutPartNumber = { ...s64(), partNumber: null };
const plan = proposeAssignment(session, withoutPartNumber);
assert.equal(plan.kind, 'ambiguous');
assert.deepEqual(plan.candidates, ['A', 'B']);
});
test('commitAssignment zaehlt den Stapel hoch und fuehrt die Liste', () => {
const session = createSession();
scan(session, s64());
scan(session, s64());
assert.equal(session.stacks.length, 1);
assert.equal(session.stacks[0].count, 2);
assert.equal(session.entries.length, 2);
});
test('undoLast nimmt den letzten Eintrag zurueck', () => {
const session = createSession();
scan(session, s64());
scan(session, s64());
const removed = undoLast(session);
assert.equal(removed.stackId, 'A');
assert.equal(session.stacks[0].count, 1);
assert.equal(session.entries.length, 1);
});
test('undoLast entfernt einen leer gewordenen Stapel', () => {
const session = createSession();
scan(session, s64());
undoLast(session);
assert.equal(session.stacks.length, 0);
assert.equal(undoLast(session), null);
});
test('moveEntry sortiert einen Eintrag um', () => {
const session = createSession();
const a = scan(session, s64());
scan(session, s32());
moveEntry(session, a.entryId, 'B');
const stackA = session.stacks.find((s) => s.id === 'A');
const stackB = session.stacks.find((s) => s.id === 'B');
assert.equal(stackA, undefined, 'leerer Stapel wird entfernt');
assert.equal(stackB.count, 2);
});
test('removeEntry entfernt einen einzelnen Eintrag', () => {
const session = createSession();
const a = scan(session, s64());
scan(session, s64());
removeEntry(session, a.entryId);
assert.equal(session.entries.length, 1);
assert.equal(session.stacks[0].count, 1);
});
test('Ergaenzung des Stapel-Specs veraendert nicht das Spec eines frueheren Eintrags', () => {
const session = createSession();
const incomplete = { ...s64(), partNumber: null };
const entry1 = scan(session, incomplete);
const stack = session.stacks.find((s) => s.id === entry1.stackId);
assert.notEqual(stack.spec, entry1.spec, 'Stapel-Spec und Eintrags-Spec duerfen kein gemeinsames Objekt sein');
assert.deepEqual(stack.spec, entry1.spec, 'inhaltlich sind beide Specs zunaechst gleich');
assert.equal(entry1.spec.partNumber, null);
const complete = s64();
scan(session, complete);
assert.equal(entry1.spec.partNumber, null, 'das Spec des ersten Eintrags darf durch eine spaetere Ergaenzung des Stapel-Specs nicht veraendert werden');
assert.equal(stack.spec.partNumber, 'M386A8K40BM1-CRC4Y');
});
test('moveEntry legt fuer einen neuen Stapel eine eigene Kopie des Specs an', () => {
const session = createSession();
const incomplete = { ...s32(), partNumber: null };
const a = scan(session, incomplete);
moveEntry(session, a.entryId, 'Z');
const stackZ = session.stacks.find((s) => s.id === 'Z');
assert.notEqual(stackZ.spec, a.spec, 'Stapel-Spec und Eintrags-Spec duerfen kein gemeinsames Objekt sein');
stackZ.spec.partNumber = 'M393A4K40BB1-CTD';
assert.equal(a.spec.partNumber, null, 'eine Ergaenzung des neu angelegten Stapel-Specs darf das Eintrags-Spec nicht veraendern');
});
test('ein Stapel ohne jede erkannte Angabe ist fuer kein Modul Kandidat', () => {
const session = createSession();
scan(session, emptySpec()); // Stapel A, vollstaendig leeres Spec (Rot-Fall)
const plan = proposeAssignment(session, s64());
assert.equal(plan.kind, 'new', 'ein leerer Stapel darf keine Kandidatur begruenden');
assert.notEqual(plan.stackId, 'A');
});
test('ein Stapel mit nur der Kapazitaet ist Kandidat fuer ein Modul gleicher Kapazitaet', () => {
const session = createSession();
scan(session, { ...emptySpec(), capacityGb: 64 });
const plan = proposeAssignment(session, { ...emptySpec(), capacityGb: 64 });
assert.equal(plan.kind, 'match');
assert.equal(plan.stackId, 'A');
});
test('ein voellig unerkanntes Modul erzeugt einen eigenen Stapel und zieht keine weiteren an sich', () => {
const session = createSession();
const first = scan(session, emptySpec());
const second = scan(session, emptySpec());
assert.notEqual(first.stackId, second.stackId, 'zwei unerkannte Module ohne gemeinsame Grundlage teilen sich keinen Stapel');
assert.equal(session.stacks.length, 2);
const plan = proposeAssignment(session, s64());
assert.equal(plan.kind, 'new', 'der leere Stapel darf ein erkanntes Modul nicht an sich ziehen');
});
test('undoLast-Vertrag: nach einem Umsortieren wird weiterhin der zuletzt erfasste Eintrag zurueckgenommen', () => {
const session = createSession();
const a = scan(session, s64());
const b = scan(session, s32());
moveEntry(session, a.entryId, 'B');
// Zuletzt ausgefuehrte Handlung war das Umsortieren von a; zuletzt erfasst wurde jedoch b.
const removed = undoLast(session);
assert.equal(removed.entryId, b.entryId, 'undoLast nimmt den zuletzt erfassten Eintrag zurueck, nicht die zuletzt ausgefuehrte Handlung (das Umsortieren)');
assert.equal(session.entries.length, 1);
assert.equal(session.entries[0].entryId, a.entryId);
assert.equal(session.entries[0].stackId, 'B', 'das Umsortieren von a bleibt von der Rueckname des unbeteiligten Eintrags b unberuehrt');
const stackA = session.stacks.find((s) => s.id === 'A');
const stackB = session.stacks.find((s) => s.id === 'B');
assert.equal(stackA, undefined, 'Stapel A ist seit dem Umsortieren leer und wurde bereits entfernt');
assert.equal(stackB.count, 1, 'Stapel B enthaelt weiterhin a, nur b wurde zurueckgenommen');
});