baldertest 0.1.0b6__py3-none-any.whl → 0.1.0b7__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 +1 -1
- _balder/balder_session.py +13 -9
- _balder/console/balder.py +1 -0
- _balder/controllers/base_device_controller.py +2 -3
- _balder/controllers/feature_controller.py +11 -12
- _balder/exceptions.py +1 -1
- _balder/executor/basic_executor.py +33 -19
- _balder/executor/executor_tree.py +46 -34
- _balder/executor/scenario_executor.py +20 -14
- _balder/executor/setup_executor.py +13 -14
- _balder/executor/testcase_executor.py +3 -6
- _balder/executor/variation_executor.py +177 -131
- _balder/previous_executor_mark.py +3 -0
- _balder/routing_path.py +1 -1
- _balder/solver.py +13 -15
- balder/exceptions.py +2 -2
- baldertest-0.1.0b7.dist-info/METADATA +388 -0
- {baldertest-0.1.0b6.dist-info → baldertest-0.1.0b7.dist-info}/RECORD +22 -22
- {baldertest-0.1.0b6.dist-info → baldertest-0.1.0b7.dist-info}/WHEEL +1 -1
- baldertest-0.1.0b6.dist-info/METADATA +0 -92
- {baldertest-0.1.0b6.dist-info → baldertest-0.1.0b7.dist-info}/LICENSE +0 -0
- {baldertest-0.1.0b6.dist-info → baldertest-0.1.0b7.dist-info}/entry_points.txt +0 -0
- {baldertest-0.1.0b6.dist-info → baldertest-0.1.0b7.dist-info}/top_level.txt +0 -0
_balder/_version.py
CHANGED
_balder/balder_session.py
CHANGED
|
@@ -60,6 +60,8 @@ class BalderSession:
|
|
|
60
60
|
self.collect_only: Union[bool, None] = None
|
|
61
61
|
#: specifies that the tests should only be collected and resolved but not executed
|
|
62
62
|
self.resolve_only: Union[bool, None] = None
|
|
63
|
+
#: specifies that all discarded variations should be printed (with information why they were discarded)
|
|
64
|
+
self.show_discarded: Union[bool, None] = None
|
|
63
65
|
#: contains a number of :class:`Setup` class strings that should only be considered for the execution
|
|
64
66
|
self.only_with_setup: Union[List[str], None] = None
|
|
65
67
|
#: contains a number of :class:`Scenario` class strings that should only be considered for the execution
|
|
@@ -246,6 +248,10 @@ class BalderSession:
|
|
|
246
248
|
'--resolve-only', action='store_true',
|
|
247
249
|
help="specifies that the tests are only collected and resolved but not executed")
|
|
248
250
|
|
|
251
|
+
self.cmd_arg_parser.add_argument(
|
|
252
|
+
'--show-discarded', action='store_true',
|
|
253
|
+
help="specifies that all discarded variations should be printed (with information why they were discarded)")
|
|
254
|
+
|
|
249
255
|
self.cmd_arg_parser.add_argument(
|
|
250
256
|
'--only-with-setup', nargs="*",
|
|
251
257
|
help="defines a number of Setup classes which should only be considered for the execution")
|
|
@@ -270,6 +276,7 @@ class BalderSession:
|
|
|
270
276
|
self.working_dir = self.parsed_args.working_dir
|
|
271
277
|
self.collect_only = self.parsed_args.collect_only
|
|
272
278
|
self.resolve_only = self.parsed_args.resolve_only
|
|
279
|
+
self.show_discarded = self.parsed_args.show_discarded
|
|
273
280
|
self.only_with_setup = self.parsed_args.only_with_setup
|
|
274
281
|
self.only_with_scenario = self.parsed_args.only_with_scenario
|
|
275
282
|
self.force_covered_by_duplicates = self.parsed_args.force_covered_by_duplicates
|
|
@@ -298,12 +305,6 @@ class BalderSession:
|
|
|
298
305
|
self.executor_tree = self.solver.get_executor_tree(plugin_manager=self.plugin_manager)
|
|
299
306
|
self.plugin_manager.execute_filter_executor_tree(executor_tree=self.executor_tree)
|
|
300
307
|
|
|
301
|
-
def execute_executor_tree(self):
|
|
302
|
-
"""
|
|
303
|
-
This method executes the :class:`ExecutorTree`.
|
|
304
|
-
"""
|
|
305
|
-
self.executor_tree.execute()
|
|
306
|
-
|
|
307
308
|
def run(self):
|
|
308
309
|
"""
|
|
309
310
|
This method executes the whole session
|
|
@@ -326,11 +327,14 @@ class BalderSession:
|
|
|
326
327
|
if not self.collect_only:
|
|
327
328
|
self.solve()
|
|
328
329
|
self.create_executor_tree()
|
|
329
|
-
|
|
330
|
+
count_valid = len(self.executor_tree.get_all_variation_executors())
|
|
331
|
+
count_discarded = len(self.executor_tree.get_all_variation_executors(return_discarded=True)) - count_valid
|
|
332
|
+
addon_text = f" ({count_discarded} discarded)" if self.show_discarded else ""
|
|
333
|
+
print(f" resolve them to {count_valid} valid variations{addon_text}")
|
|
330
334
|
print("")
|
|
331
335
|
if not self.resolve_only:
|
|
332
|
-
self.
|
|
336
|
+
self.executor_tree.execute(show_discarded=self.show_discarded)
|
|
333
337
|
else:
|
|
334
|
-
self.executor_tree.print_tree()
|
|
338
|
+
self.executor_tree.print_tree(show_discarded=self.show_discarded)
|
|
335
339
|
|
|
336
340
|
self.plugin_manager.execute_session_finished(self.executor_tree)
|
_balder/console/balder.py
CHANGED
|
@@ -15,6 +15,7 @@ def console_balder(cmd_args: Optional[List[str]] = None, working_dir: Union[str,
|
|
|
15
15
|
_console_balder_debug(cmd_args=cmd_args, working_dir=working_dir)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
# pylint: disable-next=too-many-arguments
|
|
18
19
|
def _console_balder_debug(cmd_args: Optional[List[str]] = None, working_dir: Union[str, pathlib.Path, None] = None,
|
|
19
20
|
cb_session_created: Optional[Callable] = None, cb_run_finished: Optional[Callable] = None,
|
|
20
21
|
cb_balder_exc: Optional[Callable] = None, cb_unexpected_exc: Optional[Callable] = None):
|
|
@@ -58,9 +58,8 @@ class BaseDeviceController(Controller, ABC):
|
|
|
58
58
|
This method returns the original instanced feature objects of the related device
|
|
59
59
|
"""
|
|
60
60
|
if self._original_instanced_features is None:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
'`save_all_original_instanced_features`')
|
|
61
|
+
raise RuntimeError('can not access the original instantiated features before they were set with '
|
|
62
|
+
'`save_all_original_instanced_features`')
|
|
64
63
|
return self._original_instanced_features
|
|
65
64
|
|
|
66
65
|
def save_all_original_instanced_features(self):
|
|
@@ -117,13 +117,14 @@ class FeatureController(Controller):
|
|
|
117
117
|
if self.get_method_based_for_vdevice() is not None:
|
|
118
118
|
for _, method_dict in self.get_method_based_for_vdevice().items():
|
|
119
119
|
for _, vdevice_dict in method_dict.items():
|
|
120
|
-
if for_vdevice in vdevice_dict.keys():
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
if for_vdevice not in vdevice_dict.keys():
|
|
121
|
+
continue
|
|
122
|
+
for cur_cnn in vdevice_dict[for_vdevice]:
|
|
123
|
+
if isinstance(cur_cnn, type):
|
|
124
|
+
cur_cnn = cur_cnn()
|
|
125
|
+
# clean metadata here because this is no connection between real devices
|
|
126
|
+
cur_cnn.set_metadata_for_all_subitems(None)
|
|
127
|
+
intersection.append(cur_cnn)
|
|
127
128
|
if len(intersection) == 0:
|
|
128
129
|
return [Connection()]
|
|
129
130
|
return intersection
|
|
@@ -151,8 +152,7 @@ class FeatureController(Controller):
|
|
|
151
152
|
This method returns the absolute calculated class-based-for-vdevice data for this feature.
|
|
152
153
|
"""
|
|
153
154
|
if self._abs_cls_for_vdevice is None:
|
|
154
|
-
|
|
155
|
-
raise EnvironmentError('can not access the absolute class based for-vdevices because they are not set')
|
|
155
|
+
raise RuntimeError('can not access the absolute class based for-vdevices because they are not set yet')
|
|
156
156
|
return self._abs_cls_for_vdevice
|
|
157
157
|
|
|
158
158
|
def set_class_based_for_vdevice(
|
|
@@ -718,9 +718,8 @@ class FeatureController(Controller):
|
|
|
718
718
|
This method returns the :class:`VDevice` definitions that are the original definitions for this feature.
|
|
719
719
|
"""
|
|
720
720
|
if self._original_vdevice_definitions is None:
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
'`save_all_current_vdevice_references_as_originals`')
|
|
721
|
+
raise RuntimeError('can not access the original VDevice definitions before they were set with '
|
|
722
|
+
'`save_all_current_vdevice_references_as_originals`')
|
|
724
723
|
return self._original_vdevice_definitions
|
|
725
724
|
|
|
726
725
|
def save_all_current_vdevice_references_as_originals(self):
|
_balder/exceptions.py
CHANGED
|
@@ -158,7 +158,7 @@ class IllegalVDeviceMappingError(BalderException):
|
|
|
158
158
|
"""
|
|
159
159
|
|
|
160
160
|
|
|
161
|
-
class
|
|
161
|
+
class NotApplicableVariationException(BalderException):
|
|
162
162
|
"""
|
|
163
163
|
is thrown internally after the current variation is not applicable
|
|
164
164
|
"""
|
|
@@ -87,21 +87,21 @@ class BasicExecutor(ABC):
|
|
|
87
87
|
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
|
|
88
88
|
|
|
89
89
|
@abstractmethod
|
|
90
|
-
def _prepare_execution(self):
|
|
90
|
+
def _prepare_execution(self, show_discarded):
|
|
91
91
|
"""
|
|
92
92
|
This method runs before the branch will be executed and before the fixture construction code of this branch
|
|
93
93
|
runs.
|
|
94
94
|
"""
|
|
95
95
|
|
|
96
96
|
@abstractmethod
|
|
97
|
-
def _body_execution(self):
|
|
97
|
+
def _body_execution(self, show_discarded):
|
|
98
98
|
"""
|
|
99
99
|
This method runs between the fixture construction and teardown code. It should trigger the execution of the
|
|
100
100
|
child branches.
|
|
101
101
|
"""
|
|
102
102
|
|
|
103
103
|
@abstractmethod
|
|
104
|
-
def _cleanup_execution(self):
|
|
104
|
+
def _cleanup_execution(self, show_discarded):
|
|
105
105
|
"""
|
|
106
106
|
This method runs after the branch was executed (also after the fixture teardown code ran)
|
|
107
107
|
"""
|
|
@@ -137,17 +137,29 @@ class BasicExecutor(ABC):
|
|
|
137
137
|
if isinstance(cur_child_executor.body_result, TestcaseResult):
|
|
138
138
|
cur_child_executor.body_result.set_result(result=value, exception=None)
|
|
139
139
|
|
|
140
|
-
def
|
|
140
|
+
def has_runnable_tests(self, consider_discarded_too=False) -> bool:
|
|
141
141
|
"""
|
|
142
142
|
This method returns true if this executor element is runnable. The method returns true if this element has
|
|
143
143
|
`prev_mark=RUNNABLE` and minimum one of its children has `prev_mark=RUNNABLE` too.
|
|
144
|
+
|
|
145
|
+
:param consider_discarded_too: True if the method allows DISCARDED elements too
|
|
144
146
|
"""
|
|
145
|
-
|
|
147
|
+
allowed_prev_marks = [PreviousExecutorMark.RUNNABLE]
|
|
148
|
+
|
|
149
|
+
if consider_discarded_too:
|
|
150
|
+
allowed_prev_marks.append(PreviousExecutorMark.DISCARDED)
|
|
151
|
+
|
|
152
|
+
if self.prev_mark not in allowed_prev_marks:
|
|
146
153
|
return False
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
|
|
155
|
+
if self.all_child_executors is not None:
|
|
156
|
+
# the executor has child executors -> check them
|
|
157
|
+
for cur_child in self.all_child_executors:
|
|
158
|
+
if cur_child.has_runnable_tests(consider_discarded_too):
|
|
159
|
+
return True
|
|
160
|
+
return False
|
|
161
|
+
else:
|
|
162
|
+
return True
|
|
151
163
|
|
|
152
164
|
def get_all_base_instances_of_this_branch(
|
|
153
165
|
self, with_type: Union[Type[Setup], Type[Scenario], Type[types.FunctionType]],
|
|
@@ -165,7 +177,7 @@ class BasicExecutor(ABC):
|
|
|
165
177
|
# only go through cur_executor == ExecutorTree (do not iterate with this object)
|
|
166
178
|
while cur_executor.parent_executor is not None:
|
|
167
179
|
if isinstance(cur_executor.base_instance, with_type):
|
|
168
|
-
if not only_runnable_elements or cur_executor.
|
|
180
|
+
if not only_runnable_elements or cur_executor.has_runnable_tests():
|
|
169
181
|
return [cur_executor.base_instance]
|
|
170
182
|
cur_executor = cur_executor.parent_executor
|
|
171
183
|
|
|
@@ -221,32 +233,34 @@ class BasicExecutor(ABC):
|
|
|
221
233
|
summary[cur_key] = cur_child_dict[cur_key]
|
|
222
234
|
return summary
|
|
223
235
|
|
|
224
|
-
def execute(self):
|
|
236
|
+
def execute(self, show_discarded=False):
|
|
225
237
|
"""
|
|
226
238
|
Executes the whole branch
|
|
227
239
|
"""
|
|
228
240
|
start_time = time.perf_counter()
|
|
229
|
-
self._prepare_execution()
|
|
241
|
+
self._prepare_execution(show_discarded=show_discarded)
|
|
230
242
|
|
|
231
243
|
try:
|
|
232
244
|
try:
|
|
233
|
-
self.
|
|
234
|
-
|
|
245
|
+
if self.has_runnable_tests():
|
|
246
|
+
self.fixture_manager.enter(self)
|
|
247
|
+
self.construct_result.set_result(ResultState.SUCCESS)
|
|
235
248
|
|
|
236
|
-
self._body_execution()
|
|
249
|
+
self._body_execution(show_discarded=show_discarded)
|
|
237
250
|
except Exception as exc:
|
|
238
251
|
# this has to be a construction fixture error
|
|
239
252
|
traceback.print_exception(*sys.exc_info())
|
|
240
253
|
self.construct_result.set_result(ResultState.ERROR, exc)
|
|
241
254
|
finally:
|
|
242
|
-
if self.
|
|
243
|
-
self.fixture_manager.
|
|
244
|
-
|
|
255
|
+
if self.has_runnable_tests():
|
|
256
|
+
if self.fixture_manager.is_allowed_to_leave(self):
|
|
257
|
+
self.fixture_manager.leave(self)
|
|
258
|
+
self.teardown_result.set_result(ResultState.SUCCESS)
|
|
245
259
|
except Exception as exc:
|
|
246
260
|
# this has to be a teardown fixture error
|
|
247
261
|
traceback.print_exception(*sys.exc_info())
|
|
248
262
|
self.teardown_result.set_result(ResultState.ERROR, exc)
|
|
249
263
|
|
|
250
|
-
self._cleanup_execution()
|
|
264
|
+
self._cleanup_execution(show_discarded=show_discarded)
|
|
251
265
|
|
|
252
266
|
self.execution_time_sec = time.perf_counter() - start_time
|
|
@@ -18,6 +18,7 @@ class ExecutorTree(BasicExecutor):
|
|
|
18
18
|
"""
|
|
19
19
|
This class is the root object of the executor tree structure
|
|
20
20
|
"""
|
|
21
|
+
LINE_LENGTH = 120
|
|
21
22
|
|
|
22
23
|
def __init__(self, fixture_manager: FixtureManager):
|
|
23
24
|
super().__init__()
|
|
@@ -35,18 +36,13 @@ class ExecutorTree(BasicExecutor):
|
|
|
35
36
|
|
|
36
37
|
@property
|
|
37
38
|
def all_child_executors(self) -> List[BasicExecutor]:
|
|
38
|
-
return self.
|
|
39
|
+
return self._setup_executors
|
|
39
40
|
|
|
40
41
|
@property
|
|
41
42
|
def base_instance(self) -> object:
|
|
42
43
|
"""returns None because this element is a ExecutorTree"""
|
|
43
44
|
return None
|
|
44
45
|
|
|
45
|
-
@property
|
|
46
|
-
def setup_executors(self) -> List[SetupExecutor]:
|
|
47
|
-
"""returns all setup executors of this tree"""
|
|
48
|
-
return self._setup_executors
|
|
49
|
-
|
|
50
46
|
@property
|
|
51
47
|
def fixture_manager(self) -> FixtureManager:
|
|
52
48
|
"""returns the fixture manager of this tree"""
|
|
@@ -58,13 +54,13 @@ class ExecutorTree(BasicExecutor):
|
|
|
58
54
|
|
|
59
55
|
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
|
|
60
56
|
|
|
61
|
-
def _prepare_execution(self):
|
|
57
|
+
def _prepare_execution(self, show_discarded):
|
|
62
58
|
pass
|
|
63
59
|
|
|
64
|
-
def _body_execution(self):
|
|
65
|
-
for cur_setup_executor in self.
|
|
66
|
-
if cur_setup_executor.
|
|
67
|
-
cur_setup_executor.execute()
|
|
60
|
+
def _body_execution(self, show_discarded):
|
|
61
|
+
for cur_setup_executor in self.get_setup_executors():
|
|
62
|
+
if cur_setup_executor.has_runnable_tests(consider_discarded_too=show_discarded):
|
|
63
|
+
cur_setup_executor.execute(show_discarded=show_discarded)
|
|
68
64
|
elif cur_setup_executor.prev_mark == PreviousExecutorMark.SKIP:
|
|
69
65
|
cur_setup_executor.set_result_for_whole_branch(ResultState.SKIP)
|
|
70
66
|
elif cur_setup_executor.prev_mark == PreviousExecutorMark.COVERED_BY:
|
|
@@ -72,27 +68,31 @@ class ExecutorTree(BasicExecutor):
|
|
|
72
68
|
else:
|
|
73
69
|
cur_setup_executor.set_result_for_whole_branch(ResultState.NOT_RUN)
|
|
74
70
|
|
|
75
|
-
def _cleanup_execution(self):
|
|
71
|
+
def _cleanup_execution(self, show_discarded):
|
|
76
72
|
pass
|
|
77
73
|
|
|
78
74
|
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
79
75
|
|
|
76
|
+
def get_setup_executors(self) -> List[SetupExecutor]:
|
|
77
|
+
"""returns all setup executors of this tree"""
|
|
78
|
+
return self._setup_executors
|
|
79
|
+
|
|
80
80
|
def get_all_scenario_executors(self) -> List[ScenarioExecutor]:
|
|
81
81
|
"""
|
|
82
82
|
returns a list with all scenario executors
|
|
83
83
|
"""
|
|
84
84
|
all_scenario_executor = []
|
|
85
|
-
for cur_setup_executor in self.
|
|
86
|
-
all_scenario_executor += cur_setup_executor.
|
|
85
|
+
for cur_setup_executor in self.get_setup_executors():
|
|
86
|
+
all_scenario_executor += cur_setup_executor.get_scenario_executors()
|
|
87
87
|
return all_scenario_executor
|
|
88
88
|
|
|
89
|
-
def get_all_variation_executors(self) -> List[VariationExecutor]:
|
|
89
|
+
def get_all_variation_executors(self, return_discarded=False) -> List[VariationExecutor]:
|
|
90
90
|
"""
|
|
91
91
|
returns a list with all variation executors
|
|
92
92
|
"""
|
|
93
93
|
all_variation_executor = []
|
|
94
94
|
for cur_scenario_executor in self.get_all_scenario_executors():
|
|
95
|
-
all_variation_executor += cur_scenario_executor.
|
|
95
|
+
all_variation_executor += cur_scenario_executor.get_variation_executors(return_discarded=return_discarded)
|
|
96
96
|
return all_variation_executor
|
|
97
97
|
|
|
98
98
|
def get_all_testcase_executors(self) -> List[TestcaseExecutor]:
|
|
@@ -101,8 +101,8 @@ class ExecutorTree(BasicExecutor):
|
|
|
101
101
|
"""
|
|
102
102
|
all_testcase_executor = []
|
|
103
103
|
for cur_scenario_executor in self.get_all_scenario_executors():
|
|
104
|
-
for cur_variation_executor in cur_scenario_executor.
|
|
105
|
-
all_testcase_executor += cur_variation_executor.
|
|
104
|
+
for cur_variation_executor in cur_scenario_executor.get_variation_executors():
|
|
105
|
+
all_testcase_executor += cur_variation_executor.get_testcase_executors()
|
|
106
106
|
return all_testcase_executor
|
|
107
107
|
|
|
108
108
|
def add_setup_executor(self, setup_executor: SetupExecutor):
|
|
@@ -131,33 +131,33 @@ class ExecutorTree(BasicExecutor):
|
|
|
131
131
|
|
|
132
132
|
def cleanup_empty_executor_branches(self):
|
|
133
133
|
to_remove_executor = []
|
|
134
|
-
for cur_setup_executor in self.
|
|
134
|
+
for cur_setup_executor in self.get_setup_executors():
|
|
135
135
|
cur_setup_executor.cleanup_empty_executor_branches()
|
|
136
|
-
if len(cur_setup_executor.
|
|
136
|
+
if len(cur_setup_executor.get_scenario_executors()) == 0:
|
|
137
137
|
# remove this whole executor because it has no children anymore
|
|
138
138
|
to_remove_executor.append(cur_setup_executor)
|
|
139
139
|
for cur_setup_executor in to_remove_executor:
|
|
140
140
|
self._setup_executors.remove(cur_setup_executor)
|
|
141
141
|
|
|
142
|
-
def execute(self) -> None:
|
|
142
|
+
def execute(self, show_discarded=False) -> None:
|
|
143
143
|
"""
|
|
144
144
|
This method executes this branch of the tree
|
|
145
145
|
"""
|
|
146
146
|
start_text = "START TESTSESSION"
|
|
147
147
|
end_text = "FINISH TESTSESSION"
|
|
148
|
-
line_length = 120
|
|
149
148
|
|
|
150
149
|
def print_line(text):
|
|
151
|
-
full_text = int((
|
|
152
|
-
full_text += "=" * (
|
|
150
|
+
full_text = int((self.LINE_LENGTH - (len(start_text) + 2)) / 2) * "=" + " " + text + " "
|
|
151
|
+
full_text += "=" * (self.LINE_LENGTH - len(full_text))
|
|
153
152
|
print(full_text)
|
|
154
153
|
|
|
155
154
|
print_line(start_text)
|
|
156
155
|
# check if there exists runnable elements
|
|
157
|
-
runnables = [cur_exec.
|
|
156
|
+
runnables = [cur_exec.has_runnable_tests(consider_discarded_too=show_discarded)
|
|
157
|
+
for cur_exec in self.get_setup_executors()]
|
|
158
158
|
one_or_more_runnable_setups = None if len(runnables) == 0 else max(runnables)
|
|
159
159
|
if one_or_more_runnable_setups:
|
|
160
|
-
super().execute()
|
|
160
|
+
super().execute(show_discarded=show_discarded)
|
|
161
161
|
else:
|
|
162
162
|
print("NO EXECUTABLE SETUPS/SCENARIOS FOUND")
|
|
163
163
|
print_line(end_text)
|
|
@@ -171,19 +171,31 @@ class ExecutorTree(BasicExecutor):
|
|
|
171
171
|
print(f"TOTAL {cur_key.value}: {cur_val}", end="")
|
|
172
172
|
print("")
|
|
173
173
|
|
|
174
|
-
def print_tree(self) -> None:
|
|
174
|
+
def print_tree(self, show_discarded=False) -> None:
|
|
175
175
|
"""this method is an auxiliary method which outputs the entire tree"""
|
|
176
176
|
print("RESOLVING OVERVIEW", end="\n\n")
|
|
177
|
-
for cur_setup_executor in self.
|
|
178
|
-
for cur_scenario_executor in cur_setup_executor.
|
|
179
|
-
for cur_variation_executor in cur_scenario_executor.
|
|
180
|
-
|
|
177
|
+
for cur_setup_executor in self.get_setup_executors():
|
|
178
|
+
for cur_scenario_executor in cur_setup_executor.get_scenario_executors():
|
|
179
|
+
for cur_variation_executor in cur_scenario_executor.get_variation_executors(
|
|
180
|
+
return_discarded=show_discarded):
|
|
181
|
+
applicable = cur_variation_executor.prev_mark != PreviousExecutorMark.DISCARDED
|
|
182
|
+
start_char = '+' if applicable else 'X'
|
|
183
|
+
print(start_char * self.LINE_LENGTH)
|
|
184
|
+
applicability_str = "[APPLICABLE]" if applicable else "[DISCARDED] "
|
|
185
|
+
print(f"{start_char} {applicability_str} Scenario "
|
|
186
|
+
f"`{cur_scenario_executor.base_scenario_class.__class__.__qualname__}` <-> "
|
|
181
187
|
f"Setup `{cur_setup_executor.base_setup_class.__class__.__qualname__}`")
|
|
182
188
|
mapping_printings = {}
|
|
183
189
|
for cur_scenario_device, cur_setup_device in cur_variation_executor.base_device_mapping.items():
|
|
184
190
|
mapping_printings[f" {cur_scenario_device.__qualname__}"] = str(cur_setup_device.__qualname__)
|
|
185
191
|
max_len = max(len(cur_elem) for cur_elem in mapping_printings.keys())
|
|
186
192
|
for cur_key, cur_val in mapping_printings.items():
|
|
187
|
-
print(("{:<" + str(max_len) + "} = {}").format(cur_key, cur_val))
|
|
188
|
-
for cur_testcase_excutor in cur_variation_executor.
|
|
189
|
-
print(f"
|
|
193
|
+
print(("{} {:<" + str(max_len) + "} = {}").format(start_char, cur_key, cur_val))
|
|
194
|
+
for cur_testcase_excutor in cur_variation_executor.get_testcase_executors():
|
|
195
|
+
print(f"{start_char} -> Testcase<{cur_testcase_excutor.base_testcase_callable.__qualname__}>")
|
|
196
|
+
if cur_variation_executor.prev_mark == PreviousExecutorMark.DISCARDED:
|
|
197
|
+
print(f"{start_char}")
|
|
198
|
+
print(f"{start_char} DISCARDED BECAUSE "
|
|
199
|
+
f"`{cur_variation_executor.not_applicable_variation_exc.args[0]}`")
|
|
200
|
+
print(('+' if applicable else 'X') * self.LINE_LENGTH)
|
|
201
|
+
print('')
|
|
@@ -46,7 +46,7 @@ class ScenarioExecutor(BasicExecutor):
|
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def all_child_executors(self) -> List[VariationExecutor]:
|
|
49
|
-
return self.
|
|
49
|
+
return self._variation_executors
|
|
50
50
|
|
|
51
51
|
@property
|
|
52
52
|
def parent_executor(self) -> SetupExecutor:
|
|
@@ -64,11 +64,6 @@ class ScenarioExecutor(BasicExecutor):
|
|
|
64
64
|
"""returns the :class:`Scenario` class that belongs to this executor"""
|
|
65
65
|
return self._base_scenario_class
|
|
66
66
|
|
|
67
|
-
@property
|
|
68
|
-
def variation_executors(self) -> List[VariationExecutor]:
|
|
69
|
-
"""returns all variation executors that are child executor of this scenario executor"""
|
|
70
|
-
return self._variation_executors
|
|
71
|
-
|
|
72
67
|
@property
|
|
73
68
|
def fixture_manager(self) -> FixtureManager:
|
|
74
69
|
"""returns the current active fixture manager that belongs to this scenario executor"""
|
|
@@ -91,13 +86,13 @@ class ScenarioExecutor(BasicExecutor):
|
|
|
91
86
|
|
|
92
87
|
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
|
|
93
88
|
|
|
94
|
-
def _prepare_execution(self):
|
|
89
|
+
def _prepare_execution(self, show_discarded):
|
|
95
90
|
print(f" SCENARIO {self.base_scenario_class.__class__.__name__}")
|
|
96
91
|
|
|
97
|
-
def _body_execution(self):
|
|
98
|
-
for cur_variation_executor in self.
|
|
99
|
-
if cur_variation_executor.
|
|
100
|
-
cur_variation_executor.execute()
|
|
92
|
+
def _body_execution(self, show_discarded):
|
|
93
|
+
for cur_variation_executor in self.get_variation_executors(return_discarded=show_discarded):
|
|
94
|
+
if cur_variation_executor.has_runnable_tests(show_discarded):
|
|
95
|
+
cur_variation_executor.execute(show_discarded=show_discarded)
|
|
101
96
|
elif cur_variation_executor.prev_mark == PreviousExecutorMark.SKIP:
|
|
102
97
|
cur_variation_executor.set_result_for_whole_branch(ResultState.SKIP)
|
|
103
98
|
elif cur_variation_executor.prev_mark == PreviousExecutorMark.COVERED_BY:
|
|
@@ -105,18 +100,29 @@ class ScenarioExecutor(BasicExecutor):
|
|
|
105
100
|
else:
|
|
106
101
|
cur_variation_executor.set_result_for_whole_branch(ResultState.NOT_RUN)
|
|
107
102
|
|
|
108
|
-
def _cleanup_execution(self):
|
|
103
|
+
def _cleanup_execution(self, show_discarded):
|
|
109
104
|
pass
|
|
110
105
|
|
|
111
106
|
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
112
107
|
|
|
108
|
+
def get_variation_executors(self, return_discarded=False) -> List[VariationExecutor]:
|
|
109
|
+
"""
|
|
110
|
+
:param return_discarded: True if the method should return discarded variations too
|
|
111
|
+
|
|
112
|
+
:return: returns all variation executors that are child executor of this scenario executor
|
|
113
|
+
"""
|
|
114
|
+
if not return_discarded:
|
|
115
|
+
return [cur_executor for cur_executor in self._variation_executors
|
|
116
|
+
if cur_executor.prev_mark != PreviousExecutorMark.DISCARDED]
|
|
117
|
+
return self._variation_executors
|
|
118
|
+
|
|
113
119
|
def cleanup_empty_executor_branches(self):
|
|
114
120
|
"""
|
|
115
121
|
This method removes all sub executors that are empty and not relevant anymore.
|
|
116
122
|
"""
|
|
117
123
|
to_remove_executor = []
|
|
118
|
-
for cur_variation_executor in self.
|
|
119
|
-
if len(cur_variation_executor.
|
|
124
|
+
for cur_variation_executor in self.get_variation_executors():
|
|
125
|
+
if len(cur_variation_executor.get_testcase_executors()) == 0:
|
|
120
126
|
# remove this whole executor because it has no children anymore
|
|
121
127
|
to_remove_executor.append(cur_variation_executor)
|
|
122
128
|
for cur_variation_executor in to_remove_executor:
|
|
@@ -42,7 +42,7 @@ class SetupExecutor(BasicExecutor):
|
|
|
42
42
|
|
|
43
43
|
@property
|
|
44
44
|
def all_child_executors(self) -> List[ScenarioExecutor]:
|
|
45
|
-
return self.
|
|
45
|
+
return self._scenario_executors
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def parent_executor(self) -> ExecutorTree:
|
|
@@ -58,11 +58,6 @@ class SetupExecutor(BasicExecutor):
|
|
|
58
58
|
"""returns the base :class:`Setup` that belongs to this executor"""
|
|
59
59
|
return self._base_setup_class
|
|
60
60
|
|
|
61
|
-
@property
|
|
62
|
-
def scenario_executors(self) -> List[ScenarioExecutor]:
|
|
63
|
-
"""returns a list with all scenario executors that belongs to this setup executor"""
|
|
64
|
-
return self._scenario_executors
|
|
65
|
-
|
|
66
61
|
@property
|
|
67
62
|
def fixture_manager(self) -> FixtureManager:
|
|
68
63
|
"""returns the current active fixture manager for this executor"""
|
|
@@ -70,13 +65,13 @@ class SetupExecutor(BasicExecutor):
|
|
|
70
65
|
|
|
71
66
|
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
|
|
72
67
|
|
|
73
|
-
def _prepare_execution(self):
|
|
68
|
+
def _prepare_execution(self, show_discarded):
|
|
74
69
|
print(f"SETUP {self.base_setup_class.__class__.__name__}")
|
|
75
70
|
|
|
76
|
-
def _body_execution(self):
|
|
77
|
-
for cur_scenario_executor in self.
|
|
78
|
-
if cur_scenario_executor.
|
|
79
|
-
cur_scenario_executor.execute()
|
|
71
|
+
def _body_execution(self, show_discarded):
|
|
72
|
+
for cur_scenario_executor in self.get_scenario_executors():
|
|
73
|
+
if cur_scenario_executor.has_runnable_tests(consider_discarded_too=show_discarded):
|
|
74
|
+
cur_scenario_executor.execute(show_discarded=show_discarded)
|
|
80
75
|
elif cur_scenario_executor.prev_mark == PreviousExecutorMark.SKIP:
|
|
81
76
|
cur_scenario_executor.set_result_for_whole_branch(ResultState.SKIP)
|
|
82
77
|
elif cur_scenario_executor.prev_mark == PreviousExecutorMark.COVERED_BY:
|
|
@@ -84,16 +79,20 @@ class SetupExecutor(BasicExecutor):
|
|
|
84
79
|
else:
|
|
85
80
|
cur_scenario_executor.set_result_for_whole_branch(ResultState.NOT_RUN)
|
|
86
81
|
|
|
87
|
-
def _cleanup_execution(self):
|
|
82
|
+
def _cleanup_execution(self, show_discarded):
|
|
88
83
|
pass
|
|
89
84
|
|
|
90
85
|
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
91
86
|
|
|
87
|
+
def get_scenario_executors(self) -> List[ScenarioExecutor]:
|
|
88
|
+
"""returns a list with all scenario executors that belongs to this setup executor"""
|
|
89
|
+
return self._scenario_executors
|
|
90
|
+
|
|
92
91
|
def cleanup_empty_executor_branches(self):
|
|
93
92
|
to_remove_executor = []
|
|
94
|
-
for cur_scenario_executor in self.
|
|
93
|
+
for cur_scenario_executor in self.get_scenario_executors():
|
|
95
94
|
cur_scenario_executor.cleanup_empty_executor_branches()
|
|
96
|
-
if len(cur_scenario_executor.
|
|
95
|
+
if len(cur_scenario_executor.get_variation_executors()) == 0:
|
|
97
96
|
# remove this whole executor because it has no children anymore
|
|
98
97
|
to_remove_executor.append(cur_scenario_executor)
|
|
99
98
|
for cur_scenario_executor in to_remove_executor:
|
|
@@ -76,7 +76,7 @@ class TestcaseExecutor(BasicExecutor):
|
|
|
76
76
|
|
|
77
77
|
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
|
|
78
78
|
|
|
79
|
-
def _prepare_execution(self):
|
|
79
|
+
def _prepare_execution(self, show_discarded):
|
|
80
80
|
print(f" TEST {self.base_testcase_callable.__qualname__} ", end='')
|
|
81
81
|
if self.should_be_skipped():
|
|
82
82
|
self.body_result.set_result(ResultState.SKIP)
|
|
@@ -84,7 +84,7 @@ class TestcaseExecutor(BasicExecutor):
|
|
|
84
84
|
print("[S]")
|
|
85
85
|
return
|
|
86
86
|
|
|
87
|
-
def _body_execution(self):
|
|
87
|
+
def _body_execution(self, show_discarded):
|
|
88
88
|
start_time = time.perf_counter()
|
|
89
89
|
try:
|
|
90
90
|
_, func_type = inspect_method(self.base_testcase_callable)
|
|
@@ -109,14 +109,11 @@ class TestcaseExecutor(BasicExecutor):
|
|
|
109
109
|
self.body_result.set_result(ResultState.FAILURE, exc)
|
|
110
110
|
self.test_execution_time_sec = time.perf_counter() - start_time
|
|
111
111
|
|
|
112
|
-
def _cleanup_execution(self):
|
|
112
|
+
def _cleanup_execution(self, show_discarded):
|
|
113
113
|
print(f"[{self.body_result.get_result_as_char()}]")
|
|
114
114
|
|
|
115
115
|
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
116
116
|
|
|
117
|
-
def has_runnable_elements(self) -> bool:
|
|
118
|
-
return self.prev_mark == PreviousExecutorMark.RUNNABLE
|
|
119
|
-
|
|
120
117
|
def should_run(self):
|
|
121
118
|
"""returns true if the testcase should be executed (defined in scenario)"""
|
|
122
119
|
if self.base_testcase_callable in self.parent_executor.parent_executor.all_run_tests:
|