function testing first proposal

This commit is contained in:
wgroeneveld 2018-11-28 11:49:40 +01:00
parent e28c02f169
commit 661b705a27
3 changed files with 188 additions and 12 deletions

View File

@ -1,29 +1,138 @@
from unittest import TestCase
import subprocess, os, time, json, glob
import subprocess, os, time, json, glob, functools
class OpbTestAssertions():
def __init__(self, json, case):
self.jsondata = json
self.case = case
self.register = None
self.registers = None
def reg(self, register):
def regs(self, registers):
if type(registers) is not list:
self.case.fail("Expected a list of registers")
self.registers = list(map(lambda reg: self.torawregistername(reg), registers))
return self
def torawregistername(self, register):
return int(register[1], 16)
def assertregistername(self, register):
if not register.startswith("s"):
self.case.fail("Register name should start with 's', followed with 0-F")
self.register = int(register[1], 16)
def reg(self, register):
self.assertregistername(register)
self.registers = [int(register[1], 16)]
return self
def contains(self, expected):
if self.register is None:
self.case.fail("First call reg() to assert which register to check!")
def tocontain(self, expected):
for register in self.registers:
result = self.case.checkReg(self.jsondata, "a", register, expected)
if result != "":
self.case.fail(result)
def contains(self, expected):
if self.registers is None:
self.case.fail("First call reg()/regs() to assert which register to check!")
if type(expected) is int:
return self.tocontain(expected)
if type(expected) is not list:
self.case.fail("Expected array as expected register values!")
if len(expected) != len(self.registers):
self.case.fail("Given registers and expected results arrays do not match!")
results = []
for i in range(0, len(expected)):
result = self.case.checkReg(self.jsondata, "a", self.registers[i], expected[i])
if result != "":
results.append(result)
if len(results) > 0:
self.case.fail(
"Registers do not contain expected values: \n" + functools.reduce(lambda a, b: a + "\n" + b, results))
class OpbTestMockable():
def __init__(self, case, filename):
self.case = case
self.filename = filename
self.prepender = []
self.proctotest = ""
self.appender = ["\nopbtestquitfn: output sD, FF\n"]
def testproc(self, procname):
self.proctotest = procname
return self
def setregs(self, regmap):
for key, val in regmap.items():
self.prepender.append("load " + key + ", " + str(val) + "\n")
return self
def execute(self):
with open(self.filename, 'r') as original:
data = original.readlines()
def findlinebetween(data, statement1, statement2):
linenr = 0
startcounting = False
for line in data:
if statement1 in line:
startcounting = True
if startcounting and statement2 in line:
break
linenr += 1
if linenr + 1 == len(data):
self.case.fail("No statements between " + statement1 + " and " + statement2 + " found")
return linenr
def setupproc(data):
self.prepender.append("jump " + self.proctotest + "\n")
linenr = findlinebetween(data, "proc " + self.proctotest, "}")
data = data[0:linenr] + ["jump opbtestquitfn\n"] + data[linenr:]
return data
if len(self.proctotest) > 0:
data = setupproc(data)
firstjump = findlinebetween(data, "jump", "jump")
data = data[0:firstjump] + self.prepender + data[firstjump:] + self.appender
with open(self.filename, 'w') as modified:
modified.writelines(data)
return self.case.execute_file(self.filename)
self.case.assertReg(self.jsondata, "a", self.register, expected)
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'):
@ -35,13 +144,30 @@ class OpbTestCase(TestCase):
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)
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())
@ -57,5 +183,9 @@ class OpbTestCase(TestCase):
def assertPsm(self, jsondata):
return OpbTestAssertions(jsondata, self)
def assertReg(self, jsondata, bank, nr, expected):
self.assertEqual(expected, jsondata["regs_" + bank][nr])
def checkReg(self, jsondata, bank, nr, expected):
actual = jsondata["regs_" + bank][nr]
if int(str(expected), 16) == actual:
return ""
return "reg " + bank + "," + str(nr) + " should contain " + str(expected) + " but instead contains " + str(
actual)

26
test/functions.psm4 Normal file
View File

@ -0,0 +1,26 @@
use_stack(sF, 0x3F)
jump main
proc proc1(s0 is result := 1) {
load result, 42
call proc2
}
proc proc2(s4 is test) {
load test, 42
}
proc proc3(s5 is bla) {
add bla, 1
}
func func1(s1 is val) : 1 {
load val, 52
}
main:
load s2, 11
add s2, 1
output sD, FF

20
test/functions.py Normal file
View File

@ -0,0 +1,20 @@
from opbtest import OpbTestCase
class TestFunctions(OpbTestCase):
def setUp(self):
pass
#self.do_not_cleanup_files()
def test_proc3_adds_to_existing_register(self):
result = self.load_file("functions.psm4").testproc("proc3").setregs({"s5": 2}).execute()
self.assertPsm(result).reg("s5").contains(3)
def test_proc2_testproc_does_not_execute_rest_of_psm(self):
result = self.load_file("functions.psm4").testproc("proc2").execute()
self.assertPsm(result).regs(["s2", "s4"]).contains([0, 42])
def test_proc1_calls_proc2(self):
result = self.load_file("functions.psm4").testproc("proc1").execute()
self.assertPsm(result).regs(["s0", "s4"]).contains([42, 42])