Compare commits

..

No commits in common. "6cffcd1998cf000b57ce8d7521fd7d5320c178cb" and "3c4d959cc68ab48c8f7c1221626e7a7264e9e2c0" have entirely different histories.

11 changed files with 84 additions and 315 deletions

View file

@ -11,7 +11,7 @@ class LightSensorService {
return false;
}
try {
return await LightSensor.hasSensor();
return await LightSensor.hasSensor ?? false;
} catch (_) {
return false;
}
@ -21,6 +21,6 @@ class LightSensorService {
if (!localPlatform.isAndroid) {
return const Stream<int>.empty();
}
return LightSensor.luxStream();
return LightSensor.lightSensorStream;
}
}

View file

@ -22,7 +22,7 @@ dependencies:
sdk: flutter
intl: 0.18.0
intl_utils: 2.8.2
light_sensor: 3.0.0
light_sensor: 2.0.2
m3_lightmeter_iap:
git:
url: "https://github.com/vodemn/m3_lightmeter_iap"

View file

@ -1,11 +1,9 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:light_sensor/light_sensor.dart';
import 'package:lightmeter/data/light_sensor_service.dart';
import 'package:mocktail/mocktail.dart';
import 'package:platform/platform.dart';
import '../event_channel_mock.dart';
class _MockLocalPlatform extends Mock implements LocalPlatform {}
void main() {
@ -14,44 +12,68 @@ void main() {
late _MockLocalPlatform localPlatform;
late LightSensorService service;
const methodChannel = MethodChannel('system_feature');
// TODO: add event channel mock
//const eventChannel = EventChannel('light.eventChannel');
setUp(() {
localPlatform = _MockLocalPlatform();
service = LightSensorService(localPlatform);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
});
group(
'hasSensor()',
() {
void setMockSensorAvailability({required bool hasSensor}) {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
LightSensor.methodChannel,
(methodCall) async {
test('true - Android', () async {
when(() => localPlatform.isAndroid).thenReturn(true);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, (methodCall) async {
switch (methodCall.method) {
case "sensor":
return hasSensor;
return true;
default:
return null;
}
},
);
}
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
LightSensor.methodChannel,
null,
);
});
test('true - Android', () async {
when(() => localPlatform.isAndroid).thenReturn(true);
setMockSensorAvailability(hasSensor: true);
expectLater(service.hasSensor(), completion(true));
});
test('false - Android', () async {
when(() => localPlatform.isAndroid).thenReturn(true);
setMockSensorAvailability(hasSensor: false);
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 - Android', () async {
when(() => localPlatform.isAndroid).thenReturn(true);
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));
});
@ -63,18 +85,10 @@ void main() {
);
group('luxStream', () {
test('Android', () async {
when(() => localPlatform.isAndroid).thenReturn(true);
final stream = service.luxStream();
final List<int> result = [];
final subscription = stream.listen(result.add);
await sendMockVolumeAction(LightSensor.eventChannel.name, 100);
await sendMockVolumeAction(LightSensor.eventChannel.name, 150);
await sendMockVolumeAction(LightSensor.eventChannel.name, 150);
await sendMockVolumeAction(LightSensor.eventChannel.name, 200);
expect(result, [100, 150, 150, 200]);
subscription.cancel();
});
// test('Android', () async {
// when(() => localPlatform.isAndroid).thenReturn(true);
// expect(service.luxStream(), const Stream.empty());
// });
test('iOS', () async {
when(() => localPlatform.isAndroid).thenReturn(false);

View file

@ -1,38 +0,0 @@
import 'package:lightmeter/data/models/exposure_pair.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:test/test.dart';
void main() {
test('toString()', () {
expect(
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first).toString(),
'${ApertureValue.values.first} - ${ShutterSpeedValue.values.first}',
);
});
test('==', () {
expect(
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first) ==
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first),
true,
);
expect(
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first) ==
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.last),
false,
);
});
test('hashCode', () {
expect(
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first).hashCode ==
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first).hashCode,
true,
);
expect(
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.first).hashCode ==
ExposurePair(ApertureValue.values.first, ShutterSpeedValue.values.last).hashCode,
false,
);
});
}

