LuxMeteringEvent tests

This commit is contained in:
Vadim 2023-06-12 16:10:40 +02:00
parent 7fdacfac37
commit 8e1b64da64
9 changed files with 143 additions and 22 deletions

View file

@ -15,13 +15,13 @@ import 'package:lightmeter/screens/metering/state_metering.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
final MeteringCommunicationBloc _communicationBloc;
final MeteringInteractor _meteringInteractor;
final MeteringCommunicationBloc _communicationBloc;
late final StreamSubscription<communication_states.ScreenState> _communicationSubscription;
MeteringBloc(
this._communicationBloc,
this._meteringInteractor,
this._communicationBloc,
) : super(
MeteringDataState(
ev100: null,

View file

@ -22,8 +22,28 @@ abstract class MeasuredEvent extends SourceEvent {
class MeteringInProgressEvent extends MeasuredEvent {
const MeteringInProgressEvent(super.ev100);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
return other is MeteringInProgressEvent && other.ev100 == ev100;
}
@override
int get hashCode => Object.hash(ev100, runtimeType);
}
class MeteringEndedEvent extends MeasuredEvent {
const MeteringEndedEvent(super.ev100);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
return other is MeteringEndedEvent && other.ev100 == ev100;
}
@override
int get hashCode => Object.hash(ev100, runtimeType);
}

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.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'
@ -16,35 +17,46 @@ class LightSensorContainerBloc
final MeteringInteractor _meteringInteractor;
StreamSubscription<int>? _luxSubscriptions;
double _ev100 = 0.0;
LightSensorContainerBloc(
this._meteringInteractor,
MeteringCommunicationBloc communicationBloc,
) : super(
communicationBloc,
const LightSensorInitState(),
);
const LightSensorContainerState(null),
) {
on<LuxMeteringEvent>(_onLuxMeteringEvent);
}
@override
void onCommunicationState(communication_states.SourceState communicationState) {
if (communicationState is communication_states.MeasureState) {
if (_luxSubscriptions == null) {
_luxSubscriptions = _meteringInteractor.luxStream().listen((event) {
_ev100 = log2(event.toDouble() / 2.5) + _meteringInteractor.lightSensorEvCalibration;
communicationBloc.add(communication_event.MeteringInProgressEvent(_ev100));
});
_startMetering();
} else {
communicationBloc.add(communication_event.MeteringEndedEvent(_ev100));
_luxSubscriptions?.cancel().then((_) => _luxSubscriptions = null);
_cancelMetering();
}
}
}
@override
Future<void> close() async {
communicationBloc.add(communication_event.MeteringEndedEvent(_ev100));
_luxSubscriptions?.cancel().then((_) => _luxSubscriptions = null);
_cancelMetering();
return super.close();
}
void _onLuxMeteringEvent(LuxMeteringEvent event, Emitter<LightSensorContainerState> emit) {
final ev100 = log2(event.lux.toDouble() / 2.5) + _meteringInteractor.lightSensorEvCalibration;
emit(LightSensorContainerState(ev100));
communicationBloc.add(communication_event.MeteringInProgressEvent(ev100));
}
void _startMetering() {
_luxSubscriptions = _meteringInteractor.luxStream().listen((lux) => add(LuxMeteringEvent(lux)));
}
void _cancelMetering() {
communicationBloc.add(communication_event.MeteringEndedEvent(state.ev100));
_luxSubscriptions?.cancel().then((_) => _luxSubscriptions = null);
}
}

View file

@ -1,3 +1,9 @@
abstract class LightSensorContainerEvent {
const LightSensorContainerEvent();
}
class LuxMeteringEvent extends LightSensorContainerEvent {
final int lux;
const LuxMeteringEvent(this.lux);
}

View file

@ -1,7 +1,5 @@
abstract class LightSensorContainerState {
const LightSensorContainerState();
}
class LightSensorContainerState {
final double? ev100;
class LightSensorInitState extends LightSensorContainerState {
const LightSensorInitState();
const LightSensorContainerState(this.ev100);
}

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart'
@ -21,5 +22,6 @@ abstract class EvSourceBlocBase<E, S> extends Bloc<E, S> {
return super.close();
}
@visibleForTesting
void onCommunicationState(communication_states.SourceState communicationState);
}

