import 'package:bloc_test/bloc_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; void main() { group('GameBloc', () { test('initial state has 3 rounds and empty score', () { final gameBloc = GameBloc(); expect(gameBloc.state.roundScore, equals(0)); expect(gameBloc.state.rounds, equals(3)); }); blocTest( 'GameStarted starts the game', build: GameBloc.new, act: (bloc) => bloc.add(const GameStarted()), expect: () => [ isA() ..having( (state) => state.status, 'status', GameStatus.playing, ), ], ); blocTest( 'GameOver finishes the game', build: GameBloc.new, act: (bloc) => bloc.add(const GameOver()), expect: () => [ isA() ..having( (state) => state.status, 'status', GameStatus.gameOver, ), ], ); group('RoundLost', () { blocTest( 'decreases number of rounds ' 'when there are already available rounds', build: GameBloc.new, act: (bloc) { bloc.add(const RoundLost()); }, expect: () => [ isA()..having((state) => state.rounds, 'rounds', 2), ], ); blocTest( 'sets game over when there are no more rounds', build: GameBloc.new, act: (bloc) { bloc ..add(const RoundLost()) ..add(const RoundLost()) ..add(const RoundLost()); }, expect: () => [ isA()..having((state) => state.rounds, 'rounds', 2), isA()..having((state) => state.rounds, 'rounds', 1), isA() ..having((state) => state.rounds, 'rounds', 0) ..having((state) => state.status, 'status', GameStatus.gameOver), ], ); blocTest( 'apply multiplier to roundScore and add it to totalScore ' 'when round is lost', build: GameBloc.new, seed: () => const GameState( totalScore: 10, roundScore: 5, multiplier: 3, rounds: 2, bonusHistory: [], status: GameStatus.playing, ), act: (bloc) { bloc.add(const RoundLost()); }, expect: () => [ isA() ..having((state) => state.totalScore, 'totalScore', 25) ..having((state) => state.roundScore, 'roundScore', 0) ], ); blocTest( 'resets multiplier when round is lost', build: GameBloc.new, seed: () => const GameState( totalScore: 10, roundScore: 5, multiplier: 3, rounds: 2, bonusHistory: [], status: GameStatus.playing, ), act: (bloc) { bloc.add(const RoundLost()); }, expect: () => [ isA()..having((state) => state.multiplier, 'multiplier', 1) ], ); }); group('Scored', () { blocTest( 'increases score when playing', build: GameBloc.new, act: (bloc) => bloc ..add(const GameStarted()) ..add(const Scored(points: 2)) ..add(const Scored(points: 3)), expect: () => [ isA() ..having((state) => state.status, 'status', GameStatus.playing), isA() ..having((state) => state.roundScore, 'roundScore', 2) ..having((state) => state.status, 'status', GameStatus.playing), isA() ..having((state) => state.roundScore, 'roundScore', 5) ..having((state) => state.status, 'status', GameStatus.playing), ], ); blocTest( "doesn't increase score when game is over", build: GameBloc.new, act: (bloc) { for (var i = 0; i < bloc.state.rounds; i++) { bloc.add(const RoundLost()); } bloc.add(const Scored(points: 2)); }, expect: () => [ isA() ..having((state) => state.roundScore, 'roundScore', 0) ..having((state) => state.rounds, 'rounds', 2) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), isA() ..having((state) => state.roundScore, 'roundScore', 0) ..having((state) => state.rounds, 'rounds', 1) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), isA() ..having((state) => state.roundScore, 'roundScore', 0) ..having((state) => state.rounds, 'rounds', 0) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), ], ); }); group('MultiplierIncreased', () { blocTest( 'increases multiplier ' 'when multiplier is below 6 and game is not over', build: GameBloc.new, act: (bloc) => bloc ..add(const GameStarted()) ..add(const MultiplierIncreased()) ..add(const MultiplierIncreased()), expect: () => [ isA() ..having((state) => state.status, 'status', GameStatus.playing), isA() ..having((state) => state.multiplier, 'multiplier', 2) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), isA() ..having((state) => state.multiplier, 'multiplier', 3) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), ], ); blocTest( "doesn't increase multiplier " 'when multiplier is 6 and game is not over', build: GameBloc.new, seed: () => const GameState( totalScore: 10, roundScore: 0, multiplier: 6, rounds: 3, bonusHistory: [], status: GameStatus.playing, ), act: (bloc) => bloc..add(const MultiplierIncreased()), expect: () => const [], ); blocTest( "doesn't increase multiplier " 'when game is over', build: GameBloc.new, act: (bloc) { bloc.add(const GameStarted()); for (var i = 0; i < bloc.state.rounds; i++) { bloc.add(const RoundLost()); } bloc.add(const MultiplierIncreased()); }, expect: () => [ isA() ..having((state) => state.status, 'status', GameStatus.playing), isA() ..having((state) => state.multiplier, 'multiplier', 1) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), isA() ..having((state) => state.multiplier, 'multiplier', 1) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), isA() ..having((state) => state.multiplier, 'multiplier', 1) ..having( (state) => state.status, 'status', GameStatus.gameOver, ), ], ); }); group( 'BonusActivated', () { blocTest( 'adds bonus to history', build: GameBloc.new, act: (bloc) => bloc ..add(const BonusActivated(GameBonus.googleWord)) ..add(const BonusActivated(GameBonus.dashNest)), expect: () => [ isA() ..having( (state) => state.bonusHistory, 'bonusHistory', [GameBonus.googleWord], ), isA() ..having( (state) => state.bonusHistory, 'bonusHistory', [GameBonus.googleWord, GameBonus.dashNest], ), ], ); }, ); }); }