recognize() stuerzte ab, wenn decodeBarcodes() etwas anderes als eine Liste zurueckgab (null/undefined/Objekt), da die for...of-Schleife nicht iterierbare Werte nicht abfaengt. Nicht-Listen werden nun wie eine leere Liste behandelt, ebenso wird eine nicht-string-wertige runOcr()-Rueckgabe wie leerer Text behandelt. Ausserdem gewann bei mehreren verwertbaren Barcodes im selben Bild bisher ungeprueft der erste Treffer mit gruener Ampel. Jetzt werden alle verwertbaren Codes gesammelt: genau einer bleibt gruen wie bisher, mehrere untereinander vertraegliche werden zusammengefuehrt (spaeterer Treffer ueberschreibt kein bereits gesetztes Feld) und bleiben gruen, mehrere unvertraegliche ergeben rot mit leerem Spec statt eines geratenen Ergebnisses. Korrigiert ausserdem den irrefuehrenden Warnkommentar in pn-tables.js: ein falscher Tabelleneintrag faellt auf dem Barcode-Weg nicht automatisch auf, da dort keine Texterkennung zum Abgleich laeuft. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
135 lines
5.2 KiB
JavaScript
135 lines
5.2 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 ocrAufgerufen = false;
|
|
const result = await recognize({}, {
|
|
decodeBarcodes: async () => ['M386A8K40BM1-CRC4Y'],
|
|
runOcr: async () => { ocrAufgerufen = true; return ''; },
|
|
});
|
|
assert.equal(result.source, 'barcode');
|
|
assert.equal(result.confidence, 'green');
|
|
assert.equal(result.spec.capacityGb, 64);
|
|
assert.equal(ocrAufgerufen, 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 () => ({ unerwartet: 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 ocrAufgerufen = 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 () => { ocrAufgerufen = true; return ''; },
|
|
});
|
|
assert.equal(result.source, 'none');
|
|
assert.equal(result.confidence, 'red');
|
|
assert.deepEqual(result.spec, emptySpec());
|
|
assert.equal(ocrAufgerufen, false, 'bei mehrdeutigem Barcode-Ergebnis soll nicht geraten werden');
|
|
});
|
|
|
|
test('mehrere untereinander vertraegliche Barcodes werden zusammengefuehrt und bleiben gruen', async () => {
|
|
let ocrAufgerufen = 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 () => { ocrAufgerufen = 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(ocrAufgerufen, false, 'OCR darf bei gruenem Mehrfachtreffer nicht laufen');
|
|
});
|