import 'package:flutter_test/flutter_test.dart'; import 'package:emergency/services/country_code_sources/country_code_source.dart'; import 'package:emergency/services/location_service.dart'; /// Einfache manuelle Fake-Quelle statt Mocking-Package (siehe AP4-Vorgabe: /// kein neues Mocking-Package einführen). class _FakeSource implements CountryCodeSource { _FakeSource(this._result); final String? _result; int callCount = 0; @override Future resolve() async { callCount++; return _result; } } class _FakeCache implements CountryCodeCache { _FakeCache({String? initial}) : _stored = initial; String? _stored; int resolveCallCount = 0; final List savedCodes = []; @override Future resolve() async { resolveCallCount++; return _stored; } @override Future save(String isoCode) async { savedCodes.add(isoCode); _stored = isoCode; } } /// Fake für die manuelle Auswahl (AP6). Ohne explizite Injektion würde /// `LocationService()` intern ein echtes `ManualCountryCodeSource` (und damit /// `shared_preferences`) ansprechen, was in diesen reinen Unit-Tests (kein /// `TestWidgetsFlutterBinding.ensureInitialized()`/Mock-Setup) nicht /// notwendig sein soll – die bestehenden SIM/GPS/Cache-Tests sollen von der /// manuellen Auswahl unbeeinflusst bleiben. class _FakeManualSource implements ManualCountryCodeStore { _FakeManualSource([this._result]); final String? _result; int resolveCallCount = 0; final List savedCodes = []; @override Future resolve() async { resolveCallCount++; return _result; } @override Future save(String? isoCode) async { savedCodes.add(isoCode); } } void main() { group('LocationService.resolveCountryCode()', () { test( 'SIM liefert Ergebnis -> wird verwendet, GPS/Cache werden nicht abgefragt, ' 'Ergebnis wird gecacht', () async { final sim = _FakeSource('DE'); final gps = _FakeSource('FR'); final cache = _FakeCache(initial: 'US'); final service = LocationService( simSource: sim, gpsSource: gps, cacheSource: cache, manualSource: _FakeManualSource(), ); final result = await service.resolveCountryCode(); expect(result, 'DE'); expect(sim.callCount, 1); expect(gps.callCount, 0); expect(cache.resolveCallCount, 0); expect(cache.savedCodes, ['DE']); }, ); test( 'SIM liefert null, GPS liefert Ergebnis -> wird verwendet, Cache wird nicht ' 'gelesen, aber beschrieben', () async { final sim = _FakeSource(null); final gps = _FakeSource('FR'); final cache = _FakeCache(initial: 'US'); final service = LocationService( simSource: sim, gpsSource: gps, cacheSource: cache, manualSource: _FakeManualSource(), ); final result = await service.resolveCountryCode(); expect(result, 'FR'); expect(sim.callCount, 1); expect(gps.callCount, 1); expect(cache.resolveCallCount, 0); expect(cache.savedCodes, ['FR']); }, ); test('SIM und GPS liefern null, Cache liefert Ergebnis -> wird verwendet', () async { final sim = _FakeSource(null); final gps = _FakeSource(null); final cache = _FakeCache(initial: 'US'); final service = LocationService( simSource: sim, gpsSource: gps, cacheSource: cache, manualSource: _FakeManualSource(), ); final result = await service.resolveCountryCode(); expect(result, 'US'); expect(cache.resolveCallCount, 1); // Kein erneutes Schreiben, da das Ergebnis ja bereits aus dem Cache kam. expect(cache.savedCodes, isEmpty); }); test('Alle drei automatischen Quellen liefern null -> Ergebnis ist null', () async { final sim = _FakeSource(null); final gps = _FakeSource(null); final cache = _FakeCache(); final service = LocationService( simSource: sim, gpsSource: gps, cacheSource: cache, manualSource: _FakeManualSource(), ); final result = await service.resolveCountryCode(); expect(result, isNull); expect(cache.savedCodes, isEmpty); }); test( 'manuelle Auswahl gesetzt -> hat Vorrang vor SIM/GPS/Cache, die anderen ' 'Quellen werden gar nicht erst abgefragt', () async { final sim = _FakeSource('DE'); final gps = _FakeSource('FR'); final cache = _FakeCache(initial: 'US'); final manual = _FakeManualSource('IT'); final service = LocationService( simSource: sim, gpsSource: gps, cacheSource: cache, manualSource: manual, ); final result = await service.resolveCountryCode(); expect(result, 'IT'); expect(sim.callCount, 0); expect(gps.callCount, 0); expect(cache.resolveCallCount, 0); // Die manuelle Auswahl wird bewusst nicht in den automatischen Cache // geschrieben (getrennte Mechanismen, siehe Doc-Kommentar). expect(cache.savedCodes, isEmpty); }, ); test('keine manuelle Auswahl gesetzt -> Kette fällt normal auf SIM zurück', () async { final sim = _FakeSource('DE'); final gps = _FakeSource('FR'); final cache = _FakeCache(initial: 'US'); final manual = _FakeManualSource(null); final service = LocationService( simSource: sim, gpsSource: gps, cacheSource: cache, manualSource: manual, ); final result = await service.resolveCountryCode(); expect(result, 'DE'); expect(manual.resolveCallCount, 1); }); }); group('LocationService.setManualCountryCode()', () { test('delegiert an die manuelle Quelle', () async { final manual = _FakeManualSource(); final service = LocationService( simSource: _FakeSource(null), gpsSource: _FakeSource(null), cacheSource: _FakeCache(), manualSource: manual, ); await service.setManualCountryCode('IT'); await service.setManualCountryCode(null); expect(manual.savedCodes, ['IT', null]); }); }); }