import { test } from 'node:test' import assert from 'node:assert/strict' import { parseCellFields, looksLikeAncestorCell } from './ocrParse.js' // --- The three cases required by plan Step 3.5 --- test('case 1: all five fields present and labelled', () => { const cell = [ "Belowland's Thumper", 'Tattoo: AB12', 'DOB: 03/15/2024', 'Weight: 8 lbs 4 oz', ].join('\n') assert.deepEqual(parseCellFields(cell), { farmName: "Belowland's", rabbitName: 'Thumper', earNumber: 'AB12', dob: '2024-03-15', weight: 8.25, }) }) test('case 2: only name and ear number (DOB and weight absent)', () => { const cell = ['Clover', 'RZ7'].join('\n') assert.deepEqual(parseCellFields(cell), { farmName: null, rabbitName: 'Clover', earNumber: 'RZ7', dob: null, weight: null, }) }) test('case 3: name has no possessive (rabbit name only, no farm)', () => { const cell = ['Midnight', 'Ear #: XY99'].join('\n') const result = parseCellFields(cell) assert.equal(result.farmName, null) assert.equal(result.rabbitName, 'Midnight') assert.equal(result.earNumber, 'XY99') }) // --- Per-field rule coverage --- test('possessive split handles a plain "s without apostrophe-s', () => { // "Lund Lops' Seabreeze" → farm "Lund Lops'", name "Seabreeze" const result = parseCellFields("Lund Lops' Seabreeze") assert.equal(result.farmName, "Lund Lops'") assert.equal(result.rabbitName, 'Seabreeze') }) test('weight: decimal lbs form', () => { assert.equal(parseCellFields('Bunny\nWeight 8.5 lbs').weight, 8.5) }) test('weight: bare number with no unit is not a weight', () => { assert.equal(parseCellFields('Bunny\n8.5').weight, null) }) test('dob: 2-digit year maps to 20xx and slashes/dashes both parse', () => { assert.equal(parseCellFields('Bunny\nborn 5/9/24').dob, '2024-05-09') assert.equal(parseCellFields('Bunny\n12-25-2023').dob, '2023-12-25') }) test('dob: 2-digit year beyond the current-year pivot maps to 19xx', () => { // Older slips carry 1990s ancestors; "98" must not become a future 2098 DOB. assert.equal(parseCellFields('Bunny\nDOB: 3/15/98').dob, '1998-03-15') }) test('dob: invalid month is rejected', () => { assert.equal(parseCellFields('Bunny\n13/40/2024').dob, null) }) test('dob: impossible day for the month is rejected', () => { assert.equal(parseCellFields('Bunny\n2/31/2024').dob, null) // 2024 is a leap year — 2/29 is real. assert.equal(parseCellFields('Bunny\n2/29/2024').dob, '2024-02-29') assert.equal(parseCellFields('Bunny\n2/29/2023').dob, null) }) test('ear number: labelled value wins over a later bare token', () => { const result = parseCellFields('Rocky\nTattoo: GH42\nREW') assert.equal(result.earNumber, 'GH42') }) // --- ALL-CAPS pedigrees (real-world: BASTET'S SHANGHEI etc.) --- test('all-caps possessive splits farm from name on one line', () => { const result = parseCellFields('BASTET’S SHANGHEI'.replace('’', "'")) assert.equal(result.farmName, "BASTET'S") assert.equal(result.rabbitName, 'SHANGHEI') }) test('farm on its own line, rabbit name on the next line', () => { const cell = ["BASTET'S", 'SHAMWOW', 'Ear #: BSHAMW', 'Weight: 3 # 15 oz'].join('\n') const result = parseCellFields(cell) assert.equal(result.farmName, "BASTET'S") assert.equal(result.rabbitName, 'SHAMWOW') assert.equal(result.earNumber, 'BSHAMW') }) test('an all-caps name is not mistaken for a bare ear number', () => { // "SHANGHEI" is all letters → a name, not an ear. The labelled ear wins. const cell = ['MIDNIGHT', 'Ear #: XY99'].join('\n') const result = parseCellFields(cell) assert.equal(result.rabbitName, 'MIDNIGHT') assert.equal(result.earNumber, 'XY99') }) test('a bare all-letter token is not treated as an ear number', () => { // No label, no digit → not an ear; it becomes the name instead. const result = parseCellFields('SHAMWOW') assert.equal(result.earNumber, null) assert.equal(result.rabbitName, 'SHAMWOW') }) test('looksLikeAncestorCell distinguishes a real cell from the form title', () => { assert.equal(looksLikeAncestorCell("BASTET'S SHAMWOW\nEar #: BSHAMW\nWeight: 3 lbs"), true) assert.equal(looksLikeAncestorCell("Bastet's Bunnies\nHolland Lop"), false) assert.equal(looksLikeAncestorCell(''), false) }) test('empty / whitespace cell yields all nulls', () => { assert.deepEqual(parseCellFields(' \n \n'), { farmName: null, rabbitName: null, earNumber: null, dob: null, weight: null, }) })