1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00

Implemented 'expected fail' in tests

This commit is contained in:
Ross Wilson
2016-02-15 14:51:59 +07:00
parent 35a2dc2e8f
commit c56a275f10
7 changed files with 133 additions and 34 deletions

View File

@@ -21,16 +21,16 @@ define tests to be performed. For example:
law 1
hlt
end
;! 0100 004001
;! 0101 000000
;|0100 004001
;|0101 000000
The special test comments have **';!'** in column 1. Normal comments may also
The special test comments have **';|** in column 1. Normal comments may also
exist in the file. Here the test comments are:
::
;! 0100 004001
;! 0101 000000
;|0100 004001
;|0101 000000
which tells **test_harness** to check that the PTP file generated by the
assembler does load *004001* at address *0100*, etc.
@@ -38,6 +38,37 @@ assembler does load *004001* at address *0100*, etc.
Test comments may appear anywhere in a test file, and are executed in the order
they appear in the file.
Failing tests
-------------
Sometime we might write a test that we expect to fail. A normal test that
succeeds produces no error output, but a failing test does. These *expected*
failures make it harder for the user to check that all is well.
The **unittest** module allows failures that are expected to be considered as a
test pass. We want to do the same with **test_harness**.
Tests that we expect to fail are written just the same as *normal* tests except
that we start the test comment with '**;!**'.
For example, if we want to make sure that a **BSS** generates the right number
of zero bytes we could do this:
::
; test operation of BSS
org 0100
law 1 ; 0100
bss 3 ; 0101
law 2 ; 0104
end
;|$1 04000+1
;| 0
;| 0
;| 0
;! 0 ; tests that 0104 is NOT a zero byte
;|0104 04000+2 ; retest 0104 for "law 2"
test_harness Usage
==================

View File

@@ -168,6 +168,9 @@ def get_memory(ptp):
def test_file(filename):
"""Test one ASM test file."""
# counter for number of errors
errors = 0
# assemble file into known listing file and PTP file
lst_file = '%s.lst' % TempPrefix
ptp_file = '%s.ptp' % TempPrefix
@@ -175,8 +178,9 @@ def test_file(filename):
% (ptp_file, lst_file, filename))
status = os.system(cmd)
if status:
errors += 1
warn("Error assembling file '%s'" % filename)
return
return errors # must end testing
os.remove(lst_file)
# get the test instructions from the ASM file
@@ -185,27 +189,29 @@ def test_file(filename):
lines = [line.rstrip() for line in lines]
tests = []
for (lnum, line) in enumerate(lines):
if line.startswith(';|'):
if line.startswith(';|') or line.startswith(';!'):
test_pass = line.startswith(';|')
test = line[2:]
test = test.replace('\t', ' ')
if ';' in test:
ndx = test.index(';')
test = test[:ndx].rstrip()
tests.append((lnum+1, test))
tests.append((lnum+1, test_pass, test))
# make sure we have some tests
if not tests:
errors += 1
print("No tests found in file '%s'" % filename)
return
return errors # must end testing
# get the generated code and ORG block info from the PTP file
# memory locations are in a dictionary: {addr: contents, ...}
(orgs, memory) = get_memory(ptp_file)
# interpret the test instructions and check generated code
errors = False
dot = None
for (lnum, test) in tests:
for (lnum, must_pass, test) in tests:
# check for a label
if test[0] == ' ':
# no label
@@ -221,9 +227,11 @@ def test_file(filename):
try:
dot = orgs[org_num-1]
except IndexError:
warn("File '%s' has label '%s' with bad ORG number"
% (filename, label))
return
if must_pass:
errors += 1
warn("File '%s' has label '%s' with bad ORG number: %s"
% (filename, label, test))
return errors # must end testing
address = dot
else:
address = oct_dec_int(label)
@@ -233,27 +241,34 @@ def test_file(filename):
value = eval_expr(dot, value)
if address is None:
warn("File '%s' has label '%s' with bad ORG number"
% (filename, label))
return
if must_pass:
errors += 1
warn("File '%s' has label '%s' with bad ORG number: %s"
% (filename, label, test))
return errors # must end testing
try:
mem_value = memory[address]
except KeyError:
warn("%s\n"
"%2d: %s\n"
"Test comment has check for address %04o which isn't in block"
% (filename, lnum, test, address))
else:
if mem_value != value:
errors = True
if must_pass:
errors += 1
warn("%s\n"
"%2d: %s\n"
"Memory at address %04o should be %06o, got %06o"
% (filename, lnum, test, address, value, mem_value))
"Test comment has check for address %04o which isn't in block"
% (filename, lnum, test, address))
else:
if mem_value != value:
if must_pass:
errors += 1
warn("%s\n"
"%2d: %s\n"
"Memory at address %04o should be %06o, got %06o"
% (filename, lnum, test, address, value, mem_value))
dot += 1
return errors
def warn(msg):
"""Print error message and continue."""
@@ -288,9 +303,16 @@ def run_tests(directory, prefix):
error("No test files found in directory '%s'" % directory)
# test each found file
errors = 0
files.sort()
for filename in files:
test_file(filename)
errors += test_file(filename)
if errors:
if errors == 1:
warn('There was %d error!' % errors)
else:
warn('There were %d errors!' % errors)
# remove temporary files
for f in glob.glob('%s.*' % TempPrefix):

