111 lines
4.1 KiB
Python
111 lines
4.1 KiB
Python
import glob
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import time
|
|
from unittest import TestCase
|
|
|
|
from opbtest.opbtestassertions import OpbTestAssertions
|
|
from opbtest.opbtestmockable import OpbTestMockable
|
|
|
|
|
|
class OpbTestCase(TestCase):
|
|
|
|
def do_not_cleanup_files(self):
|
|
self.nocleanup = True
|
|
|
|
def do_cleanup_files(self):
|
|
self.nocleanup = False
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
"""On inherited classes, run our `setUp` method"""
|
|
# Inspired via http://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class/17696807#17696807
|
|
if cls is not OpbTestCase and cls.setUp is not OpbTestCase.setUp:
|
|
orig_setUp = cls.setUp
|
|
def setUpOverride(self, *args, **kwargs):
|
|
OpbTestCase.setUp(self)
|
|
return orig_setUp(self, *args, **kwargs)
|
|
cls.setUp = setUpOverride
|
|
|
|
def setUp(self):
|
|
self.do_cleanup_files()
|
|
|
|
def tearDown(self):
|
|
if self.nocleanup:
|
|
return
|
|
|
|
for file in glob.glob('tmp_*'):
|
|
os.remove(file)
|
|
for file in glob.glob('*.gen.psm'):
|
|
os.remove(file)
|
|
for file in glob.glob('*.log'):
|
|
os.remove(file)
|
|
for file in glob.glob('*.mem'):
|
|
os.remove(file)
|
|
for file in glob.glob('*.fmt'):
|
|
os.remove(file)
|
|
|
|
def assertfile_exists(self, filename):
|
|
self.assertTrue(os.path.exists(filename), "Filename " + filename + " does not exist!")
|
|
|
|
def load_file(self, filename):
|
|
self.assertfile_exists(filename)
|
|
|
|
tmpname = "tmp_" + str(time.time()) + ".psm4"
|
|
with open(tmpname, "w") as file:
|
|
with open(filename, "r") as input:
|
|
lines = input.readlines()
|
|
file.writelines(lines)
|
|
|
|
return OpbTestMockable(self, tmpname)
|
|
|
|
def execute_file(self, filename):
|
|
self.assertfile_exists(filename)
|
|
psm4 = "psm4" in filename
|
|
r = subprocess.call("opbasm -{} -c {}".format("6" if psm4 else "3", filename), shell=True)
|
|
self.assertTrue(r == 0, "Opbasm compilation failed of source; filename: " + filename)
|
|
|
|
try:
|
|
json_out = subprocess.check_output(
|
|
"opbsim -v -j -m:{} --{}".format(filename.replace(".psm4" if psm4 else ".psm", ".mem"),
|
|
"pb6" if psm4 else "pb3"), shell=True)
|
|
except subprocess.CalledProcessError as e:
|
|
self.fail("Opbsim simulation failed with: " + '\n>>> '.join(('\n' + str(e.output)).splitlines()).lstrip())
|
|
|
|
json_out = json.loads(json_out)
|
|
self.assertTrue(json_out['termination'] == 'termNormal', 'Simulation failed with ' + json_out['termination'])
|
|
return self.assertPsm(json_out)
|
|
|
|
def execute_psm(self, psm):
|
|
with open("tmp_" + str(time.time()) + ".psm4", "w") as file:
|
|
file.write(psm)
|
|
return self.execute_file(file.name)
|
|
|
|
def assertPsm(self, jsondata):
|
|
return OpbTestAssertions(jsondata, self)
|
|
|
|
def _print_expectation(self, expected):
|
|
return str(expected) + " (hex: " + hex(expected).replace("0x", "").upper().zfill(2) + ")"
|
|
|
|
def _check(self, jsonindex, jsondata, index, expected):
|
|
actual = jsondata[jsonindex][index]
|
|
# try to convert both to the same type. acutal will always be an int (hex valued)
|
|
if type(expected) is str:
|
|
expected = int(expected, 16)
|
|
|
|
if expected == actual:
|
|
return ""
|
|
return "output " + jsonindex + " " + str(index) + " should contain " + self._print_expectation(expected) + " but instead contains " + self._print_expectation(actual)
|
|
|
|
def checkPort(self, jsondata, port, expected):
|
|
self._check("ports_out", jsondata, port, expected)
|
|
|
|
def checkReg(self, jsondata, bank, nr, expected):
|
|
actual = jsondata["regs_" + bank][nr]
|
|
if type(expected) is int:
|
|
expected = int(str(expected), 16)
|
|
if expected == actual:
|
|
return ""
|
|
return "reg " + bank + "," + self._print_expectation(nr) + " should contain " + str(expected) + " but instead contains " + str(actual)
|