class TestPresentStartMenuOptionsUseCase(TestCase):
    def setUp(self):
        self.minefield_repository = InMemoryMinefieldRepository()
        self.subject = PresentStartMenuOptionsUseCase(minefield_repository=self.minefield_repository)

    def test_present_start_menu_options_without_existing_minefields(self):
        menu_options = get_keywords(test_action_method=self.subject,
                                    keyword_argument='menu_options',
                                    spy_class=PresentStartMenuOptionsUseCaseObserver,
                                    spied_upon_method_name='did_present_start_menu_options')
        expected_menu_options = MenuOptions(
            options=[StartMenuOptionType.StartNewGame, StartMenuOptionType.Quit],
            initially_selected_option=StartMenuOptionType.StartNewGame)

        self.assertEqual(menu_options, expected_menu_options)

    def test_present_start_menu_options_with_existing_minefields(self):
        self.minefield_repository.create_minefield(board=Board(row_count=5, column_count=5),
                                                   mine_coordinates=frozenset([Coordinate(1, 1)]))
        menu_options = get_keywords(test_action_method=self.subject,
                                    keyword_argument='menu_options',
                                    spy_class=PresentStartMenuOptionsUseCaseObserver,
                                    spied_upon_method_name='did_present_start_menu_options')
        expected_options = [StartMenuOptionType.StartNewGame, StartMenuOptionType.ResumeGame, StartMenuOptionType.Quit]
        expected_menu_options = MenuOptions(options=expected_options,
                                            initially_selected_option=StartMenuOptionType.StartNewGame)

        self.assertEqual(menu_options, expected_menu_options)

    def test_present_start_menu_options_should_notify_observer_with_present_create_board_options_callable(self):
        present_create_board_options = get_keywords(test_action_method=self.subject,
                                                    keyword_argument='present_create_board_options',
                                                    spy_class=PresentStartMenuOptionsUseCaseObserver,
                                                    spied_upon_method_name='did_present_start_menu_options')
        create_board = get_keywords(test_action_method=present_create_board_options,
                                    keyword_argument='create_board',
                                    spy_class=PresentCreateBoardOptionsUseCaseObserver,
                                    spied_upon_method_name='did_present_create_board_options')
        create_board = partial(create_board.__call__, row_count=7, column_count=6)
        board = get_keywords(test_action_method=create_board,
                             keyword_argument='board',
                             spy_class=CreateBoardUseCaseObserver,
                             spied_upon_method_name='did_create_board')
        expected_board = Board(row_count=7, column_count=6)
        assert_boards_equal(board=board, expected_board=expected_board, test_case=self)
        board_snapshot = get_keywords(test_action_method=create_board,
                                      keyword_argument='board_snapshot',
                                      spy_class=CreateBoardUseCaseObserver,
                                      spied_upon_method_name='did_create_board')
        expected_board_snapshot = [[CellType.Unknown for column in range(6)] for row in range(7)]
        assert_board_snapshots_equal(board_snapshot=board_snapshot,
                                     expected_board_snapshot=expected_board_snapshot,
                                     test_case=self)
 def setUp(self):
     self.minefield_repository = InMemoryMinefieldRepository()
     self.turn_repository = InMemoryTurnRepository()
     board = Board(row_count=3, column_count=5)
     self.subject = CreateMinefieldUseCase(
         board=board,
         mine_planter=LazyBeeMinePlanter(),
         minefield_repository=self.minefield_repository,
         turn_repository=self.turn_repository,
     )
 def setUp(self):
     self.minefield_repository = InMemoryMinefieldRepository()
     self.subject = PresentStartMenuOptionsUseCase(minefield_repository=self.minefield_repository)
class CreateMinefieldUseCaseTest(TestCase):
    def setUp(self):
        self.minefield_repository = InMemoryMinefieldRepository()
        self.turn_repository = InMemoryTurnRepository()
        board = Board(row_count=3, column_count=5)
        self.subject = CreateMinefieldUseCase(
            board=board,
            mine_planter=LazyBeeMinePlanter(),
            minefield_repository=self.minefield_repository,
            turn_repository=self.turn_repository,
        )

    def test_create_minefield_should_create_a_minefield(self):
        spy = Mock(CreateMinefieldUseCaseObserver)
        self.subject(column_index=0, row_index=0, observer=spy)

        captured_minefield_identifier = spy.did_create_minefield.call_args[1]["minefield_identifier"]

        fetched_minefield = None

        def did_fetch_minefield(minefield: Minefield):
            nonlocal fetched_minefield
            fetched_minefield = minefield

        self.minefield_repository.fetch_minefield(
            minefield_identifier=captured_minefield_identifier, success=did_fetch_minefield
        )
        expected_mine_coordinates = [
            Coordinate(row_index=0, column_index=0),
            Coordinate(row_index=1, column_index=1),
            Coordinate(row_index=2, column_index=2),
        ]
        expected_board = Board(row_count=3, column_count=5)
        expected_minefield = Minefield(
            identifier=captured_minefield_identifier, board=expected_board, mine_coordinates=expected_mine_coordinates
        )
        assert_minefields_equal(fetched_minefield, expected_minefield, self)

    def test_create_minefield_should_create_a_first_turn(self):
        spy = Mock(CreateMinefieldUseCaseObserver)
        self.subject(row_index=0, column_index=1, observer=spy)

        captured_minefield_identifier = spy.did_create_minefield.call_args[1]["minefield_identifier"]
        captured_first_turn = spy.did_create_minefield.call_args[1]["first_turn"]

        fetched_turn_list = None
        fetched_minefield_identifier = None

        def did_fetch_ordererd_turns(turn_list: List[Turn], minefield_identifier: UUID):
            nonlocal fetched_turn_list
            nonlocal fetched_minefield_identifier
            fetched_turn_list = turn_list
            fetched_minefield_identifier = minefield_identifier

        self.turn_repository.fetch_ordered_turns(
            last_turn_identifier=captured_first_turn.identifier, success=did_fetch_ordererd_turns
        )

        expected_turn_list = [
            Turn(
                identifier=captured_first_turn.identifier,
                coordinate=Coordinate(row_index=0, column_index=1),
                action=TurnAction.RevealCell,
                parent_turn_identifier=None,
                minefield_identifier=captured_minefield_identifier,
            )
        ]

        assert_turn_lists_equal(fetched_turn_list, expected_turn_list, self)
        self.assertEqual(fetched_minefield_identifier, captured_minefield_identifier)

    def test_create_minefield_should_notify_observer_with_game_state(self):
        spy = Mock(CreateMinefieldUseCaseObserver)
        self.subject(row_index=0, column_index=1, observer=spy)

        keyword_arguments = spy.did_create_minefield.call_args[1]
        captured_game_state = keyword_arguments["game_state"]
        self.assertEqual(captured_game_state, GameState.Started)