using KronaStaffTerminal.Models; using KronaStaffTerminal.Services; using KronaStaffTerminal.Tests.Mocks; using Xunit; namespace KronaStaffTerminal.Tests; public class ScannerRecoveryTests { [Fact] public void Scanner_SimulatesUsbDisconnectAndFiresConnectionLost() { using var scanner = new MockFingerprintScanner(); scanner.Connect(0, Array.Empty<(int, string)>()); Assert.True(scanner.IsConnected); Assert.Equal(ScannerState.Connected, scanner.State); var connectionLostFired = false; ScannerState? reportedState = null; scanner.ConnectionLost += () => connectionLostFired = true; scanner.StateChanged += (state, _) => reportedState = state; // Simulate physical USB drop scanner.SimulateDisconnect(); Assert.False(scanner.IsConnected); Assert.Equal(ScannerState.Disconnected, scanner.State); Assert.True(connectionLostFired); Assert.Equal(ScannerState.Disconnected, reportedState); } [Fact] public void Scanner_SimulatesUsbReconnectAndRestoresReadyState() { using var scanner = new MockFingerprintScanner(); scanner.Connect(0, Array.Empty<(int, string)>()); scanner.SimulateDisconnect(); Assert.Equal(ScannerState.Disconnected, scanner.State); ScannerState? reportedState = null; scanner.StateChanged += (state, _) => reportedState = state; // Simulate USB re-plug scanner.SimulateReconnect(); Assert.True(scanner.IsConnected); Assert.Equal(ScannerState.Connected, scanner.State); Assert.Equal(ScannerState.Connected, reportedState); } [Fact] public void AdminPinVerification_OperatesNormallyWhenScannerIsDisconnected() { using var scanner = new MockFingerprintScanner(); scanner.SimulateDisconnect(); Assert.Equal(ScannerState.Disconnected, scanner.State); // Verify that AdminPinService functions 100% independently of hardware scanner state var (salt, hash, iterations) = AdminPinService.Hash("5555"); var settings = new TerminalSettings { AdminPinSalt = salt, AdminPinHash = hash, AdminPinIterations = iterations }; var now = DateTimeOffset.UtcNow; var allowed = AdminPinService.VerifyAndRecord( "5555", settings, now, out var error, out var rehashNeeded); Assert.True(allowed); Assert.Null(error); Assert.False(rehashNeeded); } }