MotorSignal-App/test/pr4_freshness_regression_te...

159 lines
5.0 KiB
Dart

import 'dart:async';
import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:motorcycle_dash/database/database.dart' hide TelemetrySample;
import 'package:motorcycle_dash/features/performance/performance_timer_service.dart';
import 'package:motorcycle_dash/models/telemetry_sample.dart';
void main() {
final base = DateTime.utc(2026, 9, 19);
test(
'normal READY launch retains interpolation fallback and null-speed handling',
() async {
final db = AppDatabase.forTesting(NativeDatabase.memory());
final controller = StreamController<TelemetrySample>(sync: true);
final timer = PerformanceTimerService(db, controller.stream);
addTearDown(() async {
timer.dispose();
await controller.close();
await db.close();
});
timer.setTarget(PerformanceTarget.sixty);
for (final age in <int?>[null, 0, 4001]) {
controller.add(TelemetrySample(timestamp: base, gpsAgeMs: age));
expect(timer.state.state, PerformanceState.ready);
}
// No previous speed sample: launch time falls back to this timestamp.
controller.add(TelemetrySample(timestamp: base, speed: 5, gpsAgeMs: 0));
expect(timer.state.state, PerformanceState.timing);
for (final age in <int?>[null, 0, 4001]) {
controller.add(
TelemetrySample(
timestamp: base.add(const Duration(milliseconds: 100)),
gpsAgeMs: age,
),
);
expect(timer.state.state, PerformanceState.timing);
}
controller.add(
TelemetrySample(
timestamp: base.add(const Duration(seconds: 3)),
speed: 60,
gpsAgeMs: 0,
),
);
expect(timer.state.state, PerformanceState.completed);
final runs = await db.select(db.performanceRuns).get();
expect(runs, hasLength(1));
expect(runs.single.timeMs, 3000);
},
);
test('stale READY requires new stationary evidence before launch', () async {
final db = AppDatabase.forTesting(NativeDatabase.memory());
final controller = StreamController<TelemetrySample>(sync: true);
final timer = PerformanceTimerService(db, controller.stream);
addTearDown(() async {
timer.dispose();
await controller.close();
await db.close();
});
void emit(int ms, double speed, int age) {
controller.add(
TelemetrySample(
timestamp: base.add(Duration(milliseconds: ms)),
speed: speed,
gpsAgeMs: age,
),
);
}
timer.setTarget(PerformanceTarget.sixty);
emit(0, 0, 0);
expect(timer.state.state, PerformanceState.ready);
emit(4000, 0, 4000);
expect(timer.state.state, PerformanceState.ready);
emit(4001, 0, 4001);
expect(timer.state.state, PerformanceState.idle);
emit(5000, 30, 5000);
emit(6000, 40, 0);
expect(timer.state.state, PerformanceState.idle);
emit(9000, 65, 0);
expect(timer.state.state, PerformanceState.idle);
expect(await db.select(db.performanceRuns).get(), isEmpty);
emit(10000, 0, 0);
expect(timer.state.state, PerformanceState.ready);
emit(10200, 5, 0);
expect(timer.state.state, PerformanceState.timing);
emit(13000, 65, 0);
expect(timer.state.state, PerformanceState.completed);
final runs = await db.select(db.performanceRuns).get();
expect(runs, hasLength(1));
expect(runs.single.timeMs, closeTo(2727, 1));
});
for (final coordinates in <(double?, double?)>[
(null, null),
(null, 0),
(0, null),
(double.nan, 0),
(0, double.nan),
(double.infinity, 0),
(0, double.negativeInfinity),
(90.1, 0),
(-90.1, 0),
(0, 180.1),
(0, -180.1),
]) {
for (final metadata in ['absent', 'age', 'timestamp']) {
test('invalid coordinates $coordinates with $metadata are not fresh', () {
expect(
TelemetrySample(
timestamp: base,
latitude: coordinates.$1,
longitude: coordinates.$2,
gpsAgeMs: metadata == 'age' ? 0 : null,
gpsTimestamp: metadata == 'timestamp' ? base : null,
).isGpsFresh,
isFalse,
);
});
}
}
for (final age in [3999, 4000, 4001]) {
for (final useAge in [true, false]) {
test('GPS boundary $age with explicit age $useAge', () {
expect(
TelemetrySample(
timestamp: base,
latitude: 0,
longitude: 0,
gpsAgeMs: useAge ? age : null,
gpsTimestamp: useAge
? null
: base.subtract(Duration(milliseconds: age)),
).isGpsFresh,
age <= 4000,
);
});
}
}
test('valid coordinate limits retain metadata-free compatibility', () {
for (final coordinates in [(90.0, 180.0), (-90.0, -180.0), (0.0, 0.0)]) {
expect(
TelemetrySample(
timestamp: base,
latitude: coordinates.$1,
longitude: coordinates.$2,
).isGpsFresh,
isTrue,
);
}
});
}