// // ARFlowStateMachineTests.swift // GasTankARTests // // Created by Dennis Nemec on 26.08.26. // import Testing @testable import GasTankAR struct ARFlowStateMachineTests { // MARK: - Start & Initialisierung @Test func startsInWorldNotInitializedAndRunsConfiguration() { var machine = ARFlowStateMachine(hasStoredTransform: false) let commands = machine.reduce(.started) #expect(machine.state == .worldNotInitialized) #expect(commands.contains(.runConfiguration(useImages: false, useInitialMap: true, resetTracking: false))) } @Test func initializingTracking() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingInitializing) #expect(machine.state == .initializingWorld) } // MARK: - Scene erfolgreich initialisiert → Location wählen / wiederherstellen @Test func normalTrackingWithoutStoredTransformGoesToSelectLocation() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) #expect(machine.state == .selectLocation) #expect(machine.hasPlacedTank == false) } @Test func normalTrackingWithStoredTransformRestoresTank() { var machine = ARFlowStateMachine(hasStoredTransform: true) _ = machine.reduce(.started) let commands = machine.reduce(.trackingNormal) #expect(machine.state == .immersive) #expect(machine.hasPlacedTank == true) #expect(commands.contains(.placeTank(.storedTransform))) } // MARK: - Platzieren @Test func captureFromSelectLocationPlacesTankAndPersists() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) // → selectLocation let commands = machine.reduce(.captureConfirmed) #expect(machine.state == .immersive) #expect(machine.hasPlacedTank == true) #expect(commands.contains(.placeTank(.screenCenter))) #expect(commands.contains(.persistWorldMap)) #expect(commands.contains(.persistTankTransform)) } @Test func captureIsIgnoredOutsideSelectLocation() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) // worldNotInitialized let commands = machine.reduce(.captureConfirmed) #expect(commands.isEmpty) #expect(machine.state == .worldNotInitialized) } // MARK: - Eskalation bei zu wenigen Merkmalen @Test func insufficientFeaturesEscalatesToShowOptions() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) let first = machine.reduce(.trackingInsufficientFeatures) #expect(machine.state == .initializingNotPossible) #expect(first.contains(.startMoveAroundTimer)) _ = machine.reduce(.moveAroundTimerFired) #expect(machine.state == .userMovesAround) _ = machine.reduce(.showOptionsTimerFired) #expect(machine.state == .showOptions) } @Test func timersDoNothingInWrongState() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) // Kein initializingNotPossible aktiv → moveAroundTimer ignoriert. let commands = machine.reduce(.moveAroundTimerFired) #expect(commands.isEmpty) #expect(machine.state == .worldNotInitialized) } // MARK: - Anker-Erkennung (Marker) @Test func placeAnchorMarkerStartsImageDetection() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) // selectLocation let commands = machine.reduce(.placeAnchorMarkerTapped) #expect(machine.state == .anchorDetection) #expect(commands.contains(.runConfiguration(useImages: true, useInitialMap: false, resetTracking: false))) #expect(commands.contains(.startAnchorDetectionTimer)) } @Test func anchorDetectionTimeoutAsksToCancel() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) _ = machine.reduce(.placeAnchorMarkerTapped) _ = machine.reduce(.anchorDetectionTimerFired) #expect(machine.state == .askToCancel) } @Test func imageAnchorDetectedPlacesTank() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) _ = machine.reduce(.placeAnchorMarkerTapped) let commands = machine.reduce(.imageAnchorDetected) #expect(machine.state == .immersive) #expect(machine.hasPlacedTank == true) #expect(commands.contains(.placeTank(.imageAnchor))) } @Test func imageAnchorIgnoredWhenNotDetecting() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) // selectLocation let commands = machine.reduce(.imageAnchorDetected) #expect(commands.isEmpty) #expect(machine.state == .selectLocation) } // MARK: - Relokalisierung @Test func relocalizingStartsTimerAndTimeoutFails() { var machine = ARFlowStateMachine(hasStoredTransform: true) _ = machine.reduce(.started) let relocating = machine.reduce(.trackingRelocalizing) #expect(machine.state == .relocating) #expect(relocating.contains(.startRelocationTimer)) _ = machine.reduce(.relocationTimerFired) #expect(machine.state == .relocationFailed) } @Test func normalTrackingWhilePlacedGoesImmersive() { var machine = ARFlowStateMachine(hasStoredTransform: false) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) _ = machine.reduce(.captureConfirmed) // placed → immersive _ = machine.reduce(.trackingRelocalizing) #expect(machine.state == .relocating) _ = machine.reduce(.trackingNormal) #expect(machine.state == .immersive) } // MARK: - Neu platzieren / Neustart @Test func repositionClearsTankAndReturnsToSelectLocation() { var machine = ARFlowStateMachine(hasStoredTransform: true) _ = machine.reduce(.started) _ = machine.reduce(.trackingNormal) // restored → immersive let commands = machine.reduce(.repositionTapped) #expect(machine.state == .selectLocation) #expect(machine.hasPlacedTank == false) #expect(machine.hasStoredTransform == false) #expect(commands.contains(.removeTank)) #expect(commands.contains(.clearStoredTransform)) } @Test func restartResetsTracking() { var machine = ARFlowStateMachine(hasStoredTransform: true) _ = machine.reduce(.started) _ = machine.reduce(.trackingRelocalizing) _ = machine.reduce(.relocationTimerFired) // relocationFailed let commands = machine.reduce(.restartTapped) #expect(machine.state == .worldNotInitialized) #expect(machine.hasStoredTransform == false) #expect(commands.contains(.runConfiguration(useImages: false, useInitialMap: false, resetTracking: true))) } }