|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import os, sys
|
|
|
|
from glob import glob
|
|
|
|
from re import sub
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
|
|
|
|
def escape(s):
|
|
|
|
s = s.decode()
|
|
|
|
lookup = {
|
|
|
|
"\0": "\\0",
|
|
|
|
"\t": "\\t",
|
|
|
|
"\n": '\\n"\n"',
|
|
|
|
"\r": "\\r",
|
|
|
|
"\\": "\\\\",
|
|
|
|
'"': '\\"',
|
|
|
|
}
|
|
|
|
return '""\n"{}"'.format("".join([lookup[x] if x in lookup else x for x in s]))
|
|
|
|
|
|
|
|
|
|
|
|
def chew_filename(t):
|
|
|
|
return {"func": "test_{}_fn".format(sub(r"/|\.|-", "_", t)), "desc": t}
|
|
|
|
|
|
|
|
|
|
|
|
def script_to_map(test_file):
|
|
|
|
r = {"name": chew_filename(test_file)["func"]}
|
|
|
|
with open(test_file, "rb") as f:
|
|
|
|
r["script"] = escape(f.read())
|
|
|
|
with open(test_file + ".exp", "rb") as f:
|
|
|
|
r["output"] = escape(f.read())
|
|
|
|
return r
|
|
|
|
|
|
|
|
|
|
|
|
def load_profile(profile_file, test_dirs, exclude_tests):
|
|
|
|
profile_globals = {"test_dirs": test_dirs, "exclude_tests": exclude_tests}
|
|
|
|
exec(profile_file.read(), profile_globals)
|
|
|
|
return profile_globals["test_dirs"], profile_globals["exclude_tests"]
|
|
|
|
|
|
|
|
|
|
|
|
test_function = (
|
|
|
|
"void {name}(void* data) {{\n"
|
|
|
|
" static const char pystr[] = {script};\n"
|
|
|
|
" static const char exp[] = {output};\n"
|
|
|
|
' printf("\\n");\n'
|
|
|
|
" upytest_set_expected_output(exp, sizeof(exp) - 1);\n"
|
|
|
|
" upytest_execute_test(pystr);\n"
|
|
|
|
' printf("result: ");\n'
|
|
|
|
"}}"
|
|
|
|
)
|
|
|
|
|
|
|
|
testcase_struct = "struct testcase_t {name}_tests[] = {{\n{body}\n END_OF_TESTCASES\n}};"
|
|
|
|
testcase_member = ' {{ "{desc}", {func}, TT_ENABLED_, 0, 0 }},'
|
|
|
|
|
|
|
|
testgroup_struct = "struct testgroup_t groups[] = {{\n{body}\n END_OF_GROUPS\n}};"
|
|
|
|
testgroup_member = ' {{ "{name}", {name}_tests }},'
|
|
|
|
|
|
|
|
## XXX: may be we could have `--without <groups>` argument...
|
|
|
|
|
|
|
|
test_dirs = set(
|
|
|
|
(
|
|
|
|
"basics",
|
|
|
|
"extmod",
|
|
|
|
"float",
|
|
|
|
"micropython",
|
|
|
|
"misc",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
exclude_tests = set(
|
|
|
|
(
|
|
|
|
# pattern matching in .exp
|
|
|
|
"basics/bytes_compare3.py",
|
|
|
|
"extmod/ticks_diff.py",
|
|
|
|
"extmod/time_ms_us.py",
|
|
|
|
# unicode char issue
|
|
|
|
"extmod/json_loads.py",
|
|
|
|
# doesn't output to python stdout
|
|
|
|
"extmod/re_debug.py",
|
|
|
|
"extmod/vfs_basic.py",
|
|
|
|
"extmod/vfs_fat_ramdisk.py",
|
|
|
|
"extmod/vfs_fat_fileio.py",
|
|
|
|
"extmod/vfs_fat_fsusermount.py",
|
|
|
|
"extmod/vfs_fat_oldproto.py",
|
|
|
|
# rounding issues
|
|
|
|
"float/float_divmod.py",
|
|
|
|
# requires double precision floating point to work
|
|
|
|
"float/float2int_doubleprec_intbig.py",
|
|
|
|
"float/float_format_ints_doubleprec.py",
|
|
|
|
"float/float_parse_doubleprec.py",
|
|
|
|
# different filename in output
|
|
|
|
"micropython/emg_exc.py",
|
|
|
|
"micropython/heapalloc_traceback.py",
|
|
|
|
# don't have emergency exception buffer
|
|
|
|
"micropython/heapalloc_exc_compressed_emg_exc.py",
|
|
|
|
# pattern matching in .exp
|
|
|
|
"micropython/meminfo.py",
|
|
|
|
# needs sys stdfiles
|
|
|
|
"misc/print_exception.py",
|
|
|
|
# settrace .exp files are too large
|
|
|
|
"misc/sys_settrace_loop.py",
|
|
|
|
"misc/sys_settrace_generator.py",
|
|
|
|
"misc/sys_settrace_features.py",
|
|
|
|
# don't have f-string
|
|
|
|
"basics/string_fstring.py",
|
|
|
|
"basics/string_fstring_debug.py",
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
output = []
|
|
|
|
tests = []
|
|
|
|
|
|
|
|
argparser = argparse.ArgumentParser(
|
|
|
|
description="Convert native MicroPython tests to tinytest/upytesthelper C code"
|
|
|
|
)
|
|
|
|
argparser.add_argument("--stdin", action="store_true", help="read list of tests from stdin")
|
|
|
|
argparser.add_argument("--exclude", action="append", help="exclude test by name")
|
|
|
|
argparser.add_argument(
|
|
|
|
"--profile",
|
|
|
|
type=argparse.FileType("rt", encoding="utf-8"),
|
|
|
|
help="optional profile file providing test directories and exclusion list",
|
|
|
|
)
|
|
|
|
args = argparser.parse_args()
|
|
|
|
|
|
|
|
if not args.stdin:
|
|
|
|
if args.profile:
|
|
|
|
test_dirs, exclude_tests = load_profile(args.profile, test_dirs, exclude_tests)
|
|
|
|
if args.exclude:
|
|
|
|
exclude_tests = exclude_tests.union(args.exclude)
|
|
|
|
for group in test_dirs:
|
|
|
|
tests += [test for test in glob("{}/*.py".format(group)) if test not in exclude_tests]
|
|
|
|
else:
|
|
|
|
for l in sys.stdin:
|
|
|
|
tests.append(l.rstrip())
|
|
|
|
|
|
|
|
output.extend([test_function.format(**script_to_map(test)) for test in tests])
|
|
|
|
testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests]
|
|
|
|
output.append(testcase_struct.format(name="", body="\n".join(testcase_members)))
|
|
|
|
|
|
|
|
testgroup_members = [testgroup_member.format(name=group) for group in [""]]
|
|
|
|
|
|
|
|
output.append(testgroup_struct.format(body="\n".join(testgroup_members)))
|
|
|
|
|
|
|
|
## XXX: may be we could have `--output <filename>` argument...
|
|
|
|
# Don't depend on what system locale is set, use utf8 encoding.
|
|
|
|
sys.stdout.buffer.write("\n\n".join(output).encode("utf8"))
|