mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-24 08:20:40 +00:00
Compare commits
No commits in common. "f9b18330cd89f053390bcbeab3e663897461ec0d" and "2eb94f8a09ec35694f31b4ca20da6ac6f363c8fc" have entirely different histories.
f9b18330cd
...
2eb94f8a09
8 changed files with 9 additions and 493 deletions
|
@ -53,6 +53,8 @@ class CameraContainerBloc extends EvSourceBlocBase<CameraContainerEvent, CameraC
|
||||||
on<ZoomChangedEvent>(_onZoomChanged);
|
on<ZoomChangedEvent>(_onZoomChanged);
|
||||||
on<ExposureOffsetChangedEvent>(_onExposureOffsetChanged);
|
on<ExposureOffsetChangedEvent>(_onExposureOffsetChanged);
|
||||||
on<ExposureOffsetResetEvent>(_onExposureOffsetResetEvent);
|
on<ExposureOffsetResetEvent>(_onExposureOffsetResetEvent);
|
||||||
|
|
||||||
|
add(const RequestPermissionEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -122,7 +124,7 @@ class CameraContainerBloc extends EvSourceBlocBase<CameraContainerEvent, CameraC
|
||||||
_zoomRange = await Future.wait<double>([
|
_zoomRange = await Future.wait<double>([
|
||||||
_cameraController!.getMinZoomLevel(),
|
_cameraController!.getMinZoomLevel(),
|
||||||
_cameraController!.getMaxZoomLevel(),
|
_cameraController!.getMaxZoomLevel(),
|
||||||
]).then((levels) => RangeValues(math.max(1.0, levels[0]), math.min(_maxZoom, levels[1])));
|
]).then((levels) => RangeValues(levels[0], math.min(_maxZoom, levels[1])));
|
||||||
_currentZoom = _zoomRange!.start;
|
_currentZoom = _zoomRange!.start;
|
||||||
|
|
||||||
_exposureOffsetRange = await Future.wait<double>([
|
_exposureOffsetRange = await Future.wait<double>([
|
||||||
|
@ -208,8 +210,8 @@ class CameraContainerBloc extends EvSourceBlocBase<CameraContainerEvent, CameraC
|
||||||
final speed = speedValueRatio.numerator / speedValueRatio.denominator;
|
final speed = speedValueRatio.numerator / speedValueRatio.denominator;
|
||||||
|
|
||||||
return log2(math.pow(aperture, 2)) - log2(speed) - log2(iso / 100);
|
return log2(math.pow(aperture, 2)) - log2(speed) - log2(iso / 100);
|
||||||
} catch (e) {
|
} on CameraException catch (e) {
|
||||||
log(e.toString());
|
log('Error: ${e.code}\nError Message: ${e.description}');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,32 +22,12 @@ class ZoomChangedEvent extends CameraContainerEvent {
|
||||||
final double value;
|
final double value;
|
||||||
|
|
||||||
const ZoomChangedEvent(this.value);
|
const ZoomChangedEvent(this.value);
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
if (other.runtimeType != runtimeType) return false;
|
|
||||||
return other is ZoomChangedEvent && other.value == value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(value, runtimeType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExposureOffsetChangedEvent extends CameraContainerEvent {
|
class ExposureOffsetChangedEvent extends CameraContainerEvent {
|
||||||
final double value;
|
final double value;
|
||||||
|
|
||||||
const ExposureOffsetChangedEvent(this.value);
|
const ExposureOffsetChangedEvent(this.value);
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
if (other.runtimeType != runtimeType) return false;
|
|
||||||
return other is ExposureOffsetChangedEvent && other.value == value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(value, runtimeType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExposureOffsetResetEvent extends CameraContainerEvent {
|
class ExposureOffsetResetEvent extends CameraContainerEvent {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'package:lightmeter/data/models/film.dart';
|
||||||
import 'package:lightmeter/interactors/metering_interactor.dart';
|
import 'package:lightmeter/interactors/metering_interactor.dart';
|
||||||
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart';
|
import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/widget_container_camera.dart';
|
import 'package:lightmeter/screens/metering/components/camera_container/widget_container_camera.dart';
|
||||||
import 'package:lightmeter/utils/inherited_generics.dart';
|
import 'package:lightmeter/utils/inherited_generics.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
@ -41,7 +40,7 @@ class CameraContainerProvider extends StatelessWidget {
|
||||||
create: (context) => CameraContainerBloc(
|
create: (context) => CameraContainerBloc(
|
||||||
context.get<MeteringInteractor>(),
|
context.get<MeteringInteractor>(),
|
||||||
context.read<MeteringCommunicationBloc>(),
|
context.read<MeteringCommunicationBloc>(),
|
||||||
)..add(const RequestPermissionEvent()),
|
),
|
||||||
child: CameraContainer(
|
child: CameraContainer(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
|
|
|
@ -34,28 +34,6 @@ class CameraActiveState extends CameraContainerState {
|
||||||
required this.exposureOffsetStep,
|
required this.exposureOffsetStep,
|
||||||
required this.currentExposureOffset,
|
required this.currentExposureOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
if (other.runtimeType != runtimeType) return false;
|
|
||||||
return other is CameraActiveState &&
|
|
||||||
other.zoomRange == zoomRange &&
|
|
||||||
other.currentZoom == currentZoom &&
|
|
||||||
other.exposureOffsetRange == exposureOffsetRange &&
|
|
||||||
other.exposureOffsetStep == exposureOffsetStep &&
|
|
||||||
other.currentExposureOffset == currentExposureOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(
|
|
||||||
runtimeType,
|
|
||||||
zoomRange,
|
|
||||||
currentZoom,
|
|
||||||
exposureOffsetRange,
|
|
||||||
exposureOffsetStep,
|
|
||||||
currentExposureOffset,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CameraErrorState extends CameraContainerState {
|
class CameraErrorState extends CameraContainerState {
|
||||||
|
|
|
@ -40,8 +40,6 @@ dev_dependencies:
|
||||||
build_runner: ^2.1.7
|
build_runner: ^2.1.7
|
||||||
flutter_launcher_icons: 0.11.0
|
flutter_launcher_icons: 0.11.0
|
||||||
flutter_native_splash: 2.2.16
|
flutter_native_splash: 2.2.16
|
||||||
flutter_test:
|
|
||||||
sdk: flutter
|
|
||||||
google_fonts: 3.0.1
|
google_fonts: 3.0.1
|
||||||
lint: 2.1.2
|
lint: 2.1.2
|
||||||
mocktail: 0.3.0
|
mocktail: 0.3.0
|
||||||
|
|
|
@ -51,6 +51,7 @@ void main() {
|
||||||
isA<MeasureState>(),
|
isA<MeasureState>(),
|
||||||
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', 1),
|
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', 1),
|
||||||
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', null),
|
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', null),
|
||||||
|
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', null),
|
||||||
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', 2),
|
isA<MeteringInProgressState>().having((state) => state.ev100, 'ev100', 2),
|
||||||
isA<MeasureState>(),
|
isA<MeasureState>(),
|
||||||
isA<MeteringEndedState>().having((state) => state.ev100, 'ev100', 2),
|
isA<MeteringEndedState>().having((state) => state.ev100, 'ev100', 2),
|
||||||
|
|
|
@ -1,442 +0,0 @@
|
||||||
import 'package:bloc_test/bloc_test.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:lightmeter/interactors/metering_interactor.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart'
|
|
||||||
as communication_events;
|
|
||||||
import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart'
|
|
||||||
as communication_states;
|
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/state_container_camera.dart';
|
|
||||||
import 'package:mocktail/mocktail.dart';
|
|
||||||
|
|
||||||
class _MockMeteringCommunicationBloc extends MockBloc<
|
|
||||||
communication_events.MeteringCommunicationEvent,
|
|
||||||
communication_states.MeteringCommunicationState> implements MeteringCommunicationBloc {}
|
|
||||||
|
|
||||||
class _MockMeteringInteractor extends Mock implements MeteringInteractor {}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
|
|
||||||
late _MockMeteringInteractor meteringInteractor;
|
|
||||||
late _MockMeteringCommunicationBloc communicationBloc;
|
|
||||||
late CameraContainerBloc bloc;
|
|
||||||
|
|
||||||
const cameraMethodChannel = MethodChannel('plugins.flutter.io/camera');
|
|
||||||
const cameraIdMethodChannel = MethodChannel('flutter.io/cameraPlugin/camera1');
|
|
||||||
const availableCameras = [
|
|
||||||
{
|
|
||||||
"name": "front",
|
|
||||||
"lensFacing": "front",
|
|
||||||
"sensorOrientation": 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "back",
|
|
||||||
"lensFacing": "back",
|
|
||||||
"sensorOrientation": 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Future<Object?>? cameraMethodCallSuccessHandler(MethodCall methodCall) async {
|
|
||||||
switch (methodCall.method) {
|
|
||||||
case "availableCameras":
|
|
||||||
return availableCameras;
|
|
||||||
case "create":
|
|
||||||
return {"cameraId": 1};
|
|
||||||
case "initialize":
|
|
||||||
await cameraIdMethodChannel.invokeMockMethod("initialized", {
|
|
||||||
'cameraId': 1,
|
|
||||||
'previewWidth': 2160.0,
|
|
||||||
'previewHeight': 3840.0,
|
|
||||||
'exposureMode': 'auto',
|
|
||||||
'exposurePointSupported': true,
|
|
||||||
'focusMode': 'auto',
|
|
||||||
'focusPointSupported': true,
|
|
||||||
});
|
|
||||||
return {};
|
|
||||||
case "setFlashMode":
|
|
||||||
return null;
|
|
||||||
case "getMinZoomLevel":
|
|
||||||
return 0.67;
|
|
||||||
case "getMaxZoomLevel":
|
|
||||||
return 7.0;
|
|
||||||
case "getMinExposureOffset":
|
|
||||||
return -4.0;
|
|
||||||
case "getMaxExposureOffset":
|
|
||||||
return 4.0;
|
|
||||||
case "getExposureOffsetStepSize":
|
|
||||||
return 0.1666666;
|
|
||||||
case "takePicture":
|
|
||||||
return "";
|
|
||||||
case "setExposureOffset":
|
|
||||||
// ignore: avoid_dynamic_calls
|
|
||||||
return methodCall.arguments["offset"];
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final initializedStateSequence = [
|
|
||||||
isA<CameraLoadingState>(),
|
|
||||||
isA<CameraInitializedState>(),
|
|
||||||
isA<CameraActiveState>()
|
|
||||||
.having((state) => state.zoomRange, 'zoomRange', const RangeValues(1.0, 7.0))
|
|
||||||
.having((state) => state.currentZoom, 'currentZoom', 1.0)
|
|
||||||
.having(
|
|
||||||
(state) => state.exposureOffsetRange,
|
|
||||||
'exposureOffsetRange',
|
|
||||||
const RangeValues(-4.0, 4.0),
|
|
||||||
)
|
|
||||||
.having((state) => state.exposureOffsetStep, 'exposureOffsetStep', 0.1666666)
|
|
||||||
.having((state) => state.currentExposureOffset, 'currentExposureOffset', 0.0),
|
|
||||||
];
|
|
||||||
|
|
||||||
setUpAll(() {
|
|
||||||
meteringInteractor = _MockMeteringInteractor();
|
|
||||||
communicationBloc = _MockMeteringCommunicationBloc();
|
|
||||||
|
|
||||||
when(() => meteringInteractor.cameraEvCalibration).thenReturn(0.0);
|
|
||||||
when(meteringInteractor.quickVibration).thenAnswer((_) async {});
|
|
||||||
});
|
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
bloc = CameraContainerBloc(
|
|
||||||
meteringInteractor,
|
|
||||||
communicationBloc,
|
|
||||||
);
|
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(cameraMethodChannel, cameraMethodCallSuccessHandler);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() {
|
|
||||||
bloc.close();
|
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(cameraMethodChannel, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
group(
|
|
||||||
'`RequestPermissionEvent` tests',
|
|
||||||
() {
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Request denied',
|
|
||||||
build: () => bloc,
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.requestPermission()).thenAnswer((_) async => false);
|
|
||||||
},
|
|
||||||
act: (bloc) => bloc.add(const RequestPermissionEvent()),
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.requestPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<CameraErrorState>()
|
|
||||||
.having((state) => state.error, "error", CameraErrorType.permissionNotGranted),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Request granted -> check denied',
|
|
||||||
build: () => bloc,
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.requestPermission()).thenAnswer((_) async => true);
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => false);
|
|
||||||
},
|
|
||||||
act: (bloc) => bloc.add(const RequestPermissionEvent()),
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.requestPermission()).called(1);
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<CameraLoadingState>(),
|
|
||||||
isA<CameraErrorState>()
|
|
||||||
.having((state) => state.error, "error", CameraErrorType.permissionNotGranted),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Request granted -> check granted',
|
|
||||||
build: () => bloc,
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.requestPermission()).thenAnswer((_) async => true);
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
},
|
|
||||||
act: (bloc) => bloc.add(const RequestPermissionEvent()),
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.requestPermission()).called(1);
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
...initializedStateSequence,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
group(
|
|
||||||
'`InitializeEvent`/`DeinitializeEvent` tests',
|
|
||||||
() {
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'No cameras detected error',
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(
|
|
||||||
cameraMethodChannel,
|
|
||||||
(methodCall) async {
|
|
||||||
switch (methodCall.method) {
|
|
||||||
case "availableCameras":
|
|
||||||
return const [];
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
tearDown: () {
|
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(cameraMethodChannel, null);
|
|
||||||
},
|
|
||||||
build: () => bloc,
|
|
||||||
act: (bloc) => bloc.add(const InitializeEvent()),
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<CameraLoadingState>(),
|
|
||||||
isA<CameraErrorState>()
|
|
||||||
.having((state) => state.error, "error", CameraErrorType.noCamerasDetected),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Catch other initialization errors',
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(
|
|
||||||
cameraMethodChannel,
|
|
||||||
(methodCall) async {
|
|
||||||
switch (methodCall.method) {
|
|
||||||
case "availableCameras":
|
|
||||||
return availableCameras;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
tearDown: () {
|
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
.setMockMethodCallHandler(cameraMethodChannel, null);
|
|
||||||
},
|
|
||||||
build: () => bloc,
|
|
||||||
act: (bloc) => bloc.add(const InitializeEvent()),
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<CameraLoadingState>(),
|
|
||||||
isA<CameraErrorState>().having((state) => state.error, "error", CameraErrorType.other),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'appLifecycleStateObserver',
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
},
|
|
||||||
build: () => bloc,
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const InitializeEvent());
|
|
||||||
await Future.delayed(Duration.zero);
|
|
||||||
TestWidgetsFlutterBinding.instance
|
|
||||||
.handleAppLifecycleStateChanged(AppLifecycleState.detached);
|
|
||||||
TestWidgetsFlutterBinding.instance
|
|
||||||
.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(2);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
...initializedStateSequence,
|
|
||||||
...initializedStateSequence,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
group(
|
|
||||||
'`_takePicture()` tests',
|
|
||||||
() {
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Returned ev100 == null',
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
},
|
|
||||||
build: () => bloc,
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const InitializeEvent());
|
|
||||||
await Future.delayed(Duration.zero);
|
|
||||||
bloc.onCommunicationState(const communication_states.MeasureState());
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
verifyNever(() => meteringInteractor.cameraEvCalibration);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
...initializedStateSequence,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO(vodemn): figure out how to mock `_file.readAsBytes()`
|
|
||||||
// blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
// 'Returned non-null ev100',
|
|
||||||
// setUp: () {
|
|
||||||
// when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
// TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
// .setMockMethodCallHandler(cameraMethodChannel, cameraMethodCallSuccessHandler);
|
|
||||||
// },
|
|
||||||
// tearDown: () {
|
|
||||||
// TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
||||||
// .setMockMethodCallHandler(cameraMethodChannel, null);
|
|
||||||
// },
|
|
||||||
// build: () => bloc,
|
|
||||||
// act: (bloc) async {
|
|
||||||
// bloc.add(const InitializeEvent());
|
|
||||||
// await Future.delayed(Duration.zero);
|
|
||||||
// bloc.onCommunicationState(const communication_states.MeasureState());
|
|
||||||
// },
|
|
||||||
// verify: (_) {
|
|
||||||
// verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
// verifyNever(() => meteringInteractor.cameraEvCalibration);
|
|
||||||
// verify(() {
|
|
||||||
// communicationBloc.add(const communication_events.MeteringEndedEvent(null));
|
|
||||||
// }).called(2);
|
|
||||||
// },
|
|
||||||
// expect: () => [
|
|
||||||
// ...initializedStateSequence,
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
},
|
|
||||||
skip: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
group(
|
|
||||||
'`ZoomChangedEvent` tests',
|
|
||||||
() {
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Set zoom multiple times',
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
},
|
|
||||||
build: () => bloc,
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const InitializeEvent());
|
|
||||||
await Future.delayed(Duration.zero);
|
|
||||||
bloc.add(const ZoomChangedEvent(2.0));
|
|
||||||
bloc.add(const ZoomChangedEvent(2.0));
|
|
||||||
bloc.add(const ZoomChangedEvent(2.0));
|
|
||||||
bloc.add(const ZoomChangedEvent(3.0));
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
...initializedStateSequence,
|
|
||||||
isA<CameraActiveState>()
|
|
||||||
.having((state) => state.zoomRange, 'zoomRange', const RangeValues(1.0, 7.0))
|
|
||||||
.having((state) => state.currentZoom, 'currentZoom', 2.0)
|
|
||||||
.having(
|
|
||||||
(state) => state.exposureOffsetRange,
|
|
||||||
'exposureOffsetRange',
|
|
||||||
const RangeValues(-4.0, 4.0),
|
|
||||||
)
|
|
||||||
.having((state) => state.exposureOffsetStep, 'exposureOffsetStep', 0.1666666)
|
|
||||||
.having((state) => state.currentExposureOffset, 'currentExposureOffset', 0.0),
|
|
||||||
isA<CameraActiveState>()
|
|
||||||
.having((state) => state.zoomRange, 'zoomRange', const RangeValues(1.0, 7.0))
|
|
||||||
.having((state) => state.currentZoom, 'currentZoom', 3.0)
|
|
||||||
.having(
|
|
||||||
(state) => state.exposureOffsetRange,
|
|
||||||
'exposureOffsetRange',
|
|
||||||
const RangeValues(-4.0, 4.0),
|
|
||||||
)
|
|
||||||
.having((state) => state.exposureOffsetStep, 'exposureOffsetStep', 0.1666666)
|
|
||||||
.having((state) => state.currentExposureOffset, 'currentExposureOffset', 0.0),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
group(
|
|
||||||
'`ExposureOffsetChangedEvent`/`ExposureOffsetResetEvent` tests',
|
|
||||||
() {
|
|
||||||
blocTest<CameraContainerBloc, CameraContainerState>(
|
|
||||||
'Set exposure offset multiple times and reset',
|
|
||||||
setUp: () {
|
|
||||||
when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true);
|
|
||||||
},
|
|
||||||
build: () => bloc,
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const InitializeEvent());
|
|
||||||
await Future.delayed(Duration.zero);
|
|
||||||
bloc.add(const ExposureOffsetChangedEvent(2.0));
|
|
||||||
bloc.add(const ExposureOffsetChangedEvent(2.0));
|
|
||||||
bloc.add(const ExposureOffsetChangedEvent(2.0));
|
|
||||||
bloc.add(const ExposureOffsetChangedEvent(3.0));
|
|
||||||
bloc.add(const ExposureOffsetResetEvent());
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.checkCameraPermission()).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
...initializedStateSequence,
|
|
||||||
isA<CameraActiveState>()
|
|
||||||
.having((state) => state.zoomRange, 'zoomRange', const RangeValues(1.0, 7.0))
|
|
||||||
.having((state) => state.currentZoom, 'currentZoom', 1.0)
|
|
||||||
.having(
|
|
||||||
(state) => state.exposureOffsetRange,
|
|
||||||
'exposureOffsetRange',
|
|
||||||
const RangeValues(-4.0, 4.0),
|
|
||||||
)
|
|
||||||
.having((state) => state.exposureOffsetStep, 'exposureOffsetStep', 0.1666666)
|
|
||||||
.having((state) => state.currentExposureOffset, 'currentExposureOffset', 2.0),
|
|
||||||
isA<CameraActiveState>()
|
|
||||||
.having((state) => state.zoomRange, 'zoomRange', const RangeValues(1.0, 7.0))
|
|
||||||
.having((state) => state.currentZoom, 'currentZoom', 1.0)
|
|
||||||
.having(
|
|
||||||
(state) => state.exposureOffsetRange,
|
|
||||||
'exposureOffsetRange',
|
|
||||||
const RangeValues(-4.0, 4.0),
|
|
||||||
)
|
|
||||||
.having((state) => state.exposureOffsetStep, 'exposureOffsetStep', 0.1666666)
|
|
||||||
.having((state) => state.currentExposureOffset, 'currentExposureOffset', 3.0),
|
|
||||||
isA<CameraActiveState>()
|
|
||||||
.having((state) => state.zoomRange, 'zoomRange', const RangeValues(1.0, 7.0))
|
|
||||||
.having((state) => state.currentZoom, 'currentZoom', 1.0)
|
|
||||||
.having(
|
|
||||||
(state) => state.exposureOffsetRange,
|
|
||||||
'exposureOffsetRange',
|
|
||||||
const RangeValues(-4.0, 4.0),
|
|
||||||
)
|
|
||||||
.having((state) => state.exposureOffsetStep, 'exposureOffsetStep', 0.1666666)
|
|
||||||
.having((state) => state.currentExposureOffset, 'currentExposureOffset', 0.0),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _MethodChannelMock on MethodChannel {
|
|
||||||
Future<void> invokeMockMethod(String method, dynamic arguments) async {
|
|
||||||
final data = const StandardMethodCodec().encodeMethodCall(MethodCall(method, arguments));
|
|
||||||
await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
|
|
||||||
name,
|
|
||||||
data,
|
|
||||||
(ByteData? data) {},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,13 +18,13 @@ class _MockMeteringCommunicationBloc extends MockBloc<
|
||||||
class _MockMeteringInteractor extends Mock implements MeteringInteractor {}
|
class _MockMeteringInteractor extends Mock implements MeteringInteractor {}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
late _MockMeteringInteractor meteringInteractor;
|
|
||||||
late _MockMeteringCommunicationBloc communicationBloc;
|
late _MockMeteringCommunicationBloc communicationBloc;
|
||||||
|
late _MockMeteringInteractor meteringInteractor;
|
||||||
late LightSensorContainerBloc bloc;
|
late LightSensorContainerBloc bloc;
|
||||||
|
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
meteringInteractor = _MockMeteringInteractor();
|
|
||||||
communicationBloc = _MockMeteringCommunicationBloc();
|
communicationBloc = _MockMeteringCommunicationBloc();
|
||||||
|
meteringInteractor = _MockMeteringInteractor();
|
||||||
});
|
});
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
|
|
Loading…
Reference in a new issue