feat: add io.write primitive and test runner with number literal tests

Implement the io.write() primitive function that prints a value followed by a newline, enabling basic output for testing. Add a Python test runner script (runtests) that discovers and executes .wren test files, comparing output against // expect: comments. Include initial number literal tests covering positive, negative, and zero values. Remove debug print statements from the VM interpreter and refactor primitive registration macros for cleaner code.
This commit is contained in:
Bob Nystrom
2013-10-28 05:45:40 +00:00
parent 0ad65b2a0b
commit 5fb2b6b253
7 changed files with 228 additions and 45 deletions
Executable
+187
View File
@@ -0,0 +1,187 @@
#!/usr/bin/python
from collections import defaultdict
from os import listdir
from os.path import abspath, dirname, isdir, isfile, join, realpath, relpath, splitext
import re
from subprocess import Popen, PIPE
import sys
# Runs the tests.
WREN_DIR = dirname(realpath(__file__))
TEST_DIR = join(WREN_DIR, 'test')
if sys.platform == 'win32':
WREN_APP = join(WREN_DIR, 'Debug', 'wren.exe')
if not isfile(WREN_DIR):
WREN_APP = join(WREN_DIR, 'Release', 'wren.exe')
if not isfile(WREN_APP):
sys.exit('Cannot find wren.exe!')
elif sys.platform.startswith('linux'):
WREN_APP = join(WREN_DIR, '1', 'out', 'Debug', 'wren')
if not isfile(WREN_APP):
WREN_APP = join(WREN_DIR, '1', 'out', 'Release', 'wren')
if not isfile(WREN_APP):
sys.exit('Cannot find wren!')
elif sys.platform.startswith('darwin'):
WREN_APP = join(WREN_DIR, 'build', 'Debug', 'wren')
if not isfile(WREN_APP):
WREN_APP = join(WREN_DIR, 'build', 'Release', 'wren')
if not isfile(WREN_APP):
sys.exit('Cannot find wren!')
else:
sys.exit('System not supported!')
EXPECT_PATTERN = re.compile(r'// expect: (.*)')
SKIP_PATTERN = re.compile(r'// skip: (.*)')
NONTEST_PATTERN = re.compile(r'// nontest')
if sys.platform == 'win32':
class color:
GREEN = ''
RED = ''
DEFAULT = ''
PINK = ''
YELLOW = ''
else:
class color:
GREEN = '\033[32m'
RED = '\033[31m'
DEFAULT = '\033[0m'
PINK = '\033[91m'
YELLOW = '\033[33m'
passed = 0
failed = 0
skipped = defaultdict(int)
num_skipped = 0;
def walk(dir, callback):
""" Walks [dir], and executes [callback] on each file. """
dir = abspath(dir)
for file in [file for file in listdir(dir) if not file in [".",".."]]:
nfile = join(dir, file)
if isdir(nfile):
walk(nfile, callback)
else:
callback(nfile)
def print_line(line=None):
# Erase the line.
print '\033[2K',
# Move the cursor to the beginning.
print '\r',
if line:
print line,
sys.stdout.flush()
def run_test(path):
global passed
global failed
global skipped
global num_skipped
if (splitext(path)[1] != '.wren'):
return
# Check if we are just running a subset of the tests.
if len(sys.argv) == 2:
this_test = relpath(path, join(WREN_DIR, 'test'))
if not this_test.startswith(sys.argv[1]):
return
# Make a nice short path relative to the working directory.
path = relpath(path)
# Read the test and parse out the expectations.
expect_output = []
expect_error = []
expect_return = 0
print_line('Passed: ' + color.GREEN + str(passed) + color.DEFAULT +
' Failed: ' + color.RED + str(failed) + color.DEFAULT +
' Skipped: ' + color.YELLOW + str(num_skipped) + color.DEFAULT)
line_num = 1
with open(path, 'r') as file:
for line in file:
match = EXPECT_PATTERN.search(line)
if match:
expect_output.append((match.group(1), line_num))
match = SKIP_PATTERN.search(line)
if match:
num_skipped += 1
skipped[match.group(1)] += 1
return
match = NONTEST_PATTERN.search(line)
if match:
# Not a test file at all, so ignore it.
return
line_num += 1
# Invoke wren and run the test.
proc = Popen([WREN_APP, path], stdout=PIPE, stderr=PIPE)
(out, err) = proc.communicate()
(out, err) = out.replace('\r\n', '\n'), err.replace('\r\n', '\n')
fails = []
# Validate the exit code.
if proc.returncode != 0:
fails.append('Expected return code 0 and got {0}.'.
format(proc.returncode))
else:
# Validate the output.
expect_index = 0
# Remove the trailing last empty line.
out_lines = out.split('\n')
if out_lines[-1] == '':
del out_lines[-1]
for line in out_lines:
if expect_index >= len(expect_output):
fails.append('Got output "{0}" when none was expected.'.
format(line))
elif expect_output[expect_index][0] != line:
fails.append('Expected output "{0}" on line {1} and got "{2}".'.
format(expect_output[expect_index][0],
expect_output[expect_index][1], line))
expect_index += 1
while expect_index < len(expect_output):
fails.append('Missing expected output "{0}" on line {1}.'.
format(expect_output[expect_index][0],
expect_output[expect_index][1]))
expect_index += 1
# Display the results.
if len(fails) == 0:
passed += 1
print color.GREEN + 'PASS' + color.DEFAULT + ': ' + path
else:
failed += 1
print_line(color.RED + 'FAIL' + color.DEFAULT + ': ' + path)
print
for fail in fails:
print ' ', color.PINK + fail + color.DEFAULT
print
walk(TEST_DIR, run_test)
print_line()
if failed == 0:
print 'All ' + color.GREEN + str(passed) + color.DEFAULT + ' tests passed.'
else:
print (color.GREEN + str(passed) + color.DEFAULT + ' tests passed. ' +
color.RED + str(failed) + color.DEFAULT + ' tests failed.')
for key in sorted(skipped.keys()):
print ('Skipped ' + color.YELLOW + str(skipped[key]) + color.DEFAULT +
' tests: ' + key)