# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later import os import unittest from ..bootstrap import Bootstrap from ..display.display import Display from ..display.display_manager import DisplayManager from ..entities.friendly import Merchant, Sunflower from ..entities.items import Bomb, Heart, Sword from ..entities.player import Player from ..enums import DisplayActions from ..game import Game, KeyValues, GameMode from ..menus import MainMenuValues from ..resources import ResourceManager from ..settings import Settings from ..translations import gettext as _, Translator class TestGame(unittest.TestCase): def setUp(self) -> None: """ Setup game. """ self.game = Game() self.game.new_game() self.game.logs.add_message("Hello World !") display = DisplayManager(None, self.game) self.game.display_actions = display.handle_display_action def test_load_game(self) -> None: """ Save a game and reload it. """ bomb = Bomb() self.game.map.add_entity(bomb) sword = Sword() self.game.map.add_entity(sword) # Add items in the inventory to check that it is well loaded bomb.hold(self.game.player) sword.hold(self.game.player) # Ensure that merchants can be saved merchant = Merchant() merchant.move(3, 6) self.game.map.add_entity(merchant) old_state = self.game.save_state() self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.SAVE) self.game.handle_key_pressed(KeyValues.ENTER) # Save game self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.LOAD) self.game.handle_key_pressed(KeyValues.ENTER) # Load game new_state = self.game.save_state() self.assertEqual(old_state, new_state) # Ensure that the bomb is loaded self.assertTrue(self.game.player.inventory) # Error on loading save with open(ResourceManager.get_config_path("save.json"), "w") as f: f.write("I am not a JSON file") self.assertIsNone(self.game.message) self.game.load_game() self.assertIsNotNone(self.game.message) self.game.message = None with open(ResourceManager.get_config_path("save.json"), "w") as f: f.write("{}") self.assertIsNone(self.game.message) self.game.load_game() self.assertIsNotNone(self.game.message) self.game.message = None # Load game with a dead player self.game.map.remove_entity(self.game.player) self.game.save_game() self.game.load_game() self.assertIsNotNone(self.game.message) def test_bootstrap_fail(self) -> None: """ Ensure that the test can't play the game, because there is no associated shell. Yeah, that's only for coverage. """ self.assertRaises(Exception, Bootstrap.run_game) self.assertEqual(os.getenv("TERM", "unknown"), "unknown") def test_key_translation(self) -> None: """ Test key bindings. """ self.game.settings = Settings() self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_UP_PRIMARY, self.game.settings), KeyValues.UP) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_UP_SECONDARY, self.game.settings), KeyValues.UP) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_DOWN_PRIMARY, self.game.settings), KeyValues.DOWN) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_DOWN_SECONDARY, self.game.settings), KeyValues.DOWN) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_LEFT_PRIMARY, self.game.settings), KeyValues.LEFT) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_LEFT_SECONDARY, self.game.settings), KeyValues.LEFT) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_RIGHT_PRIMARY, self.game.settings), KeyValues.RIGHT) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_RIGHT_SECONDARY, self.game.settings), KeyValues.RIGHT) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_ENTER, self.game.settings), KeyValues.ENTER) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_INVENTORY, self.game.settings), KeyValues.INVENTORY) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_CHAT, self.game.settings), KeyValues.CHAT) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_USE, self.game.settings), KeyValues.USE) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_EQUIP, self.game.settings), KeyValues.EQUIP) self.assertEqual(KeyValues.translate_key( self.game.settings.KEY_DROP, self.game.settings), KeyValues.DROP) self.assertEqual(KeyValues.translate_key(' ', self.game.settings), KeyValues.SPACE) self.assertEqual(KeyValues.translate_key('plop', self.game.settings), None) def test_key_press(self) -> None: """ Press a key and see what is done. """ self.assertEqual(self.game.state, GameMode.MAINMENU) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.START) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.START) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.RESUME) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.SAVE) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.LOAD) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.SETTINGS) self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.state, GameMode.SETTINGS) self.game.handle_key_pressed(KeyValues.SPACE) self.assertEqual(self.game.state, GameMode.MAINMENU) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.EXIT) self.assertRaises(SystemExit, self.game.handle_key_pressed, KeyValues.ENTER) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.SETTINGS) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.LOAD) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.SAVE) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.RESUME) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.main_menu.validate(), MainMenuValues.START) self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.state, GameMode.PLAY) # Kill entities for entity in self.game.map.entities.copy(): if not isinstance(entity, Player): self.game.map.remove_entity(entity) y, x = self.game.player.y, self.game.player.x self.game.handle_key_pressed(KeyValues.DOWN) new_y, new_x = self.game.player.y, self.game.player.x self.assertEqual(new_y, y + 1) self.assertEqual(new_x, x) y, x = new_y, new_x self.game.handle_key_pressed(KeyValues.RIGHT) new_y, new_x = self.game.player.y, self.game.player.x self.assertEqual(new_y, y) self.assertEqual(new_x, x + 1) y, x = self.game.player.y, self.game.player.x self.game.handle_key_pressed(KeyValues.UP) new_y, new_x = self.game.player.y, self.game.player.x self.assertEqual(new_y, y - 1) self.assertEqual(new_x, x) y, x = self.game.player.y, self.game.player.x self.game.handle_key_pressed(KeyValues.LEFT) new_y, new_x = self.game.player.y, self.game.player.x self.assertEqual(new_y, y) self.assertEqual(new_x, x - 1) self.game.handle_key_pressed(KeyValues.SPACE) self.assertEqual(self.game.state, GameMode.MAINMENU) def test_mouse_click(self) -> None: """ Simulate mouse clicks. """ self.game.state = GameMode.MAINMENU # Change the color of the artwork self.game.display_actions(DisplayActions.MOUSE, 0, 10) # Settings menu self.game.display_actions(DisplayActions.MOUSE, 25, 21) self.assertEqual(self.game.main_menu.position, 4) self.assertEqual(self.game.state, GameMode.SETTINGS) bomb = Bomb() bomb.hold(self.game.player) bomb2 = Bomb() bomb2.hold(self.game.player) self.game.state = GameMode.INVENTORY # Click nowhere self.game.display_actions(DisplayActions.MOUSE, 0, 0) self.assertEqual(self.game.state, GameMode.INVENTORY) # Click on the second item self.game.display_actions(DisplayActions.MOUSE, 8, 25) self.assertEqual(self.game.state, GameMode.INVENTORY) self.assertEqual(self.game.inventory_menu.position, 1) def test_new_game(self) -> None: """ Ensure that the start button starts a new game. """ old_map = self.game.map old_player = self.game.player self.game.handle_key_pressed(KeyValues.ENTER) # Start new game new_map = self.game.map new_player = self.game.player # Ensure that self.assertNotEqual(old_map, new_map) self.assertNotEqual(old_player, new_player) self.game.handle_key_pressed(KeyValues.SPACE) old_map = new_map old_player = new_player self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.ENTER) # Resume game new_map = self.game.map new_player = self.game.player self.assertEqual(old_map, new_map) self.assertEqual(old_player, new_player) def test_settings_menu(self) -> None: """ Ensure that the settings menu is working properly. """ self.game.settings = Settings() # Open settings menu self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.state, GameMode.SETTINGS) # Define the "move up" key to 'w' self.assertFalse(self.game.settings_menu.waiting_for_key) self.game.handle_key_pressed(KeyValues.ENTER) self.assertTrue(self.game.settings_menu.waiting_for_key) self.game.handle_key_pressed(None, 'w') self.assertFalse(self.game.settings_menu.waiting_for_key) self.assertEqual(self.game.settings.KEY_UP_PRIMARY, 'w') # Navigate to "move left" self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.UP) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) # Define the "move up" key to 'a' self.game.handle_key_pressed(KeyValues.ENTER) self.assertTrue(self.game.settings_menu.waiting_for_key) # Can't used a mapped key self.game.handle_key_pressed(None, 's') self.assertTrue(self.game.settings_menu.waiting_for_key) self.game.handle_key_pressed(None, 'a') self.assertFalse(self.game.settings_menu.waiting_for_key) self.assertEqual(self.game.settings.KEY_LEFT_PRIMARY, 'a') # Navigate to "texture pack" for ignored in range(10): self.game.handle_key_pressed(KeyValues.DOWN) # Change texture pack self.assertEqual(self.game.settings.TEXTURE_PACK, "ascii") self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.TEXTURE_PACK, "squirrel") self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.TEXTURE_PACK, "ascii") # Change language Translator.compilemessages() Translator.refresh_translations() self.game.settings.LOCALE = "en" self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.LOCALE, "fr") self.assertEqual(_("New game"), "Nouvelle partie") self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.LOCALE, "de") self.assertEqual(_("New game"), "Neu Spiel") self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.LOCALE, "es") self.assertEqual(_("New game"), "Nuevo partido") self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.LOCALE, "en") self.assertEqual(_("New game"), "New game") # Navigate to "back" button self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.state, GameMode.MAINMENU) def test_logs(self) -> None: """ Tests the use of logs """ self.assertEqual(self.game.logs.messages, ["Hello World !"]) self.game.logs.add_messages(["Hello", "World"]) self.assertEqual(self.game.logs.messages, ["Hello World !", "Hello", "World"]) self.game.logs.clear() self.assertEqual(self.game.logs.messages, []) def test_dead_screen(self) -> None: """ Kill player and render dead screen. """ self.game.state = GameMode.PLAY # Kill player self.game.player.take_damage(self.game.player, self.game.player.health + 2) y, x = self.game.player.y, self.game.player.x for key in [KeyValues.UP, KeyValues.DOWN, KeyValues.LEFT, KeyValues.RIGHT]: self.game.handle_key_pressed(key) new_y, new_x = self.game.player.y, self.game.player.x self.assertEqual(new_y, y) self.assertEqual(new_x, x) def test_not_implemented(self) -> None: """ Check that some functions are not implemented, only for coverage. """ self.assertRaises(NotImplementedError, Display.display, None) def test_messages(self) -> None: """ Display error messages. """ self.game.message = "I am an error" self.game.display_actions(DisplayActions.UPDATE) self.game.display_actions(DisplayActions.REFRESH) self.game.handle_key_pressed(None, "random key") self.assertIsNone(self.game.message) def test_inventory_menu(self) -> None: """ Open the inventory menu and interact with items. """ self.game.state = GameMode.PLAY # Open and close the inventory self.game.handle_key_pressed(KeyValues.INVENTORY) self.assertEqual(self.game.state, GameMode.INVENTORY) self.game.handle_key_pressed(KeyValues.SPACE) self.assertEqual(self.game.state, GameMode.PLAY) # Add five bombs in the inventory for ignored in range(5): bomb = Bomb() bomb.map = self.game.map bomb.map.add_entity(bomb) bomb.hold(self.game.player) self.game.handle_key_pressed(KeyValues.INVENTORY) self.assertEqual(self.game.state, GameMode.INVENTORY) # Navigate in the menu self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.inventory_menu.position, 3) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.UP) self.game.handle_key_pressed(KeyValues.DOWN) self.assertEqual(self.game.inventory_menu.position, 4) # Equip key does nothing self.game.handle_key_pressed(KeyValues.EQUIP) # Drop an item bomb = self.game.player.inventory[-1] self.assertEqual(self.game.inventory_menu.validate(), bomb) self.assertTrue(bomb.held) self.assertEqual(bomb.held_by, self.game.player) self.game.handle_key_pressed(KeyValues.DROP) self.assertFalse(bomb.held) self.assertIsNone(bomb.held_by) self.assertIsNone(bomb.owner) self.assertFalse(bomb.exploding) self.assertEqual(bomb.y, self.game.player.y) self.assertEqual(bomb.x, self.game.player.x) # Use the bomb bomb = self.game.player.inventory[-1] self.assertEqual(self.game.inventory_menu.validate(), bomb) self.assertTrue(bomb.held) self.assertEqual(bomb.held_by, self.game.player) self.game.handle_key_pressed(KeyValues.USE) self.assertFalse(bomb.held) self.assertIsNone(bomb.held_by) self.assertEqual(bomb.owner, self.game.player) self.assertTrue(bomb.exploding) self.assertEqual(bomb.y, self.game.player.y) self.assertEqual(bomb.x, self.game.player.x) def test_talk_to_sunflowers(self) -> None: """ Interact with sunflowers """ self.game.state = GameMode.PLAY sunflower = Sunflower() sunflower.move(2, 6) self.game.map.add_entity(sunflower) # Does nothing self.assertIsNone(self.game.handle_friendly_entity_chat(KeyValues.UP)) # Talk to sunflower... or not self.game.handle_key_pressed(KeyValues.CHAT) self.assertTrue(self.game.waiting_for_friendly_key) # Wrong key self.game.handle_key_pressed(KeyValues.EQUIP) self.assertFalse(self.game.waiting_for_friendly_key) self.game.handle_key_pressed(KeyValues.CHAT) self.assertTrue(self.game.waiting_for_friendly_key) self.game.handle_key_pressed(KeyValues.UP) self.assertFalse(self.game.waiting_for_friendly_key) self.assertEqual(self.game.state, GameMode.PLAY) self.assertFalse(len(self.game.logs.messages) > 1) # Talk to sunflower self.game.handle_key_pressed(KeyValues.CHAT) self.assertTrue(self.game.waiting_for_friendly_key) self.game.handle_key_pressed(KeyValues.DOWN) self.assertFalse(self.game.waiting_for_friendly_key) self.assertEqual(self.game.state, GameMode.PLAY) self.assertTrue(self.game.logs.messages) # Ensure that the message is a good message self.assertIn(self.game.logs.messages[1][21:], Sunflower.dialogue_option) # Test all directions to detect the friendly entity self.game.player.move(3, 6) self.game.handle_key_pressed(KeyValues.CHAT) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(len(self.game.logs.messages), 3) self.game.player.move(2, 7) self.game.handle_key_pressed(KeyValues.CHAT) self.game.handle_key_pressed(KeyValues.LEFT) self.assertEqual(len(self.game.logs.messages), 4) self.game.player.move(2, 5) self.game.handle_key_pressed(KeyValues.CHAT) self.game.handle_key_pressed(KeyValues.RIGHT) self.assertEqual(len(self.game.logs.messages), 5) def test_talk_to_merchant(self) -> None: """ Interact with merchants """ self.game.state = GameMode.PLAY merchant = Merchant() merchant.move(2, 6) self.game.map.add_entity(merchant) # Does nothing self.assertIsNone(self.game.handle_friendly_entity_chat(KeyValues.UP)) # Talk to merchant self.game.handle_key_pressed(KeyValues.CHAT) self.assertTrue(self.game.waiting_for_friendly_key) self.game.handle_key_pressed(KeyValues.DOWN) self.assertFalse(self.game.waiting_for_friendly_key) self.assertEqual(self.game.state, GameMode.STORE) self.assertTrue(self.game.logs.messages) # Navigate in the menu self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.UP) self.assertEqual(self.game.store_menu.position, 1) # The second item is not a heart merchant.inventory[1] = Sword() # Buy the second item by clicking on it item = self.game.store_menu.validate() self.assertIn(item, merchant.inventory) self.game.display_actions(DisplayActions.MOUSE, 8, 25) self.game.handle_key_pressed(KeyValues.ENTER) self.assertIn(item, self.game.player.inventory) self.assertNotIn(item, merchant.inventory) # Buy a heart merchant.inventory[1] = Heart() item = self.game.store_menu.validate() self.assertIn(item, merchant.inventory) self.assertEqual(item, merchant.inventory[1]) self.game.player.health = self.game.player.maxhealth - 1 - item.healing self.game.handle_key_pressed(KeyValues.ENTER) self.assertNotIn(item, self.game.player.inventory) self.assertNotIn(item, merchant.inventory) self.assertEqual(self.game.player.health, self.game.player.maxhealth - 1) # We don't have enough of money self.game.player.hazel = 0 item = self.game.store_menu.validate() self.game.handle_key_pressed(KeyValues.ENTER) self.assertNotIn(item, self.game.player.inventory) self.assertIn(item, merchant.inventory) self.assertEqual(self.game.message, _("You do not have enough money")) self.game.handle_key_pressed(KeyValues.ENTER) # Exit the menu self.game.handle_key_pressed(KeyValues.SPACE) self.assertEqual(self.game.state, GameMode.PLAY)