import 'dart:async'; import 'package:drift/native.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:motorcycle_dash/core/theme/theme.dart'; import 'package:motorcycle_dash/database/database.dart' hide TelemetrySample; import 'package:motorcycle_dash/features/performance/models/performance_launch_models.dart'; import 'package:motorcycle_dash/features/performance/performance_launch_screen.dart'; import 'package:motorcycle_dash/features/performance/performance_providers.dart'; import 'package:motorcycle_dash/features/performance/services/monotonic_clock.dart'; import 'package:motorcycle_dash/features/performance/services/performance_launch_state_machine.dart'; import 'package:motorcycle_dash/features/records/records_service.dart'; import 'package:motorcycle_dash/models/telemetry_sample.dart'; import 'package:motorcycle_dash/services/validation/telemetry_validator.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); late AppDatabase db; late StreamController telemetryController; late FakeMonotonicClock clock; late RecordsService recordsService; late SharedPreferences prefs; late PerformanceLaunchStateMachine stateMachine; late ProviderContainer container; setUp(() async { SharedPreferences.setMockInitialValues({}); prefs = await SharedPreferences.getInstance(); recordsService = RecordsService(prefs); db = AppDatabase.forTesting(NativeDatabase.memory()); telemetryController = StreamController.broadcast(); clock = FakeMonotonicClock( initialElapsedMs: 10000, initialDateTime: DateTime.utc(2026, 9, 5, 12, 0, 0), ); stateMachine = PerformanceLaunchStateMachine( db: db, telemetryStream: telemetryController.stream, recordsService: recordsService, clock: clock, countdownDurationMs: 3000, ); container = ProviderContainer( overrides: [ databaseProvider.overrideWithValue(db), monotonicClockProvider.overrideWithValue(clock), performanceLaunchProvider.overrideWith((ref) => stateMachine), ], ); }); tearDown(() async { container.dispose(); await telemetryController.close(); await db.close(); }); TelemetrySample makeSample({ required double speed, int? monotonicMs, DateTime? timestamp, int? seq, ValidationStatus status = ValidationStatus.valid, double confidence = 1.0, }) { final ms = monotonicMs ?? clock.elapsedMilliseconds; final dt = timestamp ?? clock.now; return TelemetrySample( timestamp: dt, monotonicTimestampMs: ms, sequenceNumber: seq, speed: speed, quality: TelemetryQuality( status: status, overallConfidence: confidence, speedConfidence: confidence, gpsConfidence: confidence, ), ); } Widget createTestWidget({ ThemeData? theme, Size size = const Size(393, 852), // Pixel 8a default double textScaleFactor = 1.0, }) { return UncontrolledProviderScope( container: container, child: MediaQuery( data: MediaQueryData( size: size, textScaler: TextScaler.linear(textScaleFactor), ), child: MaterialApp( theme: theme ?? AppTheme.darkTheme, home: const PerformanceLaunchScreen(), ), ), ); } group('PLM-2: Setup Experience Tests', () { testWidgets('1. Auto/Countdown selector renders and 2. 60/100 selector renders', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('launch_mode_auto')), findsOneWidget); expect(find.byKey(const ValueKey('launch_mode_countdown')), findsOneWidget); expect(find.byKey(const ValueKey('launch_target_60')), findsOneWidget); expect(find.byKey(const ValueKey('launch_target_100')), findsOneWidget); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(find.text('Auto Launch'), findsOneWidget); expect(find.text('Countdown'), findsOneWidget); expect(find.text('0–60 MPH'), findsOneWidget); expect(find.text('0–100 MPH'), findsOneWidget); }); testWidgets('BUG-009: Renders cleanly without clipping on 800x360 landscape phone', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(800, 360))); await tester.pumpAndSettle(); expect(tester.takeException(), isNull); expect(find.byKey(const ValueKey('launch_mode_auto')), findsOneWidget); expect(find.byKey(const ValueKey('launch_mode_countdown')), findsOneWidget); expect(find.byKey(const ValueKey('launch_target_60')), findsOneWidget); expect(find.byKey(const ValueKey('launch_target_100')), findsOneWidget); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(find.text('Auto Launch'), findsOneWidget); expect(find.text('Countdown'), findsOneWidget); expect(find.text('0–60 MPH'), findsOneWidget); expect(find.text('0–100 MPH'), findsOneWidget); }); testWidgets('3. ARM command uses selected configuration and 4. no local fake READY state', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); // Tap Countdown mode and 0-100 target await tester.tap(find.byKey(const ValueKey('launch_mode_countdown'))); await tester.pumpAndSettle(); await tester.tap(find.byKey(const ValueKey('launch_target_100'))); await tester.pumpAndSettle(); // Tap ARM await tester.tap(find.byKey(const ValueKey('btn_arm_launch'))); await tester.pumpAndSettle(); // Since vehicle has no telemetry yet, state should NOT be READY expect(stateMachine.state.mode, PerformanceLaunchMode.countdown); expect(stateMachine.state.target, PerformanceLaunchTarget.hundred); expect(stateMachine.state.state, PerformanceLaunchState.idle); // Verify truthful waiting state renders (no fake ready) expect(find.byKey(const ValueKey('ready_status_badge')), findsNothing); expect(find.byKey(const ValueKey('waiting_status_text')), findsOneWidget); }); }); group('PLM-2: READY Experience Tests', () { testWidgets('5. waiting state renders truthfully with moving speed & transitions to READY when stopped', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); // Emit sample moving at 15 MPH telemetryController.add(makeSample(speed: 15.0)); await tester.pump(const Duration(milliseconds: 20)); // Arm while moving await tester.tap(find.byKey(const ValueKey('btn_arm_launch'))); await tester.pumpAndSettle(); // Should display COME TO A COMPLETE STOP expect(find.text('COME TO A COMPLETE STOP'), findsOneWidget); // Now bring motorcycle to a stop (< 1.0 MPH) with valid telemetry telemetryController.add(makeSample(speed: 0.0, confidence: 1.0)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Transitions to READY! expect(find.byKey(const ValueKey('ready_status_badge')), findsOneWidget); expect(find.text('READY'), findsOneWidget); }); testWidgets('6. Auto READY says accelerate when ready and no countdown button', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, confidence: 1.0)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('ready_status_badge')), findsOneWidget); expect(find.text('Accelerate when ready'), findsOneWidget); expect(find.byKey(const ValueKey('btn_start_countdown')), findsNothing); }); testWidgets('7. Countdown READY exposes legitimate countdown start button', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, confidence: 1.0)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('ready_status_badge')), findsOneWidget); expect(find.byKey(const ValueKey('btn_start_countdown')), findsOneWidget); expect(find.text('Tap below to initiate countdown'), findsOneWidget); }); testWidgets('BUG-010: Countdown READY renders without 68px overflow on 800x360 landscape phone', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(800, 360))); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, confidence: 1.0)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(tester.takeException(), isNull); expect(find.byKey(const ValueKey('ready_status_badge')), findsOneWidget); expect(find.byKey(const ValueKey('btn_start_countdown')), findsOneWidget); expect(find.text('Start Countdown'), findsOneWidget); }); testWidgets('8. READY survives widget rebuild', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, confidence: 1.0)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('ready_status_badge')), findsOneWidget); // Trigger rebuild await tester.pumpWidget(createTestWidget(size: const Size(800, 360))); // landscape resize await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('ready_status_badge')), findsOneWidget); expect(stateMachine.state.state, PerformanceLaunchState.ready); }); }); group('PLM-2: Countdown Tests', () { testWidgets('9. 3/2/1/GO derives from authoritative monotonic state & 10. widget animation is not timing authority', (tester) async { clock.setElapsedMs(1000); await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Start countdown: scheduledGo = 1000 + 3000 = 4000 await tester.tap(find.byKey(const ValueKey('btn_start_countdown'))); await tester.pump(const Duration(milliseconds: 20)); // At t=1000ms: diff is 3000ms -> shows '3' expect(find.text('3'), findsOneWidget); // Advance monotonic clock to t=2500ms: diff is 1500ms -> shows '2' clock.setElapsedMs(2500); await tester.pump(const Duration(milliseconds: 40)); expect(find.text('2'), findsOneWidget); // Advance monotonic clock to t=3500ms: diff is 500ms -> shows '1' clock.setElapsedMs(3500); await tester.pump(const Duration(milliseconds: 40)); expect(find.text('1'), findsOneWidget); // Advance monotonic clock to t=4100ms (past scheduled GO): shows 'GO!' clock.setElapsedMs(4100); await tester.pump(const Duration(milliseconds: 40)); expect(find.text('GO!'), findsOneWidget); }); testWidgets('11. rebuild does not restart countdown and 12. orientation/viewport resize preserves schedule', (tester) async { clock.setElapsedMs(1000); await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); await tester.tap(find.byKey(const ValueKey('btn_start_countdown'))); await tester.pump(const Duration(milliseconds: 20)); final scheduledGo = stateMachine.state.scheduledGoAtMonotonicMs; expect(scheduledGo, 4000); // Advance time to t=2500 (showing 2) clock.setElapsedMs(2500); await tester.pump(const Duration(milliseconds: 40)); expect(find.text('2'), findsOneWidget); // Rotate / resize to landscape await tester.pumpWidget(createTestWidget(size: const Size(800, 360))); await tester.pump(const Duration(milliseconds: 40)); // Still at t=2500, still shows 2, scheduledGo unchanged! expect(find.text('2'), findsOneWidget); expect(stateMachine.state.scheduledGoAtMonotonicMs, scheduledGo); }); }); group('PLM-2: Launched Timing Experience Tests', () { testWidgets('13. active timing view requires no interaction, 14. speed renders, 15. timer renders', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Launch! telemetryController.add(makeSample(speed: 12.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Launched state verified expect(stateMachine.state.state, PerformanceLaunchState.launched); expect(find.byKey(const ValueKey('speed_readout')), findsOneWidget); expect(find.byKey(const ValueKey('elapsed_timer_readout')), findsOneWidget); // Update speed and time at 20 Hz telemetryController.add(makeSample(speed: 45.0, monotonicMs: 2500)); await tester.pump(const Duration(milliseconds: 20)); expect(find.text('45'), findsOneWidget); expect(find.text('1.45 s'), findsOneWidget); }); testWidgets('16. 100 target displays authoritative 60 split when available', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.hundred); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Launch telemetryController.add(makeSample(speed: 10.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); // Cross 60 MPH at t=3550ms telemetryController.add(makeSample(speed: 62.0, monotonicMs: 3550)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('split_60_readout')), findsOneWidget); expect(find.text('60 MPH SPLIT: 2.50 s'), findsOneWidget); }); testWidgets('17. 60 target does not invent intermediate split', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); telemetryController.add(makeSample(speed: 40.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); expect(find.byKey(const ValueKey('split_60_readout')), findsNothing); }); }); group('PLM-2: Result Presentation Tests', () { testWidgets('18. Auto result omits Launch Reaction', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 5.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 61.0, monotonicMs: 4250)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(stateMachine.state.state, PerformanceLaunchState.completed); expect(find.text('ACCELERATION'), findsOneWidget); expect(find.text('3.20 s'), findsOneWidget); // Launch reaction is NOT shown for Auto expect(find.byKey(const ValueKey('launch_reaction_readout')), findsNothing); expect(find.text('Launch Reaction'), findsNothing); }); testWidgets('19. Countdown result displays Launch Reaction and 20. Total From GO', (tester) async { clock.setElapsedMs(1000); await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Start countdown (scheduledGo = 4000) await tester.tap(find.byKey(const ValueKey('btn_start_countdown'))); await tester.pump(const Duration(milliseconds: 20)); // Rider moves at t=4250ms (+250ms reaction) telemetryController.add(makeSample(speed: 5.0, monotonicMs: 4250)); await tester.pump(const Duration(milliseconds: 20)); // Cross 60 at t=7450ms (3.20s acceleration, 3.45s from GO) telemetryController.add(makeSample(speed: 61.0, monotonicMs: 7450)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(stateMachine.state.state, PerformanceLaunchState.completed); expect(find.byKey(const ValueKey('launch_reaction_readout')), findsOneWidget); expect(find.text('+0.25 s'), findsOneWidget); expect(find.byKey(const ValueKey('total_from_go_readout')), findsOneWidget); expect(find.text('3.45 s'), findsOneWidget); expect(find.text('Total From GO'), findsOneWidget); }); testWidgets('21. false start displays negative Launch Reaction, 22. labeled, 23. not PR', (tester) async { clock.setElapsedMs(1000); await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Start countdown (scheduledGo = 4000) await tester.tap(find.byKey(const ValueKey('btn_start_countdown'))); await tester.pump(const Duration(milliseconds: 20)); // Rider jumps before GO at t=3750ms (-250ms false start) telemetryController.add(makeSample(speed: 5.0, monotonicMs: 3750)); await tester.pump(const Duration(milliseconds: 20)); // Timing continues actively despite false start expect(stateMachine.state.state, PerformanceLaunchState.launched); expect(stateMachine.state.isFalseStart, isTrue); expect(find.byKey(const ValueKey('speed_readout')), findsOneWidget); expect(find.byKey(const ValueKey('elapsed_timer_readout')), findsOneWidget); // Interim sample while timing telemetryController.add(makeSample(speed: 35.0, monotonicMs: 5000)); await tester.pump(const Duration(milliseconds: 20)); expect(stateMachine.state.state, PerformanceLaunchState.launched); // Reaches 60 at t=6950ms telemetryController.add(makeSample(speed: 62.0, monotonicMs: 6950)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(stateMachine.state.state, PerformanceLaunchState.completed); expect(stateMachine.state.lastResult!.isFalseStart, isTrue); expect(stateMachine.state.lastResult!.accelerationTimeSec, closeTo(3.20, 0.05)); // Verify false start badge and negative reaction expect(find.text('FALSE START'), findsOneWidget); expect(find.text('Movement detected before GO.'), findsOneWidget); expect(find.byKey(const ValueKey('launch_reaction_readout')), findsOneWidget); expect(find.text('-0.25 s'), findsOneWidget); // Verify records service was not updated expect(recordsService.state.fastest0To60, double.infinity); }); testWidgets('24. Try Again invokes authoritative reset', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 5.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 62.0, monotonicMs: 4000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_try_again')), findsOneWidget); // Tap Try Again await tester.tap(find.byKey(const ValueKey('btn_try_again'))); await tester.pumpAndSettle(); // State machine reset back to idle/setup expect(stateMachine.state.state, PerformanceLaunchState.idle); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); }); }); group('PLM-2: Telemetry Unavailable Tests', () { testWidgets('26. unavailable telemetry does not display fake READY & 27. rejected telemetry represented truthfully', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); // Arm auto launch await tester.tap(find.byKey(const ValueKey('btn_arm_launch'))); await tester.pumpAndSettle(); // Emit low confidence sample telemetryController.add(makeSample(speed: 0.0, confidence: 0.2)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); // Does NOT show READY expect(find.byKey(const ValueKey('ready_status_badge')), findsNothing); expect(find.text('WAITING FOR VALID TELEMETRY'), findsOneWidget); }); }); group('PLM-2: Responsive & Theme Tests', () { testWidgets('28. no RenderFlex overflow at 320dp width', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(320, 600))); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('29. Pixel-like portrait layout renders clean', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(412, 915))); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('30. short landscape phone layout renders clean', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(800, 360))); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('31. standard landscape layout renders clean', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(915, 412))); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('32. expanded tablet layout renders clean', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(1200, 800))); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('34. text scaling smoke test (1.5x scale)', (tester) async { await tester.pumpWidget(createTestWidget(textScaleFactor: 1.5)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('35. System/Light/Dark theme smoke test', (tester) async { await tester.pumpWidget(createTestWidget(theme: AppTheme.lightTheme)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); await tester.pumpWidget(createTestWidget(theme: AppTheme.darkTheme)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); }); group('PLM-2: Lifecycle & Orientation State Preservation Tests', () { testWidgets('36. resize does not recreate authoritative attempt & 37. rebuild does not duplicate persistence', (tester) async { await tester.pumpWidget(createTestWidget(size: const Size(412, 915))); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 5.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 61.0, monotonicMs: 4000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(stateMachine.state.state, PerformanceLaunchState.completed); // Resize/rebuild multiple times await tester.pumpWidget(createTestWidget(size: const Size(800, 360))); await tester.pumpAndSettle(); await tester.pumpWidget(createTestWidget(size: const Size(320, 600))); await tester.pumpAndSettle(); // Only ONE row in performanceRuns table await tester.runAsync(() async { final runs = await db.select(db.performanceRuns).get(); expect(runs, hasLength(1)); }); }); testWidgets('25. Done resets state machine safely', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 5.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 61.0, monotonicMs: 4000)); await tester.pump(const Duration(milliseconds: 20)); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_done')), findsOneWidget); await tester.tap(find.byKey(const ValueKey('btn_done'))); await tester.pumpAndSettle(); expect(stateMachine.state.state, PerformanceLaunchState.idle); }); testWidgets('33. IME insets do not break setup screen', (tester) async { await tester.pumpWidget( UncontrolledProviderScope( container: container, child: MediaQuery( data: const MediaQueryData( size: Size(393, 852), viewInsets: EdgeInsets.only(bottom: 350), // IME open ), child: MaterialApp( theme: AppTheme.darkTheme, home: const PerformanceLaunchScreen(), ), ), ), ); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('btn_arm_launch')), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('38. concurrent arm calls during active launch do not corrupt attempt', (tester) async { await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); stateMachine.arm(mode: PerformanceLaunchMode.auto, target: PerformanceLaunchTarget.sixty); telemetryController.add(makeSample(speed: 0.0, monotonicMs: 1000)); await tester.pump(const Duration(milliseconds: 20)); telemetryController.add(makeSample(speed: 10.0, monotonicMs: 1050)); await tester.pump(const Duration(milliseconds: 20)); expect(stateMachine.state.state, PerformanceLaunchState.launched); final initialArmedMs = stateMachine.state.armedAtMonotonicMs; // Attempt concurrent re-arm during launched state stateMachine.arm(mode: PerformanceLaunchMode.countdown, target: PerformanceLaunchTarget.hundred); expect(stateMachine.state.state, PerformanceLaunchState.launched); expect(stateMachine.state.mode, PerformanceLaunchMode.auto); expect(stateMachine.state.target, PerformanceLaunchTarget.sixty); expect(stateMachine.state.armedAtMonotonicMs, initialArmedMs); }); }); }