1#  Copyright 2008-2015 Nokia Networks
2#  Copyright 2016-     Robot Framework Foundation
3#
4#  Licensed under the Apache License, Version 2.0 (the "License");
5#  you may not use this file except in compliance with the License.
6#  You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10#  Unless required by applicable law or agreed to in writing, software
11#  distributed under the License is distributed on an "AS IS" BASIS,
12#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13#  See the License for the specific language governing permissions and
14#  limitations under the License.
15
16from robot.errors import DataError
17
18
19class XmlElementHandler(object):
20
21    def __init__(self, execution_result, root_handler=None):
22        self._stack = [(root_handler or RootHandler(), execution_result)]
23
24    def start(self, elem):
25        handler, result = self._stack[-1]
26        handler = handler.get_child_handler(elem)
27        result = handler.start(elem, result)
28        self._stack.append((handler, result))
29
30    def end(self, elem):
31        handler, result = self._stack.pop()
32        handler.end(elem, result)
33
34
35class _Handler(object):
36
37    def __init__(self):
38        self._child_handlers = dict((c.tag, c) for c in self._children())
39
40    def _children(self):
41        return []
42
43    def get_child_handler(self, elem):
44        try:
45            return self._child_handlers[elem.tag]
46        except KeyError:
47            raise DataError("Incompatible XML element '%s'." % elem.tag)
48
49    def start(self, elem, result):
50        return result
51
52    def end(self, elem, result):
53        pass
54
55    def _timestamp(self, elem, attr_name):
56        timestamp = elem.get(attr_name)
57        return timestamp if timestamp != 'N/A' else None
58
59
60class RootHandler(_Handler):
61
62    def _children(self):
63        return [RobotHandler()]
64
65
66class RobotHandler(_Handler):
67    tag = 'robot'
68
69    def start(self, elem, result):
70        generator = elem.get('generator', 'unknown').split()[0].upper()
71        result.generated_by_robot = generator == 'ROBOT'
72        if result.rpa is None:
73            result.rpa = elem.get('rpa', 'false') == 'true'
74        return result
75
76    def _children(self):
77        return [RootSuiteHandler(), StatisticsHandler(), ErrorsHandler()]
78
79
80class SuiteHandler(_Handler):
81    tag = 'suite'
82
83    def start(self, elem, result):
84        return result.suites.create(name=elem.get('name', ''),
85                                    source=elem.get('source'),
86                                    rpa=result.rpa)
87
88    def _children(self):
89        return [DocHandler(), MetadataHandler(), SuiteStatusHandler(),
90                KeywordHandler(), TestCaseHandler(), self]
91
92
93class RootSuiteHandler(SuiteHandler):
94
95    def start(self, elem, result):
96        result.suite.name = elem.get('name', '')
97        result.suite.source = elem.get('source')
98        result.suite.rpa = result.rpa
99        return result.suite
100
101    def _children(self):
102        return SuiteHandler._children(self)[:-1] + [SuiteHandler()]
103
104
105class TestCaseHandler(_Handler):
106    tag = 'test'
107
108    def start(self, elem, result):
109        return result.tests.create(name=elem.get('name', ''))
110
111    def _children(self):
112        return [DocHandler(), TagsHandler(), TimeoutHandler(),
113                TestStatusHandler(), KeywordHandler()]
114
115
116class KeywordHandler(_Handler):
117    tag = 'kw'
118
119    def start(self, elem, result):
120        return result.keywords.create(kwname=elem.get('name', ''),
121                                      libname=elem.get('library', ''),
122                                      type=elem.get('type', 'kw'))
123
124    def _children(self):
125        return [DocHandler(), ArgumentsHandler(), AssignHandler(),
126                TagsHandler(), TimeoutHandler(), KeywordStatusHandler(),
127                MessageHandler(), self]
128
129
130class MessageHandler(_Handler):
131    tag = 'msg'
132
133    def end(self, elem, result):
134        result.messages.create(elem.text or '',
135                               elem.get('level', 'INFO'),
136                               elem.get('html', 'no') == 'yes',
137                               self._timestamp(elem, 'timestamp'))
138
139
140class _StatusHandler(_Handler):
141    tag = 'status'
142
143    def _set_status(self, elem, result):
144        result.status = elem.get('status', 'FAIL')
145
146    def _set_message(self, elem, result):
147        result.message = elem.text or ''
148
149    def _set_times(self, elem, result):
150        result.starttime = self._timestamp(elem, 'starttime')
151        result.endtime = self._timestamp(elem, 'endtime')
152
153
154class KeywordStatusHandler(_StatusHandler):
155
156    def end(self, elem, result):
157        self._set_status(elem, result)
158        self._set_times(elem, result)
159        if result.type == result.TEARDOWN_TYPE:
160            self._set_message(elem, result)
161
162
163class SuiteStatusHandler(_StatusHandler):
164
165    def end(self, elem, result):
166        self._set_message(elem, result)
167        self._set_times(elem, result)
168
169
170class TestStatusHandler(_StatusHandler):
171
172    def end(self, elem, result):
173        self._set_status(elem, result)
174        self._set_message(elem, result)
175        self._set_times(elem, result)
176
177
178class DocHandler(_Handler):
179    tag = 'doc'
180
181    def end(self, elem, result):
182        result.doc = elem.text or ''
183
184
185class MetadataHandler(_Handler):
186    tag = 'metadata'
187
188    def _children(self):
189        return [MetadataItemHandler()]
190
191
192class MetadataItemHandler(_Handler):
193    tag = 'item'
194
195    def end(self, elem, result):
196        result.metadata[elem.get('name', '')] = elem.text or ''
197
198
199class TagsHandler(_Handler):
200    tag = 'tags'
201
202    def _children(self):
203        return [TagHandler()]
204
205
206class TagHandler(_Handler):
207    tag = 'tag'
208
209    def end(self, elem, result):
210        result.tags.add(elem.text or '')
211
212
213class TimeoutHandler(_Handler):
214    tag = 'timeout'
215
216    def end(self, elem, result):
217        result.timeout = elem.get('value')
218
219
220class AssignHandler(_Handler):
221    tag = 'assign'
222
223    def _children(self):
224        return [AssignVarHandler()]
225
226
227class AssignVarHandler(_Handler):
228    tag = 'var'
229
230    def end(self, elem, result):
231        result.assign += (elem.text or '',)
232
233
234class ArgumentsHandler(_Handler):
235    tag = 'arguments'
236
237    def _children(self):
238        return [ArgumentHandler()]
239
240
241class ArgumentHandler(_Handler):
242    tag = 'arg'
243
244    def end(self, elem, result):
245        result.args += (elem.text or '',)
246
247
248class ErrorsHandler(_Handler):
249    tag = 'errors'
250
251    def start(self, elem, result):
252        return result.errors
253
254    def _children(self):
255        return [MessageHandler()]
256
257
258class StatisticsHandler(_Handler):
259    tag = 'statistics'
260
261    def get_child_handler(self, elem):
262        return self
263