diff options
Diffstat (limited to 'src/miinaharava/tests')
-rw-r--r-- | src/miinaharava/tests/__init__.py | 0 | ||||
-rw-r--r-- | src/miinaharava/tests/test_app.py | 241 | ||||
-rw-r--r-- | src/miinaharava/tests/test_board.py | 295 | ||||
-rw-r--r-- | src/miinaharava/tests/test_bot.py | 54 |
4 files changed, 590 insertions, 0 deletions
diff --git a/src/miinaharava/tests/__init__.py b/src/miinaharava/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/miinaharava/tests/__init__.py diff --git a/src/miinaharava/tests/test_app.py b/src/miinaharava/tests/test_app.py new file mode 100644 index 0000000..1d13a71 --- /dev/null +++ b/src/miinaharava/tests/test_app.py @@ -0,0 +1,241 @@ +"""test_app.py - Testaa pelin suoritusta""" +# pylint: disable = missing-class-docstring, too-few-public-methods + +from io import StringIO +import unittest +from unittest.mock import patch + +from app import App + +from tui import Action + + +class KbdTest: + # pylint: disable = unused-argument, missing-function-docstring + def __init__(self, actions): + self.actions = actions + def read_action(self): + if self.actions: + action, _, _ = self.actions.pop(0) + else: + action = Action.NOOP + return action + def read_matrix_action(self, w, h, x, y): + return self.actions.pop(0) if self.actions else (Action.NOOP,x,y) + + +class TestAppClass(unittest.TestCase): + """ Testit itse appille """ + class DefaultArgs: + autoplay = 2 + intermediate = None + expert = None + board = None + mines = None + size = None + bot = None + quiet = None + delay = None + + sure_win_board = [ + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,1,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0] + ] + + sure_lose_board = [ + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,0,1,1,1,1], + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1] + ] + + dssp_win_board = [ + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0], + [0,1,1,0,1,1,0,1,0] + ] + + mini_board = [ + [0,0], + [0,1] + ] + + + def test_run(self): + """ Testataan että edes pyörähtää """ + app = App(self.DefaultArgs) + app.run() + del app + + def test_quit(self): + """ Testataan Quittaamista """ + app = App() + app.ui.kbd=KbdTest([ + (Action.QUIT,0,0), + (Action.OPEN,0,0) + ]) + app.run() + del app + + def test_many_games(self): + """ Varman voiton lauta palauttaa true """ + class Args(self.DefaultArgs): + quiet = True + for _ in range(50): + app = App(Args) + app.run() + del app + Args.intermediate = True + for _ in range(20): + app = App(Args) + app.run() + del app + Args.expert = True + for _ in range(10): + app = App(Args) + app.run() + del app + + def test_sure_win(self): + """ Varman voiton lauta palauttaa true """ + class Args(self.DefaultArgs): + board = self.sure_win_board + quiet = True + app = App(Args) + self.assertTrue(app.run()) + del app + + def test_dssp_win(self): + """ Varman voiton lauta palauttaa true """ + class Args(self.DefaultArgs): + board = self.dssp_win_board + app = App(Args) + self.assertTrue(app.run()) + del app + + def test_no_dssp_win_with_simple(self): + """ Varman voiton lauta palauttaa true """ + class Args(self.DefaultArgs): + board = self.dssp_win_board + quiet = True + bot = 1 + while True: + app = App(Args) + if not app.run(): + break + del app + + def test_sure_lose(self): + """ Varman häviön lauta palauttaa false """ + class Args(self.DefaultArgs): + board = self.sure_lose_board + app = App(Args) + self.assertFalse(app.run()) + del app + + def test_custom_size(self): + """ Varman häviön lauta palauttaa false """ + class Args(self.DefaultArgs): + size = (4, 4) + with patch('sys.stdout', new = StringIO()) as captured: + app = App(Args) + app.run() + self.assertIn("Mukautettu (4x4", captured.getvalue()) + del app + + def test_sure_win_with_actions(self): + """ Varman voiton lauta palauttaa true """ + class Args(self.DefaultArgs): + board = self.sure_win_board + autoplay = 0 + bot = 0 + app = App(Args) + app.ui.kbd=KbdTest([ + (Action.SAFE,0,0), + (Action.OPEN,0,0) + ]) + self.assertTrue(app.run()) + del app + + def test_sure_lose_with_actions(self): + """ Varman voiton lauta palauttaa true """ + class Args(self.DefaultArgs): + board = self.sure_lose_board + autoplay = 0 + app = App(Args) + app.ui.kbd=KbdTest([ + (Action.FLAG,0,0), + (Action.MINE,0,0), + (Action.OPEN,0,0) + ]) + self.assertFalse(app.run()) + del app + + def test_auto_play_hints(self): + """ Vihjeiden automaattipelaaminen toimii """ + class Args(self.DefaultArgs): + board = self.dssp_win_board + autoplay = 1 + app = App(Args) + app.ui.kbd=KbdTest([ + (Action.OPEN,0,0), + (Action.HINT,0,0), + ]) + self.assertTrue(app.run()) + del app + + def test_delay(self): + """ Hidastus toimii """ + class Args(self.DefaultArgs): + board = self.dssp_win_board + delay = 5 + app = App(Args) + with patch('time.sleep') as patched_sleep: + self.assertTrue(app.run()) + del app + patched_sleep.assert_called() + + def test_delay_can_be_off(self): + """ Hidastus ei ole aina päälle """ + class Args(self.DefaultArgs): + board = self.dssp_win_board + app = App(Args) + with patch('time.sleep') as patched_sleep: + self.assertTrue(app.run()) + del app + patched_sleep.assert_not_called() + + def test_botless_play(self): + """ Hidastus toimii """ + class Args(self.DefaultArgs): + board = self.mini_board + autoplay = 0 + delay = 50000 + app = App(Args) + app.ui.kbd=KbdTest([ + (Action.OPEN,0,0), + (Action.HINT,0,0), + (Action.OPEN,1,0), + (Action.HINT,0,0), + (Action.OPEN,0,1) + ]) + self.assertTrue(app.run()) + del app diff --git a/src/miinaharava/tests/test_board.py b/src/miinaharava/tests/test_board.py new file mode 100644 index 0000000..8aeac89 --- /dev/null +++ b/src/miinaharava/tests/test_board.py @@ -0,0 +1,295 @@ +""" tests/test_board.py - Testit pelilaudalle """ + +import unittest + +from board import Board, Level, LevelSpecs + +def matrix_equals(m1, m2): + """ matrix_equals - apufunktio testaa onko matriisit samat """ + if len(m1)!=len(m2): + return False + # pylint: disable = consider-using-enumerate + for i in range(len(m1)): + if m1[i] != m2[i]: + return False + return True + +def matrix_swap_xy(m): + """ matrix_swap_xy - palauttaa matriisin korvattu x -> y ja y -> x """ + if not m: + return None + w, h = len(m[0]), len(m) + ret_m = [[0 for _ in range(h)] for _ in range(w)] + for y in range(h): + for x in range(w): + ret_m[x][y]=m[y][x] + return ret_m + + +class TestBoardClass(unittest.TestCase): + """ pelilauden testit kattava luokka """ + + def test_init_works_and_defaults_beginner(self): + """ pelilautaolion luominen onnistuu ja defaulttaa aloittelijaksi """ + b = Board() + self.assertEqual(b.get_width(), LevelSpecs[Level.BEGINNER][0]) + self.assertEqual(b.get_height(), LevelSpecs[Level.BEGINNER][1]) + self.assertEqual(b.get_mines(), LevelSpecs[Level.BEGINNER][2]) + self.assertTrue(b.get_width()>0) + + + def test_init_with_level(self): + """ olion luominen onnistuu vaikeustasolla""" + b = Board(level=Level.EXPERT) + self.assertEqual(b.get_width(), LevelSpecs[Level.EXPERT][0]) + self.assertEqual(b.get_height(), LevelSpecs[Level.EXPERT][1]) + self.assertEqual(b.get_mines(), LevelSpecs[Level.EXPERT][2]) + + + def test_init_with_custom_dimentions(self): + """ mukautetun kentän luominen onnistuu """ + b = Board(width=13, height=14, mines=15) + self.assertEqual(b.get_width(), 13) + self.assertEqual(b.get_height(), 14) + self.assertEqual(b.get_mines(), 15) + b = Board(width=22, height=12) + self.assertEqual(b.get_width(), 22) + self.assertEqual(b.get_height(), 12) + self.assertEqual(b.get_mines(), 22) + + + def test_init_with_incorect_dimensions(self): + """ luominen ei saa onnitua mahdottomilla mitoilla """ + b = Board(width=1, height=999, mines=0) + self.assertEqual(b.get_width(), LevelSpecs[Level.BEGINNER][0]) + self.assertEqual(b.get_height(), LevelSpecs[Level.BEGINNER][1]) + self.assertEqual(b.get_mines(), LevelSpecs[Level.BEGINNER][2]) + + + def test_init_with_valid_board(self): + """ Pelilaudan luominen onnistuu kelvollisella asettelulla """ + t = [ + [0,0,0,0], + [0,0,0,1], + [0,0,0,0] + ] + b = Board(board = t) + self.assertEqual(b.get_width(), 4) + self.assertEqual(b.get_height(), 3) + self.assertEqual(b.get_mines(), 1) + + + def test_init_with_invalid_board(self): + """ Yritetään luoda peli kelvottomalla laudalla """ + t = [ + [0,0,0,0,0], + [0,0,0,1], + [0,0,0,0,0] + ] + b = Board(board = t) + # Resetoituihan aloittelijan lauta + self.assertIn(LevelSpecs[Level.BEGINNER][3], b.get_level_name()) + + t = [ + [0,1,0,0,0], + ] + b = Board(board = t) + self.assertIn(LevelSpecs[Level.BEGINNER][3], b.get_level_name()) + + t = [ + [0,0,0,0], + [0,0,0,0], + [0,0,0,0] + ] + b = Board(board = t) + self.assertIn(LevelSpecs[Level.BEGINNER][3], b.get_level_name()) + + t = [ + [1,1,1], + [1,1,1], + [1,1,1] + ] + b = Board(board = t) + self.assertIn(LevelSpecs[Level.BEGINNER][3], b.get_level_name()) + + + def test_tiles_and_masks_ok(self): + """ Luohan luokka sisäiset laatat ja maskit oikein """ + # pylint: disable = protected-access + t = [ + [0,0,0,0], + [0,0,0,1], + [0,0,0,0] + ] + b = Board(board = t) + self.assertEqual(b.get_width(), 4) + self.assertEqual(b.get_height(), 3) + self.assertEqual(b.get_mines(), 1) + + # testataan onko laatat tallennettu oikein luokkaan + t = matrix_swap_xy([ + [0,0,1,1], + [0,0,1,9], + [0,0,1,1] + ]) + self.assertTrue(matrix_equals(b._Board__tiles, t)) + + # onko maksit asetettu oikein + t = matrix_swap_xy([ + [12,12,12,12], + [12,12,12,12], + [12,12,12,12] + ]) + self.assertTrue(matrix_equals(b._Board__masked, t)) + + + def test_get_view_and_guess(self): + """ laudan näkymä on oikein senkin jälkeen kun on arvattu """ + + t = [ + [0,0,1], + [0,0,0], + [0,0,0] + ] + b = Board(board=t) + + # Antaahan pelikenttä pelkkää maskia aluksi + t = matrix_swap_xy([ + [12,12,12], + [12,12,12], + [12,12,12] + ]) + self.assertTrue(matrix_equals(b.get_view(), t)) + + # avataan yläkulma -> palatuu True + self.assertTrue(b.guess(0,0)) + + # onko näkymä nyt oikein + t = matrix_swap_xy([ + [0,1,12], + [0,1,1], + [0,0,0] + ]) + self.assertTrue(matrix_equals(b.get_view(), t)) + + # avataan alakulma jossa miina -> palautuu False + self.assertFalse(b.guess(2,0)) + + + def test_is_winning(self): + """ toimiiko voittotilanteen tunnistus """ + + t = [ + [0,1], + [0,0], + ] + b = Board(board=t) + self.assertFalse(b.is_winning()) + + # Avataan ruutu jolla ei tule viellä voittoa + t = matrix_swap_xy([ + [1,12], + [12,12] + ]) + self.assertTrue(b.guess(0,0)) + self.assertTrue(matrix_equals(b.get_view(), t)) + self.assertFalse(b.is_winning()) + + # Avataan loputkin ruudut, jolloin pitäisi voittaa + t = matrix_swap_xy([ + [1,12], + [1,1] + ]) + self.assertTrue(b.guess(0,1)) + self.assertTrue(b.guess(1,1)) + self.assertTrue(matrix_equals(b.get_view(), t)) + self.assertTrue(b.is_winning()) + + # Lupuksi avataan miina jolloin voittoa ei enää pitäisi olla + t = matrix_swap_xy([ + [1,9], + [1,1] + ]) + self.assertFalse(b.guess(1,0)) + self.assertTrue(matrix_equals(b.get_view(), t)) + self.assertFalse(b.is_winning()) + + + def test_error_conditions_in_guess(self): + """ ruudun avaus alueen ulkopuolelta tai avatussa ruudussa ei onnistu""" + t = [ + [0,1], + [0,0], + ] + b = Board(board=t) + self.assertFalse(b.guess(2,2)) + self.assertTrue(b.guess(0,0)) + self.assertFalse(b.guess(0,0)) + + + def test_get_mask(self): + """ maski annetaan oikein """ + t = [ + [1,0], + [0,0], + ] + b = Board(board=t) + self.assertEqual(b.get_mask(1,0), 12) + self.assertTrue(b.guess(1,0)) + self.assertFalse(b.get_mask(1,0)) + + + def test_flag(self): + """ ruudun lipun vaihto ja asetus toimii """ + t = [ + [0,0], + [0,1], + ] + b = Board(board=t) + self.assertEqual(b.get_mask(0,0), 12) + self.assertTrue(b.flag(0,0)) + self.assertEqual(b.get_mask(0,0), 13) + self.assertTrue(b.flag(0,0)) + self.assertEqual(b.get_mask(0,0), 10) + self.assertTrue(b.flag(0,0)) + self.assertEqual(b.get_mask(0,0), 11) + self.assertTrue(b.flag(0,0)) + self.assertEqual(b.get_mask(0,0), 12) + self.assertTrue(b.flag(0,0,10)) + self.assertEqual(b.get_mask(0,0), 10) + + + def test_flag_error_conditions(self): + """ liputus ei onnistu jos avattu, alueen ulkopuolella, outo arvo """ + t = [ + [0,1], + [1,1], + ] + b = Board(board=t) + self.assertFalse(b.flag(0,0,6)) # Lippu jota ei ole + self.assertFalse(b.flag(2,2)) # Alueen ulkopuolella + self.assertTrue(b.guess(0,0)) + self.assertFalse(b.flag(0,0)) # Avattu laatta + + + def test_reveal(self): + """ paljastuksen jälkeen näkyy laatat sellaisenaan """ + t = [ + [0,1], + [1,1], + ] + b = Board(board=t) + b.reveal() + t = matrix_swap_xy([ + [3,9], + [9,9] + ]) + self.assertTrue(matrix_equals(b.get_view(), t)) + + + def test_get_level_name(self): + """ Testataan että nykyinen vaikeustaso palautuu oikein """ + b = Board(level=Level.INTERMEDIATE) + self.assertIn(LevelSpecs[Level.INTERMEDIATE][3], b.get_level_name()) + b = Board(level=Level.INTERMEDIATE, width=25, mines=2) + self.assertIn("Mukautettu", b.get_level_name()) diff --git a/src/miinaharava/tests/test_bot.py b/src/miinaharava/tests/test_bot.py new file mode 100644 index 0000000..4dab148 --- /dev/null +++ b/src/miinaharava/tests/test_bot.py @@ -0,0 +1,54 @@ +""" tests/test_bot.py - Testaa botin toimintaa""" +# pylint: disable = missing-class-docstring, too-few-public-methods, protected-access + +import unittest + +from board import Board, Tile +from bots import DSSPBot, SimpleBot +from tui import Action + +class TestBotClass(unittest.TestCase): + """ botin testit""" + def test_init(self): + """ olioden luominen onnistuu """ + DSSPBot() + SimpleBot() + + def correctly_marking(self, open_free=False, bot_type=DSSPBot): + """ Testaa onko miinat miinoja ja vapaat vapaita alkuun avatusta """ + for _ in range(500): + brd = Board() + # jos ei aukea ylälaidasta otetaan seuraava + if not brd.guess(0,0): + continue + # vain varmat liikut + bot = bot_type(uncertain=False) + + tested = set() + while True: + action, x, y = bot.hint(brd.get_view(), 0, 0) + if (x,y) in tested: + break + tested.add((x,y)) + if action == Action.SAFE: + self.assertTrue( brd._Board__tiles[x][y] < Tile.MINE ) + if open_free: + brd.guess(x,y) + if action == Action.MINE: + self.assertTrue( brd._Board__tiles[x][y] == Tile.MINE ) + + def test_dssp_marks_correctly_with_open(self): + """ Testaa onko dssp:n miinat miinoja ja avaa vapaat """ + self.correctly_marking(True, DSSPBot) + + def test_simple_marks_correctly_with_open(self): + """ Testaa onko dssp:n miinat miinoja ja avaa vapaat """ + self.correctly_marking(True, SimpleBot) + + def test_dssp_marks_correctly(self): + """ Testaa onko dssp:n miinat miinoja ja vapaat vapaita """ + self.correctly_marking(False, DSSPBot) + + def test_simple_marks_correctly(self): + """ Testaa onko simple:n miinat miinoja ja vapaat vapaita """ + self.correctly_marking(False, SimpleBot) |