forked from robotframework/robotframework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstatus.py
More file actions
234 lines (182 loc) · 7.45 KB
/
Copy pathstatus.py
File metadata and controls
234 lines (182 loc) · 7.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from robot.errors import ExecutionFailed, PassExecution
from robot.utils import html_escape, py2to3, unic
@py2to3
class Failure(object):
def __init__(self):
self.setup = None
self.test = None
self.teardown = None
def __nonzero__(self):
return bool(self.setup or self.test or self.teardown)
@py2to3
class Exit(object):
def __init__(self, failure_mode=False, error_mode=False,
skip_teardown_mode=False):
self.failure_mode = failure_mode
self.error_mode = error_mode
self.skip_teardown_mode = skip_teardown_mode
self.failure = False
self.error = False
self.fatal = False
def failure_occurred(self, failure=None, critical=False):
if isinstance(failure, ExecutionFailed) and failure.exit:
self.fatal = True
if critical and self.failure_mode:
self.failure = True
def error_occurred(self):
if self.error_mode:
self.error = True
@property
def teardown_allowed(self):
return not (self.skip_teardown_mode and self)
def __nonzero__(self):
return self.failure or self.error or self.fatal
class _ExecutionStatus(object):
def __init__(self, parent=None, *exit_modes):
self.parent = parent
self.children = []
self.failure = Failure()
self.exit = parent.exit if parent else Exit(*exit_modes)
self._teardown_allowed = False
if parent:
parent.children.append(self)
def setup_executed(self, failure=None):
if failure and not isinstance(failure, PassExecution):
self.failure.setup = unic(failure)
self.exit.failure_occurred(failure)
self._teardown_allowed = True
def teardown_executed(self, failure=None):
if failure and not isinstance(failure, PassExecution):
self.failure.teardown = unic(failure)
self.exit.failure_occurred(failure)
def critical_failure_occurred(self):
self.exit.failure_occurred(critical=True)
def error_occurred(self):
self.exit.error_occurred()
@property
def teardown_allowed(self):
return self.exit.teardown_allowed and self._teardown_allowed
@property
def failures(self):
return bool(self.parent and self.parent.failures or
self.failure or self.exit)
def _parent_failures(self):
return self.parent and self.parent.failures
@property
def status(self):
return 'FAIL' if self.failures else 'PASS'
@property
def message(self):
if self.failure or self.exit:
return self._my_message()
if self.parent and self.parent.failures:
return self._parent_message()
return ''
def _my_message(self):
raise NotImplementedError
def _parent_message(self):
return ParentMessage(self.parent).message
class SuiteStatus(_ExecutionStatus):
def __init__(self, parent=None, exit_on_failure_mode=False,
exit_on_error_mode=False,
skip_teardown_on_exit_mode=False):
_ExecutionStatus.__init__(self, parent, exit_on_failure_mode,
exit_on_error_mode,
skip_teardown_on_exit_mode)
def _my_message(self):
return SuiteMessage(self).message
class TestStatus(_ExecutionStatus):
def __init__(self, parent, critical):
_ExecutionStatus.__init__(self, parent)
self.exit = parent.exit
self._critical = critical
def test_failed(self, failure):
self.failure.test = unic(failure)
self.exit.failure_occurred(failure, self._critical)
def _my_message(self):
return TestMessage(self).message
class _Message(object):
setup_message = NotImplemented
teardown_message = NotImplemented
also_teardown_message = NotImplemented
def __init__(self, status):
self.failure = status.failure
@property
def message(self):
message = self._get_message_before_teardown()
return self._get_message_after_teardown(message)
def _get_message_before_teardown(self):
if self.failure.setup:
return self._format_setup_or_teardown_message(self.setup_message,
self.failure.setup)
return self.failure.test or ''
def _format_setup_or_teardown_message(self, prefix, message):
if message.startswith('*HTML*'):
prefix = '*HTML* ' + prefix
message = message[6:].lstrip()
return prefix % message
def _get_message_after_teardown(self, message):
if not self.failure.teardown:
return message
if not message:
return self._format_setup_or_teardown_message(self.teardown_message,
self.failure.teardown)
return self._format_message_with_teardown_message(message)
def _format_message_with_teardown_message(self, message):
teardown = self.failure.teardown
if teardown.startswith('*HTML*'):
teardown = teardown[6:].lstrip()
if not message.startswith('*HTML*'):
message = '*HTML* ' + html_escape(message)
elif message.startswith('*HTML*'):
teardown = html_escape(teardown)
return self.also_teardown_message % (message, teardown)
class TestMessage(_Message):
setup_message = 'Setup failed:\n%s'
teardown_message = 'Teardown failed:\n%s'
also_teardown_message = '%s\n\nAlso teardown failed:\n%s'
exit_on_fatal_message = 'Test execution stopped due to a fatal error.'
exit_on_failure_message = \
'Critical failure occurred and exit-on-failure mode is in use.'
exit_on_error_message = 'Error occurred and exit-on-error mode is in use.'
def __init__(self, status):
_Message.__init__(self, status)
self.exit = status.exit
@property
def message(self):
message = super(TestMessage, self).message
if message:
return message
if self.exit.failure:
return self.exit_on_failure_message
if self.exit.fatal:
return self.exit_on_fatal_message
if self.exit.error:
return self.exit_on_error_message
return ''
class SuiteMessage(_Message):
setup_message = 'Suite setup failed:\n%s'
teardown_message = 'Suite teardown failed:\n%s'
also_teardown_message = '%s\n\nAlso suite teardown failed:\n%s'
class ParentMessage(SuiteMessage):
setup_message = 'Parent suite setup failed:\n%s'
teardown_message = 'Parent suite teardown failed:\n%s'
also_teardown_message = '%s\n\nAlso parent suite teardown failed:\n%s'
def __init__(self, status):
while status.parent and status.parent.failures:
status = status.parent
SuiteMessage.__init__(self, status)