View file

@ -6,13 +6,11 @@ void main() {
expect(SupportedLocale.en.intlName, 'en');
expect(SupportedLocale.fr.intlName, 'fr');
expect(SupportedLocale.ru.intlName, 'ru');
expect(SupportedLocale.zh.intlName, 'zh');
});
test('localizedName', () {
expect(SupportedLocale.en.localizedName, 'English');
expect(SupportedLocale.fr.localizedName, 'Français');
expect(SupportedLocale.ru.localizedName, 'Русский');
expect(SupportedLocale.zh.localizedName, '简体中文');
});
}

View file

@ -4,7 +4,6 @@ import 'package:lightmeter/data/models/ev_source_type.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/models/volume_action.dart';
import 'package:lightmeter/data/shared_prefs_service.dart';
import 'package:lightmeter/res/theme.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
@ -100,7 +99,8 @@ void main() {
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.isoKey, 200)).thenAnswer((_) => Future.value(true));
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);
});
@ -118,7 +118,8 @@ void main() {
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0)).thenAnswer((_) => Future.value(true));
when(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0))
.thenAnswer((_) => Future.value(true));
service.ndFilter = const NdValue(0);
verify(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0)).called(1);
});
@ -174,7 +175,8 @@ void main() {
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.stopTypeKey, 0)).thenAnswer((_) => Future.value(true));
when(() => sharedPreferences.setInt(UserPreferencesService.stopTypeKey, 0))
.thenAnswer((_) => Future.value(true));
service.stopType = StopType.full;
verify(() => sharedPreferences.setInt(UserPreferencesService.stopTypeKey, 0)).called(1);
});
@ -251,26 +253,6 @@ void main() {
verify(() => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false)).called(1);
});
});
group('volumeAction', () {
test('get default', () {
when(() => sharedPreferences.getBool(UserPreferencesService.volumeActionKey)).thenReturn(null);
expect(service.volumeAction, VolumeAction.shutter);
});
test('get', () {
when(() => sharedPreferences.getString(UserPreferencesService.volumeActionKey))
.thenReturn(VolumeAction.shutter.toString());
expect(service.volumeAction, VolumeAction.shutter);
});
test('set', () {
when(() => sharedPreferences.setString(UserPreferencesService.volumeActionKey, VolumeAction.shutter.toString()))
.thenAnswer((_) => Future.value(true));
service.volumeAction = VolumeAction.shutter;
verify(() => sharedPreferences.setString(UserPreferencesService.volumeActionKey, VolumeAction.shutter.toString()))
.called(1);
});
});
group('locale', () {
test('get default', () {
@ -279,7 +261,8 @@ void main() {
});
test('get', () {
when(() => sharedPreferences.getString(UserPreferencesService.localeKey)).thenReturn('SupportedLocale.ru');
when(() => sharedPreferences.getString(UserPreferencesService.localeKey))
.thenReturn('SupportedLocale.ru');
expect(service.locale, SupportedLocale.ru);
});
@ -296,12 +279,14 @@ void main() {
group('cameraEvCalibration', () {
test('get default', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey)).thenReturn(null);
when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey))
.thenReturn(null);
expect(service.cameraEvCalibration, 0.0);
});
test('get', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey)).thenReturn(2.0);
when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey))
.thenReturn(2.0);
expect(service.cameraEvCalibration, 2.0);
});
@ -318,12 +303,14 @@ void main() {
group('lightSensorEvCalibration', () {
test('get default', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey)).thenReturn(null);
when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey))
.thenReturn(null);
expect(service.lightSensorEvCalibration, 0.0);
});
test('get', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey)).thenReturn(2.0);
when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey))
.thenReturn(2.0);
expect(service.lightSensorEvCalibration, 2.0);
});
@ -367,7 +354,8 @@ void main() {
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.primaryColorKey)).thenReturn(0xff9c27b0);
when(() => sharedPreferences.getInt(UserPreferencesService.primaryColorKey))
.thenReturn(0xff9c27b0);
expect(service.primaryColor, primaryColorsList[2]);
});
@ -384,12 +372,14 @@ void main() {
group('dynamicColor', () {
test('get default', () {
when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey)).thenReturn(null);
when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey))
.thenReturn(null);
expect(service.dynamicColor, false);
});
test('get', () {
when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey)).thenReturn(true);
when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey))
.thenReturn(true);
expect(service.dynamicColor, true);
});
@ -397,7 +387,8 @@ void main() {
when(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false))
.thenAnswer((_) => Future.value(true));
service.dynamicColor = false;
verify(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false)).called(1);
verify(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false))
.called(1);
});
});
}

