Browse Source

finish team and unit stashs

Bastien Sevajol 5 years ago
parent
commit
6c0a0430fc

+ 4 - 0
opencombat/exception.py View File

@@ -23,3 +23,7 @@ class StateLoadError(OpenCombatException):
23 23
 
24 24
 class NotFoundError(OpenCombatException):
25 25
     pass
26
+
27
+
28
+class NotFoundException(OpenCombatException):
29
+    pass

+ 22 - 1
opencombat/strategy/team/model.py View File

@@ -1,13 +1,34 @@
1 1
 # coding: utf-8
2
+import typing
2 3
 
4
+from opencombat.strategy.unit.model import UnitModel
3 5
 
4
-class UnitModel(object):
6
+
7
+class TeamModel(object):
5 8
     def __init__(
6 9
         self,
10
+        id_: str,
7 11
         name: str,
12
+        country: str,
13
+        units: typing.List[UnitModel],
8 14
     ) -> None:
15
+        self._id = id_
9 16
         self._name = name
17
+        self._country = country
18
+        self._units = units
19
+
20
+    @property
21
+    def id(self) -> str:
22
+        return self._id
10 23
 
11 24
     @property
12 25
     def name(self) -> str:
13 26
         return self._name
27
+
28
+    @property
29
+    def country(self) -> str:
30
+        return self._country
31
+
32
+    @property
33
+    def units(self) -> typing.List[UnitModel]:
34
+        return self._units

+ 63 - 8
opencombat/strategy/team/stash.py View File

@@ -1,9 +1,13 @@
1 1
 # coding: utf-8
2 2
 import typing
3
+from _elementtree import Element
3 4
 
4 5
 from synergine2.config import Config
5 6
 
6
-from opencombat.strategy.unit.model import TeamModel
7
+from opencombat.exception import NotFoundException
8
+from opencombat.strategy.team.model import TeamModel
9
+from opencombat.strategy.unit.stash import UnitStash
10
+from opencombat.util import get_text_xml_element
7 11
 from opencombat.xml import XmlValidator
8 12
 
9 13
 
@@ -12,21 +16,72 @@ class TeamStash(object):
12 16
         self,
13 17
         config: Config,
14 18
         teams_file_path: str,
19
+        unit_stash: UnitStash,
15 20
     ) -> None:
16 21
         self._config = config
17
-        self._teams = None  # typing.List[TeamModel]
22
+        self._teams = None  # type: typing.List[TeamModel]
23
+        self._unit_stash = unit_stash
18 24
 
