test: coverage

pull/416/head
RuiAlonso 3 years ago
parent 2cf0e6acd7
commit cd5ed1b161

@ -48,6 +48,7 @@ class GameBloc extends Bloc<GameEvent, GameState> {
}
void _onIncreasedMultiplier(MultiplierIncreased event, Emitter emit) {
print("_onIncreasedMultiplier");
if (state.status.isPlaying) {
emit(
state.copyWith(

@ -35,6 +35,8 @@ class RampMultiplierBehavior extends Component with ParentIsA<SpaceshipRamp> {
return hasChanged && achievedFiveShots && canIncrease;
},
onNewState: (state) {
print("onNewState $state");
readBloc<GameBloc, GameState>().add(const MultiplierIncreased());
},
),

@ -11,7 +11,6 @@ import 'package:mocktail/mocktail.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/spaceship_ramp/behavior/ramp_arrow_blinking_behavior.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_components/src/components/multiball/behaviors/behaviors.dart';
class _TestGame extends Forge2DGame {
@override
@ -133,6 +132,9 @@ void main() {
);
await streamController.close();
await game.ready();
verify(bloc.onStop).called(1);
},
);
@ -168,6 +170,8 @@ void main() {
behavior.onTick();
await game.ready();
expect(behavior.timer.isRunning(), false);
},
);
@ -205,6 +209,8 @@ void main() {
behavior.onTick();
}
await game.ready();
expect(behavior.timer.isRunning(), false);
},
);

