MotorSignal-App/test/forensic_advanced_telemetry...

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);
});
});
}