wrappers.py revision 12882:dd87d7f2f3e5
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    '''
182    def __init__(self, suites, global_fixtures):
183        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
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                self.global_fixtures,
211                *(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):
224        return self.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
237