From c5865a42527ab7e6724c149aa66e1643322bc7bd Mon Sep 17 00:00:00 2001 From: alestiago Date: Wed, 27 Apr 2022 13:57:31 +0100 Subject: [PATCH] feat: removed FlutterForestCubit --- .../flutter_forest_bonus_behavior.dart | 40 ++++----- .../cubit/flutter_forest_cubit.dart | 29 ------- .../cubit/flutter_forest_state.dart | 26 ------ .../flutter_forest/flutter_forest.dart | 24 ++---- .../dash_nest_bumper/dash_nest_bumper.dart | 5 +- .../flutter_forest_bonus_behavior_test.dart | 84 +++++++++++++++++++ .../flutter_forest/flutter_forest_test.dart | 22 ----- test/helpers/mocks.dart | 2 - 8 files changed, 109 insertions(+), 123 deletions(-) delete mode 100644 lib/game/components/flutter_forest/cubit/flutter_forest_cubit.dart delete mode 100644 lib/game/components/flutter_forest/cubit/flutter_forest_state.dart create mode 100644 test/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior_test.dart diff --git a/lib/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior.dart b/lib/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior.dart index eb651715..1efbb0af 100644 --- a/lib/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior.dart +++ b/lib/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior.dart @@ -10,35 +10,29 @@ class FlutterForestBonusBehavior extends Component @override void onMount() { super.onMount(); - // TODO(alestiago): Refactor subscription management once the following is - // merged: - // https://github.com/flame-engine/flame/pull/1538 - parent.bloc.stream.listen(_onNewState); final bumpers = parent.children.whereType(); for (final bumper in bumpers) { bumper.bloc.stream.listen((state) { - if (state == DashNestBumperState.active) { - parent.bloc.onBumperActivated(bumper); - } - }); - } - } + final hasBonus = bumpers.every( + (bumper) => bumper.bloc.state == DashNestBumperState.active, + ); - void _onNewState(FlutterForestState state) { - if (state.hasBonus) { - gameRef.read().add(const BonusActivated(GameBonus.dashNest)); + if (hasBonus) { + gameRef + .read() + .add(const BonusActivated(GameBonus.dashNest)); + gameRef.add( + ControlledBall.bonus(theme: gameRef.theme) + ..initialPosition = Vector2(17.2, -52.7), + ); + parent.firstChild()?.playing = true; - gameRef.add( - ControlledBall.bonus(theme: gameRef.theme) - ..initialPosition = Vector2(17.2, -52.7), - ); - parent.firstChild()?.playing = true; - for (final bumper in state.activatedBumpers) { - bumper.bloc.onReset(); - } - - parent.bloc.onBonusApplied(); + for (final bumper in bumpers) { + bumper.bloc.onReset(); + } + } + }); } } } diff --git a/lib/game/components/flutter_forest/cubit/flutter_forest_cubit.dart b/lib/game/components/flutter_forest/cubit/flutter_forest_cubit.dart deleted file mode 100644 index 636f6abb..00000000 --- a/lib/game/components/flutter_forest/cubit/flutter_forest_cubit.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:pinball_components/pinball_components.dart'; - -part 'flutter_forest_state.dart'; - -// TODO(alestiago): Evaluate if there is any useful documentation that could -// be added to this class. -// ignore: public_member_api_docs -class FlutterForestCubit extends Cubit { - // ignore: public_member_api_docs - FlutterForestCubit() : super(const FlutterForestState.initial()); - - /// Event added when a bumper contacts with a ball. - void onBumperActivated(DashNestBumper dashNestBumper) { - emit( - state.copyWith( - activatedBumpers: state.activatedBumpers.union({dashNestBumper}), - ), - ); - } - - /// Event added after the bonus is activated. - void onBonusApplied() { - emit( - state.copyWith(activatedBumpers: const {}), - ); - } -} diff --git a/lib/game/components/flutter_forest/cubit/flutter_forest_state.dart b/lib/game/components/flutter_forest/cubit/flutter_forest_state.dart deleted file mode 100644 index d99a2986..00000000 --- a/lib/game/components/flutter_forest/cubit/flutter_forest_state.dart +++ /dev/null @@ -1,26 +0,0 @@ -// ignore_for_file: public_member_api_docs - -part of 'flutter_forest_cubit.dart'; - -class FlutterForestState extends Equatable { - const FlutterForestState({ - required this.activatedBumpers, - }); - - const FlutterForestState.initial() : this(activatedBumpers: const {}); - - final Set activatedBumpers; - - bool get hasBonus => activatedBumpers.length == 3; - - FlutterForestState copyWith({ - Set? activatedBumpers, - }) { - return FlutterForestState( - activatedBumpers: activatedBumpers ?? this.activatedBumpers, - ); - } - - @override - List get props => [activatedBumpers]; -} diff --git a/lib/game/components/flutter_forest/flutter_forest.dart b/lib/game/components/flutter_forest/flutter_forest.dart index c6824e89..327b23fb 100644 --- a/lib/game/components/flutter_forest/flutter_forest.dart +++ b/lib/game/components/flutter_forest/flutter_forest.dart @@ -6,8 +6,6 @@ import 'package:pinball/game/components/flutter_forest/behaviors/behaviors.dart' import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; -export 'cubit/flutter_forest_cubit.dart'; - /// {@template flutter_forest} /// Area positioned at the top right of the [Board] where the [Ball] /// can bounce off [DashNestBumper]s. @@ -15,8 +13,7 @@ export 'cubit/flutter_forest_cubit.dart'; class FlutterForest extends Component { /// {@macro flutter_forest} FlutterForest() - : bloc = FlutterForestCubit(), - super( + : super( children: [ Signpost( children: [ @@ -43,20 +40,9 @@ class FlutterForest extends Component { ], ); - /// {@macro flutter_forest} + /// Creates a [FlutterForest] without any children. + /// + /// This can be used for testing [FlutterForest]'s behaviors in isolation. @visibleForTesting - FlutterForest.test({ - required this.bloc, - }); - - // TODO(alestiago): Consider refactoring once the following is merged: - // https://github.com/flame-engine/flame/pull/1538 - // ignore: public_member_api_docs - final FlutterForestCubit bloc; - - @override - void onRemove() { - bloc.close(); - super.onRemove(); - } + FlutterForest.test(); } diff --git a/packages/pinball_components/lib/src/components/dash_nest_bumper/dash_nest_bumper.dart b/packages/pinball_components/lib/src/components/dash_nest_bumper/dash_nest_bumper.dart index da1c7548..7fcb23d6 100644 --- a/packages/pinball_components/lib/src/components/dash_nest_bumper/dash_nest_bumper.dart +++ b/packages/pinball_components/lib/src/components/dash_nest_bumper/dash_nest_bumper.dart @@ -80,8 +80,9 @@ class DashNestBumper extends BodyComponent with InitialPosition { /// {@macro dash_nest_bumper} @visibleForTesting - DashNestBumper.test({required this.bloc}) - : _majorRadius = 3, + DashNestBumper.test({DashNestBumperCubit? bloc}) + : bloc = bloc ?? DashNestBumperCubit(), + _majorRadius = 3, _minorRadius = 2.5; final double _majorRadius; diff --git a/test/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior_test.dart b/test/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior_test.dart new file mode 100644 index 00000000..25eb83a2 --- /dev/null +++ b/test/game/components/flutter_forest/behaviors/flutter_forest_bonus_behavior_test.dart @@ -0,0 +1,84 @@ +// ignore_for_file: cascade_invocations + +import 'dart:async'; + +import 'package:bloc_test/bloc_test.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/flutter_forest/behaviors/behaviors.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; + +import '../../../../helpers/helpers.dart'; + +void main() { + group('FlutterForestBonusBehavior', () { + late GameBloc gameBloc; + + setUp(() { + gameBloc = MockGameBloc(); + whenListen( + gameBloc, + const Stream.empty(), + initialState: const GameState.initial(), + ); + }); + + final flameBlocTester = FlameBlocTester( + gameBuilder: EmptyPinballTestGame.new, + blocBuilder: () => gameBloc, + ); + + flameBlocTester.testGameWidget( + 'adds GameBonus.dashNest to the game when all bumpers are active', + setUp: (game, tester) async { + final behavior = FlutterForestBonusBehavior(); + final parent = FlutterForest.test(); + final bumpers = [ + DashNestBumper.test(), + DashNestBumper.test(), + DashNestBumper.test(), + ]; + await parent.addAll(bumpers); + await game.ensureAdd(parent); + await parent.ensureAdd(behavior); + + for (final bumper in bumpers) { + bumper.bloc.onBallContacted(); + } + await tester.pump(); + + verify( + () => gameBloc.add(const BonusActivated(GameBonus.dashNest)), + ).called(1); + }, + ); + + flameBlocTester.testGameWidget( + 'adds a new ball to the game when all bumpers are active', + setUp: (game, tester) async { + final behavior = FlutterForestBonusBehavior(); + final parent = FlutterForest.test(); + final bumpers = [ + DashNestBumper.test(), + DashNestBumper.test(), + DashNestBumper.test(), + ]; + await parent.addAll(bumpers); + await game.ensureAdd(parent); + await parent.ensureAdd(behavior); + + for (final bumper in bumpers) { + bumper.bloc.onBallContacted(); + } + await game.ready(); + + expect( + game.descendants().whereType().single, + isNotNull, + ); + }, + ); + }); +} diff --git a/test/game/components/flutter_forest/flutter_forest_test.dart b/test/game/components/flutter_forest/flutter_forest_test.dart index 0db37840..4f32e0f4 100644 --- a/test/game/components/flutter_forest/flutter_forest_test.dart +++ b/test/game/components/flutter_forest/flutter_forest_test.dart @@ -1,9 +1,7 @@ // ignore_for_file: cascade_invocations -import 'package:bloc_test/bloc_test.dart'; import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; @@ -78,25 +76,5 @@ void main() { }, ); }); - - // TODO(alestiago): Consider refactoring once the following is merged: - // https://github.com/flame-engine/flame/pull/1538 - // ignore: public_member_api_docs - flameTester.test('closes bloc when removed', (game) async { - final bloc = MockFlutterForestCubit(); - whenListen( - bloc, - const Stream.empty(), - initialState: const FlutterForestState.initial(), - ); - when(bloc.close).thenAnswer((_) async {}); - final flutterForest = FlutterForest.test(bloc: bloc); - - await game.ensureAdd(flutterForest); - game.remove(flutterForest); - await game.ready(); - - verify(bloc.close).called(1); - }); }); } diff --git a/test/helpers/mocks.dart b/test/helpers/mocks.dart index 0f7f7464..da6f5124 100644 --- a/test/helpers/mocks.dart +++ b/test/helpers/mocks.dart @@ -85,5 +85,3 @@ class MockGameFlowController extends Mock implements GameFlowController {} class MockAlienBumper extends Mock implements AlienBumper {} class MockSparkyBumper extends Mock implements SparkyBumper {} - -class MockFlutterForestCubit extends Mock implements FlutterForestCubit {}