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'); });