Repository: ocadotechnology/aimmo

Issue:
Test coverage
Some first extra tests written to get the test coverage up a bit.


Discussion:

Resolving patch:
diff --git a/aimmo-game-creator/setup.py b/aimmo-game-creator/setup.py
--- a/aimmo-game-creator/setup.py
+++ b/aimmo-game-creator/setup.py
@@ -12,6 +12,7 @@
     ],
     tests_require=[
         'httmock',
+        'mock',
     ],
     test_suite='tests',
     zip_safe=False,


Test patch:
diff --git a/aimmo-game-creator/tests/test_worker_manager.py b/aimmo-game-creator/tests/test_worker_manager.py
--- a/aimmo-game-creator/tests/test_worker_manager.py
+++ b/aimmo-game-creator/tests/test_worker_manager.py
@@ -1,11 +1,16 @@
 from __future__ import absolute_import
 
+import cPickle as pickle
 import unittest
+
 from json import dumps, loads
 
 from httmock import HTTMock
+import mock
 
 from worker_manager import WorkerManager
+from worker_manager import LocalWorkerManager
+
 
 class ConcreteWorkerManager(WorkerManager):
     def __init__(self, *args, **kwargs):
@@ -93,3 +98,45 @@ def test_added_workers_given_correct_url(self):
                 'http://test/{}/'.format(i)
             )
             self.assertEqual(self.worker_manager.added_workers[str(i)]['name'], 'Game %s' % i)
+
+
+class TestLocalWorkerManager(unittest.TestCase):
+
+    def test_create_worker(self):
+        with mock.patch('subprocess.Popen') as mocked_popen:
+            localWorkerManager = LocalWorkerManager("")
+
+            game_id = 1
+            game_data = {
+                "test" : "test"
+            }
+
+            localWorkerManager.create_worker(game_id, game_data)
+            call_args = mocked_popen.call_args
+
+            argument_dictionary = call_args[1]
+            self.assertTrue("aimmo-game" in argument_dictionary["cwd"])
+            self.assertEqual(argument_dictionary["env"]["test"], "test")
+
+    def test_remove_worker(self):
+        self.killed = False
+        class KillableWorker():
+            def __init__(self, binder):
+                self.binder = binder
+                self.binder.killed = False
+
+            def kill(self):
+                self.binder.killed = True
+
+        localWorkerManager = LocalWorkerManager("")
+        localWorkerManager.workers = {
+            1 : KillableWorker(self)
+        }
+
+        self.assertFalse(self.killed)
+        self.assertTrue(1 in localWorkerManager.workers)
+
+        localWorkerManager.remove_worker(1)
+
+        self.assertTrue(self.killed)
+        self.assertTrue(1 not in localWorkerManager.workers)
diff --git a/aimmo-game-worker/tests/simulation/test_location.py b/aimmo-game-worker/tests/simulation/test_location.py
new file mode 100644
--- /dev/null
+++ b/aimmo-game-worker/tests/simulation/test_location.py
@@ -0,0 +1,29 @@
+from __future__ import absolute_import
+
+from unittest import TestCase
+
+from simulation.location import Location
+
+
+class TestLocation(TestCase):
+
+    def test_add(self):
+        dummy_location = Location(1, 2)
+        direction = Location(1, 1)
+        expected = Location(2, 3)
+        self.assertEqual(dummy_location + direction, expected)
+
+    def test_sub(self):
+        dummy_location = Location(3, 2)
+        direction = Location(1, 1)
+        expected = Location(2, 1)
+        self.assertEqual(dummy_location - direction, expected)
+
+    def test_repr(self):
+        dummy_location = Location(1, 2)
+        self.assertTrue("Location(1, 2)" == str(dummy_location))
+
+    def test_not_equal(self):
+        dummy_location_1 = Location(1, 1)
+        dummy_location_2 = Location(2, 2)
+        self.assertTrue(dummy_location_1 != dummy_location_2)
diff --git a/aimmo-game/tests/test_simulation/avatar/test_fog_of_war.py b/aimmo-game/tests/test_simulation/avatar/test_fog_of_war.py
new file mode 100644
--- /dev/null
+++ b/aimmo-game/tests/test_simulation/avatar/test_fog_of_war.py
@@ -0,0 +1,11 @@
+from __future__ import absolute_import
+
+from unittest import TestCase
+
+from simulation.avatar.fog_of_war import should_partially_fog
+
+
+class TestFogOfWar(TestCase):
+    def test_should_partially_fog(self):
+        self.assertFalse(should_partially_fog(no_fog_distance=20, partial_fog_distance=2, x_dist=1, y_dist=10))
+        self.assertTrue(should_partially_fog(no_fog_distance=1, partial_fog_distance=2, x_dist=20, y_dist=10))
diff --git a/aimmo-game/tests/test_simulation/test_location.py b/aimmo-game/tests/test_simulation/test_location.py
--- a/aimmo-game/tests/test_simulation/test_location.py
+++ b/aimmo-game/tests/test_simulation/test_location.py
@@ -9,39 +9,46 @@ class TestLocation(TestCase):
     def test_equal(self):
         loc_1 = Location(3, 3)
         loc_2 = Location(3, 3)