@ -1,7 +1,10 @@
// ignore_for_file: cascade_invocations
// ignore_for_file: cascade_invocations, prefer_const_constructors
import 'dart:async';
import 'package:bloc_test/bloc_test.dart';
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
@ -10,7 +13,38 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/spaceship_ramp/behavior/behavior.dart';
import 'package:pinball_flame/pinball_flame.dart';
import '../../../helpers/helpers.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.android.ramp.boardOpening.keyName,
Assets.images.android.ramp.railingForeground.keyName,
Assets.images.android.ramp.railingBackground.keyName,
Assets.images.android.ramp.main.keyName,
Assets.images.android.ramp.arrow.inactive.keyName,
Assets.images.android.ramp.arrow.active1.keyName,
Assets.images.android.ramp.arrow.active2.keyName,
Assets.images.android.ramp.arrow.active3.keyName,
Assets.images.android.ramp.arrow.active4.keyName,
Assets.images.android.ramp.arrow.active5.keyName,
]);
}
Future<void> pump(
SpaceshipRamp child, {
required SpaceshipRampCubit spaceshipRampCubit,
}) async {
await ensureAdd(
FlameBlocProvider<SpaceshipRampCubit, SpaceshipRampState>.value(
value: spaceshipRampCubit,
children: [
ZCanvasComponent(children: [child]),
],
),
);
}
}
class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {}
@ -34,18 +68,100 @@ void main() {
Assets.images.android.ramp.arrow.active4.keyName,
Assets.images.android.ramp.arrow.active5.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
final flameTester = FlameTester(_TestGame.new);
group('SpaceshipRamp', () {
flameTester.test(
'loads correctly',
(game) async {
final spaceshipRamp = SpaceshipRamp();
await game.ensureAdd(spaceshipRamp);
expect(game.children, contains(spaceshipRamp));
final bloc = _MockSpaceshipRampCubit();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: SpaceshipRampState.initial(),
);
final ramp = SpaceshipRamp();
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
expect(game.descendants(), contains(ramp));
},
);
group('loads', () {
flameTester.test(
'a SpaceshipRampBoardOpening',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: SpaceshipRampState.initial(),
);
final ramp = SpaceshipRamp();
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
expect(
game.descendants().whereType<SpaceshipRampBoardOpening>().length,
equals(1),
);
},
);
flameTester.test(
'a SpaceshipRampArrowSpriteComponent',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: SpaceshipRampState.initial(),
);
final ramp = SpaceshipRamp();
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
expect(
game
.descendants()
.whereType<SpaceshipRampArrowSpriteComponent>()
.length,
equals(1),
);
},
);
flameTester.test(
'a RampArrowBlinkingBehavior',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: SpaceshipRampState.initial(),
);
final ramp = SpaceshipRamp();
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
expect(
game.descendants().whereType<RampArrowBlinkingBehavior>().length,
equals(1),
);
},
);
});
group('renders correctly', () {
const goldenFilePath = '../golden/spaceship_ramp/';
final centerForSpaceshipRamp = Vector2(-13, -55);
@ -54,26 +170,35 @@ void main() {
'inactive sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final bloc = _MockSpaceshipRampCubit();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: SpaceshipRampState.initial(),
);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
await tester.pump();
final index = ramp.children
final current = ramp.children
.whereType<SpaceshipRampArrowSpriteComponent>()
.first
.current;
expect(
SpaceshipRampArrowSpriteState.values[index!],
SpaceshipRampArrowSpriteState.inactive,
current,
ArrowLightState.inactive,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
find.byGame<_TestGame>(),
matchesGoldenFile('${goldenFilePath}inactive.png'),
);
},
@ -83,29 +208,41 @@ void main() {
'active1 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
ramp.bloc.onAscendingBallEntered();
streamController.add(
state.copyWith(lightState: ArrowLightState.active1),
);
await game.ready();
await tester.pump();
final index = ramp.children
final current = ramp.children
.whereType<SpaceshipRampArrowSpriteComponent>()
.first
.current;
expect(
SpaceshipRampArrowSpriteState.values[index!],
SpaceshipRampArrowSpriteState.active1,
current,
ArrowLightState.active1,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
find.byGame<_TestGame>(),
matchesGoldenFile('${goldenFilePath}active1.png'),
);
},
@ -115,31 +252,41 @@ void main() {
'active2 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
ramp.bloc
..onAscendingBallEntered()
..onAscendingBallEntered();
streamController.add(
state.copyWith(lightState: ArrowLightState.active2),
);
await game.ready();
await tester.pump();
final index = ramp.children
final current = ramp.children
.whereType<SpaceshipRampArrowSpriteComponent>()
.first
.current;
expect(
SpaceshipRampArrowSpriteState.values[index!],
SpaceshipRampArrowSpriteState.active2,
current,
ArrowLightState.active2,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
find.byGame<_TestGame>(),
matchesGoldenFile('${goldenFilePath}active2.png'),
);
},
@ -149,32 +296,41 @@ void main() {
'active3 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
ramp.bloc
..onAscendingBallEntered()
..onAscendingBallEntered()
..onAscendingBallEntered();
streamController.add(
state.copyWith(lightState: ArrowLightState.active3),
);
await game.ready();
await tester.pump();
final index = ramp.children
final current = ramp.children
.whereType<SpaceshipRampArrowSpriteComponent>()
.first
.current;
expect(
SpaceshipRampArrowSpriteState.values[index!],
SpaceshipRampArrowSpriteState.active3,
current,
ArrowLightState.active3,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
find.byGame<_TestGame>(),
matchesGoldenFile('${goldenFilePath}active3.png'),
);
},
@ -184,33 +340,41 @@ void main() {
'active4 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
ramp.bloc
..onAscendingBallEntered()
..onAscendingBallEntered()
..onAscendingBallEntered()
..onAscendingBallEntered();
streamController.add(
state.copyWith(lightState: ArrowLightState.active4),
);
await game.ready();
await tester.pump();
final index = ramp.children
final current = ramp.children
.whereType<SpaceshipRampArrowSpriteComponent>()
.first
.current;
expect(
SpaceshipRampArrowSpriteState.values[index!],
SpaceshipRampArrowSpriteState.active4,
current,
ArrowLightState.active4,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
find.byGame<_TestGame>(),
matchesGoldenFile('${goldenFilePath}active4.png'),
);
},
@ -220,63 +384,62 @@ void main() {
'active5 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
ramp.bloc
..onAscendingBallEntered()
..onAscendingBallEntered()
..onAscendingBallEntered()
..onAscendingBallEntered()
..onAscendingBallEntered();
streamController.add(
state.copyWith(lightState: ArrowLightState.active5),
);
await game.ready();
await tester.pump();
final index = ramp.children
final current = ramp.children
.whereType<SpaceshipRampArrowSpriteComponent>()
.first
.current;
expect(
SpaceshipRampArrowSpriteState.values[index!],
SpaceshipRampArrowSpriteState.active5,
current,
ArrowLightState.active5,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
find.byGame<_TestGame>(),
matchesGoldenFile('${goldenFilePath}active5.png'),
);
},
);
});
flameTester.test('closes bloc when removed', (game) async {
final bloc = _MockSpaceshipRampCubit();
whenListen(
bloc,
const Stream<SpaceshipRampState>.empty(),
initialState: const SpaceshipRampState.initial(),
);
when(bloc.close).thenAnswer((_) async {});
final ramp = SpaceshipRamp.test();
await game.ensureAdd(ramp);
game.remove(ramp);
await game.ready();
verify(bloc.close).called(1);
});
group('adds', () {
flameTester.test('new children', (game) async {
final bloc = _MockSpaceshipRampCubit();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: SpaceshipRampState.initial(),
);
final component = Component();
final ramp = SpaceshipRamp(children: [component]);
await game.ensureAdd(ramp);
await game.pump(
ramp,
spaceshipRampCubit: bloc,
);
expect(ramp.children, contains(component));
});
});
@ -330,18 +493,24 @@ void main() {
});
flameTester.test('can be loaded', (game) async {
final parent = SpaceshipRamp.test();
final component = SpaceshipRampBoardOpening();
await game.ensureAdd(parent);
final parent = SpaceshipRamp.test();
await game.pump(
parent,
spaceshipRampCubit: _MockSpaceshipRampCubit(),
);
await parent.ensureAdd(component);
expect(parent.children, contains(component));
});
flameTester.test('adds a RampBallAscendingContactBehavior', (game) async {
final parent = SpaceshipRamp.test();
final component = SpaceshipRampBoardOpening();
await game.ensureAdd(parent);
await parent.ensureAdd(component);
final ramp = SpaceshipRamp.test();
await game.pump(
ramp,
spaceshipRampCubit: _MockSpaceshipRampCubit(),
);
await ramp.ensureAdd(component);
expect(
component.children.whereType<RampBallAscendingContactBehavior>().length,
equals(1),

@ -59,8 +59,6 @@ class _MockGameBloc extends Mock implements GameBloc {}
class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {}
class _FakeGameState extends Fake implements GameState {}
class _FakeGameEvent extends Fake implements GameEvent {}
void main() {
@ -70,7 +68,6 @@ void main() {
late GameBloc gameBloc;
setUp(() {
registerFallbackValue(_FakeGameState());
registerFallbackValue(_FakeGameEvent());
gameBloc = _MockGameBloc();
});
@ -82,7 +79,6 @@ void main() {
'when hits are multiples of 5 times and multiplier is less than 6',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final event = MultiplierIncreased();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
@ -95,7 +91,7 @@ void main() {
multiplier: 5,
),
);
when(() => gameBloc.add(event)).thenAnswer((_) async {});
when(() => gameBloc.add(any())).thenAnswer((_) async {});
final behavior = RampMultiplierBehavior();
final parent = SpaceshipRamp.test();
@ -109,7 +105,9 @@ void main() {
streamController.add(state.copyWith(hits: 5));
verify(() => gameBloc.add(event)).called(1);
await game.ready();
verify(() => gameBloc.add(const MultiplierIncreased())).called(1);
},
);
@ -143,6 +141,8 @@ void main() {
streamController.add(state.copyWith(hits: 5));
await game.ready();
verifyNever(() => gameBloc.add(const MultiplierIncreased()));
},
);
@ -177,6 +177,8 @@ void main() {
streamController.add(state.copyWith(hits: 1));
await game.ready();
verifyNever(() => gameBloc.add(const MultiplierIncreased()));
},
);

@ -0,0 +1,310 @@
// ignore_for_file: cascade_invocations, prefer_const_constructors
import 'dart:async';
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/components/android_acres/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.android.ramp.boardOpening.keyName,
Assets.images.android.ramp.railingForeground.keyName,
Assets.images.android.ramp.railingBackground.keyName,
Assets.images.android.ramp.main.keyName,
Assets.images.android.ramp.arrow.inactive.keyName,
Assets.images.android.ramp.arrow.active1.keyName,
Assets.images.android.ramp.arrow.active2.keyName,
Assets.images.android.ramp.arrow.active3.keyName,
Assets.images.android.ramp.arrow.active4.keyName,
Assets.images.android.ramp.arrow.active5.keyName,
Assets.images.android.rail.main.keyName,
Assets.images.android.rail.exit.keyName,
Assets.images.score.fiveThousand.keyName,
]);
}
Future<void> pump(
SpaceshipRamp child, {
required SpaceshipRampCubit spaceshipRampCubit,
required GameBloc gameBloc,
}) async {
await ensureAdd(
FlameBlocProvider<GameBloc, GameState>.value(
value: gameBloc,
children: [
FlameBlocProvider<SpaceshipRampCubit, SpaceshipRampState>.value(
value: spaceshipRampCubit,
children: [
ZCanvasComponent(children: [child]),
],
),
],
),
);
}
}
class _MockGameBloc extends Mock implements GameBloc {}
class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {}
class _FakeGameEvent extends Fake implements GameEvent {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('RampProgressBehavior', () {
late GameBloc gameBloc;
setUp(() {
registerFallbackValue(_FakeGameEvent());
gameBloc = _MockGameBloc();
});
final flameTester = FlameTester(_TestGame.new);
flameTester.test(
'adds onProgressed '
'when hits and multiplier is less than 6',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
when(() => gameBloc.state).thenReturn(
GameState.initial().copyWith(
multiplier: 1,
),
);
final behavior = RampProgressBehavior();
final parent = SpaceshipRamp.test();
await game.pump(
parent,
gameBloc: gameBloc,
spaceshipRampCubit: bloc,
);
await parent.ensureAdd(behavior);
streamController.add(state.copyWith(hits: 5));
await game.ready();
verify(bloc.onProgressed).called(1);
},
);
flameTester.test(
'adds onProgressed '
'when hits and multiplier is 6 but arrow is not full lit',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
when(() => gameBloc.state).thenReturn(
GameState.initial().copyWith(
multiplier: 6,
),
);
final behavior = RampProgressBehavior();
final parent = SpaceshipRamp.test();
await game.pump(
parent,
gameBloc: gameBloc,
spaceshipRampCubit: bloc,
);
await parent.ensureAdd(behavior);
streamController.add(state.copyWith(hits: 5));
await game.ready();
verify(bloc.onProgressed).called(1);
},
);
flameTester.test(
"doesn't add onProgressed "
'when hits and multiplier is 6 and arrow is full lit',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
when(() => gameBloc.state).thenReturn(
GameState.initial().copyWith(
multiplier: 6,
),
);
final behavior = RampProgressBehavior();
final parent = SpaceshipRamp.test();
await game.pump(
parent,
gameBloc: gameBloc,
spaceshipRampCubit: bloc,
);
await parent.ensureAdd(behavior);
streamController.add(
state.copyWith(
hits: 5,
lightState: ArrowLightState.active5,
),
);
await game.ready();
verifyNever(bloc.onProgressed);
},
);
flameTester.test(
'adds onAnimate '
'when arrow is full lit after hit and multiplier is less than 6',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
when(() => gameBloc.state).thenReturn(
GameState.initial().copyWith(
multiplier: 5,
),
);
final behavior = RampProgressBehavior();
final parent = SpaceshipRamp.test();
await game.pump(
parent,
gameBloc: gameBloc,
spaceshipRampCubit: bloc,
);
await parent.ensureAdd(behavior);
streamController.add(
state.copyWith(
hits: 5,
lightState: ArrowLightState.active5,
),
);
await game.ready();
verify(bloc.onAnimate).called(1);
},
);
flameTester.test(
"doesn't add onAnimate "
'when arrow is not full lit after hit',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
when(() => gameBloc.state).thenReturn(
GameState.initial().copyWith(
multiplier: 5,
),
);
final behavior = RampProgressBehavior();
final parent = SpaceshipRamp.test();
await game.pump(
parent,
gameBloc: gameBloc,
spaceshipRampCubit: bloc,
);
await parent.ensureAdd(behavior);
streamController.add(
state.copyWith(
hits: 4,
lightState: ArrowLightState.active4,
),
);
await game.ready();
verifyNever(bloc.onAnimate);
},
);
flameTester.test(
"doesn't add onAnimate "
'when multiplier is 6 after hit',
(game) async {
final bloc = _MockSpaceshipRampCubit();
final state = SpaceshipRampState.initial();
final streamController = StreamController<SpaceshipRampState>();
whenListen(
bloc,
streamController.stream,
initialState: state,
);
when(() => gameBloc.state).thenReturn(
GameState.initial().copyWith(
multiplier: 6,
),
);
final behavior = RampProgressBehavior();
final parent = SpaceshipRamp.test();
await game.pump(
parent,
gameBloc: gameBloc,
spaceshipRampCubit: bloc,
);
await parent.ensureAdd(behavior);
streamController.add(
state.copyWith(hits: 4),
);
await game.ready();
verifyNever(bloc.onAnimate);
},
);
});
}
Loading…
Cancel
Save