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>
194 lines
7.5 KiB
JavaScript
194 lines
7.5 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { recognize } from '../src/pipeline.js';
|
|
import { emptySpec } from '../src/spec.js';
|
|
|
|
const OCR_TEXT = '64GB 4DRx4 PC4-2400T-LD1-11-MC0 M386A8K40BM1-CRC4Y 1908';
|
|
|
|
const deps = ({ codes = [], text = '' }) => ({
|
|
decodeBarcodes: async () => codes,
|
|
runOcr: async () => text,
|
|
});
|
|
|
|
test('Barcode mit bekannter Teilenummer ergibt gruen und ueberspringt OCR', async () => {
|
|
let ocrCalled = false;
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => ['M386A8K40BM1-CRC4Y'],
|
|
runOcr: async () => { ocrCalled = true; return ''; },
|
|
});
|
|
assert.equal(result.source, 'barcode');
|
|
assert.equal(result.confidence, 'green');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
assert.equal(ocrCalled, false, 'OCR darf bei gruenem Barcode nicht laufen');
|
|
});
|
|
|
|
test('Barcode ohne bekannte Teilenummer faellt auf OCR zurueck', async () => {
|
|
const result = await recognize({}, deps({ codes: ['7325773'], text: OCR_TEXT }));
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
test('OCR-Ergebnis behaelt die Teilenummer aus dem Barcode bei', async () => {
|
|
const result = await recognize({}, deps({ codes: ['7325773'], text: '64GB 4DRx4 PC4-2400' }));
|
|
assert.equal(result.spec.partNumber, '7325773');
|
|
});
|
|
|
|
test('ohne Barcode und ohne brauchbaren Text ergibt rot', async () => {
|
|
const result = await recognize({}, deps({ codes: [], text: 'Made in Philippines' }));
|
|
assert.equal(result.source, 'none');
|
|
assert.equal(result.confidence, 'red');
|
|
});
|
|
|
|
test('OCR-Fehler fuehrt zu rot statt zu einem Absturz', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => [],
|
|
runOcr: async () => { throw new Error('tesseract nicht geladen'); },
|
|
});
|
|
assert.equal(result.confidence, 'red');
|
|
assert.equal(result.source, 'none');
|
|
});
|
|
|
|
test('Barcode-Fehler fuehrt nicht zum Abbruch, OCR uebernimmt', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => { throw new Error('zxing nicht geladen'); },
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
// --- Beanstandung 1: unerwartete Rueckgabeform statt eines Fehlers ---
|
|
|
|
test('decodeBarcodes liefert null statt einer Liste, kein Absturz', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => null,
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
test('decodeBarcodes liefert undefined statt einer Liste, kein Absturz', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => undefined,
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
test('decodeBarcodes liefert ein Objekt statt einer Liste, kein Absturz', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => ({ notAList: true }),
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
test('runOcr liefert keine Zeichenkette, wird wie leerer Text behandelt', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => [],
|
|
runOcr: async () => ({ unexpected: true }),
|
|
});
|
|
assert.equal(result.source, 'none');
|
|
assert.equal(result.confidence, 'red');
|
|
});
|
|
|
|
// --- Beanstandung 2: mehrere verwertbare Barcodes im selben Bild ---
|
|
|
|
test('mehrere unvertraegliche Barcodes ergeben rot statt eines ungeprueften ersten Treffers', async () => {
|
|
let ocrCalled = false;
|
|
const result = await recognize({}, {
|
|
// Gleiche Bauform und Dichte, aber widersprechende Geschwindigkeit:
|
|
// zwei unterschiedliche Module im selben Bild.
|
|
decodeBarcodes: async () => ['M386A8K40BM1-CRC4Y', 'M386A8K40BM1-CWE4Y'],
|
|
runOcr: async () => { ocrCalled = true; return ''; },
|
|
});
|
|
assert.equal(result.source, 'none');
|
|
assert.equal(result.confidence, 'red');
|
|
assert.deepEqual(result.spec, emptySpec());
|
|
assert.equal(ocrCalled, false, 'bei mehrdeutigem Barcode-Ergebnis soll nicht geraten werden');
|
|
});
|
|
|
|
test('mehrere untereinander vertraegliche Barcodes ergeben gruen (der erste Treffer entscheidet, es gibt nichts zusammenzufuehren)', async () => {
|
|
let ocrCalled = false;
|
|
const result = await recognize({}, {
|
|
// Zwei Lesungen desselben Etiketts (z.B. Mehrfachtreffer durch
|
|
// Spiegelung) - inhaltlich identisch, nur die Schreibweise weicht
|
|
// an einer verwechslungstoleranten Stelle ab (B/8).
|
|
decodeBarcodes: async () => ['M386A8K40BM1-CRC4Y', 'M386A8K408M1-CRC4Y'],
|
|
runOcr: async () => { ocrCalled = true; return ''; },
|
|
});
|
|
assert.equal(result.source, 'barcode');
|
|
assert.equal(result.confidence, 'green');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
assert.equal(result.spec.formFactor, 'LRDIMM');
|
|
assert.equal(result.spec.rank, '4DRx4');
|
|
assert.equal(result.spec.speed, 'PC4-2400');
|
|
assert.equal(ocrCalled, false, 'OCR darf bei gruenem Mehrfachtreffer nicht laufen');
|
|
});
|
|
|
|
// --- Beanstandung 1: haengender Adapter darf die Erkennung nicht dauerhaft blockieren ---
|
|
|
|
test('haengender Barcode-Adapter blockiert nicht dauerhaft, OCR uebernimmt', { timeout: 500 }, async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: () => new Promise(() => {}), // loest nie ein und wirft nie
|
|
runOcr: async () => OCR_TEXT,
|
|
barcodeTimeoutMs: 20,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
test('haengender OCR-Adapter blockiert nicht dauerhaft, Erkennung ergibt rot', { timeout: 500 }, async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => [],
|
|
runOcr: () => new Promise(() => {}), // loest nie ein und wirft nie
|
|
ocrTimeoutMs: 20,
|
|
});
|
|
assert.equal(result.source, 'none');
|
|
assert.equal(result.confidence, 'red');
|
|
});
|
|
|
|
// --- Beanstandung 1 (3. Runde): Mehrdeutigkeit bei unverwertbaren Barcodes ---
|
|
|
|
test('zwei widersprechende unverwertbare Barcodes: keiner erhaelt Vorrang, gelesene Teilenummer bleibt', async () => {
|
|
const result = await recognize({}, {
|
|
// Beide ohne bekanntes Nummernschema, und sie widersprechen sich -
|
|
// keiner darf die aus dem Klartext gelesene Teilenummer ueberschreiben.
|
|
decodeBarcodes: async () => ['7325773', '9999999'],
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.partNumber, 'M386A8K40BM1-CRC4Y');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
});
|
|
|
|
test('zwei unverwertbare Barcodes mit gleicher Teilenummer: Vorrang bleibt bestehen', async () => {
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => ['7325773', '7325773'],
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.partNumber, '7325773');
|
|
});
|
|
|
|
test('zwei unverwertbare Barcodes, die sich nur in einer Verwechslung unterscheiden, gelten als derselbe', async () => {
|
|
const result = await recognize({}, {
|
|
// 'O' und '0' sind eine typische Verwechslung (siehe CONFUSIONS in spec.js).
|
|
decodeBarcodes: async () => ['732O773', '7320773'],
|
|
runOcr: async () => OCR_TEXT,
|
|
});
|
|
assert.equal(result.source, 'ocr');
|
|
assert.equal(result.confidence, 'yellow');
|
|
assert.equal(result.spec.partNumber, '732O773');
|
|
});
|