fix: filtre historique, fuite mémoire OpenCV, export IA, tests
- Historique : le filtre par type de cible est désormais appliqué au chargement ; correction du piège PopupMenuItem(value: null) qui empêchait l'option « Tous » de réinitialiser le filtre ; icône colorée quand un filtre est actif - OpenCV : libération des Mat natifs (img, gray, blurred, circles) dans un finally — detectTarget tourne toutes les secondes pendant l'aperçu caméra et faisait grimper la mémoire native en continu - Export IA : distance, arme et id de session réels transmis depuis SessionProvider au lieu des placeholders (25 m / "Unknown") - Tests : remplacement du test widget cassé (BullyApp sans providers) par 14 tests qui passent — calcul de score concentrique (centre, hors cible, ratio d'image, anneaux personnalisés), agrégation des scores, analyse de groupement, et rendu du widget StatsCard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
60
test/services/grouping_analyzer_service_test.dart
Normal file
60
test/services/grouping_analyzer_service_test.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:bully/data/models/shot.dart';
|
||||
import 'package:bully/services/grouping_analyzer_service.dart';
|
||||
|
||||
Shot _shot(String id, double x, double y) =>
|
||||
Shot(id: id, x: x, y: y, score: 0, analysisId: '');
|
||||
|
||||
void main() {
|
||||
final service = GroupingAnalyzerService();
|
||||
|
||||
group('analyzeGrouping', () {
|
||||
test('liste vide → résultat vide', () {
|
||||
final result = service.analyzeGrouping([]);
|
||||
expect(result.shotCount, 0);
|
||||
expect(result.diameter, 0);
|
||||
});
|
||||
|
||||
test('un seul tir → diamètre nul, centre sur le tir', () {
|
||||
final result = service.analyzeGrouping([_shot('a', 0.3, 0.7)]);
|
||||
expect(result.shotCount, 1);
|
||||
expect(result.centerX, 0.3);
|
||||
expect(result.centerY, 0.7);
|
||||
expect(result.diameter, 0);
|
||||
});
|
||||
|
||||
test('deux tirs → centroïde au milieu et diamètre = écart', () {
|
||||
final result = service.analyzeGrouping([
|
||||
_shot('a', 0.4, 0.5),
|
||||
_shot('b', 0.6, 0.5),
|
||||
]);
|
||||
|
||||
expect(result.centerX, closeTo(0.5, 1e-9));
|
||||
expect(result.centerY, closeTo(0.5, 1e-9));
|
||||
expect(result.diameter, closeTo(0.2, 1e-9));
|
||||
expect(result.meanRadius, closeTo(0.1, 1e-9));
|
||||
// Deux tirs équidistants du centroïde → dispersion nulle.
|
||||
expect(result.standardDeviation, closeTo(0.0, 1e-9));
|
||||
});
|
||||
|
||||
test('le diamètre est la plus grande distance entre deux tirs', () {
|
||||
final result = service.analyzeGrouping([
|
||||
_shot('a', 0.2, 0.5),
|
||||
_shot('b', 0.5, 0.5),
|
||||
_shot('c', 0.8, 0.5),
|
||||
]);
|
||||
expect(result.diameter, closeTo(0.6, 1e-9));
|
||||
});
|
||||
});
|
||||
|
||||
group('getOffsetDescription', () {
|
||||
test('décalage négligeable → Centre', () {
|
||||
expect(service.getOffsetDescription(0.01, -0.01), 'Centre');
|
||||
});
|
||||
|
||||
test('décalage combiné → direction composée', () {
|
||||
expect(service.getOffsetDescription(0.1, -0.1), 'Haut-Droite');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user