aas-core-codegen 0.0.16__py3-none-any.whl → 0.0.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aas_core_codegen/__init__.py +1 -1
- aas_core_codegen/cpp/pattern/_generate.py +8 -7
- aas_core_codegen/cpp/revm/_generate.py +2 -2
- aas_core_codegen/intermediate/__init__.py +2 -0
- aas_core_codegen/intermediate/_stringify.py +9 -0
- aas_core_codegen/intermediate/_types.py +374 -44
- aas_core_codegen/python/xmlization/_generate.py +3 -1
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/METADATA +2 -2
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/RECORD +19 -17
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/WHEEL +1 -1
- dev/dev_scripts/run_tests_with_rerecord.py +5 -1
- dev/test_data/intermediate/expected/constrained_primitive/inheritance/meta_model.py +17 -0
- dev/tests/cpp/test_pattern.py +31 -31
- dev/tests/intermediate/test_pickle.py +1871 -0
- dev/tests/intermediate/test_types.py +454 -0
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/entry_points.txt +0 -0
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/licenses/AUTHORS +0 -0
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/licenses/LICENSE +0 -0
- {aas_core_codegen-0.0.16.dist-info → aas_core_codegen-0.0.17.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,1871 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# pylint: disable=missing-docstring
|
|
4
|
+
|
|
5
|
+
import ast
|
|
6
|
+
import inspect
|
|
7
|
+
import pathlib
|
|
8
|
+
import pickle
|
|
9
|
+
import re
|
|
10
|
+
import textwrap
|
|
11
|
+
import unittest
|
|
12
|
+
from typing import List, Dict, Optional, Final, Sequence
|
|
13
|
+
|
|
14
|
+
from icontract import require
|
|
15
|
+
|
|
16
|
+
from aas_core_codegen import intermediate
|
|
17
|
+
from aas_core_codegen.common import Identifier
|
|
18
|
+
|
|
19
|
+
# noinspection PyProtectedMember
|
|
20
|
+
from aas_core_codegen.intermediate import _types as intermediate_types
|
|
21
|
+
|
|
22
|
+
import tests.common
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestPickle(unittest.TestCase):
|
|
26
|
+
def test_enumeration(self) -> None:
|
|
27
|
+
source = textwrap.dedent(
|
|
28
|
+
"""\
|
|
29
|
+
from enum import Enum
|
|
30
|
+
|
|
31
|
+
class Some_enum(Enum):
|
|
32
|
+
Literal1 = "literal_1"
|
|
33
|
+
Literal2 = "literal_2"
|
|
34
|
+
|
|
35
|
+
__version__ = "dummy"
|
|
36
|
+
__xml_namespace__ = "https://dummy.com"
|
|
37
|
+
"""
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
41
|
+
source=source
|
|
42
|
+
)
|
|
43
|
+
assert error is None and symbol_table is not None
|
|
44
|
+
|
|
45
|
+
some_enum = symbol_table.must_find_enumeration(Identifier("Some_enum"))
|
|
46
|
+
|
|
47
|
+
# NOTE (mristin):
|
|
48
|
+
# We first test that ID sets are working before pickling.
|
|
49
|
+
original_id_set = some_enum.literal_id_set
|
|
50
|
+
self.assertEqual(len(original_id_set), 2)
|
|
51
|
+
self.assertIn(id(some_enum.literals[0]), original_id_set)
|
|
52
|
+
self.assertIn(id(some_enum.literals[1]), original_id_set)
|
|
53
|
+
|
|
54
|
+
pickled_data = pickle.dumps(some_enum)
|
|
55
|
+
unpickled_enum = pickle.loads(pickled_data)
|
|
56
|
+
|
|
57
|
+
# NOTE (mristin):
|
|
58
|
+
# We now test that the unpickled ID sets are also working.
|
|
59
|
+
self.assertEqual(unpickled_enum.name, "Some_enum")
|
|
60
|
+
self.assertEqual(len(unpickled_enum.literals), 2)
|
|
61
|
+
self.assertEqual(unpickled_enum.literals[0].name, "Literal1")
|
|
62
|
+
self.assertEqual(unpickled_enum.literals[1].name, "Literal2")
|
|
63
|
+
|
|
64
|
+
new_id_set = unpickled_enum.literal_id_set
|
|
65
|
+
self.assertEqual(len(new_id_set), 2)
|
|
66
|
+
self.assertIn(id(unpickled_enum.literals[0]), new_id_set)
|
|
67
|
+
self.assertIn(id(unpickled_enum.literals[1]), new_id_set)
|
|
68
|
+
|
|
69
|
+
# NOTE (mristin):
|
|
70
|
+
# The ID sets should be different since objects have new IDs after unpickling.
|
|
71
|
+
self.assertNotEqual(original_id_set, new_id_set)
|
|
72
|
+
|
|
73
|
+
def test_abstract_class(self) -> None:
|
|
74
|
+
source = textwrap.dedent(
|
|
75
|
+
"""\
|
|
76
|
+
@abstract
|
|
77
|
+
class Some_abstract_class:
|
|
78
|
+
some_property: int
|
|
79
|
+
|
|
80
|
+
@require(lambda some_property: some_property > 0)
|
|
81
|
+
def __init__(self, some_property: int) -> None:
|
|
82
|
+
self.some_property = some_property
|
|
83
|
+
|
|
84
|
+
__version__ = "dummy"
|
|
85
|
+
__xml_namespace__ = "https://dummy.com"
|
|
86
|
+
"""
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
90
|
+
source=source
|
|
91
|
+
)
|
|
92
|
+
assert error is None and symbol_table is not None
|
|
93
|
+
|
|
94
|
+
some_abstract_class = symbol_table.must_find_abstract_class(
|
|
95
|
+
Identifier("Some_abstract_class")
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
pickled_data = pickle.dumps(some_abstract_class)
|
|
99
|
+
unpickled = pickle.loads(pickled_data)
|
|
100
|
+
|
|
101
|
+
assert isinstance(unpickled, intermediate.AbstractClass)
|
|
102
|
+
|
|
103
|
+
self.assertEqual(unpickled.name, "Some_abstract_class")
|
|
104
|
+
self.assertEqual(len(unpickled.properties), 1)
|
|
105
|
+
self.assertEqual(unpickled.properties[0].name, "some_property")
|
|
106
|
+
|
|
107
|
+
# Test that ID sets are rebuilt correctly
|
|
108
|
+
self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
|
|
109
|
+
|
|
110
|
+
def test_argument(self) -> None:
|
|
111
|
+
source = textwrap.dedent(
|
|
112
|
+
"""\
|
|
113
|
+
class Some_class:
|
|
114
|
+
def some_method(self, some_arg: int) -> None:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
__version__ = "dummy"
|
|
118
|
+
__xml_namespace__ = "https://dummy.com"
|
|
119
|
+
"""
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
123
|
+
source=source
|
|
124
|
+
)
|
|
125
|
+
assert error is None and symbol_table is not None
|
|
126
|
+
|
|
127
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
128
|
+
some_method = some_class.methods[0]
|
|
129
|
+
some_arg = some_method.arguments[0]
|
|
130
|
+
|
|
131
|
+
pickled_data = pickle.dumps(some_arg)
|
|
132
|
+
unpickled = pickle.loads(pickled_data)
|
|
133
|
+
|
|
134
|
+
assert isinstance(unpickled, intermediate.Argument)
|
|
135
|
+
|
|
136
|
+
self.assertEqual(unpickled.name, "some_arg")
|
|
137
|
+
|
|
138
|
+
def test_class(self) -> None:
|
|
139
|
+
source = textwrap.dedent(
|
|
140
|
+
"""\
|
|
141
|
+
class Some_class:
|
|
142
|
+
some_property: int
|
|
143
|
+
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
some_property: int
|
|
147
|
+
) -> None:
|
|
148
|
+
self.some_property = some_property
|
|
149
|
+
|
|
150
|
+
__version__ = "dummy"
|
|
151
|
+
__xml_namespace__ = "https://dummy.com"
|
|
152
|
+
"""
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
156
|
+
source=source
|
|
157
|
+
)
|
|
158
|
+
if error is not None:
|
|
159
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
160
|
+
assert symbol_table is not None
|
|
161
|
+
|
|
162
|
+
some_class = symbol_table.must_find_class(Identifier("Some_class"))
|
|
163
|
+
|
|
164
|
+
pickled_data = pickle.dumps(some_class)
|
|
165
|
+
unpickled = pickle.loads(pickled_data)
|
|
166
|
+
|
|
167
|
+
assert isinstance(unpickled, intermediate.ConcreteClass)
|
|
168
|
+
|
|
169
|
+
self.assertEqual(unpickled.name, "Some_class")
|
|
170
|
+
|
|
171
|
+
self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
|
|
172
|
+
|
|
173
|
+
def test_concrete_class(self) -> None:
|
|
174
|
+
source = textwrap.dedent(
|
|
175
|
+
"""\
|
|
176
|
+
class Some_concrete_class:
|
|
177
|
+
some_property: int
|
|
178
|
+
|
|
179
|
+
def __init__(
|
|
180
|
+
self,
|
|
181
|
+
some_property: int
|
|
182
|
+
) -> None:
|
|
183
|
+
self.some_property = some_property
|
|
184
|
+
|
|
185
|
+
__version__ = "dummy"
|
|
186
|
+
__xml_namespace__ = "https://dummy.com"
|
|
187
|
+
"""
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
191
|
+
source=source
|
|
192
|
+
)
|
|
193
|
+
if error is not None:
|
|
194
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
195
|
+
assert symbol_table is not None
|
|
196
|
+
|
|
197
|
+
some_concrete_class = symbol_table.must_find_concrete_class(
|
|
198
|
+
Identifier("Some_concrete_class")
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
pickled_data = pickle.dumps(some_concrete_class)
|
|
202
|
+
unpickled = pickle.loads(pickled_data)
|
|
203
|
+
|
|
204
|
+
assert isinstance(unpickled, intermediate.ConcreteClass)
|
|
205
|
+
|
|
206
|
+
self.assertEqual(unpickled.name, "Some_concrete_class")
|
|
207
|
+
self.assertEqual(len(unpickled.properties), 1)
|
|
208
|
+
|
|
209
|
+
self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
|
|
210
|
+
|
|
211
|
+
def test_constant_primitive(self) -> None:
|
|
212
|
+
source = textwrap.dedent(
|
|
213
|
+
"""\
|
|
214
|
+
Some_constant: str = constant_str(
|
|
215
|
+
value="some_value",
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
__version__ = "dummy"
|
|
219
|
+
__xml_namespace__ = "https://dummy.com"
|
|
220
|
+
"""
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
224
|
+
source=source
|
|
225
|
+
)
|
|
226
|
+
if error is not None:
|
|
227
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
228
|
+
assert symbol_table is not None
|
|
229
|
+
|
|
230
|
+
some_constant = symbol_table.must_find_constant_primitive(
|
|
231
|
+
Identifier("Some_constant")
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
pickled_data = pickle.dumps(some_constant)
|
|
235
|
+
unpickled = pickle.loads(pickled_data)
|
|
236
|
+
|
|
237
|
+
assert isinstance(unpickled, intermediate.ConstantPrimitive)
|
|
238
|
+
|
|
239
|
+
self.assertEqual(unpickled.name, "Some_constant")
|
|
240
|
+
self.assertEqual(unpickled.value, "some_value")
|
|
241
|
+
|
|
242
|
+
def test_constant_set_of_primitives(self) -> None:
|
|
243
|
+
source = textwrap.dedent(
|
|
244
|
+
"""\
|
|
245
|
+
from aas_core_meta.marker import (
|
|
246
|
+
constant_set
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
Some_constant_set: Set[str] = constant_set(
|
|
250
|
+
values=["value1", "value2"]
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
__version__ = "dummy"
|
|
254
|
+
__xml_namespace__ = "https://dummy.com"
|
|
255
|
+
"""
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
259
|
+
source=source
|
|
260
|
+
)
|
|
261
|
+
if error is not None:
|
|
262
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
263
|
+
assert symbol_table is not None
|
|
264
|
+
|
|
265
|
+
some_constant_set = symbol_table.must_find_constant_set_of_primitives(
|
|
266
|
+
Identifier("Some_constant_set")
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
pickled_data = pickle.dumps(some_constant_set)
|
|
270
|
+
unpickled = pickle.loads(pickled_data)
|
|
271
|
+
|
|
272
|
+
assert isinstance(unpickled, intermediate.ConstantSetOfPrimitives)
|
|
273
|
+
|
|
274
|
+
self.assertEqual(unpickled.name, "Some_constant_set")
|
|
275
|
+
self.assertEqual(len(unpickled.literals), 2)
|
|
276
|
+
|
|
277
|
+
def test_constrained_primitive(self) -> None:
|
|
278
|
+
source = textwrap.dedent(
|
|
279
|
+
"""\
|
|
280
|
+
@invariant(lambda self: len(self) > 0, "Non-empty")
|
|
281
|
+
class Some_constrained_primitive(str):
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
__version__ = "dummy"
|
|
285
|
+
__xml_namespace__ = "https://dummy.com"
|
|
286
|
+
"""
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
290
|
+
source=source
|
|
291
|
+
)
|
|
292
|
+
if error is not None:
|
|
293
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
294
|
+
assert symbol_table is not None
|
|
295
|
+
|
|
296
|
+
some_constrained_primitive = symbol_table.must_find_constrained_primitive(
|
|
297
|
+
Identifier("Some_constrained_primitive")
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
pickled_data = pickle.dumps(some_constrained_primitive)
|
|
301
|
+
unpickled = pickle.loads(pickled_data)
|
|
302
|
+
|
|
303
|
+
assert isinstance(unpickled, intermediate.ConstrainedPrimitive)
|
|
304
|
+
|
|
305
|
+
self.assertEqual(unpickled.name, "Some_constrained_primitive")
|
|
306
|
+
|
|
307
|
+
self.assertIn(id(unpickled.invariants[0]), unpickled.invariant_id_set)
|
|
308
|
+
|
|
309
|
+
def test_constructor(self) -> None:
|
|
310
|
+
source = textwrap.dedent(
|
|
311
|
+
"""\
|
|
312
|
+
class Some_class:
|
|
313
|
+
some_property: int
|
|
314
|
+
|
|
315
|
+
def __init__(self, some_property: int) -> None:
|
|
316
|
+
self.some_property = some_property
|
|
317
|
+
|
|
318
|
+
__version__ = "dummy"
|
|
319
|
+
__xml_namespace__ = "https://dummy.com"
|
|
320
|
+
"""
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
324
|
+
source=source
|
|
325
|
+
)
|
|
326
|
+
if error is not None:
|
|
327
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
328
|
+
assert symbol_table is not None
|
|
329
|
+
|
|
330
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
331
|
+
constructor = some_class.constructor
|
|
332
|
+
|
|
333
|
+
pickled_data = pickle.dumps(constructor)
|
|
334
|
+
unpickled = pickle.loads(pickled_data)
|
|
335
|
+
|
|
336
|
+
assert isinstance(unpickled, intermediate.Constructor)
|
|
337
|
+
|
|
338
|
+
self.assertEqual(len(unpickled.arguments), 1)
|
|
339
|
+
|
|
340
|
+
def test_contract(self) -> None:
|
|
341
|
+
source = textwrap.dedent(
|
|
342
|
+
"""\
|
|
343
|
+
class Some_class:
|
|
344
|
+
@require(lambda self: True)
|
|
345
|
+
@ensure(lambda result: True)
|
|
346
|
+
def some_method(self) -> bool:
|
|
347
|
+
return True
|
|
348
|
+
|
|
349
|
+
__version__ = "dummy"
|
|
350
|
+
__xml_namespace__ = "https://dummy.com"
|
|
351
|
+
"""
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
355
|
+
source=source
|
|
356
|
+
)
|
|
357
|
+
if error is not None:
|
|
358
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
359
|
+
assert symbol_table is not None
|
|
360
|
+
|
|
361
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
362
|
+
some_method = some_class.methods[0]
|
|
363
|
+
contract = some_method.contracts.preconditions[0]
|
|
364
|
+
|
|
365
|
+
pickled_data = pickle.dumps(contract)
|
|
366
|
+
unpickled = pickle.loads(pickled_data)
|
|
367
|
+
|
|
368
|
+
assert isinstance(unpickled, intermediate.Contract)
|
|
369
|
+
|
|
370
|
+
self.assertIsNotNone(unpickled.body)
|
|
371
|
+
|
|
372
|
+
def test_contracts(self) -> None:
|
|
373
|
+
source = textwrap.dedent(
|
|
374
|
+
"""\
|
|
375
|
+
class Some_class:
|
|
376
|
+
@require(lambda self: True)
|
|
377
|
+
def some_method(self) -> None:
|
|
378
|
+
pass
|
|
379
|
+
|
|
380
|
+
__version__ = "dummy"
|
|
381
|
+
__xml_namespace__ = "https://dummy.com"
|
|
382
|
+
"""
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
386
|
+
source=source
|
|
387
|
+
)
|
|
388
|
+
if error is not None:
|
|
389
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
390
|
+
assert symbol_table is not None
|
|
391
|
+
|
|
392
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
393
|
+
some_method = some_class.methods[0]
|
|
394
|
+
contracts = some_method.contracts
|
|
395
|
+
|
|
396
|
+
pickled_data = pickle.dumps(contracts)
|
|
397
|
+
unpickled = pickle.loads(pickled_data)
|
|
398
|
+
|
|
399
|
+
assert isinstance(unpickled, intermediate.Contracts)
|
|
400
|
+
|
|
401
|
+
self.assertEqual(len(unpickled.preconditions), 1)
|
|
402
|
+
|
|
403
|
+
def test_default_primitive(self) -> None:
|
|
404
|
+
source = textwrap.dedent(
|
|
405
|
+
"""\
|
|
406
|
+
class Some_class:
|
|
407
|
+
some_property: str
|
|
408
|
+
|
|
409
|
+
def __init__(self, some_property: str = 'some_default') -> None:
|
|
410
|
+
self.some_property = some_property
|
|
411
|
+
|
|
412
|
+
__version__ = "dummy"
|
|
413
|
+
__xml_namespace__ = "https://dummy.com"
|
|
414
|
+
"""
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
418
|
+
source=source
|
|
419
|
+
)
|
|
420
|
+
if error is not None:
|
|
421
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
422
|
+
assert symbol_table is not None
|
|
423
|
+
|
|
424
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
425
|
+
|
|
426
|
+
arg = some_class.constructor.arguments_by_name[Identifier("some_property")]
|
|
427
|
+
|
|
428
|
+
default = arg.default
|
|
429
|
+
|
|
430
|
+
pickled_data = pickle.dumps(default)
|
|
431
|
+
unpickled = pickle.loads(pickled_data)
|
|
432
|
+
|
|
433
|
+
assert isinstance(unpickled, intermediate.DefaultPrimitive)
|
|
434
|
+
|
|
435
|
+
def test_default_enumeration_literal(self) -> None:
|
|
436
|
+
source = textwrap.dedent(
|
|
437
|
+
"""\
|
|
438
|
+
class Some_enum(Enum):
|
|
439
|
+
Literal1 = "literal-1"
|
|
440
|
+
Literal2 = "literal-2"
|
|
441
|
+
|
|
442
|
+
class Some_class:
|
|
443
|
+
some_property: Some_enum
|
|
444
|
+
|
|
445
|
+
def __init__(
|
|
446
|
+
self,
|
|
447
|
+
some_property: Some_enum = Some_enum.Literal1
|
|
448
|
+
) -> None:
|
|
449
|
+
self.some_property = some_property
|
|
450
|
+
|
|
451
|
+
__version__ = "dummy"
|
|
452
|
+
__xml_namespace__ = "https://dummy.com"
|
|
453
|
+
"""
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
457
|
+
source=source
|
|
458
|
+
)
|
|
459
|
+
if error is not None:
|
|
460
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
461
|
+
assert symbol_table is not None
|
|
462
|
+
|
|
463
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
464
|
+
|
|
465
|
+
arg = some_class.constructor.arguments_by_name[Identifier("some_property")]
|
|
466
|
+
|
|
467
|
+
default = arg.default
|
|
468
|
+
|
|
469
|
+
pickled_data = pickle.dumps(default)
|
|
470
|
+
unpickled = pickle.loads(pickled_data)
|
|
471
|
+
|
|
472
|
+
assert isinstance(unpickled, intermediate.DefaultEnumerationLiteral)
|
|
473
|
+
|
|
474
|
+
def test_description_of_constant(self) -> None:
|
|
475
|
+
source = textwrap.dedent(
|
|
476
|
+
"""\
|
|
477
|
+
Some_constant: str = constant_str(
|
|
478
|
+
value="some_value",
|
|
479
|
+
description="This is some constant."
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
__version__ = "dummy"
|
|
483
|
+
__xml_namespace__ = "https://dummy.com"
|
|
484
|
+
"""
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
488
|
+
source=source
|
|
489
|
+
)
|
|
490
|
+
if error is not None:
|
|
491
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
492
|
+
assert symbol_table is not None
|
|
493
|
+
|
|
494
|
+
some_constant = symbol_table.must_find_constant_primitive(
|
|
495
|
+
Identifier("Some_constant")
|
|
496
|
+
)
|
|
497
|
+
description = some_constant.description
|
|
498
|
+
assert description is not None
|
|
499
|
+
|
|
500
|
+
pickled_data = pickle.dumps(description)
|
|
501
|
+
unpickled = pickle.loads(pickled_data)
|
|
502
|
+
|
|
503
|
+
assert isinstance(unpickled, intermediate.DescriptionOfConstant), str(
|
|
504
|
+
type(unpickled)
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
self.assertEqual(unpickled.summary[0], "This is some constant.")
|
|
508
|
+
|
|
509
|
+
def test_description_of_enumeration_literal(self) -> None:
|
|
510
|
+
source = textwrap.dedent(
|
|
511
|
+
"""\
|
|
512
|
+
from enum import Enum
|
|
513
|
+
|
|
514
|
+
class Some_enum(Enum):
|
|
515
|
+
literal1 = "value1"
|
|
516
|
+
\"\"\"Describe the literal.\"\"\"
|
|
517
|
+
|
|
518
|
+
__version__ = "dummy"
|
|
519
|
+
__xml_namespace__ = "https://dummy.com"
|
|
520
|
+
"""
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
524
|
+
source=source
|
|
525
|
+
)
|
|
526
|
+
if error is not None:
|
|
527
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
528
|
+
assert symbol_table is not None
|
|
529
|
+
|
|
530
|
+
some_enum = symbol_table.must_find_enumeration(Identifier("Some_enum"))
|
|
531
|
+
literal = some_enum.literals[0]
|
|
532
|
+
description = literal.description
|
|
533
|
+
|
|
534
|
+
pickled_data = pickle.dumps(description)
|
|
535
|
+
unpickled = pickle.loads(pickled_data)
|
|
536
|
+
|
|
537
|
+
assert isinstance(unpickled, intermediate.DescriptionOfEnumerationLiteral)
|
|
538
|
+
|
|
539
|
+
self.assertEqual(unpickled.summary[0], "Describe the literal.")
|
|
540
|
+
|
|
541
|
+
def test_description_of_meta_model(self) -> None:
|
|
542
|
+
source = textwrap.dedent(
|
|
543
|
+
"""\
|
|
544
|
+
\"\"\"Meta-model description.\"\"\"
|
|
545
|
+
|
|
546
|
+
class Some_class:
|
|
547
|
+
pass
|
|
548
|
+
|
|
549
|
+
__version__ = "dummy"
|
|
550
|
+
__xml_namespace__ = "https://dummy.com"
|
|
551
|
+
"""
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
555
|
+
source=source
|
|
556
|
+
)
|
|
557
|
+
if error is not None:
|
|
558
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
559
|
+
assert symbol_table is not None
|
|
560
|
+
|
|
561
|
+
meta_model = symbol_table.meta_model
|
|
562
|
+
description = meta_model.description
|
|
563
|
+
|
|
564
|
+
pickled_data = pickle.dumps(description)
|
|
565
|
+
unpickled = pickle.loads(pickled_data)
|
|
566
|
+
|
|
567
|
+
assert isinstance(unpickled, intermediate.DescriptionOfMetaModel)
|
|
568
|
+
|
|
569
|
+
self.assertEqual(unpickled.summary[0], "Meta-model description.")
|
|
570
|
+
|
|
571
|
+
def test_description_of_our_type(self) -> None:
|
|
572
|
+
source = textwrap.dedent(
|
|
573
|
+
"""\
|
|
574
|
+
class Some_class:
|
|
575
|
+
\"\"\"Describe the class.\"\"\"
|
|
576
|
+
pass
|
|
577
|
+
|
|
578
|
+
__version__ = "dummy"
|
|
579
|
+
__xml_namespace__ = "https://dummy.com"
|
|
580
|
+
"""
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
584
|
+
source=source
|
|
585
|
+
)
|
|
586
|
+
if error is not None:
|
|
587
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
588
|
+
assert symbol_table is not None
|
|
589
|
+
|
|
590
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
591
|
+
description = some_class.description
|
|
592
|
+
|
|
593
|
+
pickled_data = pickle.dumps(description)
|
|
594
|
+
unpickled = pickle.loads(pickled_data)
|
|
595
|
+
|
|
596
|
+
assert isinstance(unpickled, intermediate.DescriptionOfOurType)
|
|
597
|
+
|
|
598
|
+
self.assertEqual(unpickled.summary[0], "Describe the class.")
|
|
599
|
+
|
|
600
|
+
def test_description_of_property(self) -> None:
|
|
601
|
+
source = textwrap.dedent(
|
|
602
|
+
"""\
|
|
603
|
+
class Some_class:
|
|
604
|
+
some_property: int
|
|
605
|
+
\"\"\"Describe the property.\"\"\"
|
|
606
|
+
|
|
607
|
+
def __init__(
|
|
608
|
+
self,
|
|
609
|
+
some_property: int
|
|
610
|
+
) -> None:
|
|
611
|
+
self.some_property = some_property
|
|
612
|
+
|
|
613
|
+
__version__ = "dummy"
|
|
614
|
+
__xml_namespace__ = "https://dummy.com"
|
|
615
|
+
"""
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
619
|
+
source=source
|
|
620
|
+
)
|
|
621
|
+
if error is not None:
|
|
622
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
623
|
+
assert symbol_table is not None
|
|
624
|
+
|
|
625
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
626
|
+
some_property = some_class.properties[0]
|
|
627
|
+
description = some_property.description
|
|
628
|
+
|
|
629
|
+
pickled_data = pickle.dumps(description)
|
|
630
|
+
unpickled = pickle.loads(pickled_data)
|
|
631
|
+
|
|
632
|
+
assert isinstance(unpickled, intermediate.DescriptionOfProperty)
|
|
633
|
+
|
|
634
|
+
self.assertEqual(unpickled.summary[0], "Describe the property.")
|
|
635
|
+
|
|
636
|
+
def test_description_of_signature(self) -> None:
|
|
637
|
+
source = textwrap.dedent(
|
|
638
|
+
"""\
|
|
639
|
+
class Some_class:
|
|
640
|
+
def some_method(self) -> None:
|
|
641
|
+
\"\"\"Describe the method.\"\"\"
|
|
642
|
+
pass
|
|
643
|
+
|
|
644
|
+
__version__ = "dummy"
|
|
645
|
+
__xml_namespace__ = "https://dummy.com"
|
|
646
|
+
"""
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
650
|
+
source=source
|
|
651
|
+
)
|
|
652
|
+
if error is not None:
|
|
653
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
654
|
+
assert symbol_table is not None
|
|
655
|
+
|
|
656
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
657
|
+
some_method = some_class.methods[0]
|
|
658
|
+
description = some_method.description
|
|
659
|
+
|
|
660
|
+
pickled_data = pickle.dumps(description)
|
|
661
|
+
unpickled = pickle.loads(pickled_data)
|
|
662
|
+
|
|
663
|
+
assert isinstance(unpickled, intermediate.DescriptionOfSignature)
|
|
664
|
+
|
|
665
|
+
self.assertEqual(unpickled.summary[0], "Describe the method.")
|
|
666
|
+
|
|
667
|
+
def test_enumeration_literal(self) -> None:
|
|
668
|
+
source = textwrap.dedent(
|
|
669
|
+
"""\
|
|
670
|
+
from enum import Enum
|
|
671
|
+
|
|
672
|
+
class Some_enum(Enum):
|
|
673
|
+
literal1 = "value1"
|
|
674
|
+
|
|
675
|
+
__version__ = "dummy"
|
|
676
|
+
__xml_namespace__ = "https://dummy.com"
|
|
677
|
+
"""
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
681
|
+
source=source
|
|
682
|
+
)
|
|
683
|
+
if error is not None:
|
|
684
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
685
|
+
assert symbol_table is not None
|
|
686
|
+
|
|
687
|
+
some_enum = symbol_table.must_find_enumeration(Identifier("Some_enum"))
|
|
688
|
+
literal = some_enum.literals[0]
|
|
689
|
+
|
|
690
|
+
pickled_data = pickle.dumps(literal)
|
|
691
|
+
unpickled = pickle.loads(pickled_data)
|
|
692
|
+
|
|
693
|
+
assert isinstance(unpickled, intermediate.EnumerationLiteral)
|
|
694
|
+
|
|
695
|
+
self.assertEqual(unpickled.name, "literal1")
|
|
696
|
+
self.assertEqual(unpickled.value, "value1")
|
|
697
|
+
|
|
698
|
+
def test_implementation_specific_method(self) -> None:
|
|
699
|
+
source = textwrap.dedent(
|
|
700
|
+
"""\
|
|
701
|
+
class Some_class:
|
|
702
|
+
@implementation_specific
|
|
703
|
+
def some_method(self) -> None:
|
|
704
|
+
pass
|
|
705
|
+
|
|
706
|
+
__version__ = "dummy"
|
|
707
|
+
__xml_namespace__ = "https://dummy.com"
|
|
708
|
+
"""
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
712
|
+
source=source
|
|
713
|
+
)
|
|
714
|
+
if error is not None:
|
|
715
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
716
|
+
assert symbol_table is not None
|
|
717
|
+
|
|
718
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
719
|
+
some_method = some_class.methods[0]
|
|
720
|
+
|
|
721
|
+
pickled_data = pickle.dumps(some_method)
|
|
722
|
+
unpickled = pickle.loads(pickled_data)
|
|
723
|
+
|
|
724
|
+
assert isinstance(unpickled, intermediate.ImplementationSpecificMethod)
|
|
725
|
+
|
|
726
|
+
self.assertEqual(unpickled.name, "some_method")
|
|
727
|
+
|
|
728
|
+
def test_implementation_specific_verification(self) -> None:
|
|
729
|
+
source = textwrap.dedent(
|
|
730
|
+
"""\
|
|
731
|
+
@verification
|
|
732
|
+
@implementation_specific
|
|
733
|
+
def some_verification(x: int) -> bool:
|
|
734
|
+
pass
|
|
735
|
+
|
|
736
|
+
__version__ = "dummy"
|
|
737
|
+
__xml_namespace__ = "https://dummy.com"
|
|
738
|
+
"""
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
742
|
+
source=source
|
|
743
|
+
)
|
|
744
|
+
if error is not None:
|
|
745
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
746
|
+
assert symbol_table is not None
|
|
747
|
+
|
|
748
|
+
verification = symbol_table.verification_functions[0]
|
|
749
|
+
|
|
750
|
+
pickled_data = pickle.dumps(verification)
|
|
751
|
+
unpickled = pickle.loads(pickled_data)
|
|
752
|
+
|
|
753
|
+
assert isinstance(unpickled, intermediate.ImplementationSpecificVerification)
|
|
754
|
+
|
|
755
|
+
self.assertEqual(unpickled.name, "some_verification")
|
|
756
|
+
|
|
757
|
+
def test_interface(self) -> None:
|
|
758
|
+
source = textwrap.dedent(
|
|
759
|
+
"""\
|
|
760
|
+
@abstract
|
|
761
|
+
class Some_abstract_class:
|
|
762
|
+
some_property: int
|
|
763
|
+
|
|
764
|
+
def __init__(
|
|
765
|
+
self,
|
|
766
|
+
some_property: int
|
|
767
|
+
) -> None:
|
|
768
|
+
self.some_property = some_property
|
|
769
|
+
|
|
770
|
+
def some_func(self) -> None:
|
|
771
|
+
pass
|
|
772
|
+
|
|
773
|
+
__version__ = "dummy"
|
|
774
|
+
__xml_namespace__ = "https://dummy.com"
|
|
775
|
+
"""
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
779
|
+
source=source
|
|
780
|
+
)
|
|
781
|
+
if error is not None:
|
|
782
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
783
|
+
assert symbol_table is not None
|
|
784
|
+
|
|
785
|
+
some_abstract_class = symbol_table.must_find_abstract_class(
|
|
786
|
+
Identifier("Some_abstract_class")
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
interface = some_abstract_class.interface
|
|
790
|
+
|
|
791
|
+
pickled_data = pickle.dumps(interface)
|
|
792
|
+
unpickled = pickle.loads(pickled_data)
|
|
793
|
+
|
|
794
|
+
assert isinstance(unpickled, intermediate.Interface)
|
|
795
|
+
|
|
796
|
+
self.assertEqual(unpickled.name, "Some_abstract_class")
|
|
797
|
+
|
|
798
|
+
self.assertIn(id(unpickled.properties[0]), unpickled.property_id_set)
|
|
799
|
+
|
|
800
|
+
def test_invariant(self) -> None:
|
|
801
|
+
source = textwrap.dedent(
|
|
802
|
+
"""\
|
|
803
|
+
@invariant(lambda self: self.some_property > 0, "Some property is positive")
|
|
804
|
+
class Some_class:
|
|
805
|
+
some_property: int
|
|
806
|
+
|
|
807
|
+
def __init__(self, some_property: int) -> None:
|
|
808
|
+
self.some_property = some_property
|
|
809
|
+
|
|
810
|
+
__version__ = "dummy"
|
|
811
|
+
__xml_namespace__ = "https://dummy.com"
|
|
812
|
+
"""
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
816
|
+
source=source
|
|
817
|
+
)
|
|
818
|
+
if error is not None:
|
|
819
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
820
|
+
assert symbol_table is not None
|
|
821
|
+
|
|
822
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
823
|
+
invariant = some_class.invariants[0]
|
|
824
|
+
|
|
825
|
+
pickled_data = pickle.dumps(invariant)
|
|
826
|
+
unpickled = pickle.loads(pickled_data)
|
|
827
|
+
|
|
828
|
+
assert isinstance(unpickled, intermediate.Invariant)
|
|
829
|
+
|
|
830
|
+
self.assertIsNotNone(unpickled.body)
|
|
831
|
+
|
|
832
|
+
def test_list_type_annotation(self) -> None:
|
|
833
|
+
source = textwrap.dedent(
|
|
834
|
+
"""\
|
|
835
|
+
class Some_class:
|
|
836
|
+
some_property: List[str]
|
|
837
|
+
|
|
838
|
+
def __init__(
|
|
839
|
+
self,
|
|
840
|
+
some_property: List[str]
|
|
841
|
+
) -> None:
|
|
842
|
+
self.some_property = some_property
|
|
843
|
+
|
|
844
|
+
__version__ = "dummy"
|
|
845
|
+
__xml_namespace__ = "https://dummy.com"
|
|
846
|
+
"""
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
850
|
+
source=source
|
|
851
|
+
)
|
|
852
|
+
if error is not None:
|
|
853
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
854
|
+
assert symbol_table is not None
|
|
855
|
+
|
|
856
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
857
|
+
some_property = some_class.properties[0]
|
|
858
|
+
type_annotation = some_property.type_annotation
|
|
859
|
+
|
|
860
|
+
pickled_data = pickle.dumps(type_annotation)
|
|
861
|
+
unpickled = pickle.loads(pickled_data)
|
|
862
|
+
|
|
863
|
+
self.assertIsInstance(unpickled, intermediate_types.ListTypeAnnotation)
|
|
864
|
+
|
|
865
|
+
def test_meta_model(self) -> None:
|
|
866
|
+
source = textwrap.dedent(
|
|
867
|
+
"""\
|
|
868
|
+
class Some_class:
|
|
869
|
+
pass
|
|
870
|
+
|
|
871
|
+
__version__ = "dummy"
|
|
872
|
+
__xml_namespace__ = "https://dummy.com"
|
|
873
|
+
"""
|
|
874
|
+
)
|
|
875
|
+
|
|
876
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
877
|
+
source=source
|
|
878
|
+
)
|
|
879
|
+
if error is not None:
|
|
880
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
881
|
+
assert symbol_table is not None
|
|
882
|
+
|
|
883
|
+
meta_model = symbol_table.meta_model
|
|
884
|
+
|
|
885
|
+
pickled_data = pickle.dumps(meta_model)
|
|
886
|
+
unpickled = pickle.loads(pickled_data)
|
|
887
|
+
|
|
888
|
+
assert isinstance(unpickled, intermediate_types.MetaModel)
|
|
889
|
+
|
|
890
|
+
self.assertEqual(unpickled.version, "dummy")
|
|
891
|
+
|
|
892
|
+
def test_method(self) -> None:
|
|
893
|
+
source = textwrap.dedent(
|
|
894
|
+
"""\
|
|
895
|
+
class Some_class:
|
|
896
|
+
def some_method(self) -> None:
|
|
897
|
+
pass
|
|
898
|
+
|
|
899
|
+
__version__ = "dummy"
|
|
900
|
+
__xml_namespace__ = "https://dummy.com"
|
|
901
|
+
"""
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
905
|
+
source=source
|
|
906
|
+
)
|
|
907
|
+
if error is not None:
|
|
908
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
909
|
+
assert symbol_table is not None
|
|
910
|
+
|
|
911
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
912
|
+
some_method = some_class.methods[0]
|
|
913
|
+
|
|
914
|
+
pickled_data = pickle.dumps(some_method)
|
|
915
|
+
unpickled = pickle.loads(pickled_data)
|
|
916
|
+
|
|
917
|
+
assert isinstance(unpickled, intermediate.UnderstoodMethod)
|
|
918
|
+
|
|
919
|
+
self.assertEqual(unpickled.name, "some_method")
|
|
920
|
+
|
|
921
|
+
def test_optional_type_annotation(self) -> None:
|
|
922
|
+
source = textwrap.dedent(
|
|
923
|
+
"""\
|
|
924
|
+
class Some_class:
|
|
925
|
+
some_property: Optional[str]
|
|
926
|
+
|
|
927
|
+
def __init__(
|
|
928
|
+
self,
|
|
929
|
+
some_property: Optional[str] = None
|
|
930
|
+
) -> None:
|
|
931
|
+
self.some_property = some_property
|
|
932
|
+
|
|
933
|
+
__version__ = "dummy"
|
|
934
|
+
__xml_namespace__ = "https://dummy.com"
|
|
935
|
+
"""
|
|
936
|
+
)
|
|
937
|
+
|
|
938
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
939
|
+
source=source
|
|
940
|
+
)
|
|
941
|
+
if error is not None:
|
|
942
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
943
|
+
assert symbol_table is not None
|
|
944
|
+
|
|
945
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
946
|
+
some_property = some_class.properties[0]
|
|
947
|
+
type_annotation = some_property.type_annotation
|
|
948
|
+
|
|
949
|
+
pickled_data = pickle.dumps(type_annotation)
|
|
950
|
+
unpickled = pickle.loads(pickled_data)
|
|
951
|
+
|
|
952
|
+
self.assertIsInstance(unpickled, intermediate_types.OptionalTypeAnnotation)
|
|
953
|
+
|
|
954
|
+
def test_our_type_annotation(self) -> None:
|
|
955
|
+
source = textwrap.dedent(
|
|
956
|
+
"""\
|
|
957
|
+
class Some_class:
|
|
958
|
+
pass
|
|
959
|
+
|
|
960
|
+
class Some_another_class:
|
|
961
|
+
some_property: Some_class
|
|
962
|
+
|
|
963
|
+
def __init__(
|
|
964
|
+
self,
|
|
965
|
+
some_property: Some_class
|
|
966
|
+
) -> None:
|
|
967
|
+
self.some_property = some_property
|
|
968
|
+
|
|
969
|
+
__version__ = "dummy"
|
|
970
|
+
__xml_namespace__ = "https://dummy.com"
|
|
971
|
+
"""
|
|
972
|
+
)
|
|
973
|
+
|
|
974
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
975
|
+
source=source
|
|
976
|
+
)
|
|
977
|
+
if error is not None:
|
|
978
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
979
|
+
assert symbol_table is not None
|
|
980
|
+
|
|
981
|
+
some_another_class = symbol_table.must_find_concrete_class(
|
|
982
|
+
Identifier("Some_another_class")
|
|
983
|
+
)
|
|
984
|
+
some_property = some_another_class.properties[0]
|
|
985
|
+
type_annotation = some_property.type_annotation
|
|
986
|
+
|
|
987
|
+
pickled_data = pickle.dumps(type_annotation)
|
|
988
|
+
unpickled = pickle.loads(pickled_data)
|
|
989
|
+
|
|
990
|
+
self.assertIsInstance(unpickled, intermediate_types.OurTypeAnnotation)
|
|
991
|
+
|
|
992
|
+
def test_pattern_verification(self) -> None:
|
|
993
|
+
source = textwrap.dedent(
|
|
994
|
+
"""\
|
|
995
|
+
@verification
|
|
996
|
+
def some_verification(x: str) -> bool:
|
|
997
|
+
return match(r"^[a-z]+$", x) is not None
|
|
998
|
+
|
|
999
|
+
__version__ = "dummy"
|
|
1000
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1001
|
+
"""
|
|
1002
|
+
)
|
|
1003
|
+
|
|
1004
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1005
|
+
source=source
|
|
1006
|
+
)
|
|
1007
|
+
if error is not None:
|
|
1008
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1009
|
+
assert symbol_table is not None
|
|
1010
|
+
|
|
1011
|
+
verification = symbol_table.verification_functions[0]
|
|
1012
|
+
|
|
1013
|
+
pickled_data = pickle.dumps(verification)
|
|
1014
|
+
unpickled = pickle.loads(pickled_data)
|
|
1015
|
+
|
|
1016
|
+
assert isinstance(unpickled, intermediate.PatternVerification)
|
|
1017
|
+
|
|
1018
|
+
self.assertEqual(unpickled.name, "some_verification")
|
|
1019
|
+
|
|
1020
|
+
def test_primitive_set_literal(self) -> None:
|
|
1021
|
+
source = textwrap.dedent(
|
|
1022
|
+
"""\
|
|
1023
|
+
from aas_core_meta.marker import (
|
|
1024
|
+
constant_set
|
|
1025
|
+
)
|
|
1026
|
+
|
|
1027
|
+
Some_constant_set: Set[str] = constant_set(
|
|
1028
|
+
values=["value1", "value2"]
|
|
1029
|
+
)
|
|
1030
|
+
|
|
1031
|
+
__version__ = "dummy"
|
|
1032
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1033
|
+
"""
|
|
1034
|
+
)
|
|
1035
|
+
|
|
1036
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1037
|
+
source=source
|
|
1038
|
+
)
|
|
1039
|
+
if error is not None:
|
|
1040
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1041
|
+
assert symbol_table is not None
|
|
1042
|
+
|
|
1043
|
+
some_constant_set = symbol_table.must_find_constant_set_of_primitives(
|
|
1044
|
+
Identifier("Some_constant_set")
|
|
1045
|
+
)
|
|
1046
|
+
literal = some_constant_set.literals[0]
|
|
1047
|
+
|
|
1048
|
+
pickled_data = pickle.dumps(literal)
|
|
1049
|
+
unpickled = pickle.loads(pickled_data)
|
|
1050
|
+
|
|
1051
|
+
assert isinstance(unpickled, intermediate.PrimitiveSetLiteral)
|
|
1052
|
+
|
|
1053
|
+
self.assertEqual(unpickled.value, "value1")
|
|
1054
|
+
|
|
1055
|
+
def test_primitive_type(self) -> None:
|
|
1056
|
+
source = textwrap.dedent(
|
|
1057
|
+
"""\
|
|
1058
|
+
class Some_class:
|
|
1059
|
+
some_property: str
|
|
1060
|
+
|
|
1061
|
+
def __init__(
|
|
1062
|
+
self,
|
|
1063
|
+
some_property: str
|
|
1064
|
+
) -> None:
|
|
1065
|
+
self.some_property = some_property
|
|
1066
|
+
|
|
1067
|
+
__version__ = "dummy"
|
|
1068
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1069
|
+
"""
|
|
1070
|
+
)
|
|
1071
|
+
|
|
1072
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1073
|
+
source=source
|
|
1074
|
+
)
|
|
1075
|
+
if error is not None:
|
|
1076
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1077
|
+
assert symbol_table is not None
|
|
1078
|
+
|
|
1079
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1080
|
+
some_property = some_class.properties[0]
|
|
1081
|
+
type_annotation = some_property.type_annotation
|
|
1082
|
+
assert isinstance(type_annotation, intermediate_types.PrimitiveTypeAnnotation)
|
|
1083
|
+
primitive_type = type_annotation.a_type
|
|
1084
|
+
|
|
1085
|
+
pickled_data = pickle.dumps(primitive_type)
|
|
1086
|
+
unpickled = pickle.loads(pickled_data)
|
|
1087
|
+
|
|
1088
|
+
self.assertEqual(unpickled, intermediate_types.PrimitiveType.STR)
|
|
1089
|
+
|
|
1090
|
+
def test_primitive_type_annotation(self) -> None:
|
|
1091
|
+
source = textwrap.dedent(
|
|
1092
|
+
"""\
|
|
1093
|
+
class Some_class:
|
|
1094
|
+
some_property: str
|
|
1095
|
+
|
|
1096
|
+
def __init__(
|
|
1097
|
+
self,
|
|
1098
|
+
some_property: str
|
|
1099
|
+
) -> None:
|
|
1100
|
+
self.some_property = some_property
|
|
1101
|
+
|
|
1102
|
+
__version__ = "dummy"
|
|
1103
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1104
|
+
"""
|
|
1105
|
+
)
|
|
1106
|
+
|
|
1107
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1108
|
+
source=source
|
|
1109
|
+
)
|
|
1110
|
+
if error is not None:
|
|
1111
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1112
|
+
assert symbol_table is not None
|
|
1113
|
+
|
|
1114
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1115
|
+
some_property = some_class.properties[0]
|
|
1116
|
+
type_annotation = some_property.type_annotation
|
|
1117
|
+
|
|
1118
|
+
pickled_data = pickle.dumps(type_annotation)
|
|
1119
|
+
unpickled = pickle.loads(pickled_data)
|
|
1120
|
+
|
|
1121
|
+
self.assertIsInstance(unpickled, intermediate_types.PrimitiveTypeAnnotation)
|
|
1122
|
+
|
|
1123
|
+
def test_property(self) -> None:
|
|
1124
|
+
source = textwrap.dedent(
|
|
1125
|
+
"""\
|
|
1126
|
+
class Some_class:
|
|
1127
|
+
some_property: str
|
|
1128
|
+
|
|
1129
|
+
def __init__(
|
|
1130
|
+
self,
|
|
1131
|
+
some_property: str
|
|
1132
|
+
) -> None:
|
|
1133
|
+
self.some_property = some_property
|
|
1134
|
+
|
|
1135
|
+
__version__ = "dummy"
|
|
1136
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1137
|
+
"""
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1141
|
+
source=source
|
|
1142
|
+
)
|
|
1143
|
+
if error is not None:
|
|
1144
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1145
|
+
assert symbol_table is not None
|
|
1146
|
+
|
|
1147
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1148
|
+
some_property = some_class.properties[0]
|
|
1149
|
+
|
|
1150
|
+
pickled_data = pickle.dumps(some_property)
|
|
1151
|
+
unpickled = pickle.loads(pickled_data)
|
|
1152
|
+
|
|
1153
|
+
assert isinstance(unpickled, intermediate.Property)
|
|
1154
|
+
|
|
1155
|
+
self.assertEqual(unpickled.name, "some_property")
|
|
1156
|
+
|
|
1157
|
+
def test_serialization(self) -> None:
|
|
1158
|
+
source = textwrap.dedent(
|
|
1159
|
+
"""\
|
|
1160
|
+
@serialization(with_model_type=True)
|
|
1161
|
+
class Some_class:
|
|
1162
|
+
some_property: str
|
|
1163
|
+
|
|
1164
|
+
def __init__(self, some_property: str) -> None:
|
|
1165
|
+
self.some_property = some_property
|
|
1166
|
+
|
|
1167
|
+
__version__ = "dummy"
|
|
1168
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1169
|
+
"""
|
|
1170
|
+
)
|
|
1171
|
+
|
|
1172
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1173
|
+
source=source
|
|
1174
|
+
)
|
|
1175
|
+
if error is not None:
|
|
1176
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1177
|
+
assert symbol_table is not None
|
|
1178
|
+
|
|
1179
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1180
|
+
serialization = some_class.serialization
|
|
1181
|
+
|
|
1182
|
+
pickled_data = pickle.dumps(serialization)
|
|
1183
|
+
unpickled = pickle.loads(pickled_data)
|
|
1184
|
+
|
|
1185
|
+
assert isinstance(unpickled, intermediate.Serialization)
|
|
1186
|
+
|
|
1187
|
+
self.assertEqual(unpickled.with_model_type, True)
|
|
1188
|
+
|
|
1189
|
+
def test_signature(self) -> None:
|
|
1190
|
+
source = textwrap.dedent(
|
|
1191
|
+
"""\
|
|
1192
|
+
@abstract
|
|
1193
|
+
class Some_abstract_class:
|
|
1194
|
+
some_property: int
|
|
1195
|
+
|
|
1196
|
+
def __init__(self, some_property: int) -> None:
|
|
1197
|
+
self.some_property = some_property
|
|
1198
|
+
|
|
1199
|
+
def some_func(self) -> None:
|
|
1200
|
+
pass
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
__version__ = "dummy"
|
|
1204
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1205
|
+
"""
|
|
1206
|
+
)
|
|
1207
|
+
|
|
1208
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1209
|
+
source=source
|
|
1210
|
+
)
|
|
1211
|
+
if error is not None:
|
|
1212
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1213
|
+
assert symbol_table is not None
|
|
1214
|
+
|
|
1215
|
+
some_abstract_class = symbol_table.must_find_abstract_class(
|
|
1216
|
+
Identifier("Some_abstract_class")
|
|
1217
|
+
)
|
|
1218
|
+
|
|
1219
|
+
signature = some_abstract_class.interface.signatures[0]
|
|
1220
|
+
|
|
1221
|
+
pickled_data = pickle.dumps(signature)
|
|
1222
|
+
unpickled = pickle.loads(pickled_data)
|
|
1223
|
+
|
|
1224
|
+
assert isinstance(unpickled, intermediate.Signature)
|
|
1225
|
+
|
|
1226
|
+
self.assertEqual(unpickled.name, "some_func")
|
|
1227
|
+
|
|
1228
|
+
def test_signature_like(self) -> None:
|
|
1229
|
+
source = textwrap.dedent(
|
|
1230
|
+
"""\
|
|
1231
|
+
@abstract
|
|
1232
|
+
class Some_abstract_class:
|
|
1233
|
+
some_property: int
|
|
1234
|
+
|
|
1235
|
+
def __init__(self, some_property: int) -> None:
|
|
1236
|
+
self.some_property = some_property
|
|
1237
|
+
|
|
1238
|
+
def some_func(self) -> None:
|
|
1239
|
+
pass
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
__version__ = "dummy"
|
|
1243
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1244
|
+
"""
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1248
|
+
source=source
|
|
1249
|
+
)
|
|
1250
|
+
if error is not None:
|
|
1251
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1252
|
+
assert symbol_table is not None
|
|
1253
|
+
|
|
1254
|
+
source = textwrap.dedent(
|
|
1255
|
+
"""\
|
|
1256
|
+
@abstract
|
|
1257
|
+
class Some_abstract_class:
|
|
1258
|
+
some_property: int
|
|
1259
|
+
|
|
1260
|
+
@require(lambda some_property: some_property > 0)
|
|
1261
|
+
def __init__(self, some_property: int) -> None:
|
|
1262
|
+
self.some_property = some_property
|
|
1263
|
+
|
|
1264
|
+
def some_func(self) -> None:
|
|
1265
|
+
pass
|
|
1266
|
+
|
|
1267
|
+
|
|
1268
|
+
__version__ = "dummy"
|
|
1269
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1270
|
+
"""
|
|
1271
|
+
)
|
|
1272
|
+
|
|
1273
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1274
|
+
source=source
|
|
1275
|
+
)
|
|
1276
|
+
if error is not None:
|
|
1277
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1278
|
+
assert symbol_table is not None
|
|
1279
|
+
|
|
1280
|
+
some_abstract_class = symbol_table.must_find_abstract_class(
|
|
1281
|
+
Identifier("Some_abstract_class")
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
signature_like: intermediate_types.SignatureLike = some_abstract_class.methods[
|
|
1285
|
+
0
|
|
1286
|
+
]
|
|
1287
|
+
|
|
1288
|
+
pickled_data = pickle.dumps(signature_like)
|
|
1289
|
+
unpickled = pickle.loads(pickled_data)
|
|
1290
|
+
|
|
1291
|
+
assert isinstance(unpickled, intermediate_types.SignatureLike)
|
|
1292
|
+
|
|
1293
|
+
self.assertEqual(unpickled.name, "some_func")
|
|
1294
|
+
|
|
1295
|
+
def test_snapshot(self) -> None:
|
|
1296
|
+
source = textwrap.dedent(
|
|
1297
|
+
"""\
|
|
1298
|
+
class Some_class:
|
|
1299
|
+
some_property: int
|
|
1300
|
+
|
|
1301
|
+
def __init__(self, some_property: int) -> None:
|
|
1302
|
+
self.some_property = some_property
|
|
1303
|
+
|
|
1304
|
+
@snapshot(lambda self: self.some_property + 1)
|
|
1305
|
+
def some_method(self) -> None:
|
|
1306
|
+
pass
|
|
1307
|
+
|
|
1308
|
+
__version__ = "dummy"
|
|
1309
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1310
|
+
"""
|
|
1311
|
+
)
|
|
1312
|
+
|
|
1313
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1314
|
+
source=source
|
|
1315
|
+
)
|
|
1316
|
+
if error is not None:
|
|
1317
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1318
|
+
assert symbol_table is not None
|
|
1319
|
+
|
|
1320
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1321
|
+
some_method = some_class.methods[0]
|
|
1322
|
+
snapshot = some_method.contracts.snapshots[0]
|
|
1323
|
+
|
|
1324
|
+
pickled_data = pickle.dumps(snapshot)
|
|
1325
|
+
unpickled = pickle.loads(pickled_data)
|
|
1326
|
+
|
|
1327
|
+
assert isinstance(unpickled, intermediate.Snapshot)
|
|
1328
|
+
|
|
1329
|
+
self.assertIsNotNone(unpickled.body)
|
|
1330
|
+
|
|
1331
|
+
def test_summary_remarks_constraints_description(self) -> None:
|
|
1332
|
+
source = textwrap.dedent(
|
|
1333
|
+
"""\
|
|
1334
|
+
class Some_class:
|
|
1335
|
+
\"\"\"
|
|
1336
|
+
Summary line.
|
|
1337
|
+
|
|
1338
|
+
Some remark.
|
|
1339
|
+
|
|
1340
|
+
:constraint A10: Soem constraint
|
|
1341
|
+
\"\"\"
|
|
1342
|
+
|
|
1343
|
+
__version__ = "dummy"
|
|
1344
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1345
|
+
"""
|
|
1346
|
+
)
|
|
1347
|
+
|
|
1348
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1349
|
+
source=source
|
|
1350
|
+
)
|
|
1351
|
+
if error is not None:
|
|
1352
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1353
|
+
assert symbol_table is not None
|
|
1354
|
+
|
|
1355
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1356
|
+
description = some_class.description
|
|
1357
|
+
|
|
1358
|
+
pickled_data = pickle.dumps(description)
|
|
1359
|
+
unpickled = pickle.loads(pickled_data)
|
|
1360
|
+
|
|
1361
|
+
assert isinstance(unpickled, intermediate.SummaryRemarksConstraintsDescription)
|
|
1362
|
+
|
|
1363
|
+
self.assertEqual(unpickled.summary[0], "Summary line.")
|
|
1364
|
+
|
|
1365
|
+
def test_summary_remarks_description(self) -> None:
|
|
1366
|
+
source = textwrap.dedent(
|
|
1367
|
+
"""\
|
|
1368
|
+
from enum import Enum
|
|
1369
|
+
|
|
1370
|
+
class Some_class:
|
|
1371
|
+
\"\"\"
|
|
1372
|
+
Summary line.
|
|
1373
|
+
|
|
1374
|
+
Some remarks.
|
|
1375
|
+
|
|
1376
|
+
Some description.
|
|
1377
|
+
\"\"\"
|
|
1378
|
+
|
|
1379
|
+
__version__ = "dummy"
|
|
1380
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1381
|
+
"""
|
|
1382
|
+
)
|
|
1383
|
+
|
|
1384
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1385
|
+
source=source
|
|
1386
|
+
)
|
|
1387
|
+
if error is not None:
|
|
1388
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1389
|
+
assert symbol_table is not None
|
|
1390
|
+
|
|
1391
|
+
some_class = symbol_table.must_find_class(Identifier("Some_class"))
|
|
1392
|
+
description = some_class.description
|
|
1393
|
+
|
|
1394
|
+
pickled_data = pickle.dumps(description)
|
|
1395
|
+
unpickled = pickle.loads(pickled_data)
|
|
1396
|
+
|
|
1397
|
+
assert isinstance(unpickled, intermediate.SummaryRemarksDescription), str(
|
|
1398
|
+
type(unpickled)
|
|
1399
|
+
)
|
|
1400
|
+
|
|
1401
|
+
self.assertEqual(unpickled.summary[0], "Summary line.")
|
|
1402
|
+
|
|
1403
|
+
def test_symbol_table(self) -> None:
|
|
1404
|
+
source = textwrap.dedent(
|
|
1405
|
+
"""\
|
|
1406
|
+
class Some_class:
|
|
1407
|
+
pass
|
|
1408
|
+
|
|
1409
|
+
__version__ = "dummy"
|
|
1410
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1411
|
+
"""
|
|
1412
|
+
)
|
|
1413
|
+
|
|
1414
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1415
|
+
source=source
|
|
1416
|
+
)
|
|
1417
|
+
if error is not None:
|
|
1418
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1419
|
+
assert symbol_table is not None
|
|
1420
|
+
|
|
1421
|
+
pickled_data = pickle.dumps(symbol_table)
|
|
1422
|
+
unpickled = pickle.loads(pickled_data)
|
|
1423
|
+
|
|
1424
|
+
assert isinstance(unpickled, intermediate.SymbolTable)
|
|
1425
|
+
|
|
1426
|
+
self.assertEqual(len(unpickled.concrete_classes), 1)
|
|
1427
|
+
|
|
1428
|
+
def test_transpilable_verification(self) -> None:
|
|
1429
|
+
source = textwrap.dedent(
|
|
1430
|
+
"""\
|
|
1431
|
+
@verification
|
|
1432
|
+
def some_verification(x: int) -> bool:
|
|
1433
|
+
return x > 0
|
|
1434
|
+
|
|
1435
|
+
__version__ = "dummy"
|
|
1436
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1437
|
+
"""
|
|
1438
|
+
)
|
|
1439
|
+
|
|
1440
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1441
|
+
source=source
|
|
1442
|
+
)
|
|
1443
|
+
if error is not None:
|
|
1444
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1445
|
+
assert symbol_table is not None
|
|
1446
|
+
|
|
1447
|
+
verification = symbol_table.verification_functions[0]
|
|
1448
|
+
|
|
1449
|
+
pickled_data = pickle.dumps(verification)
|
|
1450
|
+
unpickled = pickle.loads(pickled_data)
|
|
1451
|
+
|
|
1452
|
+
assert isinstance(unpickled, intermediate.TranspilableVerification)
|
|
1453
|
+
|
|
1454
|
+
self.assertEqual(unpickled.name, "some_verification")
|
|
1455
|
+
|
|
1456
|
+
def test_type_annotation(self) -> None:
|
|
1457
|
+
source = textwrap.dedent(
|
|
1458
|
+
"""\
|
|
1459
|
+
class Some_class:
|
|
1460
|
+
some_property: str
|
|
1461
|
+
|
|
1462
|
+
def __init__(
|
|
1463
|
+
self,
|
|
1464
|
+
some_property: str
|
|
1465
|
+
) -> None:
|
|
1466
|
+
self.some_property = some_property
|
|
1467
|
+
|
|
1468
|
+
__version__ = "dummy"
|
|
1469
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1470
|
+
"""
|
|
1471
|
+
)
|
|
1472
|
+
|
|
1473
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1474
|
+
source=source
|
|
1475
|
+
)
|
|
1476
|
+
if error is not None:
|
|
1477
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1478
|
+
assert symbol_table is not None
|
|
1479
|
+
|
|
1480
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1481
|
+
some_property = some_class.properties[0]
|
|
1482
|
+
type_annotation = some_property.type_annotation
|
|
1483
|
+
|
|
1484
|
+
pickled_data = pickle.dumps(type_annotation)
|
|
1485
|
+
unpickled = pickle.loads(pickled_data)
|
|
1486
|
+
|
|
1487
|
+
self.assertIsInstance(unpickled, intermediate_types.TypeAnnotation)
|
|
1488
|
+
|
|
1489
|
+
def test_understood_method(self) -> None:
|
|
1490
|
+
source = textwrap.dedent(
|
|
1491
|
+
"""\
|
|
1492
|
+
class Some_class:
|
|
1493
|
+
def some_method(self) -> None:
|
|
1494
|
+
pass
|
|
1495
|
+
|
|
1496
|
+
__version__ = "dummy"
|
|
1497
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1498
|
+
"""
|
|
1499
|
+
)
|
|
1500
|
+
|
|
1501
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1502
|
+
source=source
|
|
1503
|
+
)
|
|
1504
|
+
if error is not None:
|
|
1505
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1506
|
+
assert symbol_table is not None
|
|
1507
|
+
|
|
1508
|
+
some_class = symbol_table.must_find_concrete_class(Identifier("Some_class"))
|
|
1509
|
+
some_method = some_class.methods[0]
|
|
1510
|
+
|
|
1511
|
+
pickled_data = pickle.dumps(some_method)
|
|
1512
|
+
unpickled = pickle.loads(pickled_data)
|
|
1513
|
+
|
|
1514
|
+
assert isinstance(unpickled, intermediate.UnderstoodMethod)
|
|
1515
|
+
|
|
1516
|
+
self.assertEqual(unpickled.name, "some_method")
|
|
1517
|
+
|
|
1518
|
+
def test_verification(self) -> None:
|
|
1519
|
+
source = textwrap.dedent(
|
|
1520
|
+
"""\
|
|
1521
|
+
@verification
|
|
1522
|
+
def some_verification(x: int) -> bool:
|
|
1523
|
+
return x > 0
|
|
1524
|
+
|
|
1525
|
+
__version__ = "dummy"
|
|
1526
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1527
|
+
"""
|
|
1528
|
+
)
|
|
1529
|
+
|
|
1530
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1531
|
+
source=source
|
|
1532
|
+
)
|
|
1533
|
+
if error is not None:
|
|
1534
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1535
|
+
assert symbol_table is not None
|
|
1536
|
+
|
|
1537
|
+
verification = symbol_table.verification_functions[0]
|
|
1538
|
+
|
|
1539
|
+
pickled_data = pickle.dumps(verification)
|
|
1540
|
+
unpickled = pickle.loads(pickled_data)
|
|
1541
|
+
|
|
1542
|
+
assert isinstance(unpickled, intermediate.Verification)
|
|
1543
|
+
|
|
1544
|
+
self.assertEqual(unpickled.name, "some_verification")
|
|
1545
|
+
|
|
1546
|
+
def test_constant_set_of_enumeration_literals(self) -> None:
|
|
1547
|
+
source = textwrap.dedent(
|
|
1548
|
+
"""\
|
|
1549
|
+
from enum import Enum
|
|
1550
|
+
|
|
1551
|
+
from aas_core_meta.marker import (
|
|
1552
|
+
constant_set
|
|
1553
|
+
)
|
|
1554
|
+
|
|
1555
|
+
class Some_enum(Enum):
|
|
1556
|
+
Literal1 = "lit1"
|
|
1557
|
+
Literal2 = "lit2"
|
|
1558
|
+
|
|
1559
|
+
Some_constant_set: Set[Some_enum] = constant_set(
|
|
1560
|
+
values=[
|
|
1561
|
+
Some_enum.Literal1
|
|
1562
|
+
]
|
|
1563
|
+
)
|
|
1564
|
+
|
|
1565
|
+
__version__ = "dummy"
|
|
1566
|
+
__xml_namespace__ = "https://dummy.com"
|
|
1567
|
+
"""
|
|
1568
|
+
)
|
|
1569
|
+
|
|
1570
|
+
symbol_table, error = tests.common.translate_source_to_intermediate(
|
|
1571
|
+
source=source
|
|
1572
|
+
)
|
|
1573
|
+
if error is not None:
|
|
1574
|
+
raise AssertionError(tests.common.most_underlying_messages(error))
|
|
1575
|
+
assert symbol_table is not None
|
|
1576
|
+
|
|
1577
|
+
some_constant_set = symbol_table.must_find_constant_set_of_enumeration_literals(
|
|
1578
|
+
Identifier("Some_constant_set")
|
|
1579
|
+
)
|
|
1580
|
+
|
|
1581
|
+
# Test before pickling
|
|
1582
|
+
original_id_set = some_constant_set.literal_id_set
|
|
1583
|
+
self.assertEqual(len(original_id_set), 1)
|
|
1584
|
+
self.assertIn(id(some_constant_set.literals[0]), original_id_set)
|
|
1585
|
+
|
|
1586
|
+
# Pickle and unpickle
|
|
1587
|
+
pickled_data = pickle.dumps(some_constant_set)
|
|
1588
|
+
unpickled = pickle.loads(pickled_data)
|
|
1589
|
+
|
|
1590
|
+
assert isinstance(unpickled, intermediate.ConstantSetOfEnumerationLiterals)
|
|
1591
|
+
|
|
1592
|
+
# Test after unpickling
|
|
1593
|
+
self.assertEqual(unpickled.name, "Some_constant_set")
|
|
1594
|
+
self.assertEqual(len(unpickled.literals), 1)
|
|
1595
|
+
self.assertEqual(unpickled.literals[0].name, "Literal1")
|
|
1596
|
+
|
|
1597
|
+
# Test that ID sets are rebuilt correctly
|
|
1598
|
+
new_id_set = unpickled.literal_id_set
|
|
1599
|
+
self.assertEqual(len(new_id_set), 1)
|
|
1600
|
+
self.assertIn(id(unpickled.literals[0]), new_id_set)
|
|
1601
|
+
|
|
1602
|
+
|
|
1603
|
+
def _to_lower_snake_case(cls_name: str) -> str:
|
|
1604
|
+
"""
|
|
1605
|
+
Convert a class name from CamelCase to snake_case.
|
|
1606
|
+
|
|
1607
|
+
>>> _to_lower_snake_case("Enumeration")
|
|
1608
|
+
'enumeration'
|
|
1609
|
+
|
|
1610
|
+
>>> _to_lower_snake_case("EnumerationLiteral")
|
|
1611
|
+
'enumeration_literal'
|
|
1612
|
+
|
|
1613
|
+
>>> _to_lower_snake_case("ConstrainedPrimitive")
|
|
1614
|
+
'constrained_primitive'
|
|
1615
|
+
|
|
1616
|
+
>>> _to_lower_snake_case("ConstructorArgumentOfClass")
|
|
1617
|
+
'constructor_argument_of_class'
|
|
1618
|
+
|
|
1619
|
+
>>> _to_lower_snake_case("_ConstructorArgumentOfClass")
|
|
1620
|
+
'constructor_argument_of_class'
|
|
1621
|
+
"""
|
|
1622
|
+
s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", cls_name.lstrip("_"))
|
|
1623
|
+
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
|
|
1624
|
+
|
|
1625
|
+
|
|
1626
|
+
class TestAssertions(unittest.TestCase):
|
|
1627
|
+
def test_coverage(self) -> None:
|
|
1628
|
+
"""Assert that all classes from intermediate._types are covered in test methods."""
|
|
1629
|
+
all_classes = [] # type: List[str]
|
|
1630
|
+
for class_name, obj in inspect.getmembers(intermediate_types, inspect.isclass):
|
|
1631
|
+
if obj.__module__ == intermediate_types.__name__:
|
|
1632
|
+
all_classes.append(class_name)
|
|
1633
|
+
|
|
1634
|
+
expected_test_prefixes = [
|
|
1635
|
+
f"test_{_to_lower_snake_case(cls_name)}" for cls_name in all_classes
|
|
1636
|
+
]
|
|
1637
|
+
|
|
1638
|
+
test_methods = [] # type: List[str]
|
|
1639
|
+
for method_name in dir(TestPickle):
|
|
1640
|
+
if method_name.startswith("test_") and callable(
|
|
1641
|
+
getattr(TestPickle, method_name)
|
|
1642
|
+
):
|
|
1643
|
+
test_methods.append(method_name)
|
|
1644
|
+
|
|
1645
|
+
missing_tests = [] # type: List[str]
|
|
1646
|
+
for expected_prefix in expected_test_prefixes:
|
|
1647
|
+
found = any(
|
|
1648
|
+
test_method.startswith(expected_prefix) for test_method in test_methods
|
|
1649
|
+
)
|
|
1650
|
+
if not found:
|
|
1651
|
+
missing_tests.append(expected_prefix)
|
|
1652
|
+
|
|
1653
|
+
if len(missing_tests) > 0:
|
|
1654
|
+
missing_classes = []
|
|
1655
|
+
for prefix in missing_tests:
|
|
1656
|
+
assert prefix.startswith("test_") and len("test_") == 5
|
|
1657
|
+
snake_case_name = prefix[5:]
|
|
1658
|
+
|
|
1659
|
+
parts = snake_case_name.split("_")
|
|
1660
|
+
original_name = "".join(word.capitalize() for word in parts)
|
|
1661
|
+
missing_classes.append(original_name)
|
|
1662
|
+
|
|
1663
|
+
missing_tests_joined = ",\n".join(missing_tests)
|
|
1664
|
+
|
|
1665
|
+
raise AssertionError(
|
|
1666
|
+
f"Missing one or more test methods "
|
|
1667
|
+
f"in {TestPickle.__name__} for {len(missing_tests)} class(es):\n"
|
|
1668
|
+
f"{missing_tests_joined}"
|
|
1669
|
+
)
|
|
1670
|
+
|
|
1671
|
+
def test_getstate_setstate_consistency(self) -> None:
|
|
1672
|
+
class _PickableClass:
|
|
1673
|
+
"""Represent a class which has pickle/unpickle methods."""
|
|
1674
|
+
|
|
1675
|
+
getstate: Final[Optional[ast.FunctionDef]]
|
|
1676
|
+
setstate: Final[Optional[ast.FunctionDef]]
|
|
1677
|
+
id_set_properties: Final[Sequence[str]]
|
|
1678
|
+
|
|
1679
|
+
@require(
|
|
1680
|
+
lambda getstate: not (getstate is not None)
|
|
1681
|
+
or getstate.name == "__getstate__"
|
|
1682
|
+
)
|
|
1683
|
+
@require(
|
|
1684
|
+
lambda setstate: not (setstate is not None)
|
|
1685
|
+
or setstate.name == "__setstate__"
|
|
1686
|
+
)
|
|
1687
|
+
def __init__(
|
|
1688
|
+
self,
|
|
1689
|
+
id_set_properties: Sequence[str],
|
|
1690
|
+
getstate: Optional[ast.FunctionDef] = None,
|
|
1691
|
+
setstate: Optional[ast.FunctionDef] = None,
|
|
1692
|
+
) -> None:
|
|
1693
|
+
self.id_set_properties = id_set_properties
|
|
1694
|
+
self.getstate = getstate
|
|
1695
|
+
self.setstate = setstate
|
|
1696
|
+
|
|
1697
|
+
types_file = pathlib.Path(intermediate_types.__file__)
|
|
1698
|
+
source_code = types_file.read_text(encoding="utf-8")
|
|
1699
|
+
|
|
1700
|
+
tree = ast.parse(source_code)
|
|
1701
|
+
|
|
1702
|
+
class_map = {} # type: Dict[str, _PickableClass]
|
|
1703
|
+
|
|
1704
|
+
for node in ast.walk(tree):
|
|
1705
|
+
if isinstance(node, ast.ClassDef):
|
|
1706
|
+
id_set_properties = [] # type: List[str]
|
|
1707
|
+
|
|
1708
|
+
# NOTE (mristin):
|
|
1709
|
+
# We go through all type-annotated properties and pick all properties
|
|
1710
|
+
# with suffix ``*_id_set``. This will give us some guard rails to make
|
|
1711
|
+
# sure that we did not forget to pop/set these properties in
|
|
1712
|
+
# ``__getstate__`` and ``__setstate__``. However, there might be more
|
|
1713
|
+
# runtime properties which need checking. Eventually, though unlikely,
|
|
1714
|
+
# the suffix ``_id_set`` might be misleading, so then we have to add
|
|
1715
|
+
# white listing here.
|
|
1716
|
+
for item in node.body:
|
|
1717
|
+
if isinstance(item, ast.AnnAssign):
|
|
1718
|
+
if isinstance(item.target, ast.Name):
|
|
1719
|
+
property_name = item.target.id
|
|
1720
|
+
if property_name.endswith("_id_set"):
|
|
1721
|
+
id_set_properties.append(property_name)
|
|
1722
|
+
|
|
1723
|
+
getstate = None # type: Optional[ast.FunctionDef]
|
|
1724
|
+
setstate = None # type: Optional[ast.FunctionDef]
|
|
1725
|
+
|
|
1726
|
+
for item in node.body:
|
|
1727
|
+
if isinstance(item, ast.FunctionDef):
|
|
1728
|
+
if item.name == "__getstate__":
|
|
1729
|
+
getstate = item
|
|
1730
|
+
|
|
1731
|
+
elif item.name == "__setstate__":
|
|
1732
|
+
setstate = item
|
|
1733
|
+
|
|
1734
|
+
else:
|
|
1735
|
+
pass
|
|
1736
|
+
|
|
1737
|
+
if getstate is not None or setstate is not None:
|
|
1738
|
+
class_map[node.name] = _PickableClass(
|
|
1739
|
+
id_set_properties=id_set_properties,
|
|
1740
|
+
getstate=getstate,
|
|
1741
|
+
setstate=setstate,
|
|
1742
|
+
)
|
|
1743
|
+
|
|
1744
|
+
for class_name, cls in class_map.items():
|
|
1745
|
+
if cls.getstate is None and cls.setstate is None:
|
|
1746
|
+
continue
|
|
1747
|
+
|
|
1748
|
+
if cls.getstate is None and cls.setstate is not None:
|
|
1749
|
+
raise AssertionError(
|
|
1750
|
+
f"Unexpected missing __getstate__ when __setstate__ is specified "
|
|
1751
|
+
f"in the class {class_name!r}"
|
|
1752
|
+
)
|
|
1753
|
+
|
|
1754
|
+
if cls.getstate is not None and cls.setstate is None:
|
|
1755
|
+
raise AssertionError(
|
|
1756
|
+
f"Unexpected missing __setstate__ when __getstate__ is specified "
|
|
1757
|
+
f"in the class {class_name!r}"
|
|
1758
|
+
)
|
|
1759
|
+
|
|
1760
|
+
assert cls.getstate is not None and cls.setstate is not None
|
|
1761
|
+
|
|
1762
|
+
# NOTE (mristin):
|
|
1763
|
+
# We extract popped attributes from ``__getstate__``.
|
|
1764
|
+
popped_attrs = [] # type: List[str]
|
|
1765
|
+
|
|
1766
|
+
for node in ast.walk(cls.getstate):
|
|
1767
|
+
if (
|
|
1768
|
+
isinstance(node, ast.Call)
|
|
1769
|
+
and isinstance(node.func, ast.Attribute)
|
|
1770
|
+
and node.func.attr == "pop"
|
|
1771
|
+
and isinstance(node.func.value, ast.Name)
|
|
1772
|
+
and node.func.value.id == "state"
|
|
1773
|
+
):
|
|
1774
|
+
if (
|
|
1775
|
+
len(node.args) > 0
|
|
1776
|
+
and isinstance(node.args[0], ast.Constant)
|
|
1777
|
+
and isinstance(node.args[0].value, str)
|
|
1778
|
+
):
|
|
1779
|
+
popped_attrs.append(node.args[0].value)
|
|
1780
|
+
|
|
1781
|
+
setattr_attrs = [] # type: List[str]
|
|
1782
|
+
|
|
1783
|
+
for node in ast.walk(cls.setstate):
|
|
1784
|
+
if (
|
|
1785
|
+
isinstance(node, ast.Call)
|
|
1786
|
+
and isinstance(node.func, ast.Name)
|
|
1787
|
+
and node.func.id == "setattr"
|
|
1788
|
+
):
|
|
1789
|
+
# NOTE (mristin):
|
|
1790
|
+
# The second argument is the name of the attribute.
|
|
1791
|
+
if (
|
|
1792
|
+
len(node.args) >= 2
|
|
1793
|
+
and isinstance(node.args[0], ast.Name)
|
|
1794
|
+
and node.args[0].id == "self"
|
|
1795
|
+
and isinstance(node.args[1], ast.Constant)
|
|
1796
|
+
and isinstance(node.args[1].value, str)
|
|
1797
|
+
):
|
|
1798
|
+
setattr_attrs.append(node.args[1].value)
|
|
1799
|
+
|
|
1800
|
+
if set(popped_attrs) != set(setattr_attrs):
|
|
1801
|
+
raise AssertionError(
|
|
1802
|
+
f"In class {class_name!r}, there is a mismatch between "
|
|
1803
|
+
f"popped attributes in __getstate__: {sorted(popped_attrs)}, "
|
|
1804
|
+
f"and setattr attributes in __setstate__: {sorted(setattr_attrs)}"
|
|
1805
|
+
)
|
|
1806
|
+
|
|
1807
|
+
# NOTE (mristin):
|
|
1808
|
+
# We check that all properties with suffix ``_id_set`` are popped in
|
|
1809
|
+
# ``__getstate__`` and, consequently, set in ``__setstate__``.
|
|
1810
|
+
id_set_properties_set = set(cls.id_set_properties)
|
|
1811
|
+
popped_attrs_set = set(popped_attrs)
|
|
1812
|
+
if not id_set_properties_set.issubset(popped_attrs_set):
|
|
1813
|
+
missing_from_popped = id_set_properties_set - popped_attrs_set
|
|
1814
|
+
raise AssertionError(
|
|
1815
|
+
f"In class {class_name!r}, the following properties "
|
|
1816
|
+
f"containing runtime ID sets are not being popped in __getstate__: "
|
|
1817
|
+
f"{sorted(missing_from_popped)}."
|
|
1818
|
+
)
|
|
1819
|
+
|
|
1820
|
+
if len(cls.getstate.body) < 2:
|
|
1821
|
+
raise AssertionError(
|
|
1822
|
+
f"Class {class_name}: __getstate__ should have at least 2 statements"
|
|
1823
|
+
)
|
|
1824
|
+
|
|
1825
|
+
# First statement should be state = self.__dict__.copy().
|
|
1826
|
+
getstate_first_stmt = cls.getstate.body[0]
|
|
1827
|
+
if not (
|
|
1828
|
+
isinstance(getstate_first_stmt, ast.Assign)
|
|
1829
|
+
and len(getstate_first_stmt.targets) == 1
|
|
1830
|
+
and isinstance(getstate_first_stmt.targets[0], ast.Name)
|
|
1831
|
+
and getstate_first_stmt.targets[0].id == "state"
|
|
1832
|
+
):
|
|
1833
|
+
raise AssertionError(
|
|
1834
|
+
f"In class {class_name!r}, the method __getstate__ should start "
|
|
1835
|
+
f"with 'state = ...'"
|
|
1836
|
+
)
|
|
1837
|
+
|
|
1838
|
+
# Last statement should be return state.
|
|
1839
|
+
getstate_last_stmt = cls.getstate.body[-1]
|
|
1840
|
+
if not (
|
|
1841
|
+
isinstance(getstate_last_stmt, ast.Return)
|
|
1842
|
+
and isinstance(getstate_last_stmt.value, ast.Name)
|
|
1843
|
+
and getstate_last_stmt.value.id == "state"
|
|
1844
|
+
):
|
|
1845
|
+
raise AssertionError(
|
|
1846
|
+
f"In class {class_name!r}, the method __getstate__ should end "
|
|
1847
|
+
f"with 'return state'"
|
|
1848
|
+
)
|
|
1849
|
+
|
|
1850
|
+
if len(cls.setstate.body) == 0:
|
|
1851
|
+
raise AssertionError(
|
|
1852
|
+
f"In class {class_name!r}, the method __setstate__ should have "
|
|
1853
|
+
f"at least 1 statement"
|
|
1854
|
+
)
|
|
1855
|
+
|
|
1856
|
+
# First statement should be self.__dict__.update(state).
|
|
1857
|
+
setstate_first_stmt = cls.setstate.body[0]
|
|
1858
|
+
if not (
|
|
1859
|
+
isinstance(setstate_first_stmt, ast.Expr)
|
|
1860
|
+
and isinstance(setstate_first_stmt.value, ast.Call)
|
|
1861
|
+
and isinstance(setstate_first_stmt.value.func, ast.Attribute)
|
|
1862
|
+
and setstate_first_stmt.value.func.attr == "update"
|
|
1863
|
+
):
|
|
1864
|
+
raise AssertionError(
|
|
1865
|
+
f"In class {class_name!r}, the method __setstate__ should start "
|
|
1866
|
+
f"with 'self.__dict__.update(state)'"
|
|
1867
|
+
)
|
|
1868
|
+
|
|
1869
|
+
|
|
1870
|
+
if __name__ == "__main__":
|
|
1871
|
+
unittest.main()
|