aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorInigoGutierrez <inigogf.95@gmail.com>2023-06-12 20:16:04 +0200
committerInigoGutierrez <inigogf.95@gmail.com>2023-06-12 20:16:04 +0200
commitd4a81490bf1396089eb3dac5955a3a8e4cb26e37 (patch)
treef96febc7950c2742bc36f04ab13bff56851f2388 /tests
parentb08408d23186205e71dfc68634021e3236bfb45c (diff)
parent65ac3a6b050dcb88688cdc2654b1ed6693e9a160 (diff)
downloadimago-master.tar.gz
imago-master.zip
Merge branch 'devel'HEADmaster
Diffstat (limited to 'tests')
-rw-r--r--tests/test_enums.py2
-rw-r--r--tests/test_gameBoard.py28
-rw-r--r--tests/test_gameMove.py6
-rw-r--r--tests/test_gameState.py89
-rw-r--r--tests/test_imagoIO.py201
-rw-r--r--tests/test_monteCarlo.py50
-rw-r--r--tests/test_neuralNetwork.py83
-rw-r--r--tests/test_parseHelpers.py36
-rw-r--r--tests/test_sgf.py27
9 files changed, 501 insertions, 21 deletions
diff --git a/tests/test_enums.py b/tests/test_enums.py
index 73f4009..21b2057 100644
--- a/tests/test_enums.py
+++ b/tests/test_enums.py
@@ -5,7 +5,7 @@ import unittest
from imago.data.enums import Player
class TestEnums(unittest.TestCase):
- """Test parseHelpers module."""
+ """Test enums module."""
def testOtherPlayer(self):
"""Test method to get the other player"""
diff --git a/tests/test_gameBoard.py b/tests/test_gameBoard.py
index 8a7b127..c7808ac 100644
--- a/tests/test_gameBoard.py
+++ b/tests/test_gameBoard.py
@@ -114,5 +114,33 @@ class TestGameBoard(unittest.TestCase):
board.board[9][0] = Player.WHITE
self.assertEqual((9, 21), board.score())
+ def testToString(self):
+ """Test formatting of the board as a string."""
+
+ board = GameBoard(9, 9)
+ self.assertEqual(' A B C D E F G H J \n\
+9 · · · · · · · · · \n\
+8 · · · · · · · · · \n\
+7 · · · · · · · · · \n\
+6 · · · · · · · · · \n\
+5 · · · · · · · · · \n\
+4 · · · · · · · · · \n\
+3 · · · · · · · · · \n\
+2 · · · · · · · · · \n\
+1 · · · · · · · · · ', board.toString())
+
+ board.moveAndCapture(2, 6, Player.BLACK)
+ board.moveAndCapture(5, 4, Player.WHITE)
+ self.assertEqual(' A B C D E F G H J \n\
+9 · · · · · · · · · \n\
+8 · · · · · · · · · \n\
+7 · · · · · · B · · \n\
+6 · · · · · · · · · \n\
+5 · · · · · · · · · \n\
+4 · · · · W · · · · \n\
+3 · · · · · · · · · \n\
+2 · · · · · · · · · \n\
+1 · · · · · · · · · ', board.toString())
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_gameMove.py b/tests/test_gameMove.py
index 6569c5b..a7edfab 100644
--- a/tests/test_gameMove.py
+++ b/tests/test_gameMove.py
@@ -18,13 +18,13 @@ class TestGameMove(unittest.TestCase):
self.assertIsNone(firstMove.coords)
- secondMove = firstMove.addMove(1, 2)
+ secondMove = firstMove.addMoveByCoords(1, 2)
self.assertIsNone(firstMove.coords)
self.assertEqual(secondMove.coords[0], 1)
self.assertEqual(secondMove.coords[1], 2)
- thirdMove = secondMove.addMove(5, 7)
+ thirdMove = secondMove.addMoveByCoords(5, 7)
self.assertIsNone(firstMove.coords)
self.assertIsNone(thirdMove.previousMove.previousMove.coords)
@@ -66,7 +66,7 @@ class TestGameMove(unittest.TestCase):
(2,0), (2,1), (2,2)))
)
- secondMove = firstMove.addMove(1, 2)
+ secondMove = firstMove.addMoveByCoords(1, 2)
self.assertSetEqual(
secondMove.getPlayableVertices(),
set(((0,0), (0,1), (0,2),
diff --git a/tests/test_gameState.py b/tests/test_gameState.py
new file mode 100644
index 0000000..1c6b997
--- /dev/null
+++ b/tests/test_gameState.py
@@ -0,0 +1,89 @@
+"""Tests for the input/output component."""
+
+import unittest
+
+from imago.data.enums import Player
+from imago.gameLogic.gameState import GameState
+
+class TestGameState(unittest.TestCase):
+ """Test GameState component."""
+
+ def testCurrentPlayer(self):
+ """Test simple commands."""
+ size = 9
+ state = GameState(size)
+
+ self.assertEqual(state.getCurrentPlayer(), Player.BLACK)
+ self.assertEqual(state.getPlayerCode(), 'B')
+
+ state.playMove(0, 0)
+ self.assertEqual(state.getCurrentPlayer(), Player.WHITE)
+ self.assertEqual(state.getPlayerCode(), 'W')
+
+ def testPlays(self):
+ """Test simple commands."""
+ size = 3
+ state = GameState(size)
+
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+ state.playMove(1, 1)
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.BLACK, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+ state.playPass()
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.BLACK, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+ state.undo()
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.BLACK, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+ state.undo()
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+ state.passForPlayer(Player.WHITE)
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+
+ self.assertRaises(Exception, state.playMove, -1, -1)
+ self.assertEqual(state.getBoard().getBoard(),
+ [
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY],
+ [Player.EMPTY, Player.EMPTY, Player.EMPTY]
+ ])
+
+ state.lastMove = None
+ self.assertEqual(state.getCurrentPlayer(), Player.BLACK)
+ self.assertRaises(RuntimeError, state.playMove, 0, 0)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_imagoIO.py b/tests/test_imagoIO.py
new file mode 100644
index 0000000..499fdb2
--- /dev/null
+++ b/tests/test_imagoIO.py
@@ -0,0 +1,201 @@
+"""Tests for the input/output component."""
+
+import unittest
+
+import io
+import sys
+
+from imago.data.enums import DecisionAlgorithms
+from imago.engine.imagoIO import ImagoIO
+from imago.engine.parseHelpers import parseVertex
+
+class TestImagoIO(unittest.TestCase):
+ """Test ImagoIO component."""
+
+ @unittest.mock.patch('imago.engine.imagoIO.input', create=True)
+ def testSimpleCommands(self, mocked_input):
+ """Test simple commands."""
+
+ self.maxDiff = None
+
+ mocked_input.side_effect = [
+ '\n',
+ 'name\n',
+ 'version\n',
+ 'protocol_version\n',
+ 'clear_board\n',
+ '\n',
+ 'known_command\n',
+ 'known_command name\n',
+ 'known_command version\n',
+ 'known_command wrongcommand\n',
+ '\n',
+ 'boardsize\n',
+ 'boardsize 10\n',
+ '\n',
+ 'komi\n',
+ 'komi 5.5\n',
+ '\n',
+ 'play\n',
+ 'play 1\n',
+ 'play 1 2\n',
+ 'play b a1\n',
+ '\n',
+ 'undo\n',
+ 'undo\n',
+ '\n',
+ 'wrongcommand\n',
+ '\n',
+ 'quit\n'
+ ]
+
+ testout = io.StringIO()
+ imagoIO = ImagoIO(
+ decisionAlgorithmId=DecisionAlgorithms.MONTECARLO,
+ outputStream=testout
+ )
+
+ imagoIO.start()
+ value = testout.getvalue()
+ self.assertEqual(
+ '= Imago\n\n' +
+ '= 0.0.0\n\n' +
+ '= 2\n\n' +
+ '= \n\n' +
+ '? Wrong number of arguments\n' +
+ '? Usage: known_command COMMAND_NAME\n\n' +
+ '= true\n\n' +
+ '= true\n\n' +
+ '= false\n\n' +
+ '? Wrong number of arguments\n' +
+ '? Usage: boardsize <newSize>\n\n' +
+ '= \n\n' +
+ '? Wrong number of arguments\n' +
+ '? Usage: komi <newKomi>\n\n' +
+ '= \n\n' +
+ '? Wrong number of arguments\n' +
+ '? Usage: play <color> <vertex>\n\n' +
+ '? Wrong number of arguments\n' +
+ '? Usage: play <color> <vertex>\n\n' +
+ '? Invalid move: Unknown color [1].\n\n' +
+ '= \n\n' +
+ '= \n\n' +
+ '= \n\n' +
+ '? unknown command\n\n' +
+ '= \n\n',
+ value
+ )
+
+ testout.close()
+
+
+ @unittest.mock.patch('imago.engine.imagoIO.input', create=True)
+ def testListsCommands(self, mocked_input):
+ """Test command for listing all commands."""
+
+ mocked_input.side_effect = [
+ 'list_commands\n',
+ 'quit\n'
+ ]
+
+ testout = io.StringIO()
+ imagoIO = ImagoIO(
+ decisionAlgorithmId=DecisionAlgorithms.MONTECARLO,
+ outputStream=testout
+ )
+
+ commandsString = "\n".join(list(map(
+ lambda cmd: "%s - %s" % (cmd.__name__, cmd.__doc__),
+ imagoIO.commands_set)))
+
+ imagoIO.start()
+ value = testout.getvalue()
+ self.assertEqual(
+ '= ' +
+ commandsString +
+ '\n\n' +
+ '= \n\n',
+ value
+ )
+
+ testout.close()
+
+
+ @unittest.mock.patch('imago.engine.imagoIO.input', create=True)
+ def testFixedHandicap(self, mocked_input):
+ """Test command for setting fixed handicap stones."""
+
+ mocked_input.side_effect = [
+ 'fixed_handicap\n',
+ 'fixed_handicap 2\n',
+ 'quit\n'
+ ]
+
+ testout = io.StringIO()
+ imagoIO = ImagoIO(
+ decisionAlgorithmId=DecisionAlgorithms.MONTECARLO,
+ outputStream=testout
+ )
+
+ imagoIO.start()
+ value = testout.getvalue()
+ self.assertEqual(
+ '? Wrong number of arguments\n' +
+ '? Usage: fixed_handicap <count>\n\n' +
+ '= A1 A2\n\n' +
+ '= \n\n',
+ value
+ )
+
+ testout.close()
+
+
+# @unittest.mock.patch('imago.engine.imagoIO.input', create=True)
+# def testGenmove(self, mocked_input):
+# """Test command for generating a move."""
+#
+# mocked_input.side_effect = [
+# 'genmove\n',
+# 'genmove w w\n',
+# 'genmove 2\n',
+# 'quit\n'
+# ]
+#
+# testout = io.StringIO()
+# imagoIO = ImagoIO(
+# decisionAlgorithmId=DecisionAlgorithms.MONTECARLO,
+# outputStream=testout
+# )
+#
+# imagoIO.start()
+# value = testout.getvalue()
+# self.assertEqual(
+# '? Wrong number of arguments\n' +
+# '? Usage: genmove <color>\n\n' +
+# '? Wrong number of arguments\n' +
+# '? Usage: genmove <color>\n\n' +
+# '? Error: Unknown color [2].\n\n',
+# value
+# )
+#
+# mocked_input.side_effect = [
+# 'genmove w\n',
+# 'quit\n']
+#
+# testout = io.StringIO()
+# imagoIO = ImagoIO(
+# decisionAlgorithmId=DecisionAlgorithms.MONTECARLO,
+# outputStream=testout
+# )
+# imagoIO.start()
+# value = testout.getvalue()
+# vertexValue = value.split(' ')[1].split('\n')[0]
+#
+# # Test parsing vertex does not raise an error
+# parseVertex(vertexValue, imagoIO.gameEngine.gameState.size)
+#
+# testout.close()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_monteCarlo.py b/tests/test_monteCarlo.py
index b217cf9..9d1fcfc 100644
--- a/tests/test_monteCarlo.py
+++ b/tests/test_monteCarlo.py
@@ -2,6 +2,7 @@
import unittest
+from imago.engine.decisionAlgorithm import DecisionAlgorithm
from imago.gameLogic.gameState import GameState
from imago.engine.monteCarlo import MCTS
from imago.engine.monteCarlo import MCTSNode
@@ -17,8 +18,55 @@ class TestMonteCarlo(unittest.TestCase):
tree = MCTS(state.lastMove)
#print(tree.pickMove().toString())
+ def testForceNextMove(self):
+ """Test forcing next move."""
+
+ # Next move before expansion (no children nodes)
+ state = GameState(TEST_BOARD_SIZE)
+ tree = MCTS(state.lastMove)
+ self.assertEqual(set(), tree.root.children)
+ tree.forceNextMove((0, 1))
+ self.assertEqual(set(), tree.root.children)
+
+ # Next move after expansion (with children nodes)
+ tree.expansions = 2
+ tree.simulationsPerExpansion = 2
+ tree.pickMove()
+ self.assertEqual(tree.expansions, len(tree.root.children))
+ nextMoveCoords = list(tree.root.children)[0].move.coords
+ tree.forceNextMove(nextMoveCoords)
+
+ def testPass(self):
+ """Test passing as next move."""
+ state = GameState(TEST_BOARD_SIZE)
+ tree = MCTS(state.lastMove)
+ self.assertFalse(tree.root.move.isPass)
+ tree.forceNextMove("pass")
+ self.assertTrue(tree.root.move.isPass)
+
+ def testClearBoard(self):
+ """Test clearing board returns root to original and retains information."""
+ state = GameState(TEST_BOARD_SIZE)
+ tree = MCTS(state.lastMove)
+
+ firstMoveCoords = (0,0)
+ secondMoveCoords = (1,0)
+ thirdMoveCoords = (0,1)
+
+ tree.forceNextMove(firstMoveCoords)
+ tree.forceNextMove(secondMoveCoords)
+ tree.forceNextMove(thirdMoveCoords)
+ tree.clearBoard()
+
+ nextNode = list(tree.root.children)[0]
+ self.assertEqual(firstMoveCoords, nextNode.move.coords)
+ nextNode = list(nextNode.children)[0]
+ self.assertEqual(secondMoveCoords, nextNode.move.coords)
+ nextNode = list(nextNode.children)[0]
+ self.assertEqual(thirdMoveCoords, nextNode.move.coords)
+
#def testSimulation(self):
- # """Test calculation of group liberties."""
+ # """Test Monte Carlo simulation."""
# board = GameBoard(TEST_BOARD_SIZE, TEST_BOARD_SIZE)
# move = GameMove(board)
# node = MCTSNode(move, None)
diff --git a/tests/test_neuralNetwork.py b/tests/test_neuralNetwork.py
new file mode 100644
index 0000000..42ba4a1
--- /dev/null
+++ b/tests/test_neuralNetwork.py
@@ -0,0 +1,83 @@
+"""Tests for neural network module."""
+
+import os
+import shutil
+import unittest
+
+from imago.data.enums import DecisionAlgorithms
+from imago.sgfParser.sgf import loadGameTree
+from imago.gameLogic.gameState import GameState
+from imago.engine.keras.neuralNetwork import NeuralNetwork
+from imago.engine.keras.denseNeuralNetwork import DenseNeuralNetwork
+from imago.engine.keras.convNeuralNetwork import ConvNeuralNetwork
+from imago.engine.keras.keras import Keras
+
+class TestNeuralNetwork(unittest.TestCase):
+ """Test neural network module."""
+
+ def testLoadBaseClass(self):
+ """Test error when creating model with the base NeuralNetwork class"""
+
+ self.assertRaises(NotImplementedError,
+ NeuralNetwork,
+ "non/existing/file")
+
+ def testNetworks(self):
+ """Test creation of initial model for dense neural network"""
+
+ testModel = 'testModel'
+ testModelPlot = 'testModelPlot'
+
+ games = []
+ for file in [
+ '../collections/minigo/matches/1.sgf',
+ '../collections/minigo/matches/2.sgf',
+ '../collections/minigo/matches/3.sgf'
+ ]:
+ games.append(loadGameTree(file))
+ matches = [game.getMainLineOfPlay() for game in games]
+
+ nn = DenseNeuralNetwork(modelPath=testModel, boardSize=9)
+ nn.trainModel(matches, epochs=1, verbose=0)
+
+ game = GameState(9)
+ nn.pickMove(game.lastMove, game.getCurrentPlayer())
+
+ nn.saveModel(testModel)
+ self.assertTrue(os.path.isdir(testModel))
+ shutil.rmtree(testModel, ignore_errors=True)
+
+ nn.saveModel()
+ self.assertTrue(os.path.isdir(testModel))
+ nn = DenseNeuralNetwork(modelPath=testModel, boardSize=9)
+
+ nn.saveModelPlot(testModelPlot)
+ self.assertTrue(os.path.isfile(testModelPlot))
+
+ shutil.rmtree(testModel, ignore_errors=True)
+ os.remove(testModelPlot)
+
+ nn = ConvNeuralNetwork(testModel, boardSize=9)
+
+ def testKeras(self):
+ """Test keras model loading."""
+
+ gameState = GameState(9)
+ move = gameState.lastMove
+
+ keras = Keras(move)
+ keras.forceNextMove("pass")
+
+ keras = Keras(move, DecisionAlgorithms.DENSE)
+ keras.forceNextMove((3,3))
+
+ keras = Keras(move, DecisionAlgorithms.CONV)
+ self.assertRaises(RuntimeError, keras.forceNextMove, "wrongmove")
+ pickedCoords = keras.pickMove()
+ self.assertTrue(len(pickedCoords) == 2 or pickedCoords == "pass")
+
+ self.assertRaises(RuntimeError, Keras, move, DecisionAlgorithms.MONTECARLO)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_parseHelpers.py b/tests/test_parseHelpers.py
index 7bbf152..c1405fb 100644
--- a/tests/test_parseHelpers.py
+++ b/tests/test_parseHelpers.py
@@ -26,7 +26,7 @@ class TestParseHelpers(unittest.TestCase):
)
parsedMove = parseHelpers.parseMove(["B", "t1"], TEST_BOARD_SIZE)
- targetMove = parseHelpers.GtpMove(Player.BLACK, [18, 18])
+ targetMove = parseHelpers.GtpMove(Player.BLACK, (18, 18))
self.assertEqual(parsedMove.color, targetMove.color)
self.assertEqual(parsedMove.vertex, targetMove.vertex)
@@ -54,26 +54,26 @@ class TestParseHelpers(unittest.TestCase):
"""Test correct inputs and their resulting coordinates for parseVertex."""
self.assertEqual(parseHelpers.parseVertex(
"a1", TEST_BOARD_SIZE),
- [18,0])
+ (18,0))
self.assertEqual(parseHelpers.parseVertex(
"b1", TEST_BOARD_SIZE),
- [18,1])
+ (18,1))
self.assertEqual(parseHelpers.parseVertex(
"a2", TEST_BOARD_SIZE),
- [17,0])
+ (17,0))
self.assertEqual(parseHelpers.parseVertex(
"b2", TEST_BOARD_SIZE),
- [17,1])
+ (17,1))
self.assertEqual(parseHelpers.parseVertex(
"T1", TEST_BOARD_SIZE),
- [18,18])
+ (18,18))
self.assertEqual(parseHelpers.parseVertex(
"T19", TEST_BOARD_SIZE),
- [0,18])
+ (0,18))
self.assertEqual(parseHelpers.parseVertex(
"A19", TEST_BOARD_SIZE),
- [0,0])
+ (0,0))
self.assertEqual(parseHelpers.parseVertex(
"pass", TEST_BOARD_SIZE),
@@ -81,10 +81,14 @@ class TestParseHelpers(unittest.TestCase):
def testVertexToString(self):
"""Test converting vertices to strings."""
- self.assertEqual(parseHelpers.vertexToString([0,0], TEST_BOARD_SIZE), "A19")
- self.assertEqual(parseHelpers.vertexToString([1,0], TEST_BOARD_SIZE), "A18")
- self.assertEqual(parseHelpers.vertexToString([2,0], TEST_BOARD_SIZE), "A17")
- self.assertEqual(parseHelpers.vertexToString([0,1], TEST_BOARD_SIZE), "B19")
+
+ # Try with vertices as tuples
+ self.assertEqual(parseHelpers.vertexToString((0,0), TEST_BOARD_SIZE), "A19")
+ self.assertEqual(parseHelpers.vertexToString((1,0), TEST_BOARD_SIZE), "A18")
+ self.assertEqual(parseHelpers.vertexToString((2,0), TEST_BOARD_SIZE), "A17")
+ self.assertEqual(parseHelpers.vertexToString((0,1), TEST_BOARD_SIZE), "B19")
+
+ # Try with vertices as arrays
self.assertEqual(parseHelpers.vertexToString([0,2], TEST_BOARD_SIZE), "C19")
self.assertEqual(parseHelpers.vertexToString([0,18], TEST_BOARD_SIZE), "T19")
self.assertEqual(parseHelpers.vertexToString([18,0], TEST_BOARD_SIZE), "A1")
@@ -93,10 +97,10 @@ class TestParseHelpers(unittest.TestCase):
self.assertEqual(parseHelpers.vertexToString("pass", TEST_BOARD_SIZE), "pass")
wrongVertices = [
- [-1,0],
- [0,-1],
- [-1,-1],
- [19,0],
+ (-1,0),
+ (0,-1),
+ (-1,-1),
+ (19,0),
[0,19],
[19,19],
[0],
diff --git a/tests/test_sgf.py b/tests/test_sgf.py
new file mode 100644
index 0000000..1266429
--- /dev/null
+++ b/tests/test_sgf.py
@@ -0,0 +1,27 @@
+"""Tests for processing of SGF files."""
+
+import unittest
+
+from imago.sgfParser.sgfyacc import parser
+
+TESTING_SGF = 'tests/testingSGF.sgf'
+
+class TestSGF(unittest.TestCase):
+ """Test processing SGF files."""
+
+ def testToGameTree(self):
+ """Test converting file to GameTree"""
+
+ file = open(TESTING_SGF, "r")
+ text = file.read()
+ file.close()
+
+ astNode = parser.parse(text)
+
+ astNode.toGameMoveTree()
+
+ astNode.toString()
+
+
+if __name__ == '__main__':
+ unittest.main()