View file

@ -34,8 +34,8 @@ class _MeteringFlowState extends State<MeteringFlow> {
BlocProvider(create: (_) => MeteringCommunicationBloc()),
BlocProvider(
create: (context) => MeteringBloc(
context.read<MeteringCommunicationBloc>(),
context.get<MeteringInteractor>(),
context.read<MeteringCommunicationBloc>(),
),
),
],

View file

@ -20,14 +20,14 @@ class _MockMeteringCommunicationBloc extends MockBloc<
class _MockMeteringInteractor extends Mock implements MeteringInteractor {}
void main() {
late _MockMeteringCommunicationBloc communicationBloc;
late _MockMeteringInteractor meteringInteractor;
late _MockMeteringCommunicationBloc communicationBloc;
late MeteringBloc bloc;
const iso100 = IsoValue(100, StopType.full);
setUpAll(() {
communicationBloc = _MockMeteringCommunicationBloc();
meteringInteractor = _MockMeteringInteractor();
communicationBloc = _MockMeteringCommunicationBloc();
when<IsoValue>(() => meteringInteractor.iso).thenReturn(iso100);
when<NdValue>(() => meteringInteractor.ndFilter).thenReturn(NdValue.values.first);
@ -40,8 +40,8 @@ void main() {
setUp(() {
bloc = MeteringBloc(
communicationBloc,
meteringInteractor,
communicationBloc,
);
});

View file

@ -0,0 +1,83 @@
import 'package:bloc_test/bloc_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/light_sensor_container/bloc_container_light_sensor.dart';
import 'package:lightmeter/screens/metering/components/light_sensor_container/state_container_light_sensor.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';
class _MockMeteringCommunicationBloc extends MockBloc<
communication_events.MeteringCommunicationEvent,
communication_states.MeteringCommunicationState> implements MeteringCommunicationBloc {}
class _MockMeteringInteractor extends Mock implements MeteringInteractor {}
void main() {
late _MockMeteringCommunicationBloc communicationBloc;
late _MockMeteringInteractor meteringInteractor;
late LightSensorContainerBloc bloc;
setUpAll(() {
communicationBloc = _MockMeteringCommunicationBloc();
meteringInteractor = _MockMeteringInteractor();
});
setUp(() {
bloc = LightSensorContainerBloc(
meteringInteractor,
communicationBloc,
);
});
tearDown(() {
bloc.close();
});
group(
'`LuxMeteringEvent` tests',
() {
const List<int> luxIterable = [1, 2, 3];
final List<double> resultList = luxIterable.map((lux) => log2(lux / 2.5)).toList();
blocTest<LightSensorContainerBloc, LightSensorContainerState>(
'Turn measuring on/off',
build: () => bloc,
setUp: () {
when(() => meteringInteractor.luxStream())
.thenAnswer((_) => Stream.fromIterable(luxIterable));
when(() => meteringInteractor.lightSensorEvCalibration).thenReturn(0.0);
},
act: (bloc) async {
bloc.onCommunicationState(const communication_states.MeasureState());
await Future.delayed(Duration.zero);
bloc.onCommunicationState(const communication_states.MeasureState());
},
verify: (_) {
verify(() => meteringInteractor.luxStream().listen((_) {})).called(1);
verify(() => meteringInteractor.lightSensorEvCalibration).called(3);
verify(() {
communicationBloc.add(communication_events.MeteringInProgressEvent(resultList[0]));
}).called(1);
verify(() {
communicationBloc.add(communication_events.MeteringInProgressEvent(resultList[1]));
}).called(1);
verify(() {
communicationBloc.add(communication_events.MeteringInProgressEvent(resultList[2]));
}).called(1);
verify(() {
communicationBloc.add(communication_events.MeteringEndedEvent(resultList[2]));
}).called(2); // +1 from dispose
},
expect: () => [
isA<LightSensorContainerState>().having((state) => state.ev100, 'ev100', resultList[0]),
isA<LightSensorContainerState>().having((state) => state.ev100, 'ev100', resultList[1]),
isA<LightSensorContainerState>().having((state) => state.ev100, 'ev100', resultList[2]),
],
);
},
);
}