+
         self.assertEqual(loc_1, loc_2)
         self.assertFalse(loc_1 != loc_2)
 
     def test_x_not_equal(self):
         loc_1 = Location(3, 3)
         loc_2 = Location(4, 3)
+
         self.assertNotEqual(loc_1, loc_2)
         self.assertFalse(loc_1 == loc_2)
 
     def test_y_not_equal(self):
         loc_1 = Location(4, 4)
         loc_2 = Location(4, 3)
+
         self.assertNotEqual(loc_1, loc_2)
         self.assertFalse(loc_1 == loc_2)
 
     def test_add(self):
         loc_1 = Location(1, 2)
         loc_2 = Location(3, 4)
+
         expected = Location(4, 6)
         self.assertEqual(loc_1 + loc_2, expected)
 
     def test_sub(self):
         loc_1 = Location(1, 2)
         loc_2 = Location(3, 4)
+
         expected = Location(-2, -2)
         self.assertEqual(loc_1 - loc_2, expected)
 
     def test_hash_equal(self):
         loc_1 = Location(3, 3)
         loc_2 = Location(3, 3)
+
         self.assertEqual(hash(loc_1), hash(loc_2))
 
     def test_serialise(self):
         loc = Location(3, 9)
+
         expected = {'x': 3, 'y': 9}
         self.assertEqual(loc.serialise(), expected)
diff --git a/aimmo-game/tests/test_simulation/test_turn_manager.py b/aimmo-game/tests/test_simulation/test_turn_manager.py
--- a/aimmo-game/tests/test_simulation/test_turn_manager.py
+++ b/aimmo-game/tests/test_simulation/test_turn_manager.py
@@ -6,6 +6,7 @@
 from simulation.game_state import GameState
 from simulation.location import Location
 from simulation.turn_manager import ConcurrentTurnManager
+from simulation.turn_manager import SequentialTurnManager
 from .dummy_avatar import DummyAvatarManager
 from .dummy_avatar import MoveEastDummy
 from .dummy_avatar import MoveNorthDummy
@@ -32,16 +33,22 @@ class TestTurnManager(unittest.TestCase):
     def construct_default_avatar_appearance(self):
         return AvatarAppearance("#000", "#ddd", "#777", "#fff")
 
-    def construct_turn_manager(self, avatars, locations):
+    def construct_turn_manager(self, avatars, locations, manager):
         self.avatar_manager = DummyAvatarManager(avatars)
         self.game_state = MockGameState(InfiniteMap(), self.avatar_manager)
