Add unit test infrastructure

This commit is contained in:
mbanth
2021-05-19 16:07:40 +01:00
parent 1ddbfdd8c1
commit 9b2efd07ad
6 changed files with 508 additions and 1 deletions

View File

@@ -0,0 +1,127 @@
# Copyright 2021 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import os.path
import pytest
import subprocess
target = os.environ.get('TARGET', 'all_possible')
print("target = ", target)
def pytest_collect_file(parent, path):
if(path.ext == ".xe"):
if(target == 'all_possible'):
return UnityTestSource.from_parent(parent, fspath=path)
if(target == 'XCOREAI' and ('xcoreai' in path.basename)):
return UnityTestSource.from_parent(parent, fspath=path)
if(target == 'XCORE200' and ('xcore200' in path.basename)):
return UnityTestSource.from_parent(parent, fspath=path)
class UnityTestSource(pytest.File):
def collect(self):
# Find the binary built from the runner for this test file
#
# Assume the following directory layout:
# unit_tests/ <- Test root directory
# |-- bin/ <- Compiled binaries of the test runners
# |-- conftest.py <- This file
# |-- runners/ <- Auto-generated buildable source of test binaries
# |-- src/ <- Unity test functions
# `-- wscript <- Build system file used to generate/build runners
print("self.name = ",self.name)
#xe_name = ((os.path.basename(self.name)).split("."))[0] + ".xe"
#test_bin_path = os.path.join('bin', xe_name)
#
#test_root_dir_name = os.path.basename(os.path.dirname(__file__))
#test_src_path = os.path.basename(str(self.fspath))
#test_src_name = os.path.splitext(test_src_path)[0]
#test_bin_name_si = os.path.join(
# test_src_name + '_single_issue.xe')
#test_bin_path_si = os.path.join('bin',
# test_bin_name_si)
#yield UnityTestExecutable.from_parent(self, name=test_bin_path_si)
#test_bin_name_di = os.path.join(
# test_src_name + '_dual_issue.xe')
#test_bin_path_di = os.path.join('bin',
# test_bin_name_di)
yield UnityTestExecutable.from_parent(self, name=self.name)
class UnityTestExecutable(pytest.Item):
def __init__(self, name, parent):
super(UnityTestExecutable, self).__init__(name, parent)
self._nodeid = self.name # Override the naming to suit C better
def runtest(self):
# Run the binary in the simulator
simulator_fail = False
test_output = None
try:
if('xcore200' in self.name):
print("run axe for executable ", self.name)
test_output = subprocess.check_output(['axe', self.name], text=True)
else:
print("run xrun for executable ", self.name)
test_output = subprocess.check_output(['xrun', '--io', '--id', '0', self.name], text=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
# Unity exits non-zero if an assertion fails
simulator_fail = True
test_output = e.output
# Parse the Unity output
unity_pass = False
test_output = test_output.split('\n')
for line in test_output:
if 'test' in line:
test_report = line.split(':')
# Unity output is as follows:
# <test_source>:<line_number>:<test_case>:PASS
# <test_source>:<line_number>:<test_case>:FAIL:<failure_reason>
test_source = test_report[0]
line_number = test_report[1]
test_case = test_report[2]
result = test_report[3]
failure_reason = None
print('\n {}()'.format(test_case)),
if result == 'PASS':
unity_pass = True
continue
if result == 'FAIL':
failure_reason = test_report[4]
print('') # Insert line break after test_case print
raise UnityTestException(self, {'test_source': test_source,
'line_number': line_number,
'test_case': test_case,
'failure_reason':
failure_reason})
if simulator_fail:
raise Exception(self, "Simulation failed.")
if not unity_pass:
raise Exception(self, "Unity test output not found.")
print('') # Insert line break after final test_case which passed
def repr_failure(self, excinfo):
if isinstance(excinfo.value, UnityTestException):
return '\n'.join([str(self.parent).strip('<>'),
'{}:{}:{}()'.format(
excinfo.value[1]['test_source'],
excinfo.value[1]['line_number'],
excinfo.value[1]['test_case']),
'Failure reason:',
excinfo.value[1]['failure_reason']])
else:
return str(excinfo.value)
def reportinfo(self):
# It's not possible to give sensible line number info for an executable
# so we return it as 0.
#
# The source line number will instead be recovered from the Unity print
# statements.
return self.fspath, 0, self.name
class UnityTestException(Exception):
pass