(a) Reset h/mi/e after each event so a later event with no H:M:E of its own no longer inherits the previous event's time-of-day (fabricated audit timestamp + dedupeKey). (b) Track consumed high-half token indices so one g/d token can no longer be paired with two adjacent grants (wrong reconstructed card numbers). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
190 lines
7.4 KiB
TypeScript
190 lines
7.4 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import {
|
|
parseHeatSyncLog,
|
|
normalizeWebhookEvents,
|
|
cardMatchesEvent,
|
|
type DoorIngestEvent,
|
|
} from '@/lib/door-log-logic'
|
|
|
|
function ev(p: Partial<DoorIngestEvent>): DoorIngestEvent {
|
|
return { result: 'granted', cardNumber: null, cardUid: null, occurredAt: null, detail: '', dedupeKey: '', ...p }
|
|
}
|
|
|
|
describe('parseHeatSyncLog', () => {
|
|
it('parses a granted event and reconstructs a small card number', () => {
|
|
const log = '<pre>\nG: 12345\ng: 0\n</pre>'
|
|
const ev = parseHeatSyncLog(log)
|
|
expect(ev).toHaveLength(1)
|
|
expect(ev[0].result).toBe('granted')
|
|
expect(ev[0].cardNumber).toBe('12345')
|
|
expect(ev[0].cardUid).toBeNull()
|
|
})
|
|
|
|
it('reconstructs a card number split across the divisor (high*32767 + low)', () => {
|
|
// 40000 = 1*32767 + 7233
|
|
const log = 'G: 7233\ng: 1'
|
|
const ev = parseHeatSyncLog(log)
|
|
expect(ev[0].cardNumber).toBe('40000')
|
|
})
|
|
|
|
it('parses a denied event from D/d', () => {
|
|
const log = 'D: 100\nd: 0'
|
|
const ev = parseHeatSyncLog(log)
|
|
expect(ev[0].result).toBe('denied')
|
|
expect(ev[0].cardNumber).toBe('100')
|
|
})
|
|
|
|
it('stamps best-effort H:M:E time-of-day when present', () => {
|
|
const log = 'H: 9\nM: 5\nE: 3\nG: 50\ng: 0'
|
|
const ev = parseHeatSyncLog(log)
|
|
expect(ev[0].detail).toContain('09:05:03')
|
|
expect(ev[0].dedupeKey).toContain('09:05:03')
|
|
})
|
|
|
|
it('ignores empty ring slots (NUL keys) and unrelated keys', () => {
|
|
const log = ' |