feat(v5): Etappe W-1 — Laufwerk: Wache, Typ, Auswerfen mit Nachsehen
Ampel / ampel (push) Successful in 1m21s
Ampel / ampel (push) Successful in 1m21s
kern/laufwerk in drei Schichten: codes.ts (Steuercodes HERGELEITET wie win_ioctl.py, gegen die Doku-Zahlen getestet), win32.ts (der einzige koffi-Ort im Kern, Muster aus beweise/laufwerk.js), disc.ts (Logik gegen die LaufwerkApi-Schnittstelle — classify mit den cdrom.py-Schwellen, Geraete-Info mit ready/empty/unknown + Klartext-Grund, Auswurf als entriegeln→auswerfen→NACHSEHEN mit injizierbarem Warten). Dazu wache.ts im 3-Sekunden-Takt (§ 5 Plan A): Uebergangslogik pur, gescheiterte Runde behaelt den Stand (R2) und meldet laut (R4). Fenster zeigt Laufwerke live (Modell, Typ, Groesse, Grund) mit Auswerfen-Knopf; Ereigniszeilen fuer Disc rein/raus und Fehler. Bündel-Falle gefunden und behoben: Ein woertliches require überlebt Rollup nicht — win32 wird per dynamischem import() als eigener Chunk gebaut; der Fehler war dank R4 im Fenster sichtbar statt still. Gemessen am echten BU40N (30.08.2026, RIPPY_MESSUNG=1): Laufwerk G: status=ready typ=bluray groesse=33759690752 modell=HL-DT-ST BD-RE BU40N 1.03 serial=0025114C0149 Der Auswurf-Beweis (messung.auswurf) folgt am Ende der Sitzung — der BU40N kann die Schublade nicht selbst einziehen. 52 Tests gruen (Steuercodes, classify, Auswurf-Ablauf, Geraete-Info, Wache, Smoke weiterhin gruen mit Laufwerks-Kachel im Bild). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6ed8035dcc
commit
a45069af5e
@@ -0,0 +1,90 @@
|
||||
// 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<string, GeraeteInfo> {
|
||||
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()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user