fix(runtest.py): A workaround to bypass errors that occur when deleting temporary files (#4093)

- Replace sys.exit with exceptions for better error handling in test assertions
- Update exception handling in compile_wast_to_wasm to catch all exceptions
- Improve error messages and logging
- Use `--ignore-whitespace` option for git apply in spec_test function
- Use raw string notation for regex patterns.  *The "SyntaxWarning: invalid escape sequence" in Python The warning has been upgraded to SyntaxWarning since Python 3.12, and it is expected to become a SyntaxError in future versions.*
- Add early return for non-loadable AOT compilation to prevent unnecessary assertions
- Redirect stderr to stdout in test_case for unified output
- Update `create_tmpfiles()`  to improve clarity and handling of temporary files
This commit is contained in:
liang.he 2025-03-20 14:25:13 +08:00 committed by GitHub
parent 1f14f4ec0a
commit 06ea960e76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 191 additions and 151 deletions

View File

@ -145,7 +145,7 @@ def run_clang_format_diff(root: Path, commits: str) -> bool:
found = False
for summary in [x for x in diff_content if x.startswith("diff --git")]:
# b/path/to/file -> path/to/file
with_invalid_format = re.split("\s+", summary)[-1][2:]
with_invalid_format = re.split(r"\s+", summary)[-1][2:]
if not is_excluded(with_invalid_format):
print(f"--- {with_invalid_format} failed on code style checking.")
found = True

View File

@ -206,7 +206,7 @@ def get_line_info_from_function_addr_sourcemapping(
if not line:
continue
m = re.match("(.*):(\d+):(\d+)", line)
m = re.match(r"(.*):(\d+):(\d+)", line)
if m:
function_file, function_line, function_column = m.groups()
continue

View File

@ -247,7 +247,7 @@ def test_case(
CMD,
bufsize=1,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
) as p:
try:
@ -285,7 +285,9 @@ def test_case(
except subprocess.TimeoutExpired:
print("failed with TimeoutExpired")
raise Exception(case_name)
except Exception as e:
print(f"An unexpected error occurred: {e}")
raise e
def test_suite(
target,

View File

@ -7,6 +7,7 @@ import array
import atexit
import math
import os
import pathlib
import re
import shutil
import struct
@ -81,9 +82,8 @@ def log(data, end='\n'):
print(data, end=end)
sys.stdout.flush()
def create_tmp_file(suffix: str) -> str:
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp_file:
return tmp_file.name
def create_tmp_file(prefix: str, suffix: str) -> str:
return tempfile.NamedTemporaryFile(prefix=prefix, suffix=suffix, delete=False).name
# TODO: do we need to support '\n' too
import platform
@ -181,7 +181,16 @@ class Runner():
# queue, so we keep it for non-windows platforms.
[outs,_,_] = select([self.stdout], [], [], 1)
if self.stdout in outs:
return True, self.stdout.read(1)
try:
stdout_byte = self.stdout.read(1)
except ValueError:
return True, None
except OSError:
return True, None
except Exception as e:
print("Exception: ", e)
return False, None
return True, stdout_byte
else:
return False, None
@ -212,6 +221,8 @@ class Runner():
buf = self.buf[0:end-len(prompt)]
self.buf = self.buf[end:]
return buf
log("left read_to_prompt() because of timeout")
return None
def writeline(self, str):
@ -249,14 +260,14 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result):
header = runner.read_to_prompt(prompts, timeout=timeout)
if not header and is_need_execute_result:
log(" ---------- will terminate cause the case needs result while there is none inside of buf. ----------")
sys.exit(1)
raise Exception("get nothing from Runner")
if not header == None:
if header:
log("Started with:\n%s" % header)
else:
log("Did not one of following prompt(s): %s" % repr(prompts))
log(" Got : %s" % repr(r.buf))
sys.exit(1)
raise Exception("Did not one of following prompt(s)")
### WebAssembly specific
@ -551,7 +562,7 @@ def parse_assertion_value(val):
if not val:
return None, ""
splitted = re.split('\s+', val)
splitted = re.split(r'\s+', val)
splitted = [s for s in splitted if s]
type = splitted[0].split(".")[0]
lane_type = splitted[1] if len(splitted) > 2 else ""
@ -790,8 +801,8 @@ def test_assert(r, opts, mode, cmd, expected):
return True
## 0x9:i32,-0x1:i32 -> ['0x9:i32', '-0x1:i32']
expected_list = re.split(',', expected)
out_list = re.split(',', out)
expected_list = re.split(r',', expected)
out_list = re.split(r',', out)
if len(expected_list) != len(out_list):
raise Exception("Failed:\n Results count incorrect:\n expected: '%s'\n got: '%s'" % (expected, out))
for i in range(len(expected_list)):
@ -806,34 +817,34 @@ def test_assert_return(r, opts, form):
n. to search a pattern like (assert_return (invoke $module_name function_name ... ) ...)
"""
# params, return
m = re.search('^\(assert_return\s+\(invoke\s+"((?:[^"]|\\\")*)"\s+(\(.*\))\s*\)\s*(\(.*\))\s*\)\s*$', form, re.S)
m = re.search(r'^\(assert_return\s+\(invoke\s+"((?:[^"]|\\\")*)"\s+(\(.*\))\s*\)\s*(\(.*\))\s*\)\s*$', form, re.S)
# judge if assert_return cmd includes the module name
n = re.search('^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"((?:[^"]|\\\")*)"\s+(\(.*\))\s*\)\s*(\(.*\))\s*\)\s*$', form, re.S)
n = re.search(r'^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"((?:[^"]|\\\")*)"\s+(\(.*\))\s*\)\s*(\(.*\))\s*\)\s*$', form, re.S)
# print("assert_return with {}".format(form))
if not m:
# no params, return
m = re.search('^\(assert_return\s+\(invoke\s+"((?:[^"]|\\\")*)"\s*\)\s+()(\(.*\))\s*\)\s*$', form, re.S)
m = re.search(r'^\(assert_return\s+\(invoke\s+"((?:[^"]|\\\")*)"\s*\)\s+()(\(.*\))\s*\)\s*$', form, re.S)
if not m:
# params, no return
m = re.search('^\(assert_return\s+\(invoke\s+"([^"]*)"\s+(\(.*\))()\s*\)\s*\)\s*$', form, re.S)
m = re.search(r'^\(assert_return\s+\(invoke\s+"([^"]*)"\s+(\(.*\))()\s*\)\s*\)\s*$', form, re.S)
if not m:
# no params, no return
m = re.search('^\(assert_return\s+\(invoke\s+"([^"]*)"\s*()()\)\s*\)\s*$', form, re.S)
m = re.search(r'^\(assert_return\s+\(invoke\s+"([^"]*)"\s*()()\)\s*\)\s*$', form, re.S)
if not m:
# params, return
if not n:
# no params, return
n = re.search('^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"((?:[^"]|\\\")*)"\s*\)\s+()(\(.*\))\s*\)\s*$', form, re.S)
n = re.search(r'^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"((?:[^"]|\\\")*)"\s*\)\s+()(\(.*\))\s*\)\s*$', form, re.S)
if not n:
# params, no return
n = re.search('^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s+(\(.*\))()\s*\)\s*\)\s*$', form, re.S)
n = re.search(r'^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s+(\(.*\))()\s*\)\s*\)\s*$', form, re.S)
if not n:
# no params, no return
n = re.search('^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"*()()\)\s*\)\s*$', form, re.S)
n = re.search(r'^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"*()()\)\s*\)\s*$', form, re.S)
if not m and not n:
if re.search('^\(assert_return\s+\(get.*\).*\)$', form, re.S):
if re.search(r'^\(assert_return\s+\(get.*\).*\)$', form, re.S):
log("ignoring assert_return get")
return
else:
@ -852,7 +863,7 @@ def test_assert_return(r, opts, form):
if m.group(2) == '':
args = []
else:
#args = [re.split(' +', v)[1].replace('_', "") for v in re.split("\)\s*\(", m.group(2)[1:-1])]
#args = [re.split(r' +', v)[1].replace('_', "") for v in re.split(r"\)\s*\(", m.group(2)[1:-1])]
# split arguments with ')spaces(', remove leading and tailing ) and (
args_type_and_value = re.split(r'\)\s+\(', m.group(2)[1:-1])
args_type_and_value = [s.replace('_', '') for s in args_type_and_value]
@ -863,7 +874,7 @@ def test_assert_return(r, opts, form):
for arg in args_type_and_value:
# remove leading and tailing spaces, it might confuse following assertions
arg = arg.strip()
splitted = re.split('\s+', arg)
splitted = re.split(r'\s+', arg)
splitted = [s for s in splitted if s]
if splitted[0] in ["i32.const", "i64.const"]:
@ -881,7 +892,7 @@ def test_assert_return(r, opts, form):
numbers, _ = cast_v128_to_i64x2(splitted[2:], 'v128', splitted[1])
assert(len(numbers) == 2), "has to reform arguments into i64x2"
args.append(f"{numbers[0]:#x}\{numbers[1]:#x}")
args.append(f"{numbers[0]:#x}\\{numbers[1]:#x}")
elif "ref.null" == splitted[0]:
args.append("null")
elif "ref.extern" == splitted[0]:
@ -896,7 +907,7 @@ def test_assert_return(r, opts, form):
if m.group(3) == '':
returns= []
else:
returns = re.split("\)\s*\(", m.group(3)[1:-1])
returns = re.split(r"\)\s*\(", m.group(3)[1:-1])
# processed numbers in strings
if len(returns) == 1 and returns[0] in ["ref.array", "ref.struct", "ref.i31",
"ref.eq", "ref.any", "ref.extern",
@ -921,8 +932,7 @@ def test_assert_return(r, opts, form):
except:
_, exc, _ = sys.exc_info()
log("Run wamrc failed:\n got: '%s'" % r.buf)
ret_code = 1
sys.exit(1)
raise Exception("Run wamrc failed 1")
r = run_wasm_with_repl(module+".wasm", module+".aot" if test_aot else module, opts, r)
# Wait for the initial prompt
try:
@ -941,23 +951,23 @@ def test_assert_return(r, opts, form):
# convert (ref.null extern/func) into (ref.null null)
n1 = n.group(3).replace("(ref.null extern)", "(ref.null null)")
n1 = n1.replace("ref.null func)", "(ref.null null)")
args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", n1[1:-1])]
args = [re.split(r' +', v)[1] for v in re.split(r"\)\s*\(", n1[1:-1])]
_, expected = parse_assertion_value(n.group(4)[1:-1])
test_assert(r, opts, "return", "%s %s" % (func, " ".join(args)), expected)
def test_assert_trap(r, opts, form):
# params
m = re.search('^\(assert_trap\s+\(invoke\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form)
m = re.search(r'^\(assert_trap\s+\(invoke\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form)
# judge if assert_return cmd includes the module name
n = re.search('^\(assert_trap\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form, re.S)
n = re.search(r'^\(assert_trap\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form, re.S)
if not m:
# no params
m = re.search('^\(assert_trap\s+\(invoke\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form)
m = re.search(r'^\(assert_trap\s+\(invoke\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form)
if not m:
if not n:
# no params
n = re.search('^\(assert_trap\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form, re.S)
n = re.search(r'^\(assert_trap\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form, re.S)
if not m and not n:
raise Exception("unparsed assert_trap: '%s'" % form)
@ -969,7 +979,7 @@ def test_assert_trap(r, opts, form):
# convert (ref.null extern/func) into (ref.null null)
m1 = m.group(2).replace("(ref.null extern)", "(ref.null null)")
m1 = m1.replace("ref.null func)", "(ref.null null)")
args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m1[1:-1])]
args = [re.split(r' +', v)[1] for v in re.split(r"\)\s*\(", m1[1:-1])]
expected = "Exception: %s" % m.group(3)
test_assert(r, opts, "trap", "%s %s" % (func, " ".join(args)), expected)
@ -987,8 +997,7 @@ def test_assert_trap(r, opts, form):
except:
_, exc, _ = sys.exc_info()
log("Run wamrc failed:\n got: '%s'" % r.buf)
ret_code = 1
sys.exit(1)
raise Exception("Run wamrc failed 2")
r = run_wasm_with_repl(module+".wasm", module+".aot" if test_aot else module, opts, r)
# Wait for the initial prompt
try:
@ -1002,23 +1011,23 @@ def test_assert_trap(r, opts, form):
if n.group(3) == '':
args = []
else:
args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", n.group(3)[1:-1])]
args = [re.split(r' +', v)[1] for v in re.split(r"\)\s*\(", n.group(3)[1:-1])]
expected = "Exception: %s" % n.group(4)
test_assert(r, opts, "trap", "%s %s" % (func, " ".join(args)), expected)
def test_assert_exhaustion(r,opts,form):
# params
m = re.search('^\(assert_exhaustion\s+\(invoke\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form)
m = re.search(r'^\(assert_exhaustion\s+\(invoke\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form)
if not m:
# no params
m = re.search('^\(assert_exhaustion\s+\(invoke\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form)
m = re.search(r'^\(assert_exhaustion\s+\(invoke\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form)
if not m:
raise Exception("unparsed assert_exhaustion: '%s'" % form)
func = m.group(1)
if m.group(2) == '':
args = []
else:
args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m.group(2)[1:-1])]
args = [re.split(r' +', v)[1] for v in re.split(r"\)\s*\(", m.group(2)[1:-1])]
expected = "Exception: %s\n" % m.group(3)
test_assert(r, opts, "exhaustion", "%s %s" % (func, " ".join(args)), expected)
@ -1035,7 +1044,7 @@ def test_assert_wasmexception(r,opts,form):
# \)\s*
# \)\s*
# $
m = re.search('^\(assert_exception\s+\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*\)\s*$', form)
m = re.search(r'^\(assert_exception\s+\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*\)\s*$', form)
if not m:
# no params
@ -1046,24 +1055,24 @@ def test_assert_wasmexception(r,opts,form):
# \)\s*
# \)\s*
# $
m = re.search('^\(assert_exception\s+\(invoke\s+"([^"]+)"\s*()\)\s*\)\s*$', form)
m = re.search(r'^\(assert_exception\s+\(invoke\s+"([^"]+)"\s*()\)\s*\)\s*$', form)
if not m:
raise Exception("unparsed assert_exception: '%s'" % form)
func = m.group(1) # function name
if m.group(2) == '': # arguments
args = []
else:
args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m.group(2)[1:-1])]
args = [re.split(r' +', v)[1] for v in re.split(r"\)\s*\(", m.group(2)[1:-1])]
expected = "Exception: uncaught wasm exception\n"
test_assert(r, opts, "wasmexception", "%s %s" % (func, " ".join(args)), expected)
def do_invoke(r, opts, form):
# params
m = re.search('^\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*$', form)
m = re.search(r'^\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*$', form)
if not m:
# no params
m = re.search('^\(invoke\s+"([^"]+)"\s*()\)\s*$', form)
m = re.search(r'^\(invoke\s+"([^"]+)"\s*()\)\s*$', form)
if not m:
raise Exception("unparsed invoke: '%s'" % form)
func = m.group(1)
@ -1074,7 +1083,7 @@ def do_invoke(r, opts, form):
if m.group(2) == '':
args = []
else:
args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m.group(2)[1:-1])]
args = [re.split(r' +', v)[1] for v in re.split(r"\)\s*\(", m.group(2)[1:-1])]
log("Invoking %s(%s)" % (
func, ", ".join([str(a) for a in args])))
@ -1114,8 +1123,8 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts):
log("Running: %s" % " ".join(cmd))
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError as e:
print(str(e))
except Exception as e:
print(e)
return False
return True
@ -1238,13 +1247,17 @@ def run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r):
return r
def create_tmpfiles(wast_name):
def create_tmpfiles(file_name, test_aot, temp_file_repo):
tempfiles = []
tempfiles.append(create_tmp_file(".wast"))
tempfiles.append(create_tmp_file(".wasm"))
tempfiles.append(create_tmp_file(file_name, ".wast"))
tempfiles.append(create_tmp_file(file_name, ".wasm"))
if test_aot:
tempfiles.append(create_tmp_file(".aot"))
tempfiles.append(create_tmp_file(file_name, ".aot"))
else:
tempfiles.append(None)
assert len(tempfiles) == 3, "tempfiles should have 3 elements"
# add these temp file to temporal repo, will be deleted when finishing the test
temp_file_repo.extend(tempfiles)
@ -1263,6 +1276,9 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile,
if test_aot:
r = compile_wasm_to_aot(wasm_tempfile, aot_tempfile, True, opts, r)
if not loadable:
return
try:
assert_prompt(r, ['Compile success'], opts.start_fail_timeout, True)
except:
@ -1275,8 +1291,7 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile,
else:
log("Run wamrc failed:\n expected: '%s'\n got: '%s'" % \
(expected, r.buf))
ret_code = 1
sys.exit(1)
raise Exception("Run wamrc failed 3")
r = run_wasm_with_repl(wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
@ -1296,6 +1311,20 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile,
raise Exception("Failed:\n expected: '%s'\n got: '%s'" % \
(expected, r.buf))
def recently_added_wasm(temp_file_repo):
for f in reversed(temp_file_repo):
if not f:
continue
assert os.path.exists(f), f"temp file {f} should exist"
if os.path.getsize(f) == 0:
continue
if f.endswith(".wasm"):
return f
if __name__ == "__main__":
opts = parser.parse_args(sys.argv[1:])
# print('Input param :',opts)
@ -1314,16 +1343,10 @@ if __name__ == "__main__":
else:
SKIP_TESTS = C_SKIP_TESTS
wast_tempfile = create_tmp_file(".wast")
wasm_tempfile = create_tmp_file(".wasm")
if test_aot:
aot_tempfile = create_tmp_file(".aot")
# could be potientially compiled to aot
# with the future following call test_assert_xxx,
# add them to temp_file_repo now even if no actual following file,
# it will be simple ignore during final deletion if not exist
prefix = wasm_tempfile.split(".wasm")[0]
temp_file_repo.append(prefix + ".aot")
case_file = pathlib.Path(opts.test_file.name)
assert(case_file.exists()), f"Test file {case_file} doesn't exist"
tmpfile_stem = case_file.stem + "_"
ret_code = 0
try:
@ -1335,22 +1358,26 @@ if __name__ == "__main__":
for form in forms:
# log("\n### Current Case is " + form + "\n")
wast_tempfile, wasm_tempfile, aot_tempfile = create_tmpfiles(
tmpfile_stem, test_aot, temp_file_repo)
if ";;" == form[0:2]:
log(form)
elif skip_test(form, SKIP_TESTS):
log("Skipping test: %s" % form[0:60])
elif re.match("^\(assert_trap\s+\(module", form):
elif re.match(r"^\(assert_trap\s+\(module", form):
test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
elif re.match("^\(assert_exhaustion\\b.*", form):
elif re.match(r"^\(assert_exhaustion\b.*", form):
test_assert_exhaustion(r, opts, form)
elif re.match("^\(assert_exception\\b.*", form):
elif re.match(r"^\(assert_exception\b.*", form):
test_assert_wasmexception(r, opts, form)
elif re.match("^\(assert_unlinkable\\b.*", form):
elif re.match(r"^\(assert_unlinkable\b.*", form):
test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r, False)
elif re.match("^\(assert_malformed\\b.*", form):
elif re.match(r"^\(assert_malformed\b.*", form):
# remove comments in wast
form,n = re.subn(";;.*\n", "", form)
m = re.match("^\(assert_malformed\s*\(module binary\s*(\".*\").*\)\s*\"(.*)\"\s*\)$", form, re.DOTALL)
m = re.match(r"^\(assert_malformed\s*\(module binary\s*(\".*\").*\)\s*\"(.*)\"\s*\)$", form, re.DOTALL)
if m:
# workaround: spec test changes error message to "malformed" while iwasm still use "invalid"
@ -1359,7 +1386,7 @@ if __name__ == "__main__":
with open(wasm_tempfile, 'wb') as f:
s = m.group(1)
while s:
res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL)
res = re.match(r"[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL)
if IS_PY_3:
context = res.group(1).replace("\\", "\\x").encode("latin1").decode("unicode-escape").encode("latin1")
f.write(context)
@ -1414,51 +1441,43 @@ if __name__ == "__main__":
else:
log("Run wamrc failed:\n expected: '%s'\n got: '%s'" % \
(error_msg, r.buf))
ret_code = 1
sys.exit(1)
raise Exception("Run wamrc failed 4")
r = run_wasm_with_repl(wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
elif re.match("^\(assert_malformed\s*\(module quote", form):
elif re.match(r"^\(assert_malformed\s*\(module quote", form):
log("ignoring assert_malformed module quote")
else:
log("unrecognized assert_malformed")
elif re.match("^\(assert_return[_a-z]*_nan\\b.*", form):
elif re.match(r"^\(assert_return[_a-z]*_nan\b.*", form):
log("ignoring assert_return_.*_nan")
pass
elif re.match(".*\(invoke\s+\$\\b.*", form):
elif re.match(r".*\(invoke\s+\$\b.*", form):
# invoke a particular named module's function
if form.startswith("(assert_return"):
test_assert_return(r,opts,form)
elif form.startswith("(assert_trap"):
test_assert_trap(r,opts,form)
elif re.match("^\(module\\b.*", form):
elif re.match(r"^\(module\b.*", form):
# if the module includes the particular name startswith $
m = re.search("^\(module\s+\$.\S+", form)
m = re.search(r"^\(module\s+\$.\S+", form)
if m:
# get module name
module_name = re.split('\$', m.group(0).strip())[1]
module_name = re.split(r'\$', m.group(0).strip())[1]
if module_name:
# create temporal files
temp_files = create_tmpfiles(module_name)
temp_files = create_tmpfiles(module_name, test_aot, temp_file_repo)
if not compile_wast_to_wasm(form, temp_files[0], temp_files[1], opts):
raise Exception("compile wast to wasm failed")
if test_aot:
r = compile_wasm_to_aot(temp_files[1], temp_files[2], True, opts, r)
# could be potientially compiled to aot
# with the future following call test_assert_xxx,
# add them to temp_file_repo now even if no actual following file,
# it will be simple ignore during final deletion if not exist
prefix = temp_files[1].split(".wasm")[0]
temp_file_repo.append(prefix + ".aot")
try:
assert_prompt(r, ['Compile success'], opts.start_timeout, False)
except:
_, exc, _ = sys.exc_info()
log("Run wamrc failed:\n got: '%s'" % r.buf)
ret_code = 1
sys.exit(1)
raise Exception("Run wamrc failed 5")
temp_module_table[module_name] = temp_files[1]
r = run_wasm_with_repl(temp_files[1], temp_files[2] if test_aot else None, opts, r)
else:
@ -1472,8 +1491,7 @@ if __name__ == "__main__":
except:
_, exc, _ = sys.exc_info()
log("Run wamrc failed:\n got: '%s'" % r.buf)
ret_code = 1
sys.exit(1)
raise Exception("Run wamrc failed 6")
r = run_wasm_with_repl(wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
@ -1485,38 +1503,51 @@ if __name__ == "__main__":
raise Exception("Failed:\n expected: '%s'\n got: '%s'" % \
(repr(exc), r.buf))
elif re.match("^\(assert_return\\b.*", form):
elif re.match(r"^\(assert_return\b.*", form):
assert(r), "iwasm repl runtime should be not null"
test_assert_return(r, opts, form)
elif re.match("^\(assert_trap\\b.*", form):
elif re.match(r"^\(assert_trap\b.*", form):
test_assert_trap(r, opts, form)
elif re.match("^\(invoke\\b.*", form):
elif re.match(r"^\(invoke\b.*", form):
assert(r), "iwasm repl runtime should be not null"
do_invoke(r, opts, form)
elif re.match("^\(assert_invalid\\b.*", form):
test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
elif re.match("^\(register\\b.*", form):
elif re.match(r"^\(assert_invalid\b.*", form):
# loading invalid module will raise an error directly, so shell prompt won't show here
test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r, False)
elif re.match(r"^\(register\b.*", form):
# get module's new name from the register cmd
name_new =re.split('\"',re.search('\".*\"',form).group(0))[1]
if name_new:
new_module = os.path.join(tempfile.gettempdir(), name_new + ".wasm")
shutil.copyfile(temp_module_table.get(name_new, wasm_tempfile), new_module)
# add new_module copied from the old into temp_file_repo[]
temp_file_repo.append(new_module)
if test_aot:
new_module_aot = os.path.join(tempfile.gettempdir(), name_new + ".aot")
r = compile_wasm_to_aot(new_module, new_module_aot, True, opts, r)
try:
assert_prompt(r, ['Compile success'], opts.start_timeout, True)
except:
raise Exception("compile wasm to aot failed")
# add aot module into temp_file_repo[]
temp_file_repo.append(new_module_aot)
else:
name_new =re.split(r'\"',re.search(r'\".*\"',form).group(0))[1]
if not name_new:
# there is no name defined in register cmd
raise Exception("can not find module name from the register")
raise Exception(f"Not following register cmd pattern {form}")
# assumption
# - There exists a module in the form of (module $name).
# - The nearest module in the form of (module), without $name, is the candidate for registration.
recently_wasm = recently_added_wasm(temp_file_repo)
if not name_new in temp_module_table:
print(temp_file_repo)
print(f"Module {name_new} is not found in temp_module_table. use the nearest module {recently_wasm}")
for_registration = temp_module_table.get(name_new, recently_wasm)
assert os.path.exists(for_registration), f"module {for_registration} is not found"
new_module = os.path.join(tempfile.gettempdir(), name_new + ".wasm")
# for_registration(tmpfile) --copy-> name_new.wasm
shutil.copyfile(for_registration, new_module)
# add new_module copied from the old into temp_file_repo[]
temp_file_repo.append(new_module)
if test_aot:
new_module_aot = os.path.join(tempfile.gettempdir(), name_new + ".aot")
r = compile_wasm_to_aot(new_module, new_module_aot, True, opts, r)
try:
assert_prompt(r, ['Compile success'], opts.start_timeout, True)
except:
raise Exception("compile wasm to aot failed")
# add aot module into temp_file_repo[]
temp_file_repo.append(new_module_aot)
else:
raise Exception("unrecognized form '%s...'" % form[0:40])
except Exception as e:
@ -1524,35 +1555,42 @@ if __name__ == "__main__":
print("THE FINAL EXCEPTION IS {}".format(e))
ret_code = 101
shutil.copyfile(wasm_tempfile, os.path.join(opts.log_dir, os.path.basename(wasm_tempfile)))
if opts.aot or opts.xip:
shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)))
if "indirect-mode" in str(e):
compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "object")
shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+'.o'))
subprocess.check_call(["llvm-objdump", "-r", aot_tempfile])
compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "ir")
shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+".ir"))
try:
shutil.copyfile(wasm_tempfile, os.path.join(opts.log_dir, os.path.basename(wasm_tempfile)))
if opts.aot or opts.xip:
shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)))
if "indirect-mode" in str(e):
compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "object")
shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+'.o'))
subprocess.check_call(["llvm-objdump", "-r", aot_tempfile])
compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "ir")
shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+".ir"))
except Exception as e:
print("Failed to copy files to log directory: %s" % e)
ret_code = 102
else:
ret_code = 0
finally:
if not opts.no_cleanup:
log("Removing tempfiles")
os.remove(wast_tempfile)
os.remove(wasm_tempfile)
if test_aot:
os.remove(aot_tempfile)
try:
if not opts.no_cleanup:
# remove the files under /tempfiles/ and copy of .wasm files
log(f"Removing {temp_file_repo}")
# remove the files under /tempfiles/ and copy of .wasm files
if temp_file_repo:
for t in temp_file_repo:
if(len(str(t))!=0 and os.path.exists(t)):
# None and empty
if not t:
continue
if os.path.exists(t):
os.remove(t)
else:
log(f"Leaving {temp_file_repo}")
except Exception as e:
print("Failed to remove tempfiles: %s" % e)
# ignore the exception
ret_code = 0
log("### End testing %s" % opts.test_file.name)
else:
log("Leaving tempfiles: %s" % ([wast_tempfile, wasm_tempfile]))
log(f"### End testing {opts.test_file.name} with {ret_code}")
sys.exit(ret_code)

View File

@ -448,9 +448,9 @@ function spec_test()
# May 31, 2012 [interpreter] implement atomic.wait and atomic.notify (#194)
git reset --hard 09f2831349bf409187abb6f7868482a8079f2264
git apply ../../spec-test-script/thread_proposal_ignore_cases.patch || exit 1
git apply ../../spec-test-script/thread_proposal_fix_atomic_case.patch || exit 1
git apply ../../spec-test-script/thread_proposal_remove_memory64_flag_case.patch
git apply --ignore-whitespace ../../spec-test-script/thread_proposal_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/thread_proposal_fix_atomic_case.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/thread_proposal_remove_memory64_flag_case.patch
elif [ ${ENABLE_EH} == 1 ]; then
echo "checkout exception-handling test cases"
@ -459,7 +459,7 @@ function spec_test()
# Jun 6, 2023 Merge branch 'upstream' into merge-upstream
git reset --hard 51c721661b671bb7dc4b3a3acb9e079b49778d36
git apply ../../spec-test-script/exception_handling.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/exception_handling.patch || exit 1
elif [[ ${ENABLE_GC} == 1 ]]; then
echo "checkout spec for GC proposal"
@ -469,12 +469,12 @@ function spec_test()
# Dec 9, 2024. Merge branch 'funcref'
git reset --hard 756060f5816c7e2159f4817fbdee76cf52f9c923
git apply ../../spec-test-script/gc_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/gc_ignore_cases.patch || exit 1
if [[ ${ENABLE_QEMU} == 1 ]]; then
# Decrease the recursive count for tail call cases as nuttx qemu's
# native stack size is much smaller
git apply ../../spec-test-script/gc_nuttx_tail_call.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/gc_nuttx_tail_call.patch || exit 1
fi
# As of version 1.0.36, wabt is still unable to correctly handle the GC proposal.
@ -497,7 +497,7 @@ function spec_test()
git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast test/core/data.wast
# Patch table64 extension
git checkout 940398cd4823522a9b36bec4984be4b153dedb81 -- test/core/call_indirect.wast test/core/table.wast test/core/table_copy.wast test/core/table_copy_mixed.wast test/core/table_fill.wast test/core/table_get.wast test/core/table_grow.wast test/core/table_init.wast test/core/table_set.wast test/core/table_size.wast
git apply ../../spec-test-script/memory64_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/memory64_ignore_cases.patch || exit 1
elif [[ ${ENABLE_MULTI_MEMORY} == 1 ]]; then
echo "checkout spec for multi memory proposal"
@ -508,9 +508,9 @@ function spec_test()
# Reset to commit: "Merge pull request #48 from backes/specify-memcpy-immediate-order"
git reset --hard fbc99efd7a788db300aec3dd62a14577ec404f1b
git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast
git apply ../../spec-test-script/multi_memory_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/multi_memory_ignore_cases.patch || exit 1
if [[ ${RUNNING_MODE} == "aot" ]]; then
git apply ../../spec-test-script/multi_module_aot_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/multi_module_aot_ignore_cases.patch || exit 1
fi
else
echo "checkout spec for default proposal"
@ -520,15 +520,15 @@ function spec_test()
# Dec 20, 2024. Use WPT version of test harness for HTML core test conversion (#1859)
git reset --hard f3a0e06235d2d84bb0f3b5014da4370613886965
git apply ../../spec-test-script/ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/ignore_cases.patch || exit 1
if [[ ${ENABLE_SIMD} == 1 ]]; then
git apply ../../spec-test-script/simd_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/simd_ignore_cases.patch || exit 1
fi
if [[ ${ENABLE_MULTI_MODULE} == 1 ]]; then
git apply ../../spec-test-script/multi_module_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/multi_module_ignore_cases.patch || exit 1
if [[ ${RUNNING_MODE} == "aot" ]]; then
git apply ../../spec-test-script/multi_module_aot_ignore_cases.patch || exit 1
git apply --ignore-whitespace ../../spec-test-script/multi_module_aot_ignore_cases.patch || exit 1
fi
fi
fi