19
-        schema_file_path = self._config.get(
25
+        self.schema_file_path = self._config.get(
20 26
             'global.teams_schema',
21 27
             'opencombat/strategy/teams.xsd',
22 28
         )
23 29
         self._xml_validator = XmlValidator(
24 30
             config,
25
-            schema_file_path,
31
+            self.schema_file_path,
26 32
         )
33
+        self._root_element = self._xml_validator.validate_and_return(
34
+            teams_file_path,
35
+        )
36
+
37
+    def _get_computed_teams(self) -> typing.List[TeamModel]:
38
+        teams = []
39
+
40
+        for team_element in self._root_element.findall('team'):
41
+            team_element = typing.cast(Element, team_element)
42
+
43
+            team_id = team_element.attrib['id']
44
+            team_country = team_element.attrib['country']
45
+            team_name = get_text_xml_element(team_element, 'name')
46
+            team_units = []
47
+
48
+            units_element = team_element.find('units')
49
+            for unit_element in units_element.findall('unit'):
50
+                unit_id = get_text_xml_element(unit_element, 'id')
51
+                unit = self._unit_stash.get_unit(unit_id, team_country)
52
+                team_units.append(unit)
53
+
54
+            teams.append(
55
+                TeamModel(
56
+                    id_=team_id,
57
+                    country=team_country,
58
+                    name=team_name,
59
+                    units=team_units
60
+                )
61
+            )
27 62
 
28
-    def get_teams(self) -> typing.List[TeamModel]:
29
-        pass
63
+        return teams
30 64
 
31
-    def get_team(self, unit_id: str) -> TeamModel:
32
-        pass
65
+    @property
66
+    def teams(self) -> typing.List[TeamModel]:
67
+        if self._teams is None:
68
+            self._teams = self._get_computed_teams()
69
+
70
+        return self._teams
71
+
72
+    def get_team(
73
+        self,
74
+        team_id: str,
75
+        team_country: str,
76
+    ) -> TeamModel:
77
+        for team in self.teams:
78
+            if team.id == team_id and team.country == team_country:
79
+                return team
80
+
81
+        raise NotFoundException(
82
+            'No team matching with id "{}" and country "{}" in "{}"'.format(
83
+                team_id,
84
+                team_country,
85
+                self.schema_file_path,
86
+            )
87
+        )

+ 22 - 1
opencombat/strategy/unit/model.py View File

@@ -1,13 +1,34 @@
1 1
 # coding: utf-8
2
+import typing
2 3
 
4
+from opencombat.simulation.subject import TileSubject
3 5
 
4
-class TeamModel(object):
6
+
7
+class UnitModel(object):
5 8
     def __init__(
6 9
         self,
10
+        id_: str,
7 11
         name: str,
12
+        class_: typing.Type[TileSubject],
13
+        country: str,
8 14
     ) -> None:
15
+        self._id = id_
9 16
         self._name = name
17
+        self._class = class_
18
+        self._country = country
19
+
20
+    @property
21
+    def id(self) -> str:
22
+        return self._id
10 23
 
11 24
     @property
12 25
     def name(self) -> str:
13 26
         return self._name
27
+
28
+    @property
29
+    def class_(self) -> typing.Type[TileSubject]:
30
+        return self._class
31
+
32
+    @property
33
+    def country(self) -> str:
34
+        return self._country

+ 59 - 8
opencombat/strategy/unit/stash.py View File

@@ -1,9 +1,13 @@
1 1
 # coding: utf-8
2 2
 import typing
3
+from _elementtree import Element
3 4
 
4 5
 from synergine2.config import Config
5 6
 
7
+from opencombat.exception import NotFoundException
6 8
 from opencombat.strategy.team.model import UnitModel
9
+from opencombat.util import get_text_xml_element
10
+from opencombat.util import get_class_from_string_path
7 11
 from opencombat.xml import XmlValidator
8 12
 
9 13
 
@@ -14,19 +18,66 @@ class UnitStash(object):
14 18
         units_file_path: str,
15 19
     ) -> None:
16 20
         self._config = config
17
-        self._units = None  # typing.List[UnitModel]
21
+        self._units = None  # type: typing.List[UnitModel]
18 22
 