-        self.turn_manager = ConcurrentTurnManager(game_state=self.game_state,
+        self.turn_manager = manager(game_state=self.game_state,
                                                   end_turn_callback=lambda: None,
                                                   completion_url='')
         for index, location in enumerate(locations):
             self.game_state.add_avatar(index, "", location)
         return self.turn_manager
 
+    def construct_concurrent_turn_manager(self, avatars, locations):
+        return self.construct_turn_manager(avatars, locations, ConcurrentTurnManager)
+
+    def construct_sequential_turn_manager(self, avatars, locations):
+        return self.construct_turn_manager(avatars, locations, SequentialTurnManager)
+
     def assert_at(self, avatar, location):
         self.assertEqual(avatar.location, location)
         cell = self.game_state.world_map.get_cell(location)
@@ -53,33 +60,33 @@ def get_avatar(self, player_id):
     def run_turn(self):
         self.turn_manager.run_turn()
 
-    def test_run_turn(self):
+    def run_by_manager_turn(self, construct_manager):
         '''
         Given:  > _
         (1)
         Expect: _ o
         '''
-        self.construct_turn_manager([MoveEastDummy], [ORIGIN])
+        construct_manager([MoveEastDummy], [ORIGIN])
         avatar = self.get_avatar(0)
 
         self.assert_at(avatar, ORIGIN)
         self.run_turn()
         self.assert_at(avatar, RIGHT_OF_ORIGIN)
 
-    def test_run_several_turns(self):
+    def run_by_manager_several_turns(self, construct_manager):
         '''
         Given:  > _ _ _ _ _
         (5)
         Expect: _ _ _ _ _ o
         '''
-        self.construct_turn_manager([MoveEastDummy], [ORIGIN])
+        construct_manager([MoveEastDummy], [ORIGIN])
         avatar = self.get_avatar(0)
 
         self.assertEqual(avatar.location, ORIGIN)
         [self.run_turn() for _ in range(5)]
         self.assertEqual(avatar.location, FIVE_RIGHT_OF_ORIGIN)
 
-    def test_run_several_turns_and_avatars(self):
+    def run_by_manager_several_turns_and_avatars(self, construct_manager):
         '''
         Given:  > _ _ _ _ _
                 > _ _ _ _ _
@@ -87,7 +94,7 @@ def test_run_several_turns_and_avatars(self):
         Expect: _ _ _ _ _ o
                 _ _ _ _ _ o
         '''
-        self.construct_turn_manager([MoveEastDummy, MoveEastDummy],
+        construct_manager([MoveEastDummy, MoveEastDummy],
                                     [ORIGIN,        ABOVE_ORIGIN])
         avatar0 = self.get_avatar(0)
         avatar1 = self.get_avatar(1)
@@ -98,13 +105,13 @@ def test_run_several_turns_and_avatars(self):
         self.assert_at(avatar0, FIVE_RIGHT_OF_ORIGIN)
         self.assert_at(avatar1, FIVE_RIGHT_OF_ORIGIN_AND_ONE_ABOVE)
 
-    def test_move_chain_succeeds(self):
+    def run_by_manager_move_chain_succeeds(self, construct_manager):
         '''
         Given:  > > > > > _
 
         Expect: _ o o o o o
         '''
-        self.construct_turn_manager([MoveEastDummy for _ in range(5)],
+        construct_manager([MoveEastDummy for _ in range(5)],
                                     [Location(x, 0) for x in range(5)])
         avatars = [self.get_avatar(i) for i in range(5)]
 
@@ -112,13 +119,13 @@ def test_move_chain_succeeds(self):
         self.run_turn()
         [self.assert_at(avatars[x], Location(x + 1, 0)) for x in range(5)]
 
-    def test_move_chain_fails_occupied(self):
+    def run_by_manager_move_chain_fails_occupied(self, construct_manager):
         '''
         Given:  > > x _
 
         Expect: x x x _
         '''
-        self.construct_turn_manager([MoveEastDummy, MoveEastDummy, WaitDummy],
+        construct_manager([MoveEastDummy, MoveEastDummy, WaitDummy],
                                     [Location(x, 0) for x in range(3)])
         avatars = [self.get_avatar(i) for i in range(3)]
 
@@ -126,14 +133,14 @@ def test_move_chain_fails_occupied(self):
         self.run_turn()
         [self.assert_at(avatars[x], Location(x, 0)) for x in range(3)]
 
-    def test_move_chain_fails_collision(self):
+    def run_by_manager_move_chain_fails_collision(self, construct_manager):
         '''
         Given:  > > > _ <
         (1)
         Expect: x x x _ x
         '''
         locations = [Location(0, 0), Location(1, 0), Location(2, 0), Location(4, 0)]
-        self.construct_turn_manager(
+        construct_manager(
             [MoveEastDummy, MoveEastDummy, MoveEastDummy, MoveWestDummy],
             locations)
         avatars = [self.get_avatar(i) for i in range(4)]
@@ -142,7 +149,7 @@ def test_move_chain_fails_collision(self):
         self.run_turn()
         [self.assert_at(avatars[i], locations[i]) for i in range(4)]
 
-    def test_move_chain_fails_cycle(self):
+    def run_by_manager_move_chain_fails_cycle(self, construct_manager):
         '''
         Given:  > v
                 ^ <
@@ -151,7 +158,7 @@ def test_move_chain_fails_cycle(self):
                 x x
         '''
         locations = [Location(0, 1), Location(1, 1), Location(1, 0), Location(0, 0)]
-        self.construct_turn_manager(
+        construct_manager(
             [MoveEastDummy, MoveSouthDummy, MoveWestDummy, MoveNorthDummy],
             locations)
         avatars = [self.get_avatar(i) for i in range(4)]
@@ -160,7 +167,7 @@ def test_move_chain_fails_cycle(self):
         self.run_turn()
         [self.assert_at(avatars[i], locations[i]) for i in range(4)]
 
-    def test_move_chain_fails_spiral(self):
+    def run_by_manager_move_chain_fails_spiral(self, construct_manager):
         '''
         Given:  > > v
                   ^ <
@@ -173,7 +180,7 @@ def test_move_chain_fails_spiral(self):
                      Location(2, 1),
                      Location(2, 0),
                      Location(1, 0)]
-        self.construct_turn_manager(
+        construct_manager(
             [MoveEastDummy, MoveEastDummy, MoveSouthDummy, MoveWestDummy, MoveNorthDummy],
             locations)
         avatars = [self.get_avatar(i) for i in range(5)]
@@ -182,5 +189,59 @@ def test_move_chain_fails_spiral(self):
         self.run_turn()
         [self.assert_at(avatars[i], locations[i]) for i in range(5)]
 
+    def build_test_by_constructor(self, constructor):
+        self.run_by_manager_turn(constructor)
+        self.run_by_manager_several_turns_and_avatars(constructor)
+        self.run_by_manager_several_turns(constructor)
+        self.run_by_manager_move_chain_fails_spiral(constructor)
+        self.run_by_manager_move_chain_fails_cycle(constructor)
+        self.run_by_manager_move_chain_fails_occupied(constructor)
+
+    def test_concurrent_turn_manager(self):
+        constructor = lambda x, y: self.construct_concurrent_turn_manager(x, y)
+        self.build_test_by_constructor(constructor)
+        self.run_by_manager_move_chain_fails_collision(constructor)
+        self.run_by_manager_move_chain_succeeds(constructor)
+
+    def sequential_move_chain_consecutive_avatars_fails(self):
+        '''
+        Given:  > > > > > _
+        Expect: _ o o o o o
+
+        This should fail for the sequential manager as the first avatar will bump into the second one
+        '''
+        self.construct_sequential_turn_manager([MoveEastDummy for _ in range(5)],
+                          [Location(x, 0) for x in range(5)])
+        avatars = [self.get_avatar(i) for i in range(5)]
+
+        [self.assert_at(avatars[x], Location(x, 0)) for x in range(5)]
+        self.run_turn()
+        [self.assert_at(avatars[x], Location(x, 0)) for x in range(4)]
+        self.assert_at(avatars[4], Location(5, 0))
+
+    def sequential_move_chain_fails_collision(self):
+        '''
+        Given:  > > > _ <
+        (1)
+        Expect: x x x _ x
+        '''
+        locations = [Location(0, 0), Location(1, 0), Location(2, 0), Location(4, 0)]
+        self.construct_sequential_turn_manager(
+            [MoveEastDummy, MoveEastDummy, MoveEastDummy, MoveWestDummy],
+            locations)
+        avatars = [self.get_avatar(i) for i in range(4)]
+
+        [self.assert_at(avatars[i], locations[i]) for i in range(4)]
+        self.run_turn()
+        [self.assert_at(avatars[i], locations[i]) for i in [0, 1, 3]]
+        self.assert_at(avatars[2], Location(3, 0))
+
+    def test_sequential_turn_manager(self):
+        constructor = lambda x, y: self.construct_sequential_turn_manager(x, y)
+        self.build_test_by_constructor(constructor)
+        self.sequential_move_chain_consecutive_avatars_fails()
+        self.sequential_move_chain_fails_collision()
+
+
 if __name__ == '__main__':
     unittest.main()