View file

@ -4,8 +4,6 @@ import 'package:lightmeter/data/volume_events_service.dart';
import 'package:mocktail/mocktail.dart';
import 'package:platform/platform.dart';
import '../event_channel_mock.dart';
class _MockLocalPlatform extends Mock implements LocalPlatform {}
void main() {
@ -62,18 +60,10 @@ void main() {
});
group('volumeButtonsEventStream', () {
test('Android', () async {
when(() => localPlatform.isAndroid).thenReturn(true);
final stream = service.volumeButtonsEventStream();
final List<int> result = [];
final subscription = stream.listen(result.add);
await sendMockVolumeAction(VolumeEventsService.volumeEventsChannel.name, 24);
await sendMockVolumeAction(VolumeEventsService.volumeEventsChannel.name, 25);
await sendMockVolumeAction(VolumeEventsService.volumeEventsChannel.name, 20);
await sendMockVolumeAction(VolumeEventsService.volumeEventsChannel.name, 24);
expect(result, [24, 25, 24]);
subscription.cancel();
});
// test('Android', () async {
// when(() => localPlatform.isAndroid).thenReturn(true);
// expect(service.volumeButtonsEventStream(), const Stream.empty());
// });
test('iOS', () async {
when(() => localPlatform.isAndroid).thenReturn(false);

View file

@ -1,10 +0,0 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
Future<void> sendMockVolumeAction(String channelName, int keyCode) async {
await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
channelName,
const StandardMethodCodec().encodeSuccessEnvelope(keyCode),
(ByteData? data) {},
);
}

View file

@ -1,116 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/equipment_profile_picker/widget_picker_equipment_profiles.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
import '../../../../../application_mock.dart';
import 'utils.dart';
class _MockIAPStorageService extends Mock implements IAPStorageService {}
void main() {
late final _MockIAPStorageService mockIAPStorageService;
setUpAll(() {
mockIAPStorageService = _MockIAPStorageService();
when(() => mockIAPStorageService.equipmentProfiles).thenReturn(_mockEquipmentProfiles);
when(() => mockIAPStorageService.selectedEquipmentProfileId).thenReturn('');
});
Future<void> pumpApplication(WidgetTester tester) async {
await tester.pumpWidget(
IAPProducts(
products: [
IAPProduct(
storeId: IAPProductType.paidFeatures.storeId,
status: IAPProductStatus.purchased,
)
],
child: EquipmentProfileProvider(
storageService: mockIAPStorageService,
child: const WidgetTestApplicationMock(
child: Row(children: [Expanded(child: EquipmentProfilePicker())]),
),
),
),
);
await tester.pumpAndSettle();
}
testWidgets(
'Check dialog icon and title consistency',
(tester) async {
await pumpApplication(tester);
expectReadingValueContainerText(S.current.equipmentProfile);
await tester.openAnimatedPicker<EquipmentProfilePicker>();
expect(find.byIcon(Icons.camera), findsOneWidget);
expectDialogPickerText<EquipmentProfile>(S.current.equipmentProfile);
},
);
group(
'Display selected value',
() {
testWidgets(
'None',
(tester) async {
when(() => mockIAPStorageService.selectedEquipmentProfileId).thenReturn('');
await pumpApplication(tester);
expectReadingValueContainerText(S.current.none);
await tester.openAnimatedPicker<EquipmentProfilePicker>();
expectRadioListTile<EquipmentProfile>(S.current.none, isSelected: true);
},
);
testWidgets(
'Praktica + Zenitar',
(tester) async {
when(() => mockIAPStorageService.selectedEquipmentProfileId).thenReturn(_mockEquipmentProfiles.first.id);
await pumpApplication(tester);
expectReadingValueContainerText(_mockEquipmentProfiles.first.name);
await tester.openAnimatedPicker<EquipmentProfilePicker>();
expectRadioListTile<EquipmentProfile>(_mockEquipmentProfiles.first.name, isSelected: true);
},
);
},
);
}
final _mockEquipmentProfiles = [
EquipmentProfile(
id: '1',
name: 'Praktica + Zenitar',
apertureValues: ApertureValue.values.sublist(
ApertureValue.values.indexOf(const ApertureValue(1.7, StopType.half)),
ApertureValue.values.indexOf(const ApertureValue(16, StopType.full)) + 1,
),
ndValues: NdValue.values.sublist(0, 3),
shutterSpeedValues: ShutterSpeedValue.values.sublist(
ShutterSpeedValue.values.indexOf(const ShutterSpeedValue(1000, true, StopType.full)),
ShutterSpeedValue.values.indexOf(const ShutterSpeedValue(16, false, StopType.full)) + 1,
),
isoValues: const [
IsoValue(50, StopType.full),
IsoValue(100, StopType.full),
IsoValue(200, StopType.full),
IsoValue(250, StopType.third),
IsoValue(400, StopType.full),
IsoValue(500, StopType.third),
IsoValue(800, StopType.full),
IsoValue(1600, StopType.full),
IsoValue(3200, StopType.full),
],
),
const EquipmentProfile(
id: '2',
name: 'Praktica + Jupiter',
apertureValues: ApertureValue.values,
ndValues: NdValue.values,
shutterSpeedValues: ShutterSpeedValue.values,
isoValues: IsoValue.values,
),
];

View file

@ -1,61 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/iso_picker/widget_picker_iso.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import '../../../../../application_mock.dart';
import 'utils.dart';
void main() {
Future<void> pumpApplication(
WidgetTester tester, {
List<IsoValue> values = IsoValue.values,
IsoValue selectedValue = const IsoValue(100, StopType.full),
}) async {
assert(values.contains(selectedValue));
await tester.pumpWidget(
WidgetTestApplicationMock(
child: Row(
children: [
Expanded(
child: IsoValuePicker(
selectedValue: selectedValue,
values: values,
onChanged: (_) {},
),
),
],
),
),
);
await tester.pumpAndSettle();
}
testWidgets(
'Check dialog icon and title consistency',
(tester) async {
await pumpApplication(tester);
expectReadingValueContainerText(S.current.iso);
await tester.openAnimatedPicker<IsoValuePicker>();
expect(find.byIcon(Icons.iso), findsOneWidget);
expectDialogPickerText<IsoValue>(S.current.iso);
expectDialogPickerText<IsoValue>(S.current.filmSpeed);
},
);
group(
'Display selected value',
() {
testWidgets(
'Any',
(tester) async {
await pumpApplication(tester);
expectReadingValueContainerText('100');
await tester.openAnimatedPicker<IsoValuePicker>();
expectRadioListTile<IsoValue>('100', isSelected: true);
},
);
},
);
}

View file

@ -42,6 +42,7 @@ void main() {
expectDialogPickerText<NdValue>(S.current.nd);
expectDialogPickerText<NdValue>(S.current.ndFilterFactor);
},
skip: true,
);
group(