Extends the test framework to prepare for compilation tests
Fix: it2 would have different working for emit eof
This commit is contained in:
parent
1b8333fcfa
commit
7672da6ad3
@ -2,14 +2,14 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
def emit(string):
|
def emit(string):
|
||||||
sys.stdout.write(string)
|
sys.stdout.buffer.write(string.encode('latin_1'))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
def trace(header, value):
|
def trace(header, value):
|
||||||
if os.environ.get('TRACE'):
|
if os.environ.get('TRACE'):
|
||||||
sys.stderr.write(f'{header}={value!r}\n')
|
sys.stderr.write(f'{header}={value!r}\n')
|
||||||
|
|
||||||
eof = chr(0)
|
eof = chr(0xFF)
|
||||||
eol = chr(10)
|
eol = chr(10)
|
||||||
quote = chr(34)
|
quote = chr(34)
|
||||||
PEEK = None
|
PEEK = None
|
||||||
@ -354,14 +354,14 @@ def emitheader():
|
|||||||
emitln(" return a + b[0]")
|
emitln(" return a + b[0]")
|
||||||
emitln("")
|
emitln("")
|
||||||
emitln("def emit(string):")
|
emitln("def emit(string):")
|
||||||
emitln(" sys.stdout.write(string)")
|
emitln(" sys.stdout.buffer.write(string.encode('latin_1'))")
|
||||||
emitln(" sys.stdout.flush()")
|
emitln(" sys.stdout.flush()")
|
||||||
emitln("")
|
emitln("")
|
||||||
emitln("def trace(header, value):")
|
emitln("def trace(header, value):")
|
||||||
emitln(" if os.environ.get('TRACE'):")
|
emitln(" if os.environ.get('TRACE'):")
|
||||||
emitln(" sys.stderr.write(f'{header}={value!r}\\n')")
|
emitln(" sys.stderr.write(f'{header}={value!r}\\n')")
|
||||||
emitln("")
|
emitln("")
|
||||||
emitln("eof = chr(0)")
|
emitln("eof = chr(0xFF)")
|
||||||
emitln("eol = chr(10)")
|
emitln("eol = chr(10)")
|
||||||
emitln("quote = chr(34)")
|
emitln("quote = chr(34)")
|
||||||
emitln("")
|
emitln("")
|
||||||
|
|||||||
@ -431,14 +431,14 @@ emitheader:
|
|||||||
emitln " return a + b[0]"
|
emitln " return a + b[0]"
|
||||||
emitln ""
|
emitln ""
|
||||||
emitln "def emit(string):"
|
emitln "def emit(string):"
|
||||||
emitln " sys.stdout.write(string)"
|
emitln " sys.stdout.buffer.write(string.encode('latin_1'))"
|
||||||
emitln " sys.stdout.flush()"
|
emitln " sys.stdout.flush()"
|
||||||
emitln ""
|
emitln ""
|
||||||
emitln "def trace(header, value):"
|
emitln "def trace(header, value):"
|
||||||
emitln " if os.environ.get('TRACE'):"
|
emitln " if os.environ.get('TRACE'):"
|
||||||
emitln " sys.stderr.write(f'{header}={value!r}\\n')"
|
emitln " sys.stderr.write(f'{header}={value!r}\\n')"
|
||||||
emitln ""
|
emitln ""
|
||||||
emitln "eof = chr(0)"
|
emitln "eof = chr(0xFF)"
|
||||||
emitln "eol = chr(10)"
|
emitln "eol = chr(10)"
|
||||||
emitln "quote = chr(34)"
|
emitln "quote = chr(34)"
|
||||||
emitln ""
|
emitln ""
|
||||||
|
|||||||
@ -532,7 +532,7 @@ emitheader:
|
|||||||
emitln "#include <string.h>"
|
emitln "#include <string.h>"
|
||||||
emitln ""
|
emitln ""
|
||||||
emitln ""
|
emitln ""
|
||||||
emitln "char var_eof[2] = {-1, 0};"
|
emitln "char var_eof[2] = {0xFF, 0};"
|
||||||
emitln "char var_eol[2] = {10, 0};"
|
emitln "char var_eol[2] = {10, 0};"
|
||||||
emitln "char var_quote[2] = {34, 0};"
|
emitln "char var_quote[2] = {34, 0};"
|
||||||
emitln "char var_false[1] = {0};"
|
emitln "char var_false[1] = {0};"
|
||||||
|
|||||||
14
README.md
14
README.md
@ -121,6 +121,20 @@ Calls the given function with the given arguments. If the function's return valu
|
|||||||
|
|
||||||
Writes the name and value of the variable passed to stderr if the TRACE environment variable is set.
|
Writes the name and value of the variable passed to stderr if the TRACE environment variable is set.
|
||||||
|
|
||||||
|
### Standard library constants
|
||||||
|
|
||||||
|
#### eof
|
||||||
|
|
||||||
|
End of file character, zero byte.
|
||||||
|
|
||||||
|
#### eol
|
||||||
|
|
||||||
|
End of line character.
|
||||||
|
|
||||||
|
#### quote
|
||||||
|
|
||||||
|
Double quote character.
|
||||||
|
|
||||||
### Standard library functions
|
### Standard library functions
|
||||||
|
|
||||||
#### addstringchar a b
|
#### addstringchar a b
|
||||||
|
|||||||
3
tests/.gitignore
vendored
3
tests/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/*.results
|
/*/*.act.*
|
||||||
|
/Makefile.mk
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
.PRECIOUS: build/%.it0.py build/%.it0.c
|
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
PYVERSION=3.12
|
PYVERSION=3.12
|
||||||
@ -8,31 +7,23 @@ PYPREFIX=/usr
|
|||||||
CYTHON=cython3
|
CYTHON=cython3
|
||||||
CC=gcc
|
CC=gcc
|
||||||
|
|
||||||
# builtincheckfalse is separate since it's supposed to crash. It's a test for the test 'framework', if you will.
|
all: verify-results
|
||||||
TESTLIST=$(shell ls *.lang0 | grep -v 'builtincheckfalse' | sed 's/.lang0//')
|
|
||||||
|
|
||||||
all: check
|
Makefile.mk: generate-recipes.py $(wildcard test_stdlib_constants/*.exp.*) $(wildcard test_stdlib_functions/*.exp.*)
|
||||||
|
python3 generate-recipes.py Makefile.mk it0 it1 it2
|
||||||
|
|
||||||
check: all-it0.results all-it1.results all-it2.results
|
include Makefile.mk
|
||||||
! grep -v 'Success' $^
|
|
||||||
|
|
||||||
all-it0.results: $(addprefix build/,$(addsuffix .it0, $(TESTLIST))) build/builtincheckfalse.it0
|
|
||||||
-rm -f $@
|
|
||||||
cat test-input.txt | build/builtincheckfalse.it0 2> /dev/null 2>&1 | grep 'Success'
|
|
||||||
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it0 >> $@ ; echo "" >> $@ ;)
|
|
||||||
|
|
||||||
all-it1.results: $(addprefix build/,$(addsuffix .it1, $(TESTLIST))) build/builtincheckfalse.it1
|
|
||||||
-rm -f $@
|
|
||||||
cat test-input.txt | build/builtincheckfalse.it1 2> /dev/null 2>&1 | grep 'Success'
|
|
||||||
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it1 >> $@ ; echo "" >> $@ ;)
|
|
||||||
|
|
||||||
all-it2.results: $(addprefix build/,$(addsuffix .it2, $(TESTLIST))) build/builtincheckfalse.it2
|
|
||||||
-rm -f $@
|
|
||||||
cat test-input.txt | build/builtincheckfalse.it2 2> /dev/null 2>&1 | grep 'Success'
|
|
||||||
$(foreach test,$(TESTLIST), echo -n "$(test) " >> $@; cat test-input.txt | ./build/$(test).it2 >> $@ ; echo "" >> $@ ;)
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -f *.results build/*.it0* build/*.it1* build/*.it2*
|
find build -name '*.c' -delete
|
||||||
|
find build -name '*.it0' -delete
|
||||||
|
find build -name '*.it1' -delete
|
||||||
|
find build -name '*.it2' -delete
|
||||||
|
find build -name '*.py' -delete
|
||||||
|
find build -name '*.tmp' -delete
|
||||||
|
find . -name '*.act.*.result' -delete
|
||||||
|
find . -name '*.act.*.stdout' -delete
|
||||||
|
find . -name '*.act.*.stderr' -delete
|
||||||
|
|
||||||
###
|
###
|
||||||
# it0
|
# it0
|
||||||
|
|||||||
14
tests/build/test_stdlib_functions/.gitignore
vendored
Normal file
14
tests/build/test_stdlib_functions/.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*.it0
|
||||||
|
/*.it0.c
|
||||||
|
/*.it0.o
|
||||||
|
/*.it0.py
|
||||||
|
/*.it0.py.tmp
|
||||||
|
/*.it1
|
||||||
|
/*.it1.c
|
||||||
|
/*.it1.o
|
||||||
|
/*.it1.py
|
||||||
|
/*.it1.py.tmp
|
||||||
|
/*.it2
|
||||||
|
/*.it2.c
|
||||||
|
/*.it2.c.tmp
|
||||||
|
/*.it2.o
|
||||||
103
tests/generate-recipes.py
Normal file
103
tests/generate-recipes.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class Rule:
|
||||||
|
def __init__(self, target: str, prerequisites: list[str], recipe: list[str]) -> None:
|
||||||
|
self.target = target
|
||||||
|
self.prerequisites = prerequisites
|
||||||
|
self.recipe = recipe
|
||||||
|
|
||||||
|
def make_lines(self):
|
||||||
|
return [
|
||||||
|
self.target + ': ' + ' '.join(self.prerequisites),
|
||||||
|
] + [
|
||||||
|
'\t' + line
|
||||||
|
for line in self.recipe
|
||||||
|
] + ['']
|
||||||
|
|
||||||
|
def get_file_list():
|
||||||
|
return glob.glob('test_*/*.lang0')
|
||||||
|
|
||||||
|
def make_rules(file_path, lang0it):
|
||||||
|
result: list[Rule] = []
|
||||||
|
|
||||||
|
act_result = file_path.replace('.lang0', f'.act.{lang0it}.result')
|
||||||
|
act_stdout = file_path.replace('.lang0', f'.act.{lang0it}.stdout')
|
||||||
|
act_stderr = file_path.replace('.lang0', f'.act.{lang0it}.stderr')
|
||||||
|
stdin = file_path.replace('.lang0', '.stdin')
|
||||||
|
exp_stdout = file_path.replace('.lang0', '.exp.stdout')
|
||||||
|
exp_stderr = file_path.replace('.lang0', '.exp.stderr')
|
||||||
|
|
||||||
|
program = file_path.replace('.lang0', f'.{lang0it}')
|
||||||
|
|
||||||
|
if os.path.isfile(exp_stdout) or os.path.isfile(exp_stderr):
|
||||||
|
result.append(Rule(
|
||||||
|
act_stdout,
|
||||||
|
['build/' + program],
|
||||||
|
[
|
||||||
|
(f'cat {stdin} | ' if os.path.isfile(stdin) else 'echo x | ')
|
||||||
|
+ f'build/{program} 1> {act_stdout} 2> {act_stderr}',
|
||||||
|
]
|
||||||
|
))
|
||||||
|
|
||||||
|
exp_list = [exp_stdout, exp_stderr]
|
||||||
|
act_list = [act_stdout, act_stderr]
|
||||||
|
|
||||||
|
result.append(Rule(
|
||||||
|
act_result,
|
||||||
|
[
|
||||||
|
fil
|
||||||
|
for exp_file, act_file in zip(exp_list, act_list, strict=True)
|
||||||
|
if os.path.isfile(exp_file)
|
||||||
|
for fil in [exp_file, act_file]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'rm -f $@',
|
||||||
|
] + [
|
||||||
|
f'-diff {exp_file} {act_file} >> $@'
|
||||||
|
for exp_file, act_file in zip(exp_list, act_list, strict=True)
|
||||||
|
if os.path.isfile(exp_file)
|
||||||
|
]
|
||||||
|
))
|
||||||
|
|
||||||
|
assert result[-1].prerequisites, f'Missing expectations for {file_path}'
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def main(program, write_to, *lang0it):
|
||||||
|
rule_list_list = [
|
||||||
|
make_rules(file_path, it)
|
||||||
|
for file_path in get_file_list()
|
||||||
|
for it in lang0it
|
||||||
|
]
|
||||||
|
|
||||||
|
result_targets = [
|
||||||
|
rule.target
|
||||||
|
for rule_list in rule_list_list
|
||||||
|
for rule in rule_list
|
||||||
|
if rule.target.endswith('.result')
|
||||||
|
]
|
||||||
|
|
||||||
|
rule_list_list.append([Rule(
|
||||||
|
'verify-results',
|
||||||
|
result_targets,
|
||||||
|
[
|
||||||
|
'@echo Finding failed test results...',
|
||||||
|
'@find $^ -not -empty -print -exec false {} +',
|
||||||
|
'@echo All tests passed.'
|
||||||
|
]
|
||||||
|
)])
|
||||||
|
|
||||||
|
data = '\n'.join(
|
||||||
|
line
|
||||||
|
for rule_list in rule_list_list
|
||||||
|
for rule in rule_list
|
||||||
|
for line in rule.make_lines()
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(write_to, 'wt', encoding='ASCII') as fil:
|
||||||
|
fil.write(data)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(*sys.argv)
|
||||||
@ -1,3 +0,0 @@
|
|||||||
main:
|
|
||||||
emit "Success"
|
|
||||||
/
|
|
||||||
1
tests/test_stdlib_constants/test_eof.exp.stdout
Normal file
1
tests/test_stdlib_constants/test_eof.exp.stdout
Normal file
@ -0,0 +1 @@
|
|||||||
|
<EFBFBD>
|
||||||
3
tests/test_stdlib_constants/test_eof.lang0
Normal file
3
tests/test_stdlib_constants/test_eof.lang0
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
main:
|
||||||
|
emit eof
|
||||||
|
/
|
||||||
1
tests/test_stdlib_constants/test_eol.exp.stdout
Normal file
1
tests/test_stdlib_constants/test_eol.exp.stdout
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
3
tests/test_stdlib_constants/test_eol.lang0
Normal file
3
tests/test_stdlib_constants/test_eol.lang0
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
main:
|
||||||
|
emit eol
|
||||||
|
/
|
||||||
1
tests/test_stdlib_constants/test_quote.exp.stdout
Normal file
1
tests/test_stdlib_constants/test_quote.exp.stdout
Normal file
@ -0,0 +1 @@
|
|||||||
|
"
|
||||||
3
tests/test_stdlib_constants/test_quote.lang0
Normal file
3
tests/test_stdlib_constants/test_quote.lang0
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
main:
|
||||||
|
emit quote
|
||||||
|
/
|
||||||
1
tests/test_stdlib_functions/test_emit.exp.stdout
Normal file
1
tests/test_stdlib_functions/test_emit.exp.stdout
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hello, world!
|
||||||
4
tests/test_stdlib_functions/test_emit.lang0
Normal file
4
tests/test_stdlib_functions/test_emit.lang0
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
main:
|
||||||
|
emit "Hello"
|
||||||
|
emit ", world!"
|
||||||
|
/
|
||||||
Loading…
x
Reference in New Issue
Block a user