// Tests der Disc-Wache — die Übergangs-Logik pur, und der Fehlerpfad: // Eine gescheiterte Runde darf den Zustand NICHT löschen (R2) und muss // gemeldet werden (R4). import { describe, expect, it } from 'vitest' import type { GeraeteInfo } from '../src/gemeinsam/nachrichten' import { DiscWache, laufwerksUnterschiede } from '../src/kern/laufwerk/wache' function geraet(id: string, status: GeraeteInfo['status'], typ: GeraeteInfo['typ'] = 'unknown'): GeraeteInfo { return { id, name: `Laufwerk ${id}:`, typ, pfad: `\\\\.\\${id}:`, status, modell: '', seriennummer: '', groesseBytes: 0, grund: '', } } function alsMap(...geraete: GeraeteInfo[]): Map { return new Map(geraete.map((g) => [g.id, g])) } describe('laufwerksUnterschiede', () => { it('empty → ready ist eine eingelegte Disc', () => { const ereignisse = laufwerksUnterschiede(alsMap(geraet('G', 'empty')), alsMap(geraet('G', 'ready', 'bluray'))) expect(ereignisse).toEqual([{ art: 'disc-eingelegt', geraet: expect.objectContaining({ id: 'G' }) }]) }) it('ready → empty ist eine entnommene Disc', () => { const ereignisse = laufwerksUnterschiede(alsMap(geraet('G', 'ready')), alsMap(geraet('G', 'empty'))) expect(ereignisse).toEqual([{ art: 'disc-entnommen', geraet: expect.objectContaining({ id: 'G' }) }]) }) it('ready → unknown ist KEINE Entnahme — „konnte nicht nachsehen" (R2)', () => { const ereignisse = laufwerksUnterschiede(alsMap(geraet('G', 'ready')), alsMap(geraet('G', 'unknown'))) expect(ereignisse).toEqual([]) }) it('neues Laufwerk mit Disc meldet beides', () => { const ereignisse = laufwerksUnterschiede(alsMap(), alsMap(geraet('G', 'ready', 'dvd'))) expect(ereignisse.map((e) => e.art)).toEqual(['laufwerk-neu', 'disc-eingelegt']) }) it('verschwundenes Laufwerk wird gemeldet', () => { const ereignisse = laufwerksUnterschiede(alsMap(geraet('G', 'empty')), alsMap()) expect(ereignisse).toEqual([{ art: 'laufwerk-weg', id: 'G' }]) }) }) describe('DiscWache', () => { it('meldet Änderungen und behält bei einem Rundenfehler den Stand (R2/R4)', () => { let stand: GeraeteInfo[] = [geraet('G', 'empty')] let lesenBricht = false const meldungen: string[] = [] const fehler: string[] = [] const wache = new DiscWache( () => { if (lesenBricht) throw new Error('Win32 kaputt') return stand }, (meldung) => meldungen.push(meldung.ereignisse.map((e) => e.art).join(',') || 'stand'), (f) => fehler.push(String(f)), 999_999, ) wache.starten() // Runde 1: erster Stand expect(wache.aktuellerStand()).toHaveLength(1) expect(meldungen).toEqual(['laufwerk-neu']) stand = [geraet('G', 'ready', 'bluray')] wache.runde() // Runde 2: Disc rein expect(meldungen).toEqual(['laufwerk-neu', 'disc-eingelegt']) lesenBricht = true wache.runde() // Runde 3: Lesen bricht — Stand bleibt, Fehler gemeldet expect(fehler).toHaveLength(1) expect(wache.aktuellerStand()).toHaveLength(1) expect(wache.aktuellerStand()[0].status).toBe('ready') lesenBricht = false wache.runde() // Runde 4: nichts geändert — keine neue Meldung expect(meldungen).toHaveLength(2) wache.stoppen() }) })