View File

@@ -4,6 +4,6 @@
hlt
end
;|0100 004002 ; is actually 004001
;!0100 004002 ; is actually 004001
;|0101 000000
;|0102 000001 ; address outside block
;!0102 000001 ; address outside block

View File

@@ -4,6 +4,6 @@
hlt
end
;|$1 004000 + 2 ; is actually 004001
;!$1 004000 + 2 ; is actually 004001
;| 000000
;| 000001 ; address outside block
;! 000001 ; address outside block

View File

@@ -4,5 +4,6 @@
hlt
end
;|$3 004001 ; bad ORG number
;| 000000
;!$3 004001 ; bad ORG number
;|0100 004000 + 1
;|0101 000000

View File

@@ -573,7 +573,7 @@ def pass_1(lines):
elif opcode == 'DATA':
# a single data word
if not addr or eval_expr(addr) is None:
error("BSS pseudo-op has a bad value")
error("DATA pseudo-op has a bad value")
return False
if label:
define_label(label, Dot, lnum)
@@ -598,6 +598,25 @@ def pass_1(lines):
define_label(label, Dot, lnum)
Dot += ascii_words
elif opcode == 'ASCIIZ':
# ASCII string, pack two bytes/word, ensure zero byte fill at end
if not addr:
error("ASCIIZ pseudo-op must have a data field")
if addr[0] not in "'\"":
error("ASCIIZ pseudo-op must data field must be a delimited string")
delim = addr[0]
if addr[-1] != delim:
error("ASCIIZ pseudo-op has a badly delimited delimited string")
addr = addr[1:-1]
ascii_len = len(addr) + 1
ascii_words = ascii_len / 2
if ascii_len % 2:
ascii_words += 1
if label:
define_label(label, Dot, lnum)
Dot += ascii_words
elif opcode == 'INC':
# start of short vector mode
if not addr:
@@ -760,6 +779,32 @@ def pass_2(lines):
write_list(word_value, Dot, list_lnum, list_line)
Dot += 1
elif opcode == 'ASCIIZ':
# 'addr' must exist and be a quote-delimited string
if not addr:
error("ASCIIZ pseudo-op must have a data field")
if addr[0] not in "'\"":
error("ASCIIZ pseudo-op must data field must be a delimited string")
delim = addr[0]
if addr[-1] != delim:
error("ASCIIZ pseudo-op has a badly delimited delimited string")
addr = addr[1:-1]
len_addr = len(addr)
list_lnum = lnum
list_line = line
for i in range(0, len_addr-1, 2):
word_value = (ord(addr[i]) << 8) + ord(addr[i+1])
emit_word(word_value)
write_list(word_value, Dot, list_lnum, list_line)
list_lnum = ''
list_line = ''
Dot += 1
if len_addr % 2:
word_value = (ord(addr[-1]) << 8)
emit_word(word_value)
write_list(word_value, Dot, list_lnum, list_line)
Dot += 1
elif opcode == 'INC':
if not addr:
error("INC pseudo-op must have a data field")