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