blob: b2b887b0f9b51b10aa9b8925f64fac5f23ccd446 [file] [log] [blame]
# Copyright (c) 2019-2020 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2017 Mark D. Hill and David A. Wood
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Sean Wilson
'''
Module contains wrappers for test items that have been
loaded by the testlib :class:`testlib.loader.Loader`.
'''
import itertools
import testlib.uid as uid
from testlib.state import Status, Result
class TestCaseMetadata():
def __init__(self, name, uid, path, result, status, suite_uid):
self.name = name
self.uid = uid
self.path = path
self.status = status
self.result = result
self.suite_uid = suite_uid
class TestSuiteMetadata():
def __init__(self, name, uid, tags, path, status, result):
self.name = name
self.uid = uid
self.tags = tags
self.path = path
self.status = status
self.result = result
class LibraryMetadata():
def __init__(self, name, result, status):
self.name = name
self.result = result
self.status = status
class LoadedTestable(object):
'''
Base class for loaded test items.
:property:`result` and :property:`status` setters
notify testlib via the :func:`log_result` and :func:`log_status`
of the updated status.
'''
def __init__(self, obj):
self.obj = obj
self.metadata = self._generate_metadata()
@property
def status(self):
return self.metadata.status
@status.setter
def status(self, status):
self.log_status(status)
self.metadata.status = status
@property
def result(self):
return self.metadata.result
@result.setter
def result(self, result):
self.log_result(result)
self.metadata.result = result
@property
def uid(self):
return self.metadata.uid
@property
def name(self):
return self.metadata.name
@property
def fixtures(self):
return self.obj.fixtures
@fixtures.setter
def fixtures(self, fixtures):
self.obj.fixtures = fixtures
@property
def runner(self):
return self.obj.runner
@property
def time(self):
return self.metadata.time
@time.setter
def time(self, value):
self.metadata.time = value
# TODO Change log to provide status_update, result_update for all types.
def log_status(self, status):
import testlib.log as log
log.test_log.status_update(self, status)
def log_result(self, result):
import testlib.log as log
log.test_log.result_update(self, result)
def __iter__(self):
return iter(())
class LoadedTest(LoadedTestable):
def __init__(self, test_obj, loaded_suite, path):
self.parent_suite = loaded_suite
self._path = path
LoadedTestable.__init__(self, test_obj)
def test(self, *args, **kwargs):
self.obj.test(*args, **kwargs)
def _generate_metadata(self):
return TestCaseMetadata( **{
'name':self.obj.name,
'path': self._path,
'uid': uid.TestUID(self._path,
self.obj.name,
self.parent_suite.name),
'status': Status.Unscheduled,
'result': Result(Result.NotRun),
'suite_uid': self.parent_suite.metadata.uid
})
class LoadedSuite(LoadedTestable):
def __init__(self, suite_obj, path):
self._path = path
LoadedTestable.__init__(self, suite_obj)
self.tests = self._wrap_children(suite_obj)
def _wrap_children(self, suite_obj):
return [LoadedTest(test, self, self.metadata.path)
for test in suite_obj]
def _generate_metadata(self):
return TestSuiteMetadata( **{
'name': self.obj.name,
'tags':self.obj.tags,
'path': self._path,
'uid': uid.SuiteUID(self._path, self.obj.name),
'status': Status.Unscheduled,
'result': Result(Result.NotRun)
})
def __iter__(self):
return iter(self.tests)
@property
def tags(self):
return self.metadata.tags
class LoadedLibrary(LoadedTestable):
'''
Wraps a collection of all loaded test suites and
provides utility functions for accessing fixtures.
'''
def __init__(self, suites):
LoadedTestable.__init__(self, suites)
def _generate_metadata(self):
return LibraryMetadata( **{
'name': 'Test Library',
'status': Status.Unscheduled,
'result': Result(Result.NotRun)
})
def __iter__(self):
'''
:returns: an iterator over contained :class:`TestSuite` objects.
'''
return iter(self.obj)
def all_fixtures(self):
'''
:returns: an interator overall all global, suite,
and test fixtures
'''
return itertools.chain(itertools.chain(
*(suite.fixtures for suite in self.obj)),
*(self.test_fixtures(suite) for suite in self.obj)
)
def test_fixtures(self, suite):
'''
:returns: an interator over all fixtures of each
test contained in the given suite
'''
return itertools.chain(*(test.fixtures for test in suite))
@property
def fixtures(self):
global_fixtures = []
for fixture in self.all_fixtures():
if fixture.is_global():
global_fixtures.append(fixture)
return global_fixtures
@property
def uid(self):
return self.name
@property
def suites(self):
return self.obj
@suites.setter
def suites(self, suites):
self.obj = suites