From 318891cd6446dab4d21cab0f07f281cbe840c0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Mon, 22 Dec 2025 17:15:36 +0000 Subject: [PATCH 1/9] first steps of provider test --- .../riverpod/faculty_locations_provider.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart b/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart index 92e791f94..711cf8de4 100644 --- a/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart +++ b/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:uni/controller/fetchers/location_fetcher/location_fetcher.dart'; import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset.dart'; import 'package:uni/model/entities/location_group.dart'; import 'package:uni/model/providers/riverpod/cached_async_notifier.dart'; @@ -10,17 +11,24 @@ final locationsProvider = class FacultyLocationsNotifier extends CachedAsyncNotifier> { + + final LocationFetcher? _fetcher; + + FacultyLocationsNotifier({LocationFetcher? fetcher}) : _fetcher = fetcher; // contructor + + LocationFetcher get fetcher => _fetcher ?? LocationFetcherAsset(); // getter, if _fetcher is null(not a mock) it will use the fetcher as before + @override Duration? get cacheDuration => const Duration(days: 30); @override Future> loadFromStorage() { - return LocationFetcherAsset().getLocations(); + return fetcher.getLocations(); } @override Future> loadFromRemote() { //since locations are stored in assets, we don't need internet for this. - return LocationFetcherAsset().getLocations(); + return fetcher.getLocations(); } } From 961b76b02b006938dc793bea2657ec89aff8dfdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Mon, 22 Dec 2025 20:23:55 +0000 Subject: [PATCH 2/9] feat: add unit test for faculty locations provider using manual fake --- .../faculty_locations_provider_test.dart | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart new file mode 100644 index 000000000..b8b26efdc --- /dev/null +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -0,0 +1,81 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset.dart'; +import 'package:uni/controller/local_storage/preferences_controller.dart'; +import 'package:uni/model/entities/location_group.dart'; +import 'package:uni/model/providers/riverpod/faculty_locations_provider.dart'; + +class FakeLocationFetcher extends LocationFetcherAsset { + List mockedReturn = []; + + @override + Future> getLocations() async { + return mockedReturn; + } +} + +void main() { + late FakeLocationFetcher fakeFetcher; + late ProviderContainer container; + + setUp(() async { + SharedPreferences.setMockInitialValues({}); + PreferencesController.prefs = await SharedPreferences.getInstance(); + + fakeFetcher = FakeLocationFetcher(); + + container = ProviderContainer( + overrides: [ + locationsProvider.overrideWith( + () => FacultyLocationsNotifier(fetcher: fakeFetcher), + ), + ], + ); + addTearDown(() => container.dispose()); + }); + + test('Must load locations with success using a Fake class', () async { + // O teu JSON estava certinho de acordo com o teu getFromJSON! + const String rawJson = ''' + { + "data": [ + { + "id": 0, + "lat": 41.17, + "lng": -8.59, + "isFloorless": false, + "locations": { + "0": [ + { + "id": 0, + "name": "Sala B004", + "type": "ROOMS", + "args": {"firstRoom":"B004","lastRoom":"B007"} + } + ] + } + } + ] + } + '''; + + final groups = await fakeFetcher.getFromJSON(rawJson); + + fakeFetcher.mockedReturn = groups; + + container.read(locationsProvider); + + await Future.delayed(Duration.zero); + + final finalState = container.read(locationsProvider); + + final data = finalState.value; + + expect(data, isNotNull); + expect(data, isNotEmpty); + expect(data!.length, 1); + expect(data.first.id, 0); + }); +} \ No newline at end of file From ac0eb29ca7f76892388ea4eefaca821e60a811d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Tue, 23 Dec 2025 16:19:34 +0000 Subject: [PATCH 3/9] test: implement unit tests for FacultyLocationsProvider --- .../faculty_locations_provider_test.dart | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart index b8b26efdc..1d707d1e9 100644 --- a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -37,8 +37,7 @@ void main() { }); test('Must load locations with success using a Fake class', () async { - // O teu JSON estava certinho de acordo com o teu getFromJSON! - const String rawJson = ''' + const rawJson = ''' { "data": [ { @@ -67,7 +66,7 @@ void main() { container.read(locationsProvider); - await Future.delayed(Duration.zero); + await Future.delayed(Duration.zero); final finalState = container.read(locationsProvider); @@ -78,4 +77,38 @@ void main() { expect(data!.length, 1); expect(data.first.id, 0); }); -} \ No newline at end of file + + test('Must not crash when given an empty list', () async { + fakeFetcher.mockedReturn = []; + + container.read(locationsProvider); + + await Future.delayed(Duration.zero); + + final state = container.read(locationsProvider); + + final data = state.value; + + expect(data, isEmpty); + expect(data, isNotNull); + }); + + test('Should throw an exception when JSON is not on the right format', () { + const String brokenJSON = '{"error": "wrong format"}'; // its missing the data key + + expect( + () async => await fakeFetcher.getFromJSON(brokenJSON), + throwsA(isA()) + ); + + }); + + test('Should emit AsyncLoading state when initialization starts', () { + final state = container.read(locationsProvider); + + expect(state.isLoading, isTrue); + expect(state.hasValue, isFalse); + expect(state, isA()); + }); + +} From 1240dcc876ead6ac50fdfd1b324713fb17c0342d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Tue, 23 Dec 2025 16:50:34 +0000 Subject: [PATCH 4/9] resolve lint warnings --- .../unit/providers/faculty_locations_provider_test.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart index 1d707d1e9..104cae13c 100644 --- a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -1,6 +1,5 @@ -import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:latlong2/latlong.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; @@ -94,10 +93,10 @@ void main() { }); test('Should throw an exception when JSON is not on the right format', () { - const String brokenJSON = '{"error": "wrong format"}'; // its missing the data key + const brokenJSON = '{"error": "wrong format"}'; // its missing the data key expect( - () async => await fakeFetcher.getFromJSON(brokenJSON), + () => fakeFetcher.getFromJSON(brokenJSON), throwsA(isA()) ); @@ -108,7 +107,7 @@ void main() { expect(state.isLoading, isTrue); expect(state.hasValue, isFalse); - expect(state, isA()); + expect(state, isA?>>()); }); } From 28f6f3e6305d00d5d627f7c1dc5ef44b64aafbff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Tue, 23 Dec 2025 16:54:46 +0000 Subject: [PATCH 5/9] apply dart format --- .../providers/faculty_locations_provider_test.dart | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart index 104cae13c..157b97d49 100644 --- a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -60,7 +60,7 @@ void main() { '''; final groups = await fakeFetcher.getFromJSON(rawJson); - + fakeFetcher.mockedReturn = groups; container.read(locationsProvider); @@ -69,9 +69,9 @@ void main() { final finalState = container.read(locationsProvider); - final data = finalState.value; + final data = finalState.value; - expect(data, isNotNull); + expect(data, isNotNull); expect(data, isNotEmpty); expect(data!.length, 1); expect(data.first.id, 0); @@ -81,7 +81,7 @@ void main() { fakeFetcher.mockedReturn = []; container.read(locationsProvider); - + await Future.delayed(Duration.zero); final state = container.read(locationsProvider); @@ -96,10 +96,9 @@ void main() { const brokenJSON = '{"error": "wrong format"}'; // its missing the data key expect( - () => fakeFetcher.getFromJSON(brokenJSON), - throwsA(isA()) + () => fakeFetcher.getFromJSON(brokenJSON), + throwsA(isA()), ); - }); test('Should emit AsyncLoading state when initialization starts', () { @@ -109,5 +108,4 @@ void main() { expect(state.hasValue, isFalse); expect(state, isA?>>()); }); - } From 85764ec161208c1ec84a82e35c314c48e82729e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Tue, 23 Dec 2025 16:59:57 +0000 Subject: [PATCH 6/9] apply official dart format to provider --- .../providers/riverpod/faculty_locations_provider.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart b/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart index 711cf8de4..3d9fa6e89 100644 --- a/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart +++ b/packages/uni_app/lib/model/providers/riverpod/faculty_locations_provider.dart @@ -11,12 +11,14 @@ final locationsProvider = class FacultyLocationsNotifier extends CachedAsyncNotifier> { + FacultyLocationsNotifier({LocationFetcher? fetcher}) + : _fetcher = fetcher; // constructor final LocationFetcher? _fetcher; - FacultyLocationsNotifier({LocationFetcher? fetcher}) : _fetcher = fetcher; // contructor - - LocationFetcher get fetcher => _fetcher ?? LocationFetcherAsset(); // getter, if _fetcher is null(not a mock) it will use the fetcher as before + LocationFetcher get fetcher => + _fetcher ?? + LocationFetcherAsset(); // getter, if _fetcher is null(not a mock) it will use the fetcher as before @override Duration? get cacheDuration => const Duration(days: 30); From 4b81d0f750cc6de8c2f4c286f3b2b97ce3b02e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Sun, 28 Dec 2025 00:43:26 +0000 Subject: [PATCH 7/9] changes in the unit tests and added validation for json values --- .../lib/model/entities/location_group.dart | 20 ++- .../faculty_locations_provider_test.dart | 123 +++++++++++++----- 2 files changed, 107 insertions(+), 36 deletions(-) diff --git a/packages/uni_app/lib/model/entities/location_group.dart b/packages/uni_app/lib/model/entities/location_group.dart index db3e2672c..53b36383a 100644 --- a/packages/uni_app/lib/model/entities/location_group.dart +++ b/packages/uni_app/lib/model/entities/location_group.dart @@ -17,7 +17,20 @@ class LocationGroup { }) : floors = locations != null ? groupBy(locations, (location) => location.floor) - : Map.identity(); + : Map.identity() { + + if (latlng.latitude < -90 || latlng.latitude > 90) { + throw ArgumentError('Invalid latitude: ${latlng.latitude}'); + } + + if (latlng.longitude < -180 || latlng.longitude > 180) { + throw ArgumentError('Invalid longitude: ${latlng.longitude}'); + } + + if (id != null && id! < 0) { + throw ArgumentError('ID must not be negative'); + } + } factory LocationGroup.fromJson(Map json) => _$LocationGroupFromJson(json); @@ -29,6 +42,11 @@ class LocationGroup { /// Returns the Location with the most weight Location? getLocationWithMostWeight() { final allLocations = floors.values.expand((x) => x).toList(); + + if (allLocations.isEmpty){ + return null; + } + return allLocations.reduce( (current, next) => current.weight > next.weight ? current : next, ); diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart index 157b97d49..2fcbf0470 100644 --- a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -1,16 +1,22 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:latlong2/latlong.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/model/entities/location_group.dart'; +import 'package:uni/model/entities/locations/room_group_location.dart'; import 'package:uni/model/providers/riverpod/faculty_locations_provider.dart'; class FakeLocationFetcher extends LocationFetcherAsset { List mockedReturn = []; + Exception? mockedError; @override Future> getLocations() async { + if(mockedError != null){ + throw mockedError!; + } return mockedReturn; } } @@ -36,32 +42,21 @@ void main() { }); test('Must load locations with success using a Fake class', () async { - const rawJson = ''' - { - "data": [ - { - "id": 0, - "lat": 41.17, - "lng": -8.59, - "isFloorless": false, - "locations": { - "0": [ - { - "id": 0, - "name": "Sala B004", - "type": "ROOMS", - "args": {"firstRoom":"B004","lastRoom":"B007"} - } - ] - } - } - ] - } - '''; + final roomGroup = RoomGroupLocation( + 0, + 'B004', + 'B007', + locationGroupId: 0, + ); + + final manualGroup = LocationGroup( + const LatLng(41.17, -8.59), + id: 0, + locations: [roomGroup], + ); - final groups = await fakeFetcher.getFromJSON(rawJson); - fakeFetcher.mockedReturn = groups; + fakeFetcher.mockedReturn = [manualGroup]; container.read(locationsProvider); @@ -75,30 +70,38 @@ void main() { expect(data, isNotEmpty); expect(data!.length, 1); expect(data.first.id, 0); + expect(data.first.floors[0]!.first, equals(roomGroup)); }); - test('Must not crash when given an empty list', () async { - fakeFetcher.mockedReturn = []; + test('Must not crash when given empty values', () async { + final manualGroup = LocationGroup( + const LatLng(0, 0), + locations: [], + ); + + fakeFetcher.mockedReturn = [manualGroup]; container.read(locationsProvider); await Future.delayed(Duration.zero); final state = container.read(locationsProvider); - final data = state.value; - expect(data, isEmpty); - expect(data, isNotNull); + expect(data!.first.floors, isEmpty); }); - test('Should throw an exception when JSON is not on the right format', () { - const brokenJSON = '{"error": "wrong format"}'; // its missing the data key + test('See how provider reacts to possible erros on the fetcher', () async { + fakeFetcher.mockedError = Exception('Data corruption or Network failure'); - expect( - () => fakeFetcher.getFromJSON(brokenJSON), - throwsA(isA()), - ); + try { + await container.read(locationsProvider.future); + } catch (_) { + } + + final state = container.read(locationsProvider); + expect(state.hasError, isTrue); + expect(state.error.toString(), contains('Data corruption or Network failure')); }); test('Should emit AsyncLoading state when initialization starts', () { @@ -108,4 +111,54 @@ void main() { expect(state.hasValue, isFalse); expect(state, isA?>>()); }); + + test('Provider must reload with new value', () async { + final manualGroup = LocationGroup( + const LatLng(0, 0), + locations: [], + ); + + fakeFetcher.mockedReturn = [manualGroup]; + + await container.read(locationsProvider.future); + + final newGroup = LocationGroup( + const LatLng(0, 0), + id: 2, + locations: [], + ); + + fakeFetcher.mockedReturn = [newGroup]; + + container.invalidate(locationsProvider); + await container.read(locationsProvider.future); + + final state = container.read(locationsProvider); + expect(state.value!.first.id, 2); + }); + + test('Must recover from an error to a success state', () async { + fakeFetcher.mockedError = Exception('Exception'); + try{ + await container.read(locationsProvider.futue); + }catch(_){} + expect(container.read(locationsProvider).hasError, isTrue); + + fakeFetcher.mockedError = null; + + final manualGroup = LocationGroup( + const LatLng(0, 0), + id: 1, + locations: [], + ); + + fakeFetcher.mockedReturn = [manualGroup]; + + container.invalidate(locationsProvider); + await container.read(locationsProvider.future); + + final state = container.read(locationsProvider); + + expect(state.value!.first.id, 1); + }); } From f9115411ddeab71374c37237d427a8b86eae63b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Sun, 28 Dec 2025 00:45:02 +0000 Subject: [PATCH 8/9] linter fixes --- .../lib/model/entities/location_group.dart | 9 ++-- .../faculty_locations_provider_test.dart | 50 ++++++------------- 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/packages/uni_app/lib/model/entities/location_group.dart b/packages/uni_app/lib/model/entities/location_group.dart index 53b36383a..776b4b221 100644 --- a/packages/uni_app/lib/model/entities/location_group.dart +++ b/packages/uni_app/lib/model/entities/location_group.dart @@ -17,12 +17,11 @@ class LocationGroup { }) : floors = locations != null ? groupBy(locations, (location) => location.floor) - : Map.identity() { - + : Map.identity() { if (latlng.latitude < -90 || latlng.latitude > 90) { throw ArgumentError('Invalid latitude: ${latlng.latitude}'); } - + if (latlng.longitude < -180 || latlng.longitude > 180) { throw ArgumentError('Invalid longitude: ${latlng.longitude}'); } @@ -42,8 +41,8 @@ class LocationGroup { /// Returns the Location with the most weight Location? getLocationWithMostWeight() { final allLocations = floors.values.expand((x) => x).toList(); - - if (allLocations.isEmpty){ + + if (allLocations.isEmpty) { return null; } diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart index 2fcbf0470..ee6ce89fd 100644 --- a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -14,7 +14,7 @@ class FakeLocationFetcher extends LocationFetcherAsset { @override Future> getLocations() async { - if(mockedError != null){ + if (mockedError != null) { throw mockedError!; } return mockedReturn; @@ -42,20 +42,14 @@ void main() { }); test('Must load locations with success using a Fake class', () async { - final roomGroup = RoomGroupLocation( - 0, - 'B004', - 'B007', - locationGroupId: 0, - ); + final roomGroup = RoomGroupLocation(0, 'B004', 'B007', locationGroupId: 0); final manualGroup = LocationGroup( const LatLng(41.17, -8.59), id: 0, - locations: [roomGroup], + locations: [roomGroup], ); - fakeFetcher.mockedReturn = [manualGroup]; container.read(locationsProvider); @@ -74,10 +68,7 @@ void main() { }); test('Must not crash when given empty values', () async { - final manualGroup = LocationGroup( - const LatLng(0, 0), - locations: [], - ); + final manualGroup = LocationGroup(const LatLng(0, 0), locations: []); fakeFetcher.mockedReturn = [manualGroup]; @@ -96,12 +87,14 @@ void main() { try { await container.read(locationsProvider.future); - } catch (_) { - } + } catch (_) {} final state = container.read(locationsProvider); - expect(state.hasError, isTrue); - expect(state.error.toString(), contains('Data corruption or Network failure')); + expect(state.hasError, isTrue); + expect( + state.error.toString(), + contains('Data corruption or Network failure'), + ); }); test('Should emit AsyncLoading state when initialization starts', () { @@ -113,20 +106,13 @@ void main() { }); test('Provider must reload with new value', () async { - final manualGroup = LocationGroup( - const LatLng(0, 0), - locations: [], - ); + final manualGroup = LocationGroup(const LatLng(0, 0), locations: []); fakeFetcher.mockedReturn = [manualGroup]; await container.read(locationsProvider.future); - final newGroup = LocationGroup( - const LatLng(0, 0), - id: 2, - locations: [], - ); + final newGroup = LocationGroup(const LatLng(0, 0), id: 2, locations: []); fakeFetcher.mockedReturn = [newGroup]; @@ -139,18 +125,14 @@ void main() { test('Must recover from an error to a success state', () async { fakeFetcher.mockedError = Exception('Exception'); - try{ + try { await container.read(locationsProvider.futue); - }catch(_){} + } catch (_) {} expect(container.read(locationsProvider).hasError, isTrue); fakeFetcher.mockedError = null; - - final manualGroup = LocationGroup( - const LatLng(0, 0), - id: 1, - locations: [], - ); + + final manualGroup = LocationGroup(const LatLng(0, 0), id: 1, locations: []); fakeFetcher.mockedReturn = [manualGroup]; From 0b1cc62886f47549d2e3cadd27827dbbbe423f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pinto?= Date: Sun, 28 Dec 2025 00:51:06 +0000 Subject: [PATCH 9/9] added group test --- .../faculty_locations_provider_test.dart | 149 ++++++++++-------- 1 file changed, 80 insertions(+), 69 deletions(-) diff --git a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart index ee6ce89fd..677489929 100644 --- a/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart +++ b/packages/uni_app/test/unit/providers/faculty_locations_provider_test.dart @@ -41,106 +41,117 @@ void main() { addTearDown(() => container.dispose()); }); - test('Must load locations with success using a Fake class', () async { - final roomGroup = RoomGroupLocation(0, 'B004', 'B007', locationGroupId: 0); + group('locationsProvider test', () { + test('Must load locations with success using a Fake class', () async { + final roomGroup = RoomGroupLocation( + 0, + 'B004', + 'B007', + locationGroupId: 0, + ); - final manualGroup = LocationGroup( - const LatLng(41.17, -8.59), - id: 0, - locations: [roomGroup], - ); + final manualGroup = LocationGroup( + const LatLng(41.17, -8.59), + id: 0, + locations: [roomGroup], + ); - fakeFetcher.mockedReturn = [manualGroup]; + fakeFetcher.mockedReturn = [manualGroup]; - container.read(locationsProvider); + container.read(locationsProvider); - await Future.delayed(Duration.zero); + await Future.delayed(Duration.zero); - final finalState = container.read(locationsProvider); + final finalState = container.read(locationsProvider); - final data = finalState.value; + final data = finalState.value; - expect(data, isNotNull); - expect(data, isNotEmpty); - expect(data!.length, 1); - expect(data.first.id, 0); - expect(data.first.floors[0]!.first, equals(roomGroup)); - }); + expect(data, isNotNull); + expect(data, isNotEmpty); + expect(data!.length, 1); + expect(data.first.id, 0); + expect(data.first.floors[0]!.first, equals(roomGroup)); + }); - test('Must not crash when given empty values', () async { - final manualGroup = LocationGroup(const LatLng(0, 0), locations: []); + test('Must not crash when given empty values', () async { + final manualGroup = LocationGroup(const LatLng(0, 0), locations: []); - fakeFetcher.mockedReturn = [manualGroup]; + fakeFetcher.mockedReturn = [manualGroup]; - container.read(locationsProvider); + container.read(locationsProvider); - await Future.delayed(Duration.zero); + await Future.delayed(Duration.zero); - final state = container.read(locationsProvider); - final data = state.value; + final state = container.read(locationsProvider); + final data = state.value; - expect(data!.first.floors, isEmpty); - }); + expect(data!.first.floors, isEmpty); + }); - test('See how provider reacts to possible erros on the fetcher', () async { - fakeFetcher.mockedError = Exception('Data corruption or Network failure'); + test('See how provider reacts to possible erros on the fetcher', () async { + fakeFetcher.mockedError = Exception('Data corruption or Network failure'); - try { - await container.read(locationsProvider.future); - } catch (_) {} + try { + await container.read(locationsProvider.future); + } catch (_) {} - final state = container.read(locationsProvider); - expect(state.hasError, isTrue); - expect( - state.error.toString(), - contains('Data corruption or Network failure'), - ); - }); + final state = container.read(locationsProvider); + expect(state.hasError, isTrue); + expect( + state.error.toString(), + contains('Data corruption or Network failure'), + ); + }); - test('Should emit AsyncLoading state when initialization starts', () { - final state = container.read(locationsProvider); + test('Should emit AsyncLoading state when initialization starts', () { + final state = container.read(locationsProvider); - expect(state.isLoading, isTrue); - expect(state.hasValue, isFalse); - expect(state, isA?>>()); - }); + expect(state.isLoading, isTrue); + expect(state.hasValue, isFalse); + expect(state, isA?>>()); + }); - test('Provider must reload with new value', () async { - final manualGroup = LocationGroup(const LatLng(0, 0), locations: []); + test('Provider must reload with new value', () async { + final manualGroup = LocationGroup(const LatLng(0, 0), locations: []); - fakeFetcher.mockedReturn = [manualGroup]; + fakeFetcher.mockedReturn = [manualGroup]; - await container.read(locationsProvider.future); + await container.read(locationsProvider.future); - final newGroup = LocationGroup(const LatLng(0, 0), id: 2, locations: []); + final newGroup = LocationGroup(const LatLng(0, 0), id: 2, locations: []); - fakeFetcher.mockedReturn = [newGroup]; + fakeFetcher.mockedReturn = [newGroup]; - container.invalidate(locationsProvider); - await container.read(locationsProvider.future); + container.invalidate(locationsProvider); + await container.read(locationsProvider.future); - final state = container.read(locationsProvider); - expect(state.value!.first.id, 2); - }); + final state = container.read(locationsProvider); + expect(state.value!.first.id, 2); + }); - test('Must recover from an error to a success state', () async { - fakeFetcher.mockedError = Exception('Exception'); - try { - await container.read(locationsProvider.futue); - } catch (_) {} - expect(container.read(locationsProvider).hasError, isTrue); + test('Must recover from an error to a success state', () async { + fakeFetcher.mockedError = Exception('Exception'); + try { + await container.read(locationsProvider.future); + } catch (_) {} + expect(container.read(locationsProvider).hasError, isTrue); - fakeFetcher.mockedError = null; + fakeFetcher.mockedError = null; - final manualGroup = LocationGroup(const LatLng(0, 0), id: 1, locations: []); + final manualGroup = LocationGroup( + const LatLng(0, 0), + id: 1, + locations: [], + ); - fakeFetcher.mockedReturn = [manualGroup]; + fakeFetcher.mockedReturn = [manualGroup]; - container.invalidate(locationsProvider); - await container.read(locationsProvider.future); + container.invalidate(locationsProvider); + await container.read(locationsProvider.future); - final state = container.read(locationsProvider); + final state = container.read(locationsProvider); - expect(state.value!.first.id, 1); + expect(state.value!.first.id, 1); + }); }); }