Skip to content

Commit d48185e

Browse files
committed
Add a pytest for the inputs and holding definitions
1 parent 0e16518 commit d48185e

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

tests/test_definitions.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import pytest
2+
import re
3+
4+
from luxtronik.datatypes import Base
5+
from luxtronik.definitions.holdings import HOLDINGS_DEFINITIONS_LIST
6+
from luxtronik.definitions.inputs import INPUTS_DEFINITIONS_LIST
7+
8+
KEY_IDX = "index"
9+
KEY_COUNT = "count"
10+
KEY_NAMES = "names"
11+
KEY_TYPE = "type"
12+
KEY_WRT = "writeable"
13+
KEY_SINCE = "since"
14+
KEY_UNTIL = "until"
15+
KEY_DESC = "description"
16+
17+
18+
class RunTestDefinitions:
19+
20+
# override this
21+
definitions = None
22+
23+
def get_names(self, definition):
24+
names = definition.get(KEY_NAMES, [])
25+
if isinstance(names, str):
26+
names = [names]
27+
return names
28+
29+
def test_structure(self):
30+
for definition in self.definitions:
31+
assert KEY_IDX in definition, \
32+
f"{KEY_IDX} not defined: {definition}"
33+
assert isinstance(definition[KEY_IDX], int), \
34+
f"{KEY_IDX} must be of type 'int': {definition}"
35+
36+
if KEY_COUNT in definition:
37+
assert isinstance(definition[KEY_COUNT], int), \
38+
f"{KEY_COUNT} must be of type 'int': {definition}"
39+
40+
if KEY_NAMES in definition:
41+
assert isinstance(definition[KEY_NAMES], list) \
42+
or isinstance(definition[KEY_NAMES], str), \
43+
f"{KEY_NAMES} must be of type 'list' or 'str': {definition}"
44+
if isinstance(definition[KEY_NAMES], list):
45+
for name in definition[KEY_NAMES]:
46+
assert isinstance(name, str), f"Entry of {KEY_NAMES} " \
47+
f"must be of type 'int': {definition}"
48+
49+
if KEY_TYPE in definition:
50+
assert issubclass(definition[KEY_TYPE], Base), \
51+
f"{KEY_TYPE} must be inherit from 'Base': {definition}"
52+
53+
if KEY_WRT in definition:
54+
assert isinstance(definition[KEY_WRT], bool), \
55+
f"{KEY_WRT} must be of type 'bool': {definition}"
56+
57+
if KEY_SINCE in definition:
58+
assert isinstance(definition[KEY_SINCE], str), \
59+
f"{KEY_SINCE} must be of type 'str': {definition}"
60+
61+
if KEY_UNTIL in definition:
62+
assert isinstance(definition[KEY_UNTIL], str), \
63+
f"{KEY_UNTIL} must be of type 'str': {definition}"
64+
65+
if KEY_DESC in definition:
66+
assert isinstance(definition[KEY_DESC], str), \
67+
f"{KEY_DESC} must be of type 'str': {definition}"
68+
69+
def test_index(self):
70+
for definition in self.definitions:
71+
idx = definition.get(KEY_IDX, 0)
72+
assert idx >= 0, \
73+
f"The index must be greater or equal than zero: {definition}"
74+
75+
def test_index_ascending(self):
76+
prev = self.definitions[0]
77+
78+
for definition in self.definitions:
79+
prev_idx = prev.get(KEY_IDX, -1)
80+
this_idx = definition.get(KEY_IDX, 0)
81+
assert prev_idx <= this_idx, \
82+
f"The definitions must be arranged in ascending order. " \
83+
f"This allows us to avoid sorting them afterwards." \
84+
f"this = {definition}" \
85+
f"other = {prev}"
86+
prev = definition
87+
88+
def test_count(self):
89+
for definition in self.definitions:
90+
count = definition.get(KEY_COUNT, 1)
91+
assert count > 0, \
92+
f"Count field must be greater than zero: {definition}"
93+
94+
def test_name_valid(self):
95+
for definition in self.definitions:
96+
names = self.get_names(definition)
97+
for name in names:
98+
sanitized = re.sub(r"[^a-z0-9_]", "", name)
99+
assert sanitized == name, \
100+
f"The name may only contain a-z0-9_"
101+
assert sanitized != "", \
102+
f"Name must not be empty."
103+
104+
def test_name_unique(self):
105+
length = len(self.definitions)
106+
107+
for i in range(length):
108+
i_def = self.definitions[i]
109+
i_names = self.get_names(i_def)
110+
for j in range(i + 1, length):
111+
j_def = self.definitions[j]
112+
j_names = self.get_names(j_def)
113+
for i_name in i_names:
114+
for j_name in j_names:
115+
assert i_name!= j_name, \
116+
f"All names of the same type must be unique. " \
117+
f"this = {i_def}" \
118+
f"other = {j_def}"
119+
120+
def test_data_type(self):
121+
for definition in self.definitions:
122+
if KEY_TYPE in definition:
123+
data_type = definition.get(KEY_TYPE, Base)
124+
assert data_type is not None, \
125+
f"Type must be set."
126+
127+
###############################################################################
128+
# Tests
129+
###############################################################################
130+
131+
class TestHoldingsDefinitions(RunTestDefinitions):
132+
133+
definitions = HOLDINGS_DEFINITIONS_LIST
134+
135+
136+
class TestInputsDefinitions(RunTestDefinitions):
137+
138+
definitions = INPUTS_DEFINITIONS_LIST

0 commit comments

Comments
 (0)