19
-        schema_file_path = self._config.get(
23
+        self.schema_file_path = self._config.get(
20 24
             'global.teams_schema',
21
-            'opencombat/strategy/teams.xsd',
25
+            'opencombat/strategy/units.xsd',
22 26
         )
23 27
         self._xml_validator = XmlValidator(
24 28
             config,
25
-            schema_file_path,
29
+            self.schema_file_path,
26 30
         )
31
+        self._root_element = self._xml_validator.validate_and_return(
32
+            units_file_path,
33
+        )
34
+
35
+    def _get_computed_units(self) -> typing.List[UnitModel]:
36
+        units = []
37
+
38
+        for unit_element in self._root_element.findall('unit'):
39
+            unit_element = typing.cast(Element, unit_element)
40
+
41
+            unit_id = unit_element.attrib['id']
42
+            unit_country = unit_element.attrib['country']
43
+            unit_name = get_text_xml_element(unit_element, 'name')
44
+            unit_class_path = get_text_xml_element(unit_element, 'type')
45
+            unit_class = get_class_from_string_path(
46
+                self._config,
47
+                unit_class_path,
48
+            )
49
+
50
+            units.append(
51
+                UnitModel(
52
+                    id_=unit_id,
53
+                    name=unit_name,
54
+                    class_=unit_class,
55
+                    country=unit_country,
56
+                )
57
+            )
27 58
 
28
-    def get_units(self) -> typing.List[UnitModel]:
29
-        pass
59
+        return units
30 60
 
31
-    def get_unit(self, unit_id: str) -> UnitModel:
32
-        pass
61
+    @property
62
+    def units(self) -> typing.List[UnitModel]:
63
+        if self._units is None:
64
+            self._units = self._get_computed_units()
65
+
66
+        return self._units
67
+
68
+    def get_unit(
69
+        self,
70
+        unit_id: str,
71
+        unit_country: str,
72
+    ) -> UnitModel:
73
+        for unit in self.units:
74
+            if unit.id == unit_id and unit.country == unit_country:
75
+                return unit
76
+
77
+        raise NotFoundException(
78
+            'No unit matching with id "{}" and country "{}" in "{}"'.format(
79
+                unit_id,
80
+                unit_country,
81
+                self.schema_file_path,
82
+            )
83
+        )

+ 37 - 0
tests/fixtures/teams.xml View File

@@ -0,0 +1,37 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<teams>
3
+    <team id="std_team" country="URSS">
4
+        <name>Standard team</name>
5
+        <units>
6
+            <unit>
7
+                <id>std_soldier</id>
8
+            </unit>
9
+            <unit>
10
+                <id>std_soldier</id>
11
+            </unit>
12
+            <unit>
13
+                <id>std_soldier</id>
14
+            </unit>
15
+            <unit>
16
+                <id>std_soldier</id>
17
+            </unit>
18
+        </units>
19
+    </team>
20
+    <team id="std_team" country="DE">
21
+        <name>Standard team</name>
22
+        <units>
23
+            <unit>
24
+                <id>std_soldier</id>
25
+            </unit>
26
+            <unit>
27
+                <id>std_soldier</id>
28
+            </unit>
29
+            <unit>
30
+                <id>std_soldier</id>
31
+            </unit>
32
+            <unit>
33
+                <id>std_soldier</id>
34
+            </unit>
35
+        </units>
36
+    </team>
37
+</teams>

+ 11 - 0
tests/fixtures/units.xml View File

@@ -0,0 +1,11 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<units>
3
+    <unit id="std_soldier" country="URSS">
4
+        <name>Standard soldier</name>
5
+        <type>opencombat.simulation.subject.ManSubject</type>
6
+    </unit>
7
+    <unit id="std_soldier" country="DE">
8
+        <name>Standard soldier</name>
9
+        <type>opencombat.simulation.subject.ManSubject</type>
10
+    </unit>
11
+</units>

+ 94 - 0
tests/strategy/test_teams.py View File

@@ -1,13 +1,107 @@
1 1
 # coding: utf-8
2
+import pytest
2 3
 from synergine2.config import Config
3 4
 
5
+from opencombat.exception import NotFoundException
6
+from opencombat.strategy.team.model import TeamModel
4 7
 from opencombat.strategy.team.stash import TeamStash
8
+from opencombat.strategy.unit.model import UnitModel
9
+from opencombat.strategy.unit.stash import UnitStash
10
+
11
+
12
+@pytest.fixture
13
+def unit_stash(
14
+    config: Config,
15
+) -> UnitStash:
16
+    return UnitStash(
17
+        config,
18
+        'tests/fixtures/units.xml',
19
+    )
5 20
 
6 21
 
7 22
 def test_units_stash__ok__instantiate(
8 23
     config: Config,
24
+    unit_stash: UnitStash,
9 25
 ):
10 26
     TeamStash(
11 27
         config,
12 28
         'opencombat/strategy/teams.xml',
29
+        unit_stash=unit_stash,
13 30
     )
31
+
32
+
33
+def test_team_stash__ok__get_teams(
34
+    config: Config,
35
+    unit_stash: UnitStash,
36
+):
37
+    stash = TeamStash(
38
+        config,
39
+        'tests/fixtures/teams.xml',
40
+        unit_stash=unit_stash,
41
+    )
42
+    assert stash.teams
43
+    assert 2 == len(stash.teams)
44
+    assert isinstance(stash.teams[0], TeamModel)
45
+    assert isinstance(stash.teams[1], TeamModel)
46
+
47
+    assert 'std_team' == stash.teams[0].id
48
+    assert 'Standard team' == stash.teams[0].name
49
+    assert 'URSS' == stash.teams[0].country
50
+    assert stash.teams[0].units
51
+    assert 4 == len(stash.teams[0].units)
52
+    assert isinstance(stash.teams[0].units[0], UnitModel)
53
+    assert 'std_soldier' == stash.teams[0].units[0].id
54
+    assert 'std_soldier' == stash.teams[0].units[1].id
55
+    assert 'std_soldier' == stash.teams[0].units[2].id
56
+    assert 'std_soldier' == stash.teams[0].units[3].id
57
+
58
+    assert 'std_team' == stash.teams[1].id
59
+    assert 'Standard team' == stash.teams[1].name
60
+    assert 'DE' == stash.teams[1].country
61
+    assert stash.teams[0].units
62
+    assert 4 == len(stash.teams[1].units)
63
+    assert isinstance(stash.teams[1].units[0], UnitModel)
64
+    assert 'std_soldier' == stash.teams[1].units[0].id
65
+    assert 'std_soldier' == stash.teams[1].units[1].id
66
+    assert 'std_soldier' == stash.teams[1].units[2].id
67
+    assert 'std_soldier' == stash.teams[1].units[3].id
68
+
69
+
70
+def test_teams_stash__ok__get_unit(
71
+    config: Config,
72
+    unit_stash: UnitStash,
73
+):
74
+    stash = TeamStash(
75
+        config,
76
+        'tests/fixtures/teams.xml',
77
+        unit_stash=unit_stash,
78
+    )
79
+    assert stash.get_team('std_team', 'URSS')
80
+
81
+
82
+def test_teams_stash__error__get_team_wrong_country(
83
+    config: Config,
84
+    unit_stash: UnitStash,
85
+):
86
+    stash = TeamStash(
87
+        config,
88
+        'tests/fixtures/teams.xml',
89
+        unit_stash=unit_stash,
90
+    )
91
+
92
+    with pytest.raises(NotFoundException):
93
+        stash.get_team('std_team', 'UNKNOWN')
94
+
95
+
96
+def test_teams_stash__error__get_team_wrong_id(
97
+    config: Config,
98
+    unit_stash: UnitStash,
99
+):
100
+    stash = TeamStash(
101
+        config,
102
+        'tests/fixtures/teams.xml',
103
+        unit_stash=unit_stash,
104
+    )
105
+
106
+    with pytest.raises(NotFoundException):
107
+        stash.get_team('unknown', 'URSS')

+ 61 - 0
tests/strategy/test_units.py View File

@@ -1,6 +1,10 @@
1 1
 # coding: utf-8
2
+import pytest
2 3
 from synergine2.config import Config
3 4
 
5
+from opencombat.exception import NotFoundException
6
+from opencombat.simulation.subject import ManSubject
7
+from opencombat.strategy.team.model import UnitModel
4 8
 from opencombat.strategy.unit.stash import UnitStash
5 9
 
6 10
 
@@ -11,3 +15,60 @@ def test_units_stash__ok__instantiate(
11 15
         config,
12 16
         'opencombat/strategy/units.xml',
13 17
     )
18
+
19
+
20
+def test_units_stash__ok__get_units(
21
+    config: Config,
22
+):
23
+    stash = UnitStash(
24
+        config,
25
+        'tests/fixtures/units.xml',
26
+    )
27
+    assert stash.units
28
+    assert 2 == len(stash.units)
29
+    assert isinstance(stash.units[0], UnitModel)
30
+    assert isinstance(stash.units[1], UnitModel)
31
+
32
+    assert 'std_soldier' == stash.units[0].id
33
+    assert 'Standard soldier' == stash.units[0].name
34
+    assert 'URSS' == stash.units[0].country
35
+    assert ManSubject == stash.units[0].class_
36
+
37
+    assert 'std_soldier' == stash.units[1].id
38
+    assert 'Standard soldier' == stash.units[1].name
39
+    assert 'DE' == stash.units[1].country
40
+    assert ManSubject == stash.units[1].class_
41
+
42
+
43
+def test_units_stash__ok__get_unit(
44
+    config: Config,
45
+):
46
+    stash = UnitStash(
47
+        config,
48
+        'tests/fixtures/units.xml',
49
+    )
50
+    assert stash.get_unit('std_soldier', 'URSS')
51
+
52
+
53
+def test_units_stash__error__get_unit_wrong_country(
54
+    config: Config,
55
+):
56
+    stash = UnitStash(
57
+        config,
58
+        'tests/fixtures/units.xml',
59
+    )
60
+
61
+    with pytest.raises(NotFoundException):
62
+        stash.get_unit('std_soldier', 'UNKNOWN')
63
+
64
+
65
+def test_units_stash__error__get_unit_wrong_id(
66
+    config: Config,
67
+):
68
+    stash = UnitStash(
69
+        config,
70
+        'tests/fixtures/units.xml',
71
+    )
72
+
73
+    with pytest.raises(NotFoundException):
74
+        stash.get_unit('unknown', 'URSS')