From 0c581347330199f6e9c201e8581dc7a30c82cf3f Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Fri, 23 Jun 2023 10:35:33 +0200 Subject: [PATCH] ML-62 Services tests (#82) * removed redundant `UserPreferencesService` from `MeteringBloc` * wip * post-merge fixes * `MeasureEvent` tests * `MeasureEvent` tests revision * `MeasureEvent` tests added timeout * added stubs for other `MeteringBloc` events * rewritten `MeteringBloc` logic * wip * `IsoChangedEvent` tests * refined `IsoChangedEvent` tests * `NdChangedEvent` tests * `FilmChangedEvent` tests * `MeteringCommunicationBloc` tests * added test run to ci * overriden `==` for `MeasuredState` * `LuxMeteringEvent` tests * refined `LuxMeteringEvent` tests * rename * wip * wip * `InitializeEvent`/`DeinitializeEvent` tests * clamp minZoomLevel * fixed `MeteringCommunicationBloc` tests * wip * `ZoomChangedEvent` tests * `ExposureOffsetChangedEvent`/`ExposureOffsetResetEvent` tests * renamed test groups * added test coverage script * improved `CameraContainerBloc` test coverage * `EquipmentProfileChangedEvent` tests * verify response vibration * fixed running all tests * `MeteringCommunicationBloc` equality tests * `CameraContainerBloc` equality tests * removed generated code from coverage * `MeteringScreenLayoutFeature` tests * `SupportedLocale` tests * `Film` tests * `CaffeineService` tests * `UserPreferencesService` tests (wip) * `LightSensorService` tests (wip) * `migrateOldKeys()` tests * ignore currently unused getters & setters * gradle upgrade * `reset(sharedPreferences);` calls count * typo --- android/app/build.gradle | 6 +- android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/data/caffeine_service.dart | 4 +- lib/data/shared_prefs_service.dart | 91 ++-- test/data/caffeine_service_test.dart | 76 ++++ test/data/light_sensor_service_test.dart | 71 ++++ test/data/shared_prefs_service_test.dart | 392 ++++++++++++++++++ 8 files changed, 590 insertions(+), 54 deletions(-) create mode 100644 test/data/caffeine_service_test.dart create mode 100644 test/data/light_sensor_service_test.dart create mode 100644 test/data/shared_prefs_service_test.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 4bc9578..53774dc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -33,10 +33,6 @@ apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" -gradle.beforeProject({ project-> - project.setProperty("target-platform", "android-arm,android-arm64") -}) - android { compileSdkVersion 33 ndkVersion flutter.ndkVersion @@ -112,5 +108,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.android.billingclient:billing-ktx:5.1.0" + implementation "com.android.billingclient:billing-ktx:6.0.0" } diff --git a/android/build.gradle b/android/build.gradle index 346e639..84e662d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:7.4.2' classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index cb24abd..3c472b9 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/lib/data/caffeine_service.dart b/lib/data/caffeine_service.dart index cfb0d50..da36968 100644 --- a/lib/data/caffeine_service.dart +++ b/lib/data/caffeine_service.dart @@ -9,7 +9,7 @@ class CaffeineService { return _methodChannel.invokeMethod("isKeepScreenOn").then((value) => value!); } - Future keepScreenOn(bool keep) async { - await _methodChannel.invokeMethod("setKeepScreenOn", keep); + Future keepScreenOn(bool keep) async { + return _methodChannel.invokeMethod("setKeepScreenOn", keep).then((value) => value!); } } diff --git a/lib/data/shared_prefs_service.dart b/lib/data/shared_prefs_service.dart index a86a7d1..e90df0e 100644 --- a/lib/data/shared_prefs_service.dart +++ b/lib/data/shared_prefs_service.dart @@ -10,30 +10,31 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:shared_preferences/shared_preferences.dart'; class UserPreferencesService { - static const _isoKey = "iso"; - static const _ndFilterKey = "ndFilter"; + static const isoKey = "iso"; + static const ndFilterKey = "ndFilter"; - static const _evSourceTypeKey = "evSourceType"; - static const _cameraEvCalibrationKey = "cameraEvCalibration"; - static const _lightSensorEvCalibrationKey = "lightSensorEvCalibration"; - static const _meteringScreenLayoutKey = "meteringScreenLayout"; - static const _filmKey = "film"; + static const evSourceTypeKey = "evSourceType"; + static const cameraEvCalibrationKey = "cameraEvCalibration"; + static const lightSensorEvCalibrationKey = "lightSensorEvCalibration"; + static const meteringScreenLayoutKey = "meteringScreenLayout"; + static const filmKey = "film"; - static const _caffeineKey = "caffeine"; - static const _hapticsKey = "haptics"; - static const _localeKey = "locale"; + static const caffeineKey = "caffeine"; + static const hapticsKey = "haptics"; + static const localeKey = "locale"; - static const _themeTypeKey = "themeType"; - static const _primaryColorKey = "primaryColor"; - static const _dynamicColorKey = "dynamicColor"; + static const themeTypeKey = "themeType"; + static const primaryColorKey = "primaryColor"; + static const dynamicColorKey = "dynamicColor"; final SharedPreferences _sharedPreferences; UserPreferencesService(this._sharedPreferences) { - _migrateOldKeys(); + migrateOldKeys(); } - Future _migrateOldKeys() async { + @visibleForTesting + Future migrateOldKeys() async { final legacyIsoIndex = _sharedPreferences.getInt("curIsoIndex"); if (legacyIsoIndex != null) { iso = IsoValue.values[legacyIsoIndex]; @@ -69,22 +70,22 @@ class UserPreferencesService { } IsoValue get iso => - IsoValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(_isoKey) ?? 100)); - set iso(IsoValue value) => _sharedPreferences.setInt(_isoKey, value.value); + IsoValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(isoKey) ?? 100)); + set iso(IsoValue value) => _sharedPreferences.setInt(isoKey, value.value); NdValue get ndFilter => - NdValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(_ndFilterKey) ?? 0)); - set ndFilter(NdValue value) => _sharedPreferences.setInt(_ndFilterKey, value.value); + NdValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(ndFilterKey) ?? 0)); + set ndFilter(NdValue value) => _sharedPreferences.setInt(ndFilterKey, value.value); EvSourceType get evSourceType => - EvSourceType.values[_sharedPreferences.getInt(_evSourceTypeKey) ?? 0]; - set evSourceType(EvSourceType value) => _sharedPreferences.setInt(_evSourceTypeKey, value.index); + EvSourceType.values[_sharedPreferences.getInt(evSourceTypeKey) ?? 0]; + set evSourceType(EvSourceType value) => _sharedPreferences.setInt(evSourceTypeKey, value.index); - bool get caffeine => _sharedPreferences.getBool(_caffeineKey) ?? false; - set caffeine(bool value) => _sharedPreferences.setBool(_caffeineKey, value); + bool get caffeine => _sharedPreferences.getBool(caffeineKey) ?? false; + set caffeine(bool value) => _sharedPreferences.setBool(caffeineKey, value); MeteringScreenLayoutConfig get meteringScreenLayout { - final configJson = _sharedPreferences.getString(_meteringScreenLayoutKey); + final configJson = _sharedPreferences.getString(meteringScreenLayoutKey); if (configJson != null) { return MeteringScreenLayoutConfigJson.fromJson( json.decode(configJson) as Map, @@ -98,44 +99,44 @@ class UserPreferencesService { } set meteringScreenLayout(MeteringScreenLayoutConfig value) => - _sharedPreferences.setString(_meteringScreenLayoutKey, json.encode(value.toJson())); + _sharedPreferences.setString(meteringScreenLayoutKey, json.encode(value.toJson())); - bool get haptics => _sharedPreferences.getBool(_hapticsKey) ?? true; - set haptics(bool value) => _sharedPreferences.setBool(_hapticsKey, value); + bool get haptics => _sharedPreferences.getBool(hapticsKey) ?? true; + set haptics(bool value) => _sharedPreferences.setBool(hapticsKey, value); SupportedLocale get locale => SupportedLocale.values.firstWhere( - (e) => e.toString() == _sharedPreferences.getString(_localeKey), + (e) => e.toString() == _sharedPreferences.getString(localeKey), orElse: () => SupportedLocale.en, ); - set locale(SupportedLocale value) => _sharedPreferences.setString(_localeKey, value.toString()); + set locale(SupportedLocale value) => _sharedPreferences.setString(localeKey, value.toString()); - double get cameraEvCalibration => _sharedPreferences.getDouble(_cameraEvCalibrationKey) ?? 0.0; + double get cameraEvCalibration => _sharedPreferences.getDouble(cameraEvCalibrationKey) ?? 0.0; set cameraEvCalibration(double value) => - _sharedPreferences.setDouble(_cameraEvCalibrationKey, value); + _sharedPreferences.setDouble(cameraEvCalibrationKey, value); double get lightSensorEvCalibration => - _sharedPreferences.getDouble(_lightSensorEvCalibrationKey) ?? 0.0; + _sharedPreferences.getDouble(lightSensorEvCalibrationKey) ?? 0.0; set lightSensorEvCalibration(double value) => - _sharedPreferences.setDouble(_lightSensorEvCalibrationKey, value); + _sharedPreferences.setDouble(lightSensorEvCalibrationKey, value); - ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(_themeTypeKey) ?? 0]; - set themeType(ThemeType value) => _sharedPreferences.setInt(_themeTypeKey, value.index); + ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(themeTypeKey) ?? 0]; + set themeType(ThemeType value) => _sharedPreferences.setInt(themeTypeKey, value.index); - Color get primaryColor => Color(_sharedPreferences.getInt(_primaryColorKey) ?? 0xff2196f3); - set primaryColor(Color value) => _sharedPreferences.setInt(_primaryColorKey, value.value); + Color get primaryColor => Color(_sharedPreferences.getInt(primaryColorKey) ?? 0xff2196f3); + set primaryColor(Color value) => _sharedPreferences.setInt(primaryColorKey, value.value); - bool get dynamicColor => _sharedPreferences.getBool(_dynamicColorKey) ?? false; - set dynamicColor(bool value) => _sharedPreferences.setBool(_dynamicColorKey, value); + bool get dynamicColor => _sharedPreferences.getBool(dynamicColorKey) ?? false; + set dynamicColor(bool value) => _sharedPreferences.setBool(dynamicColorKey, value); Film get film => Film.values.firstWhere( - (e) => e.name == _sharedPreferences.getString(_filmKey), + (e) => e.name == _sharedPreferences.getString(filmKey), orElse: () => Film.values.first, ); - set film(Film value) => _sharedPreferences.setString(_filmKey, value.name); + set film(Film value) => _sharedPreferences.setString(filmKey, value.name); - String get selectedEquipmentProfileId => ''; - set selectedEquipmentProfileId(String id) {} + String get selectedEquipmentProfileId => ''; // coverage:ignore-line + set selectedEquipmentProfileId(String id) {} // coverage:ignore-line - List get equipmentProfiles => []; - set equipmentProfiles(List profiles) {} + List get equipmentProfiles => []; // coverage:ignore-line + set equipmentProfiles(List profiles) {} // coverage:ignore-line } diff --git a/test/data/caffeine_service_test.dart b/test/data/caffeine_service_test.dart new file mode 100644 index 0000000..0c80fac --- /dev/null +++ b/test/data/caffeine_service_test.dart @@ -0,0 +1,76 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/caffeine_service.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + late CaffeineService service; + + const methodChannel = MethodChannel('com.vodemn.lightmeter/keepScreenOn'); + Future? methodCallSuccessHandler(MethodCall methodCall) async { + switch (methodCall.method) { + case "isKeepScreenOn": + return true; + case "setKeepScreenOn": + return methodCall.arguments as bool; + default: + return null; + } + } + + setUp(() { + service = const CaffeineService(); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, methodCallSuccessHandler); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + }); + + group( + 'isKeepScreenOn()', + () { + test('true', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case "isKeepScreenOn": + return true; + default: + return null; + } + }); + expectLater(service.isKeepScreenOn(), completion(true)); + }); + + test('false', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case "isKeepScreenOn": + return false; + default: + return null; + } + }); + expectLater(service.isKeepScreenOn(), completion(false)); + }); + }, + ); + + group( + 'keepScreenOn()', + () { + test('true', () async => expectLater(service.keepScreenOn(true), completion(true))); + + test('false', () async => expectLater(service.keepScreenOn(false), completion(false))); + }, + ); +} diff --git a/test/data/light_sensor_service_test.dart b/test/data/light_sensor_service_test.dart new file mode 100644 index 0000000..1256e18 --- /dev/null +++ b/test/data/light_sensor_service_test.dart @@ -0,0 +1,71 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/light_sensor_service.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + late LightSensorService service; + + const methodChannel = MethodChannel('system_feature'); + // TODO: add event channel mock + //const eventChannel = EventChannel('light.eventChannel'); + + setUp(() { + service = const LightSensorService(); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + }); + + group( + 'hasSensor()', + () { + test('true', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case "sensor": + return true; + default: + return null; + } + }); + expectLater(service.hasSensor(), completion(true)); + }); + + test('false', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case "sensor": + return false; + default: + return null; + } + }); + expectLater(service.hasSensor(), completion(false)); + }); + test('null', () async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case "sensor": + return null; + default: + return null; + } + }); + expectLater(service.hasSensor(), completion(false)); + }); + }, + ); +} diff --git a/test/data/shared_prefs_service_test.dart b/test/data/shared_prefs_service_test.dart new file mode 100644 index 0000000..6143141 --- /dev/null +++ b/test/data/shared_prefs_service_test.dart @@ -0,0 +1,392 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/models/ev_source_type.dart'; +import 'package:lightmeter/data/models/film.dart'; +import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; +import 'package:lightmeter/data/models/supported_locale.dart'; +import 'package:lightmeter/data/models/theme_type.dart'; +import 'package:lightmeter/data/shared_prefs_service.dart'; +import 'package:lightmeter/providers/theme_provider.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class _MockSharedPreferences extends Mock implements SharedPreferences {} + +void main() { + late _MockSharedPreferences sharedPreferences; + late UserPreferencesService service; + + setUpAll(() { + sharedPreferences = _MockSharedPreferences(); + service = UserPreferencesService(sharedPreferences); + }); + + tearDown(() { + reset(sharedPreferences); + }); + + group('migrateOldKeys()', () { + test('no legacy keys', () async { + when(() => sharedPreferences.getInt("curIsoIndex")).thenReturn(null); + when(() => sharedPreferences.getInt("curndIndex")).thenReturn(null); + when(() => sharedPreferences.getDouble("cameraCalibr")).thenReturn(null); + when(() => sharedPreferences.getDouble("sensorCalibr")).thenReturn(null); + when(() => sharedPreferences.getBool("vibrate")).thenReturn(null); + + when(() => sharedPreferences.remove("curIsoIndex")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("curndIndex")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("cameraCalibr")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("sensorCalibr")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("vibrate")).thenAnswer((_) async => true); + + await service.migrateOldKeys(); + + verifyNever(() => sharedPreferences.remove("curIsoIndex")); + verifyNever(() => sharedPreferences.remove("curndIndex")); + verifyNever(() => sharedPreferences.remove("cameraCalibr")); + verifyNever(() => sharedPreferences.remove("sensorCalibr")); + verifyNever(() => sharedPreferences.remove("vibrate")); + }); + + test('migrate all keys', () async { + when(() => sharedPreferences.getInt("curIsoIndex")).thenReturn(1); + when(() => sharedPreferences.getInt("curndIndex")).thenReturn(0); + when(() => sharedPreferences.getDouble("cameraCalibr")).thenReturn(1.0); + when(() => sharedPreferences.getDouble("sensorCalibr")).thenReturn(-1.0); + when(() => sharedPreferences.getBool("vibrate")).thenReturn(false); + + when( + () => sharedPreferences.setInt(UserPreferencesService.isoKey, IsoValue.values[1].value), + ).thenAnswer((_) => Future.value(true)); + when( + () => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, NdValue.values[0].value), + ).thenAnswer((_) => Future.value(true)); + when( + () => sharedPreferences.setDouble(UserPreferencesService.cameraEvCalibrationKey, 1.0), + ).thenAnswer((_) => Future.value(true)); + when( + () => sharedPreferences.setDouble(UserPreferencesService.lightSensorEvCalibrationKey, -1.0), + ).thenAnswer((_) => Future.value(true)); + when( + () => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false), + ).thenAnswer((_) => Future.value(true)); + + when(() => sharedPreferences.remove("curIsoIndex")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("curndIndex")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("cameraCalibr")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("sensorCalibr")).thenAnswer((_) async => true); + when(() => sharedPreferences.remove("vibrate")).thenAnswer((_) async => true); + + await service.migrateOldKeys(); + + verify(() => sharedPreferences.remove("curIsoIndex")).called(1); + verify(() => sharedPreferences.remove("curndIndex")).called(1); + verify(() => sharedPreferences.remove("cameraCalibr")).called(1); + verify(() => sharedPreferences.remove("sensorCalibr")).called(1); + verify(() => sharedPreferences.remove("vibrate")).called(1); + }); + }); + + group('iso', () { + test('get default', () { + when(() => sharedPreferences.getInt(UserPreferencesService.isoKey)).thenReturn(null); + expect(service.iso, const IsoValue(100, StopType.full)); + }); + + test('get', () { + when(() => sharedPreferences.getInt(UserPreferencesService.isoKey)).thenReturn(100); + expect(service.iso, const IsoValue(100, StopType.full)); + }); + + test('set', () { + when(() => sharedPreferences.setInt(UserPreferencesService.isoKey, 200)) + .thenAnswer((_) => Future.value(true)); + service.iso = const IsoValue(200, StopType.full); + verify(() => sharedPreferences.setInt(UserPreferencesService.isoKey, 200)).called(1); + }); + }); + + group('ndFilter', () { + test('get default', () { + when(() => sharedPreferences.getInt(UserPreferencesService.ndFilterKey)).thenReturn(null); + expect(service.ndFilter, const NdValue(0)); + }); + + test('get', () { + when(() => sharedPreferences.getInt(UserPreferencesService.ndFilterKey)).thenReturn(4); + expect(service.ndFilter, const NdValue(4)); + }); + + test('set', () { + when(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0)) + .thenAnswer((_) => Future.value(true)); + service.ndFilter = const NdValue(0); + verify(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0)).called(1); + }); + }); + + group('evSourceType', () { + test('get default', () { + when(() => sharedPreferences.getInt(UserPreferencesService.evSourceTypeKey)).thenReturn(null); + expect(service.evSourceType, EvSourceType.camera); + }); + + test('get', () { + when(() => sharedPreferences.getInt(UserPreferencesService.evSourceTypeKey)).thenReturn(1); + expect(service.evSourceType, EvSourceType.sensor); + }); + + test('set', () { + when(() => sharedPreferences.setInt(UserPreferencesService.evSourceTypeKey, 1)) + .thenAnswer((_) => Future.value(true)); + service.evSourceType = EvSourceType.sensor; + verify(() => sharedPreferences.setInt(UserPreferencesService.evSourceTypeKey, 1)).called(1); + }); + }); + + group('caffeine', () { + test('get default', () { + when(() => sharedPreferences.getBool(UserPreferencesService.caffeineKey)).thenReturn(null); + expect(service.caffeine, false); + }); + + test('get', () { + when(() => sharedPreferences.getBool(UserPreferencesService.caffeineKey)).thenReturn(true); + expect(service.caffeine, true); + }); + + test('set', () { + when(() => sharedPreferences.setBool(UserPreferencesService.caffeineKey, false)) + .thenAnswer((_) => Future.value(true)); + service.caffeine = false; + verify(() => sharedPreferences.setBool(UserPreferencesService.caffeineKey, false)).called(1); + }); + }); + + group('meteringScreenLayout', () { + test('get default', () { + when( + () => sharedPreferences.getString(UserPreferencesService.meteringScreenLayoutKey), + ).thenReturn(null); + expect( + service.meteringScreenLayout, + { + MeteringScreenLayoutFeature.extremeExposurePairs: true, + MeteringScreenLayoutFeature.filmPicker: true, + }, + ); + }); + + test('get', () { + when( + () => sharedPreferences.getString(UserPreferencesService.meteringScreenLayoutKey), + ).thenReturn("""{"0":false,"1":true}"""); + expect( + service.meteringScreenLayout, + { + MeteringScreenLayoutFeature.extremeExposurePairs: false, + MeteringScreenLayoutFeature.filmPicker: true, + }, + ); + }); + + test('set', () { + when( + () => sharedPreferences.setString( + UserPreferencesService.meteringScreenLayoutKey, + """{"0":false,"1":true}""", + ), + ).thenAnswer((_) => Future.value(true)); + service.meteringScreenLayout = { + MeteringScreenLayoutFeature.extremeExposurePairs: false, + MeteringScreenLayoutFeature.filmPicker: true, + }; + verify( + () => sharedPreferences.setString( + UserPreferencesService.meteringScreenLayoutKey, + """{"0":false,"1":true}""", + ), + ).called(1); + }); + }); + + group('haptics', () { + test('get default', () { + when(() => sharedPreferences.getBool(UserPreferencesService.hapticsKey)).thenReturn(null); + expect(service.haptics, true); + }); + + test('get', () { + when(() => sharedPreferences.getBool(UserPreferencesService.hapticsKey)).thenReturn(true); + expect(service.haptics, true); + }); + + test('set', () { + when(() => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false)) + .thenAnswer((_) => Future.value(true)); + service.haptics = false; + verify(() => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false)).called(1); + }); + }); + + group('locale', () { + test('get default', () { + when(() => sharedPreferences.getString(UserPreferencesService.localeKey)).thenReturn(null); + expect(service.locale, SupportedLocale.en); + }); + + test('get', () { + when(() => sharedPreferences.getString(UserPreferencesService.localeKey)) + .thenReturn('SupportedLocale.ru'); + expect(service.locale, SupportedLocale.ru); + }); + + test('set', () { + when( + () => sharedPreferences.setString(UserPreferencesService.localeKey, 'SupportedLocale.en'), + ).thenAnswer((_) => Future.value(true)); + service.locale = SupportedLocale.en; + verify( + () => sharedPreferences.setString(UserPreferencesService.localeKey, 'SupportedLocale.en'), + ).called(1); + }); + }); + + group('cameraEvCalibration', () { + test('get default', () { + when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey)) + .thenReturn(null); + expect(service.cameraEvCalibration, 0.0); + }); + + test('get', () { + when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey)) + .thenReturn(2.0); + expect(service.cameraEvCalibration, 2.0); + }); + + test('set', () { + when( + () => sharedPreferences.setDouble(UserPreferencesService.cameraEvCalibrationKey, 1.0), + ).thenAnswer((_) => Future.value(true)); + service.cameraEvCalibration = 1.0; + verify( + () => sharedPreferences.setDouble(UserPreferencesService.cameraEvCalibrationKey, 1.0), + ).called(1); + }); + }); + + group('lightSensorEvCalibration', () { + test('get default', () { + when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey)) + .thenReturn(null); + expect(service.lightSensorEvCalibration, 0.0); + }); + + test('get', () { + when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey)) + .thenReturn(2.0); + expect(service.lightSensorEvCalibration, 2.0); + }); + + test('set', () { + when( + () => sharedPreferences.setDouble(UserPreferencesService.lightSensorEvCalibrationKey, 1.0), + ).thenAnswer((_) => Future.value(true)); + service.lightSensorEvCalibration = 1.0; + verify( + () => sharedPreferences.setDouble(UserPreferencesService.lightSensorEvCalibrationKey, 1.0), + ).called(1); + }); + }); + + group('themeType', () { + test('get default', () { + when(() => sharedPreferences.getInt(UserPreferencesService.themeTypeKey)).thenReturn(null); + expect(service.themeType, ThemeType.light); + }); + + test('get', () { + when(() => sharedPreferences.getInt(UserPreferencesService.themeTypeKey)).thenReturn(1); + expect(service.themeType, ThemeType.dark); + }); + + test('set', () { + when( + () => sharedPreferences.setInt(UserPreferencesService.themeTypeKey, 1), + ).thenAnswer((_) => Future.value(true)); + service.themeType = ThemeType.dark; + verify( + () => sharedPreferences.setInt(UserPreferencesService.themeTypeKey, 1), + ).called(1); + }); + }); + + group('primaryColor', () { + test('get default', () { + when(() => sharedPreferences.getInt(UserPreferencesService.primaryColorKey)).thenReturn(null); + expect(service.primaryColor, ThemeProvider.primaryColorsList[5]); + }); + + test('get', () { + when(() => sharedPreferences.getInt(UserPreferencesService.primaryColorKey)) + .thenReturn(0xff9c27b0); + expect(service.primaryColor, ThemeProvider.primaryColorsList[2]); + }); + + test('set', () { + when( + () => sharedPreferences.setInt(UserPreferencesService.primaryColorKey, 0xff000000), + ).thenAnswer((_) => Future.value(true)); + service.primaryColor = Colors.black; + verify( + () => sharedPreferences.setInt(UserPreferencesService.primaryColorKey, 0xff000000), + ).called(1); + }); + }); + + group('dynamicColor', () { + test('get default', () { + when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey)) + .thenReturn(null); + expect(service.dynamicColor, false); + }); + + test('get', () { + when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey)) + .thenReturn(true); + expect(service.dynamicColor, true); + }); + + test('set', () { + when(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false)) + .thenAnswer((_) => Future.value(true)); + service.dynamicColor = false; + verify(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false)) + .called(1); + }); + }); + + group('film', () { + test('get default', () { + when(() => sharedPreferences.getString(UserPreferencesService.filmKey)).thenReturn(null); + expect(service.film, Film.values.first); + }); + + test('get', () { + when(() => sharedPreferences.getString(UserPreferencesService.filmKey)) + .thenReturn('Fomapan ACTION 400'); + expect(service.film, const FomapanFilm.action400()); + }); + + test('set', () { + when(() => sharedPreferences.setString(UserPreferencesService.filmKey, 'Fomapan ACTION 400')) + .thenAnswer((_) => Future.value(true)); + service.film = const FomapanFilm.action400(); + verify( + () => sharedPreferences.setString(UserPreferencesService.filmKey, 'Fomapan ACTION 400'), + ).called(1); + }); + }); +}