wrappers.py (12882:dd87d7f2f3e5) wrappers.py (14141:b3ceff47211a)
1# Copyright (c) 2019 ARM Limited
2# All rights reserved
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
1# Copyright (c) 2017 Mark D. Hill and David A. Wood
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Sean Wilson
28
29'''
30Module contains wrappers for test items that have been
31loaded by the testlib :class:`testlib.loader.Loader`.
32'''
33import itertools
34
35import log
36import uid
37from state import Status, Result
38
39class TestCaseMetadata():
40 def __init__(self, name, uid, path, result, status, suite_uid):
41 self.name = name
42 self.uid = uid
43 self.path = path
44 self.status = status
45 self.result = result
46 self.suite_uid = suite_uid
47
48
49class TestSuiteMetadata():
50 def __init__(self, name, uid, tags, path, status, result):
51 self.name = name
52 self.uid = uid
53 self.tags = tags
54 self.path = path
55 self.status = status
56 self.result = result
57
58
59class LibraryMetadata():
60 def __init__(self, name, result, status):
61 self.name = name
62 self.result = result
63 self.status = status
64
65
66class LoadedTestable(object):
67 '''
68 Base class for loaded test items.
69
70 :property:`result` and :property:`status` setters
71 notify testlib via the :func:`log_result` and :func:`log_status`
72 of the updated status.
73 '''
74 def __init__(self, obj):
75 self.obj = obj
76 self.metadata = self._generate_metadata()
77
78 @property
79 def status(self):
80 return self.metadata.status
81
82 @status.setter
83 def status(self, status):
84 self.log_status(status)
85 self.metadata.status = status
86
87 @property
88 def result(self):
89 return self.metadata.result
90
91 @result.setter
92 def result(self, result):
93 self.log_result(result)
94 self.metadata.result = result
95
96 @property
97 def uid(self):
98 return self.metadata.uid
99
100 @property
101 def name(self):
102 return self.metadata.name
103
104 @property
105 def fixtures(self):
106 return self.obj.fixtures
107
108 @fixtures.setter
109 def fixtures(self, fixtures):
110 self.obj.fixtures = fixtures
111
112 @property
113 def runner(self):
114 return self.obj.runner
115
116 # TODO Change log to provide status_update, result_update for all types.
117 def log_status(self, status):
118 log.test_log.status_update(self, status)
119
120 def log_result(self, result):
121 log.test_log.result_update(self, result)
122
123 def __iter__(self):
124 return iter(())
125
126
127class LoadedTest(LoadedTestable):
128 def __init__(self, test_obj, loaded_suite, path):
129 self.parent_suite = loaded_suite
130 self._path = path
131 LoadedTestable.__init__(self, test_obj)
132
133 def test(self, *args, **kwargs):
134 self.obj.test(*args, **kwargs)
135
136 def _generate_metadata(self):
137 return TestCaseMetadata( **{
138 'name':self.obj.name,
139 'path': self._path,
140 'uid': uid.TestUID(self._path,
141 self.obj.name,
142 self.parent_suite.name),
143 'status': Status.Unscheduled,
144 'result': Result(Result.NotRun),
145 'suite_uid': self.parent_suite.metadata.uid
146 })
147
148
149class LoadedSuite(LoadedTestable):
150 def __init__(self, suite_obj, path):
151 self._path = path
152 LoadedTestable.__init__(self, suite_obj)
153 self.tests = self._wrap_children(suite_obj)
154
155 def _wrap_children(self, suite_obj):
156 return [LoadedTest(test, self, self.metadata.path)
157 for test in suite_obj]
158
159 def _generate_metadata(self):
160 return TestSuiteMetadata( **{
161 'name': self.obj.name,
162 'tags':self.obj.tags,
163 'path': self._path,
164 'uid': uid.SuiteUID(self._path, self.obj.name),
165 'status': Status.Unscheduled,
166 'result': Result(Result.NotRun)
167 })
168
169 def __iter__(self):
170 return iter(self.tests)
171
172 @property
173 def tags(self):
174 return self.metadata.tags
175
176
177class LoadedLibrary(LoadedTestable):
178 '''
179 Wraps a collection of all loaded test suites and
180 provides utility functions for accessing fixtures.
181 '''
13# Copyright (c) 2017 Mark D. Hill and David A. Wood
14# All rights reserved.
15#
16# Redistribution and use in source and binary forms, with or without
17# modification, are permitted provided that the following conditions are
18# met: redistributions of source code must retain the above copyright
19# notice, this list of conditions and the following disclaimer;
20# redistributions in binary form must reproduce the above copyright
21# notice, this list of conditions and the following disclaimer in the
22# documentation and/or other materials provided with the distribution;
23# neither the name of the copyright holders nor the names of its
24# contributors may be used to endorse or promote products derived from
25# this software without specific prior written permission.
26#
27# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38#
39# Authors: Sean Wilson
40
41'''
42Module contains wrappers for test items that have been
43loaded by the testlib :class:`testlib.loader.Loader`.
44'''
45import itertools
46
47import log
48import uid
49from state import Status, Result
50
51class TestCaseMetadata():
52 def __init__(self, name, uid, path, result, status, suite_uid):
53 self.name = name
54 self.uid = uid
55 self.path = path
56 self.status = status
57 self.result = result
58 self.suite_uid = suite_uid
59
60
61class TestSuiteMetadata():
62 def __init__(self, name, uid, tags, path, status, result):
63 self.name = name
64 self.uid = uid
65 self.tags = tags
66 self.path = path
67 self.status = status
68 self.result = result
69
70
71class LibraryMetadata():
72 def __init__(self, name, result, status):
73 self.name = name
74 self.result = result
75 self.status = status
76
77
78class LoadedTestable(object):
79 '''
80 Base class for loaded test items.
81
82 :property:`result` and :property:`status` setters
83 notify testlib via the :func:`log_result` and :func:`log_status`
84 of the updated status.
85 '''
86 def __init__(self, obj):
87 self.obj = obj
88 self.metadata = self._generate_metadata()
89
90 @property
91 def status(self):
92 return self.metadata.status
93
94 @status.setter
95 def status(self, status):
96 self.log_status(status)
97 self.metadata.status = status
98
99 @property
100 def result(self):
101 return self.metadata.result
102
103 @result.setter
104 def result(self, result):
105 self.log_result(result)
106 self.metadata.result = result
107
108 @property
109 def uid(self):
110 return self.metadata.uid
111
112 @property
113 def name(self):
114 return self.metadata.name
115
116 @property
117 def fixtures(self):
118 return self.obj.fixtures
119
120 @fixtures.setter
121 def fixtures(self, fixtures):
122 self.obj.fixtures = fixtures
123
124 @property
125 def runner(self):
126 return self.obj.runner
127
128 # TODO Change log to provide status_update, result_update for all types.
129 def log_status(self, status):
130 log.test_log.status_update(self, status)
131
132 def log_result(self, result):
133 log.test_log.result_update(self, result)
134
135 def __iter__(self):
136 return iter(())
137
138
139class LoadedTest(LoadedTestable):
140 def __init__(self, test_obj, loaded_suite, path):
141 self.parent_suite = loaded_suite
142 self._path = path
143 LoadedTestable.__init__(self, test_obj)
144
145 def test(self, *args, **kwargs):
146 self.obj.test(*args, **kwargs)
147
148 def _generate_metadata(self):
149 return TestCaseMetadata( **{
150 'name':self.obj.name,
151 'path': self._path,
152 'uid': uid.TestUID(self._path,
153 self.obj.name,
154 self.parent_suite.name),
155 'status': Status.Unscheduled,
156 'result': Result(Result.NotRun),
157 'suite_uid': self.parent_suite.metadata.uid
158 })
159
160
161class LoadedSuite(LoadedTestable):
162 def __init__(self, suite_obj, path):
163 self._path = path
164 LoadedTestable.__init__(self, suite_obj)
165 self.tests = self._wrap_children(suite_obj)
166
167 def _wrap_children(self, suite_obj):
168 return [LoadedTest(test, self, self.metadata.path)
169 for test in suite_obj]
170
171 def _generate_metadata(self):
172 return TestSuiteMetadata( **{
173 'name': self.obj.name,
174 'tags':self.obj.tags,
175 'path': self._path,
176 'uid': uid.SuiteUID(self._path, self.obj.name),
177 'status': Status.Unscheduled,
178 'result': Result(Result.NotRun)
179 })
180
181 def __iter__(self):
182 return iter(self.tests)
183
184 @property
185 def tags(self):
186 return self.metadata.tags
187
188
189class LoadedLibrary(LoadedTestable):
190 '''
191 Wraps a collection of all loaded test suites and
192 provides utility functions for accessing fixtures.
193 '''
182 def __init__(self, suites, global_fixtures):
194 def __init__(self, suites):
183 LoadedTestable.__init__(self, suites)
195 LoadedTestable.__init__(self, suites)
184 self.global_fixtures = global_fixtures
185
186 def _generate_metadata(self):
187 return LibraryMetadata( **{
188 'name': 'Test Library',
189 'status': Status.Unscheduled,
190 'result': Result(Result.NotRun)
191 })
192
193 def __iter__(self):
194 '''
195 :returns: an iterator over contained :class:`TestSuite` objects.
196 '''
197 return iter(self.obj)
198
196
197 def _generate_metadata(self):
198 return LibraryMetadata( **{
199 'name': 'Test Library',
200 'status': Status.Unscheduled,
201 'result': Result(Result.NotRun)
202 })
203
204 def __iter__(self):
205 '''
206 :returns: an iterator over contained :class:`TestSuite` objects.
207 '''
208 return iter(self.obj)
209
199 def all_fixture_tuples(self):
200 return itertools.chain(
201 self.global_fixtures,
202 *(suite.fixtures for suite in self.obj))
203
204 def all_fixtures(self):
205 '''
206 :returns: an interator overall all global, suite,
207 and test fixtures
208 '''
209 return itertools.chain(itertools.chain(
210 def all_fixtures(self):
211 '''
212 :returns: an interator overall all global, suite,
213 and test fixtures
214 '''
215 return itertools.chain(itertools.chain(
210 self.global_fixtures,
211 *(suite.fixtures for suite in self.obj)),
216 *(suite.fixtures for suite in self.obj)),
212 *(self.test_fixtures(suite) for suite in self.obj)
213 )
214
215 def test_fixtures(self, suite):
216 '''
217 :returns: an interator over all fixtures of each
218 test contained in the given suite
219 '''
220 return itertools.chain(*(test.fixtures for test in suite))
221
222 @property
223 def fixtures(self):
217 *(self.test_fixtures(suite) for suite in self.obj)
218 )
219
220 def test_fixtures(self, suite):
221 '''
222 :returns: an interator over all fixtures of each
223 test contained in the given suite
224 '''
225 return itertools.chain(*(test.fixtures for test in suite))
226
227 @property
228 def fixtures(self):
224 return self.global_fixtures
229 global_fixtures = []
230 for fixture in self.all_fixtures():
231 if fixture.is_global():
232 global_fixtures.append(fixture)
233 return global_fixtures
225
226 @property
227 def uid(self):
228 return self.name
229
230 @property
231 def suites(self):
232 return self.obj
233
234 @suites.setter
235 def suites(self, suites):
236 self.obj = suites
234
235 @property
236 def uid(self):
237 return self.name
238
239 @property
240 def suites(self):
241 return self.obj
242
243 @suites.setter
244 def suites(self, suites):
245 self.obj = suites