142 lines
4.8 KiB
Dart
142 lines
4.8 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:drift/native.dart';
|
|
import 'package:motorcycle_dash/models/telemetry_sample.dart';
|
|
import 'package:motorcycle_dash/services/validation/telemetry_validator.dart';
|
|
import 'package:motorcycle_dash/features/performance/performance_timer_service.dart';
|
|
import 'package:motorcycle_dash/database/database.dart' hide TelemetrySample;
|
|
|
|
void main() {
|
|
group('Phase 9 Forensic Validation: Performance Timer & Run Verification', () {
|
|
late AppDatabase db;
|
|
|
|
setUp(() {
|
|
db = AppDatabase.forTesting(NativeDatabase.memory());
|
|
});
|
|
|
|
tearDown(() async {
|
|
await db.close();
|
|
});
|
|
|
|
test('Performance timer ignores rejected samples during 0-60 sprint', () async {
|
|
final samples = <TelemetrySample>[];
|
|
final stream = Stream<TelemetrySample>.fromIterable(samples);
|
|
final timer = PerformanceTimerService(db, stream);
|
|
timer.setTarget(PerformanceTarget.sixty);
|
|
|
|
expect(timer.state.state, PerformanceState.ready);
|
|
});
|
|
|
|
test('Sample quality overall confidence weights GPS 40%, speed 30%, lean 20%, G-force 10%', () {
|
|
final validator = TelemetryValidator();
|
|
final sample = TelemetrySample(
|
|
timestamp: DateTime(2026, 8, 28, 12, 0, 0),
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
speed: 50.0,
|
|
gpsAccuracy: 3.0,
|
|
gpsAgeMs: 50,
|
|
leanAngle: 15.0,
|
|
longitudinalG: 0.1,
|
|
lateralG: 0.2,
|
|
);
|
|
|
|
final quality = validator.validate(sample);
|
|
expect(quality.gpsConfidence, 1.0);
|
|
expect(quality.speedConfidence, 1.0);
|
|
expect(quality.leanConfidence, 1.0);
|
|
expect(quality.gForceConfidence, 1.0);
|
|
expect(quality.overallConfidence, greaterThanOrEqualTo(0.95));
|
|
});
|
|
|
|
test('Sample quality correctly discounts degraded GPS freshness (1.5s age)', () {
|
|
final validator = TelemetryValidator();
|
|
final sample = TelemetrySample(
|
|
timestamp: DateTime(2026, 8, 28, 12, 0, 0),
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
speed: 45.0,
|
|
gpsAccuracy: 5.0,
|
|
gpsAgeMs: 1500, // 1.5s old fix
|
|
leanAngle: 0.0,
|
|
);
|
|
|
|
final quality = validator.validate(sample);
|
|
expect(quality.gpsConfidence, lessThanOrEqualTo(0.45));
|
|
expect(quality.isSuspect, isTrue);
|
|
});
|
|
|
|
test('Sample quality flags reverse timestamp delta <= 0 as suspect', () {
|
|
final validator = TelemetryValidator();
|
|
final baseTime = DateTime(2026, 8, 28, 12, 0, 0);
|
|
|
|
validator.validate(TelemetrySample(timestamp: baseTime, speed: 30.0));
|
|
final reverseSample = TelemetrySample(
|
|
timestamp: baseTime.subtract(const Duration(milliseconds: 50)),
|
|
speed: 30.0,
|
|
);
|
|
|
|
final quality = validator.validate(reverseSample);
|
|
expect(quality.isSuspect, isTrue);
|
|
expect(quality.reasons.any((r) => r.contains('Duplicate or reverse timestamp')), isTrue);
|
|
});
|
|
|
|
test('Sample quality flags large telemetry gap > 2000ms', () {
|
|
final validator = TelemetryValidator();
|
|
final baseTime = DateTime(2026, 8, 28, 12, 0, 0);
|
|
|
|
validator.validate(TelemetrySample(timestamp: baseTime, speed: 30.0));
|
|
final gapSample = TelemetrySample(
|
|
timestamp: baseTime.add(const Duration(milliseconds: 2500)),
|
|
speed: 30.0,
|
|
);
|
|
|
|
final quality = validator.validate(gapSample);
|
|
expect(quality.isSuspect, isTrue);
|
|
expect(validator.timestampGapCount, 1);
|
|
expect(quality.reasons.any((r) => r.contains('Large telemetry gap')), isTrue);
|
|
});
|
|
|
|
test('Teleportation filter handles legitimate highway distance in 1.0s without rejecting', () {
|
|
final validator = TelemetryValidator();
|
|
final baseTime = DateTime(2026, 8, 28, 12, 0, 0);
|
|
|
|
// Move 30 meters in 1.0s (67 MPH)
|
|
validator.validate(TelemetrySample(
|
|
timestamp: baseTime,
|
|
latitude: 37.774900,
|
|
longitude: -122.419400,
|
|
speed: 67.0,
|
|
gpsAccuracy: 3.0,
|
|
));
|
|
|
|
final legitimateSample = TelemetrySample(
|
|
timestamp: baseTime.add(const Duration(milliseconds: 1000)),
|
|
latitude: 37.775170, // ~30 meters north
|
|
longitude: -122.419400,
|
|
speed: 67.0,
|
|
gpsAccuracy: 3.0,
|
|
);
|
|
|
|
final quality = validator.validate(legitimateSample);
|
|
expect(quality.isValid, isTrue);
|
|
expect(quality.isRejected, isFalse);
|
|
});
|
|
|
|
test('Zero speed at standstill does not create false acceleration alerts', () {
|
|
final validator = TelemetryValidator();
|
|
final sample = TelemetrySample(
|
|
timestamp: DateTime(2026, 8, 28, 12, 0, 0),
|
|
speed: 0.0,
|
|
longitudinalG: 0.0,
|
|
lateralG: 0.0,
|
|
leanAngle: 0.0,
|
|
);
|
|
|
|
final quality = validator.validate(sample);
|
|
expect(quality.isStationary, isTrue);
|
|
expect(quality.isAccelerating, isFalse);
|
|
expect(quality.isBraking, isFalse);
|
|
});
|
|
});
|
|
}
|