baldertest 0.1.0b12__py3-none-any.whl → 0.1.0b13__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.
- _balder/_version.py +8 -3
- _balder/cnnrelations/and_connection_relation.py +28 -1
- _balder/cnnrelations/base_connection_relation.py +1 -1
- _balder/collector.py +101 -113
- _balder/connection.py +76 -80
- _balder/controllers/device_controller.py +5 -24
- _balder/controllers/feature_controller.py +2 -2
- _balder/controllers/normal_scenario_setup_controller.py +1 -2
- _balder/controllers/scenario_controller.py +121 -0
- _balder/controllers/vdevice_controller.py +2 -23
- _balder/decorator_connect.py +3 -3
- _balder/decorator_covered_by.py +28 -36
- _balder/executor/basic_executable_executor.py +13 -6
- _balder/executor/basic_executor.py +31 -4
- _balder/executor/executor_tree.py +5 -4
- _balder/executor/parametrized_testcase_executor.py +2 -2
- _balder/executor/scenario_executor.py +12 -71
- _balder/executor/setup_executor.py +4 -3
- _balder/executor/testcase_executor.py +35 -19
- _balder/executor/unresolved_parametrized_testcase_executor.py +32 -57
- _balder/executor/variation_executor.py +21 -48
- _balder/feature.py +2 -1
- _balder/feature_replacement_mapping.py +39 -1
- _balder/fixture_manager.py +1 -1
- _balder/fixture_metadata.py +1 -1
- _balder/routing_path.py +18 -10
- _balder/scenario.py +2 -2
- _balder/setup.py +2 -1
- _balder/testresult.py +4 -3
- _balder/utils/__init__.py +0 -0
- _balder/{utils.py → utils/functions.py} +29 -31
- _balder/utils/inner_device_managing_metaclass.py +14 -0
- _balder/utils/mixin_can_be_covered_by_executor.py +24 -0
- _balder/utils/typings.py +4 -0
- {baldertest-0.1.0b12.dist-info → baldertest-0.1.0b13.dist-info}/METADATA +3 -2
- {baldertest-0.1.0b12.dist-info → baldertest-0.1.0b13.dist-info}/RECORD +40 -36
- {baldertest-0.1.0b12.dist-info → baldertest-0.1.0b13.dist-info}/WHEEL +1 -1
- {baldertest-0.1.0b12.dist-info → baldertest-0.1.0b13.dist-info}/entry_points.txt +0 -0
- {baldertest-0.1.0b12.dist-info → baldertest-0.1.0b13.dist-info/licenses}/LICENSE +0 -0
- {baldertest-0.1.0b12.dist-info → baldertest-0.1.0b13.dist-info}/top_level.txt +0 -0
|
@@ -9,15 +9,17 @@ from _balder.executor.basic_executable_executor import BasicExecutableExecutor
|
|
|
9
9
|
from _balder.fixture_execution_level import FixtureExecutionLevel
|
|
10
10
|
from _balder.previous_executor_mark import PreviousExecutorMark
|
|
11
11
|
from _balder.testresult import ResultState, TestcaseResult
|
|
12
|
-
from _balder.utils import
|
|
12
|
+
from _balder.utils.functions import get_method_type
|
|
13
|
+
from _balder.utils.mixin_can_be_covered_by_executor import MixinCanBeCoveredByExecutor
|
|
13
14
|
|
|
14
15
|
if TYPE_CHECKING:
|
|
16
|
+
from _balder.executor.scenario_executor import ScenarioExecutor
|
|
15
17
|
from _balder.executor.variation_executor import VariationExecutor
|
|
16
18
|
from _balder.fixture_manager import FixtureManager
|
|
17
19
|
from _balder.scenario import Scenario
|
|
18
20
|
|
|
19
21
|
|
|
20
|
-
class TestcaseExecutor(BasicExecutableExecutor):
|
|
22
|
+
class TestcaseExecutor(BasicExecutableExecutor, MixinCanBeCoveredByExecutor):
|
|
21
23
|
"""
|
|
22
24
|
A TestcaseExecutor class represents an actual single test that can be executed. It therefore references exactly to a
|
|
23
25
|
test method of a scenario that can be executed on the specific setup this executor belongs to.
|
|
@@ -65,6 +67,10 @@ class TestcaseExecutor(BasicExecutableExecutor):
|
|
|
65
67
|
def parent_executor(self) -> VariationExecutor:
|
|
66
68
|
return self._parent_executor
|
|
67
69
|
|
|
70
|
+
@property
|
|
71
|
+
def scenario_executor(self) -> ScenarioExecutor:
|
|
72
|
+
return self.parent_executor.parent_executor
|
|
73
|
+
|
|
68
74
|
@property
|
|
69
75
|
def base_instance(self) -> object:
|
|
70
76
|
"""
|
|
@@ -99,15 +105,23 @@ class TestcaseExecutor(BasicExecutableExecutor):
|
|
|
99
105
|
|
|
100
106
|
def _prepare_execution(self, show_discarded):
|
|
101
107
|
print(f" TEST {self.full_test_name_str} ", end='')
|
|
108
|
+
|
|
109
|
+
def _body_execution(self, show_discarded):
|
|
110
|
+
self.test_execution_time_sec = 0
|
|
111
|
+
|
|
102
112
|
if self.should_be_skipped():
|
|
103
113
|
self.body_result.set_result(ResultState.SKIP)
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
return
|
|
115
|
+
if self.should_be_ignored():
|
|
116
|
+
self.body_result.set_result(ResultState.NOT_RUN)
|
|
117
|
+
return
|
|
118
|
+
if self.is_covered_by():
|
|
119
|
+
self.body_result.set_result(ResultState.COVERED_BY)
|
|
120
|
+
return
|
|
106
121
|
|
|
107
|
-
def _body_execution(self, show_discarded):
|
|
108
122
|
start_time = time.perf_counter()
|
|
109
123
|
try:
|
|
110
|
-
|
|
124
|
+
func_type = get_method_type(self.base_testcase_obj.__class__, self.base_testcase_callable)
|
|
111
125
|
all_args = self.get_all_test_method_args()
|
|
112
126
|
if func_type == "staticmethod":
|
|
113
127
|
# testcase is a staticmethod - no special first attribute
|
|
@@ -151,6 +165,16 @@ class TestcaseExecutor(BasicExecutableExecutor):
|
|
|
151
165
|
return True
|
|
152
166
|
return False
|
|
153
167
|
|
|
168
|
+
def is_covered_by(self):
|
|
169
|
+
"""returns true if the testcase is covered-by"""
|
|
170
|
+
return self.prev_mark == PreviousExecutorMark.COVERED_BY
|
|
171
|
+
|
|
172
|
+
def has_skipped_tests(self) -> bool:
|
|
173
|
+
return self.prev_mark == PreviousExecutorMark.SKIP
|
|
174
|
+
|
|
175
|
+
def has_covered_by_tests(self) -> bool:
|
|
176
|
+
return self.prev_mark == PreviousExecutorMark.COVERED_BY
|
|
177
|
+
|
|
154
178
|
def cleanup_empty_executor_branches(self, consider_discarded=False):
|
|
155
179
|
"""
|
|
156
180
|
This method searches the whole tree and removes branches where an executor item has no own children. It can
|
|
@@ -160,25 +184,17 @@ class TestcaseExecutor(BasicExecutableExecutor):
|
|
|
160
184
|
"""
|
|
161
185
|
|
|
162
186
|
def get_covered_by_element(self) -> List[Union[Scenario, callable]]:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
all_covered_by_data = []
|
|
168
|
-
scenario_executor = self.parent_executor.parent_executor
|
|
169
|
-
scenario_class = scenario_executor.base_scenario_class
|
|
170
|
-
covered_by_dict_resolved = scenario_executor.get_covered_by_dict()
|
|
171
|
-
if self.base_testcase_callable in covered_by_dict_resolved.keys():
|
|
172
|
-
all_covered_by_data += covered_by_dict_resolved[self.base_testcase_callable]
|
|
173
|
-
if scenario_class in covered_by_dict_resolved.keys():
|
|
174
|
-
all_covered_by_data += covered_by_dict_resolved[scenario_class]
|
|
187
|
+
covered_by_dict = self.scenario_executor.base_scenario_controller.get_abs_covered_by_dict()
|
|
188
|
+
all_covered_by_data = covered_by_dict.get(self.base_testcase_callable.__name__, [])
|
|
189
|
+
# also add all scenario specified covered-by elements
|
|
190
|
+
all_covered_by_data.extend(covered_by_dict.get(None, []))
|
|
175
191
|
return all_covered_by_data
|
|
176
192
|
|
|
177
193
|
def get_all_test_method_args(self):
|
|
178
194
|
"""
|
|
179
195
|
returns all kwargs values for the test method
|
|
180
196
|
"""
|
|
181
|
-
|
|
197
|
+
func_type = get_method_type(self.base_testcase_obj.__class__, self.base_testcase_callable)
|
|
182
198
|
return self.fixture_manager.get_all_attribute_values(
|
|
183
199
|
self,
|
|
184
200
|
self.base_testcase_obj.__class__,
|
|
@@ -11,14 +11,16 @@ from _balder.executor.parametrized_testcase_executor import ParametrizedTestcase
|
|
|
11
11
|
from _balder.parametrization import Parameter
|
|
12
12
|
from _balder.previous_executor_mark import PreviousExecutorMark
|
|
13
13
|
from _balder.testresult import BranchBodyResult
|
|
14
|
+
from _balder.utils.mixin_can_be_covered_by_executor import MixinCanBeCoveredByExecutor
|
|
14
15
|
|
|
15
16
|
if TYPE_CHECKING:
|
|
17
|
+
from _balder.executor.scenario_executor import ScenarioExecutor
|
|
16
18
|
from _balder.executor.variation_executor import VariationExecutor
|
|
17
19
|
from _balder.scenario import Scenario
|
|
18
20
|
from _balder.setup import Setup
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
class UnresolvedParametrizedTestcaseExecutor(BasicExecutor):
|
|
23
|
+
class UnresolvedParametrizedTestcaseExecutor(BasicExecutor, MixinCanBeCoveredByExecutor):
|
|
22
24
|
"""
|
|
23
25
|
This executor class represents a group of dynamically parametrized tests.
|
|
24
26
|
"""
|
|
@@ -37,9 +39,6 @@ class UnresolvedParametrizedTestcaseExecutor(BasicExecutor):
|
|
|
37
39
|
# holds the specific static parameters for this unresolved group
|
|
38
40
|
self._static_parameters = static_parameters if static_parameters is not None else {}
|
|
39
41
|
|
|
40
|
-
# holds the dynamically created testcase executors as soon as this executor is entered
|
|
41
|
-
self._testcase_executors = None
|
|
42
|
-
|
|
43
42
|
# contains the result object for the BODY part of this branch
|
|
44
43
|
self.body_result = BranchBodyResult(self)
|
|
45
44
|
|
|
@@ -47,14 +46,18 @@ class UnresolvedParametrizedTestcaseExecutor(BasicExecutor):
|
|
|
47
46
|
def parent_executor(self) -> VariationExecutor:
|
|
48
47
|
return self._parent_executor
|
|
49
48
|
|
|
49
|
+
@property
|
|
50
|
+
def scenario_executor(self) -> ScenarioExecutor:
|
|
51
|
+
return self.parent_executor.parent_executor
|
|
52
|
+
|
|
50
53
|
@property
|
|
51
54
|
def base_testcase_callable(self) -> callable:
|
|
52
55
|
"""returns the testcase function"""
|
|
53
56
|
return self._base_testcase_callable
|
|
54
57
|
|
|
55
58
|
@property
|
|
56
|
-
def all_child_executors(self) ->
|
|
57
|
-
return
|
|
59
|
+
def all_child_executors(self) -> None:
|
|
60
|
+
return None
|
|
58
61
|
|
|
59
62
|
@property
|
|
60
63
|
def base_testcase_obj(self) -> Scenario:
|
|
@@ -69,29 +72,11 @@ class UnresolvedParametrizedTestcaseExecutor(BasicExecutor):
|
|
|
69
72
|
returns the base class instance to which this executor instance belongs"""
|
|
70
73
|
return self._base_testcase_callable
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"""returns true if the parametrization has been resolved"""
|
|
75
|
-
return self._testcase_executors is not None
|
|
76
|
-
|
|
77
|
-
def has_runnable_tests(self, consider_discarded_too=False) -> bool:
|
|
78
|
-
"""
|
|
79
|
-
This method returns true if this executor element is runnable. The method returns true if this element has
|
|
80
|
-
`prev_mark=RUNNABLE` and minimum one of its children has `prev_mark=RUNNABLE` too.
|
|
81
|
-
|
|
82
|
-
:param consider_discarded_too: True if the method allows DISCARDED elements too
|
|
83
|
-
"""
|
|
84
|
-
if self.parametrization_has_been_resolved:
|
|
85
|
-
return super().has_runnable_tests(consider_discarded_too=consider_discarded_too)
|
|
75
|
+
def has_skipped_tests(self) -> bool:
|
|
76
|
+
return self.prev_mark == PreviousExecutorMark.SKIP
|
|
86
77
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if consider_discarded_too:
|
|
90
|
-
allowed_prev_marks.append(PreviousExecutorMark.DISCARDED)
|
|
91
|
-
|
|
92
|
-
if self.prev_mark not in allowed_prev_marks:
|
|
93
|
-
return False
|
|
94
|
-
return True
|
|
78
|
+
def has_covered_by_tests(self) -> bool:
|
|
79
|
+
return self.prev_mark == PreviousExecutorMark.COVERED_BY
|
|
95
80
|
|
|
96
81
|
def get_all_base_instances_of_this_branch(
|
|
97
82
|
self, with_type: Type[Setup] | Type[Scenario] | Type[types.FunctionType],
|
|
@@ -105,43 +90,33 @@ class UnresolvedParametrizedTestcaseExecutor(BasicExecutor):
|
|
|
105
90
|
return []
|
|
106
91
|
|
|
107
92
|
def get_covered_by_element(self) -> List[Scenario | callable]:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
all_covered_by_data = []
|
|
113
|
-
scenario_executor = self.parent_executor.parent_executor
|
|
114
|
-
scenario_class = scenario_executor.base_scenario_class
|
|
115
|
-
covered_by_dict_resolved = scenario_executor.get_covered_by_dict()
|
|
116
|
-
if self.base_testcase_callable in covered_by_dict_resolved.keys():
|
|
117
|
-
all_covered_by_data += covered_by_dict_resolved[self.base_testcase_callable]
|
|
118
|
-
if scenario_class in covered_by_dict_resolved.keys():
|
|
119
|
-
all_covered_by_data += covered_by_dict_resolved[scenario_class]
|
|
93
|
+
covered_by_dict = self.scenario_executor.base_scenario_controller.get_abs_covered_by_dict()
|
|
94
|
+
all_covered_by_data = covered_by_dict.get(self.base_testcase_callable.__name__, [])
|
|
95
|
+
# also add all scenario specified covered-by elements
|
|
96
|
+
all_covered_by_data.extend(covered_by_dict.get(None, []))
|
|
120
97
|
return all_covered_by_data
|
|
121
98
|
|
|
122
|
-
def
|
|
123
|
-
"""returns all sub testcase executors that belongs to this variation-executor"""
|
|
124
|
-
if self._testcase_executors is None:
|
|
125
|
-
return [self]
|
|
126
|
-
return self._testcase_executors
|
|
127
|
-
|
|
128
|
-
def resolve_dynamic_parametrization(self):
|
|
99
|
+
def get_resolved_parametrized_testcase_executors(self):
|
|
129
100
|
"""
|
|
130
101
|
resolves the dynamic parametrization - should be called when setup features are active in the scenario
|
|
131
102
|
"""
|
|
132
|
-
|
|
103
|
+
executors = []
|
|
133
104
|
|
|
134
105
|
parametrization = self.get_parametrization()
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
106
|
+
|
|
107
|
+
if not parametrization:
|
|
108
|
+
return []
|
|
109
|
+
|
|
110
|
+
for cur_parametrization in parametrization:
|
|
111
|
+
executors.append(
|
|
112
|
+
ParametrizedTestcaseExecutor(
|
|
113
|
+
self._base_testcase_callable,
|
|
114
|
+
parent=self.parent_executor,
|
|
115
|
+
parametrization=cur_parametrization,
|
|
116
|
+
unresolved_group_obj=self
|
|
144
117
|
)
|
|
118
|
+
)
|
|
119
|
+
return executors
|
|
145
120
|
|
|
146
121
|
def get_parametrization(self) -> List[OrderedDict[str, Any]] | None:
|
|
147
122
|
"""
|
|
@@ -171,7 +171,7 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
171
171
|
self.exchange_unmapped_vdevice_references()
|
|
172
172
|
self.update_vdevice_referenced_feature_instances()
|
|
173
173
|
self.set_conn_dependent_methods()
|
|
174
|
-
self.
|
|
174
|
+
self.resolve_and_exchange_unresolved_parametrization()
|
|
175
175
|
|
|
176
176
|
def _body_execution(self, show_discarded):
|
|
177
177
|
if show_discarded and not self.can_be_applied():
|
|
@@ -179,13 +179,10 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
179
179
|
return
|
|
180
180
|
|
|
181
181
|
for cur_testcase_executor in self.get_testcase_executors():
|
|
182
|
-
if cur_testcase_executor.has_runnable_tests()
|
|
183
|
-
|
|
182
|
+
if (cur_testcase_executor.has_runnable_tests()
|
|
183
|
+
or cur_testcase_executor.has_skipped_tests()
|
|
184
|
+
or cur_testcase_executor.has_covered_by_tests()):
|
|
184
185
|
cur_testcase_executor.execute()
|
|
185
|
-
elif cur_testcase_executor.prev_mark == PreviousExecutorMark.SKIP:
|
|
186
|
-
cur_testcase_executor.set_result_for_whole_branch(ResultState.SKIP)
|
|
187
|
-
elif cur_testcase_executor.prev_mark == PreviousExecutorMark.COVERED_BY:
|
|
188
|
-
cur_testcase_executor.set_result_for_whole_branch(ResultState.COVERED_BY)
|
|
189
186
|
else:
|
|
190
187
|
cur_testcase_executor.set_result_for_whole_branch(ResultState.NOT_RUN)
|
|
191
188
|
|
|
@@ -335,16 +332,9 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
335
332
|
return super().testsummary()
|
|
336
333
|
return ResultSummary()
|
|
337
334
|
|
|
338
|
-
def get_testcase_executors(self) -> List[TestcaseExecutor]:
|
|
335
|
+
def get_testcase_executors(self) -> List[TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor]:
|
|
339
336
|
"""returns all sub testcase executors that belongs to this variation-executor"""
|
|
340
|
-
|
|
341
|
-
for cur_executor in self._testcase_executors:
|
|
342
|
-
if (isinstance(cur_executor, UnresolvedParametrizedTestcaseExecutor) and
|
|
343
|
-
cur_executor.parametrization_has_been_resolved):
|
|
344
|
-
result += cur_executor.get_testcase_executors()
|
|
345
|
-
else:
|
|
346
|
-
result.append(cur_executor)
|
|
347
|
-
return result
|
|
337
|
+
return self._testcase_executors.copy()
|
|
348
338
|
|
|
349
339
|
def add_testcase_executor(self, testcase_executor: TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor):
|
|
350
340
|
"""
|
|
@@ -388,12 +378,9 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
388
378
|
setup_dev: FeatureVDeviceMapping() for setup_dev in self.base_device_mapping.values()
|
|
389
379
|
}
|
|
390
380
|
for cur_scenario_device, cur_setup_device in self.base_device_mapping.items():
|
|
391
|
-
cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
392
381
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
DeviceController.get_for(cur_scenario_device).get_all_instantiated_feature_objects()
|
|
396
|
-
for cur_attr_name, cur_scenario_feature_obj in cur_scenario_device_features.items():
|
|
382
|
+
for cur_attr_name, cur_scenario_feature_obj in \
|
|
383
|
+
DeviceController.get_for(cur_scenario_device).get_all_instantiated_feature_objects().items():
|
|
397
384
|
active_scenario_vdevice, mapped_scenario_device = cur_scenario_feature_obj.active_vdevice_device_mapping
|
|
398
385
|
|
|
399
386
|
cur_setup_feature_objs = self._get_matching_setup_features_for(
|
|
@@ -407,13 +394,14 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
407
394
|
f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
|
|
408
395
|
cur_setup_feature_obj = cur_setup_feature_objs[0]
|
|
409
396
|
|
|
397
|
+
all_abs_inner_vdevs_of_setup = \
|
|
398
|
+
FeatureController.get_for(cur_setup_feature_obj.__class__).get_abs_inner_vdevice_classes()
|
|
399
|
+
used_setup_vdevice, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
|
|
400
|
+
|
|
410
401
|
if mapped_scenario_device is None:
|
|
411
402
|
# we have exactly one matching candidate, but also no vDevice mapping
|
|
412
403
|
# check if the matching candidate has a vDevice mapping
|
|
413
|
-
|
|
414
|
-
cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
|
|
415
|
-
if mapped_setup_device is None \
|
|
416
|
-
and len(cleanup_feature_controller.get_abs_inner_vdevice_classes()) > 0:
|
|
404
|
+
if mapped_setup_device is None and len(all_abs_inner_vdevs_of_setup) > 0:
|
|
417
405
|
# there is no vDevice mapping on scenario and no vDevice mapping on setup level, but the
|
|
418
406
|
# feature defined vDevices -> NOT APPLICABLE
|
|
419
407
|
logger.warning(
|
|
@@ -427,19 +415,14 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
427
415
|
f'`{cur_scenario_feature_obj.__class__.__name__}` (used by scenario device '
|
|
428
416
|
f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
|
|
429
417
|
|
|
430
|
-
all_assigned_setup_features.append(cur_setup_feature_obj)
|
|
431
418
|
if cur_attr_name not in feature_replacement[cur_scenario_device].attr_names:
|
|
432
|
-
cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
|
|
433
|
-
|
|
434
|
-
used_setup_vdevice, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
|
|
435
419
|
|
|
436
420
|
# if there is a vDevice mapping on scenario level, but not on setup level, so update the
|
|
437
421
|
# VDevice-Device-Mapping there
|
|
438
422
|
if mapped_scenario_device is not None and mapped_setup_device is None:
|
|
439
423
|
# search the equivalent vDevice on setup level and use this one (we had not to check it,
|
|
440
424
|
# because check was already done in collector-stage)
|
|
441
|
-
setup_vdevices = [cur_vdevice for cur_vdevice
|
|
442
|
-
in cleanup_feature_controller.get_abs_inner_vdevice_classes()
|
|
425
|
+
setup_vdevices = [cur_vdevice for cur_vdevice in all_abs_inner_vdevs_of_setup
|
|
443
426
|
if cur_vdevice.__name__ == active_scenario_vdevice.__name__]
|
|
444
427
|
used_setup_vdevice = setup_vdevices[0]
|
|
445
428
|
# set the mapping
|
|
@@ -463,21 +446,7 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
463
446
|
scenario_feature=cur_scenario_feature_obj,
|
|
464
447
|
setup_feature=cur_setup_feature_obj)
|
|
465
448
|
|
|
466
|
-
|
|
467
|
-
for cur_setup_feature in cur_setup_features.values():
|
|
468
|
-
if cur_setup_feature not in all_assigned_setup_features:
|
|
469
|
-
# determine free name
|
|
470
|
-
idx = 0
|
|
471
|
-
autonomous_name = None
|
|
472
|
-
while (autonomous_name is None
|
|
473
|
-
or autonomous_name in feature_replacement[cur_scenario_device].attr_names):
|
|
474
|
-
autonomous_name = f"_autonomous_feat_{idx}"
|
|
475
|
-
idx += 1
|
|
476
|
-
feature_replacement[cur_scenario_device].add(
|
|
477
|
-
attr_name=autonomous_name,
|
|
478
|
-
scenario_feature=None,
|
|
479
|
-
setup_feature=cur_setup_feature
|
|
480
|
-
)
|
|
449
|
+
feature_replacement[cur_scenario_device].add_remaining_setup_features_as_autonomous(cur_setup_device)
|
|
481
450
|
|
|
482
451
|
# set the result to internal properties
|
|
483
452
|
self._feature_replacement = feature_replacement
|
|
@@ -902,8 +871,12 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
902
871
|
|
|
903
872
|
cur_setup_feature_controller.set_active_method_variation(method_selection=method_var_selection)
|
|
904
873
|
|
|
905
|
-
def
|
|
874
|
+
def resolve_and_exchange_unresolved_parametrization(self):
|
|
906
875
|
"""resolves the parametrization if there are any :class:`UnresolvedParametrizedTestcaseExecutor` in the tree"""
|
|
876
|
+
replaced_executors = []
|
|
907
877
|
for cur_child in self._testcase_executors:
|
|
908
878
|
if isinstance(cur_child, UnresolvedParametrizedTestcaseExecutor):
|
|
909
|
-
cur_child.
|
|
879
|
+
replaced_executors.extend(cur_child.get_resolved_parametrized_testcase_executors())
|
|
880
|
+
else:
|
|
881
|
+
replaced_executors.append(cur_child)
|
|
882
|
+
self._testcase_executors = replaced_executors
|
_balder/feature.py
CHANGED
|
@@ -3,9 +3,10 @@ from typing import Type, Dict, Tuple, Union
|
|
|
3
3
|
|
|
4
4
|
from _balder.device import Device
|
|
5
5
|
from _balder.vdevice import VDevice
|
|
6
|
+
from _balder.utils.inner_device_managing_metaclass import InnerDeviceManagingMetaclass
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
class Feature:
|
|
9
|
+
class Feature(metaclass=InnerDeviceManagingMetaclass):
|
|
9
10
|
"""
|
|
10
11
|
This is the basic feature class. It represents an abstract class that should not be used directly. It is the base
|
|
11
12
|
class for all feature elements.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
from typing import Union
|
|
1
|
+
from typing import Union, Type
|
|
2
2
|
import dataclasses
|
|
3
|
+
from .device import Device
|
|
3
4
|
from .feature import Feature
|
|
5
|
+
from .controllers import DeviceController
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class FeatureReplacementMapping:
|
|
@@ -37,6 +39,20 @@ class FeatureReplacementMapping:
|
|
|
37
39
|
"""
|
|
38
40
|
return [mapping.attr_name for mapping in self._mappings]
|
|
39
41
|
|
|
42
|
+
@property
|
|
43
|
+
def all_scenario_features(self) -> list[Feature]:
|
|
44
|
+
"""
|
|
45
|
+
returns all scenario features
|
|
46
|
+
"""
|
|
47
|
+
return [mapping.scenario_feature for mapping in self._mappings]
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def all_setup_features(self) -> list[Feature]:
|
|
51
|
+
"""
|
|
52
|
+
returns all setup features
|
|
53
|
+
"""
|
|
54
|
+
return [mapping.setup_feature for mapping in self._mappings]
|
|
55
|
+
|
|
40
56
|
def add(self, attr_name: str, scenario_feature: Union[Feature, None], setup_feature: Feature):
|
|
41
57
|
"""
|
|
42
58
|
adds a new mapping
|
|
@@ -67,3 +83,25 @@ class FeatureReplacementMapping:
|
|
|
67
83
|
if mapping.setup_feature == setup_feature:
|
|
68
84
|
return mapping.scenario_feature
|
|
69
85
|
raise KeyError(f'cannot find setup feature for {setup_feature}')
|
|
86
|
+
|
|
87
|
+
def add_remaining_setup_features_as_autonomous(self, cur_setup_device: Type[Device]):
|
|
88
|
+
"""
|
|
89
|
+
Adds all features that were not added as autonomous features.
|
|
90
|
+
"""
|
|
91
|
+
cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
92
|
+
|
|
93
|
+
# also add all setup features that are not assigned as autonomous features
|
|
94
|
+
for cur_setup_feature in cur_setup_features.values():
|
|
95
|
+
if cur_setup_feature not in self.all_setup_features:
|
|
96
|
+
# determine free name
|
|
97
|
+
idx = 0
|
|
98
|
+
autonomous_name = None
|
|
99
|
+
while (autonomous_name is None
|
|
100
|
+
or autonomous_name in self.attr_names):
|
|
101
|
+
autonomous_name = f"_autonomous_feat_{idx}"
|
|
102
|
+
idx += 1
|
|
103
|
+
self.add(
|
|
104
|
+
attr_name=autonomous_name,
|
|
105
|
+
scenario_feature=None,
|
|
106
|
+
setup_feature=cur_setup_feature
|
|
107
|
+
)
|
_balder/fixture_manager.py
CHANGED
|
@@ -19,7 +19,7 @@ from _balder.exceptions import LostInExecutorTreeException, FixtureReferenceErro
|
|
|
19
19
|
UnclearUniqueClassReference
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
-
from _balder.utils import MethodLiteralType
|
|
22
|
+
from _balder.utils.functions import MethodLiteralType
|
|
23
23
|
from _balder.executor.executor_tree import ExecutorTree
|
|
24
24
|
|
|
25
25
|
|
_balder/fixture_metadata.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
from typing import Union, Type, Callable, Generator, TYPE_CHECKING
|
|
3
3
|
import dataclasses
|
|
4
4
|
|
|
5
|
-
from .utils import MethodLiteralType
|
|
5
|
+
from .utils.typings import MethodLiteralType
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from _balder.scenario import Scenario
|
_balder/routing_path.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import List, Union, Dict, Type, Tuple, TYPE_CHECKING
|
|
2
|
+
from typing import List, Union, Dict, Type, Tuple, Iterable, TYPE_CHECKING
|
|
3
3
|
|
|
4
4
|
import copy
|
|
5
5
|
from _balder.connection import Connection
|
|
@@ -57,11 +57,24 @@ class RoutingPath:
|
|
|
57
57
|
|
|
58
58
|
# ---------------------------------- STATIC METHODS ----------------------------------------------------------------
|
|
59
59
|
|
|
60
|
+
@staticmethod
|
|
61
|
+
def __get_abs_setup_dev_cnns_for(setup_devices: Iterable[Type[Device]]) -> List[Connection]:
|
|
62
|
+
"""
|
|
63
|
+
Determines all absolute device connections for a given list of setup devices.
|
|
64
|
+
"""
|
|
65
|
+
setup_devices_cnns = []
|
|
66
|
+
for cur_setup_device in setup_devices:
|
|
67
|
+
for cur_cnn_list in DeviceController.get_for(cur_setup_device).get_all_absolute_connections().values():
|
|
68
|
+
setup_devices_cnns.extend(cur_cnn_list)
|
|
69
|
+
# remove duplicates
|
|
70
|
+
return list(set(setup_devices_cnns))
|
|
71
|
+
|
|
60
72
|
@staticmethod
|
|
61
73
|
def route_through(
|
|
62
|
-
scenario_connection: Connection,
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
scenario_connection: Connection,
|
|
75
|
+
device_mapping: Dict[Type[Device], Type[Device]],
|
|
76
|
+
alternative_setup_device_cnns: Union[List[Connection], None] = None
|
|
77
|
+
) -> List[RoutingPath]:
|
|
65
78
|
"""
|
|
66
79
|
This static method tries to route the given ``scenario_connection`` with the device_mapping. It returns a list
|
|
67
80
|
of all matched routings between the mapped devices, where the routing is valid to support the requested
|
|
@@ -77,12 +90,7 @@ class RoutingPath:
|
|
|
77
90
|
"""
|
|
78
91
|
setup_devices_cnns = alternative_setup_device_cnns
|
|
79
92
|
if alternative_setup_device_cnns is None:
|
|
80
|
-
setup_devices_cnns =
|
|
81
|
-
for cur_setup_device in device_mapping.values():
|
|
82
|
-
for cur_cnn_list in DeviceController.get_for(cur_setup_device).get_all_absolute_connections().values():
|
|
83
|
-
setup_devices_cnns.extend(cur_cnn_list)
|
|
84
|
-
# remove duplicates
|
|
85
|
-
setup_devices_cnns = list(set(setup_devices_cnns))
|
|
93
|
+
setup_devices_cnns = RoutingPath.__get_abs_setup_dev_cnns_for(device_mapping.values())
|
|
86
94
|
|
|
87
95
|
from_setup_device = device_mapping[scenario_connection.from_device]
|
|
88
96
|
to_setup_device = device_mapping[scenario_connection.to_device]
|
_balder/scenario.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
from _balder.utils.inner_device_managing_metaclass import InnerDeviceManagingMetaclass
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
class Scenario:
|
|
5
|
+
class Scenario(metaclass=InnerDeviceManagingMetaclass):
|
|
5
6
|
"""
|
|
6
7
|
This is the basic scenario class. It represents an abstract class that should be the base class for all scenarios.
|
|
7
8
|
"""
|
|
8
|
-
RUN = []
|
|
9
9
|
SKIP = []
|
|
10
10
|
IGNORE = []
|
|
11
11
|
|
_balder/setup.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
from _balder.utils.inner_device_managing_metaclass import InnerDeviceManagingMetaclass
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
class Setup:
|
|
5
|
+
class Setup(metaclass=InnerDeviceManagingMetaclass):
|
|
5
6
|
"""
|
|
6
7
|
This is the abstract basic setup class. It has to be the base class for all setups.
|
|
7
8
|
"""
|
_balder/testresult.py
CHANGED
|
@@ -106,9 +106,10 @@ class BranchBodyResult(_Result):
|
|
|
106
106
|
"""returns the determined result for the inner branch of the related executor"""
|
|
107
107
|
relative_result = ResultState.NOT_RUN
|
|
108
108
|
priority_order = ResultState.priority_order()
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
if self._related_executor.all_child_executors:
|
|
110
|
+
for cur_child in self._related_executor.all_child_executors:
|
|
111
|
+
if priority_order.index(cur_child.executor_result) < priority_order.index(relative_result):
|
|
112
|
+
relative_result = cur_child.executor_result
|
|
112
113
|
self._result = relative_result
|
|
113
114
|
return self._result
|
|
114
115
|
|
|
File without changes
|