diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 566ee1918d1..7746f2e889a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,7 @@ jobs: sudo ./llvm.sh ${LLVM_VERSION} sudo apt-get install clang-format clang-format-${LLVM_VERSION} clang-tidy-${LLVM_VERSION} - run: flake8 + - run: ruff check - run: ./scripts/clang-format-diff.sh - name: clang-tidy run: | diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000000..69c92ac2bae --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,42 @@ +target-version = "py310" + +exclude = [ + 'third_party', + 'test/lit/lit.cfg.py', + 'test/spec/testsuite', +] + +[lint] +select = [ + "ARG", + "ASYNC", + "B", + "C4", + "C90", + "COM", + "E", + "F", + "I", + "PERF", + "PIE", + "PL", + "UP", + "W", + "YTT", +] + +ignore = [ + "C901", # https://docs.astral.sh/ruff/rules/complex-structure/ + "B006", # https://docs.astral.sh/ruff/rules/mutable-argument-default/ + "B011", # https://docs.astral.sh/ruff/rules/assert-false/ + "B023", # https://docs.astral.sh/ruff/rules/function-uses-loop-variable/ + "E501", # https://docs.astral.sh/ruff/rules/line-too-long/ + "PERF401", # https://docs.astral.sh/ruff/rules/manual-list-comprehension/ + "PLR0912", # https://docs.astral.sh/ruff/rules/too-many-branches/ + "PLR0913", # https://docs.astral.sh/ruff/rules/too-many-arguments/ + "PLR0915", # https://docs.astral.sh/ruff/rules/too-many-statements/ + "PLR2004", # https://docs.astral.sh/ruff/rules/magic-value-comparison/ + "PLW0603", # https://docs.astral.sh/ruff/rules/global-statement/ + "PLW1510", # https://docs.astral.sh/ruff/rules/subprocess-run-without-check/ + "PLW2901", # https://docs.astral.sh/ruff/rules/redefined-loop-name/ +] diff --git a/check.py b/check.py index 857989bd885..06d2493cc7c 100755 --- a/check.py +++ b/check.py @@ -15,21 +15,16 @@ # limitations under the License. import glob +import io import os import subprocess import sys import unittest -from multiprocessing.pool import ThreadPool from collections import OrderedDict +from multiprocessing.pool import ThreadPool from pathlib import Path -import io -from scripts.test import binaryenjs -from scripts.test import lld -from scripts.test import shared -from scripts.test import support -from scripts.test import wasm2js -from scripts.test import wasm_opt +from scripts.test import binaryenjs, lld, shared, support, wasm2js, wasm_opt def get_changelog_version(): @@ -38,7 +33,7 @@ def get_changelog_version(): lines = [line for line in lines if len(line.split()) == 1] lines = [line for line in lines if line.startswith('v')] version = lines[0][1:] - print("Parsed CHANGELOG.md version: %s" % version) + print(f"Parsed CHANGELOG.md version: {version}") return int(version) @@ -52,16 +47,16 @@ def run_version_tests(): not any(f.endswith(s) for s in not_executable_suffix) and any(os.path.basename(f).startswith(s) for s in executable_prefix)] executables = sorted(executables) - assert len(executables) + assert executables changelog_version = get_changelog_version() for e in executables: - print('.. %s --version' % e) + print(f'.. {e} --version') proc = subprocess.run([e, '--version'], capture_output=True, text=True) - assert len(proc.stderr) == 0, 'Expected no stderr, got:\n%s' % proc.stderr + assert len(proc.stderr) == 0, f'Expected no stderr, got:\n{proc.stderr}' out = proc.stdout - assert os.path.basename(e).replace('.exe', '') in out, 'Expected version to contain program name, got:\n%s' % out - assert len(out.strip().splitlines()) == 1, 'Expected only version info, got:\n%s' % out + assert os.path.basename(e).replace('.exe', '') in out, f'Expected version to contain program name, got:\n{out}' + assert len(out.strip().splitlines()) == 1, f'Expected only version info, got:\n{out}' parts = out.split() assert parts[1] == 'version' version = int(parts[2]) @@ -155,7 +150,8 @@ def run_wasm_reduce_tests(): print('..', os.path.basename(t)) # convert to wasm support.run_command(shared.WASM_AS + [t, '-o', 'a.wasm', '-all']) - support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec -all ' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm', '--timeout=4']) + cmd = shared.WASM_OPT[0] + support.run_command(shared.WASM_REDUCE + ['a.wasm', f'--command={cmd} b.wasm --fuzz-exec -all ', '-t', 'b.wasm', '-w', 'c.wasm', '--timeout=4']) expected = t + '.txt' support.run_command(shared.WASM_DIS + ['c.wasm', '-o', 'a.wat']) with open('a.wat') as seen: @@ -168,14 +164,15 @@ def run_wasm_reduce_tests(): # TODO: re-enable multivalue once it is better optimized support.run_command(shared.WASM_OPT + [os.path.join(shared.options.binaryen_test, 'lit/basic/signext.wast'), '-ttf', '-Os', '-o', 'a.wasm', '--detect-features', '--disable-multivalue']) before = os.stat('a.wasm').st_size - support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec --detect-features' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm']) + cmd = shared.WASM_OPT[0] + support.run_command(shared.WASM_REDUCE + ['a.wasm', f'--command={cmd} b.wasm --fuzz-exec --detect-features', '-t', 'b.wasm', '-w', 'c.wasm']) after = os.stat('c.wasm').st_size # This number is a custom threshold to check if we have shrunk the # output sufficiently assert after < 0.85 * before, [before, after] -def run_spec_test(wast, stdout=None, stderr=None): +def run_spec_test(wast, stdout=None): cmd = shared.WASM_SHELL + [wast] output = support.run_command(cmd, stdout=stdout, stderr=subprocess.PIPE) # filter out binaryen interpreter logging that the spec suite @@ -184,7 +181,7 @@ def run_spec_test(wast, stdout=None, stderr=None): return '\n'.join(filtered) + '\n' -def run_opt_test(wast, stdout=None, stderr=None): +def run_opt_test(wast, stdout=None): # check optimization validation cmd = shared.WASM_OPT + [wast, '-O', '-all', '-q'] support.run_command(cmd, stdout=stdout) @@ -200,7 +197,7 @@ def check_expected(actual, expected, stdout=None): shared.fail(actual, expected) -def run_one_spec_test(wast: Path, stdout=None, stderr=None): +def run_one_spec_test(wast: Path, stdout=None): test_name = wast.name # /path/to/binaryen/test/spec/foo.wast -> test-spec-foo @@ -215,7 +212,7 @@ def run_one_spec_test(wast: Path, stdout=None, stderr=None): # some spec tests should fail (actual process failure, not just assert_invalid) try: - actual = run_spec_test(str(wast), stdout=stdout, stderr=stderr) + actual = run_spec_test(str(wast), stdout=stdout) except Exception as e: if ('wasm-validator error' in str(e) or 'error: ' in str(e)) and '.fail.' in test_name: print('<< test failed as expected >>', file=stdout) @@ -237,23 +234,23 @@ def run_one_spec_test(wast: Path, stdout=None, stderr=None): print(f' testing split module {i}', file=stdout) split_name = base_name + f'_split{i}.wast' support.write_wast(split_name, module) - run_opt_test(split_name, stdout=stdout, stderr=stderr) # also that our optimizer doesn't break on it + run_opt_test(split_name, stdout=stdout) # also that our optimizer doesn't break on it - result_wast_file = shared.binary_format_check(split_name, verify_final_result=False, base_name=base_name, stdout=stdout, stderr=stderr) + result_wast_file = shared.binary_format_check(split_name, verify_final_result=False, base_name=base_name, stdout=stdout) with open(result_wast_file) as f: result_wast = f.read() # add the asserts, and verify that the test still passes transformed_spec_file.write(result_wast + '\n' + '\n'.join(asserts)) # compare all the outputs to the expected output - actual = run_spec_test(transformed_path, stdout=stdout, stderr=stderr) + actual = run_spec_test(transformed_path, stdout=stdout) check_expected(actual, os.path.join(shared.get_test_dir('spec'), 'expected-output', test_name + '.log'), stdout=stdout) def run_spec_test_with_wrapped_stdout(wast: Path): out = io.StringIO() try: - run_one_spec_test(wast, stdout=out, stderr=out) + run_one_spec_test(wast, stdout=out) except Exception as e: # Serialize exceptions into the output string buffer # so they can be reported on the main thread. @@ -412,7 +409,7 @@ def main(): for r in shared.requested: if r not in all_suites: - print('invalid test suite: %s (see --list-suites)\n' % r) + print(f'invalid test suite: {r} (see --list-suites)\n') return 1 if not shared.requested: diff --git a/requirements-dev.txt b/requirements-dev.txt index 35d2ce4581a..48eeb74ef5c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,5 +4,6 @@ # Install with `pip3 install -r requirements-dev.txt` flake8==7.3.0 +ruff==0.14.1 filecheck==0.0.22 lit==0.11.0.post1 diff --git a/scripts/auto_update_tests.py b/scripts/auto_update_tests.py index 1b77c238449..c81b1150597 100755 --- a/scripts/auto_update_tests.py +++ b/scripts/auto_update_tests.py @@ -19,12 +19,7 @@ import sys from collections import OrderedDict -from test import binaryenjs -from test import lld -from test import shared -from test import support -from test import wasm2js -from test import wasm_opt +from test import binaryenjs, lld, shared, support, wasm2js, wasm_opt def update_example_tests(): @@ -119,7 +114,8 @@ def update_reduce_tests(): print('..', os.path.basename(t)) # convert to wasm support.run_command(shared.WASM_AS + [t, '-o', 'a.wasm', '-all']) - print(support.run_command(shared.WASM_REDUCE + ['a.wasm', '--command=%s b.wasm --fuzz-exec -all' % shared.WASM_OPT[0], '-t', 'b.wasm', '-w', 'c.wasm'])) + cmd = shared.WASM_OPT[0] + print(support.run_command(shared.WASM_REDUCE + ['a.wasm', f'--command={cmd} b.wasm --fuzz-exec -all', '-t', 'b.wasm', '-w', 'c.wasm'])) expected = t + '.txt' support.run_command(shared.WASM_DIS + ['c.wasm', '-o', expected]) diff --git a/scripts/bundle_clusterfuzz.py b/scripts/bundle_clusterfuzz.py index 2c4f2932292..63164fee8c3 100755 --- a/scripts/bundle_clusterfuzz.py +++ b/scripts/bundle_clusterfuzz.py @@ -155,7 +155,7 @@ for i, test in enumerate(all_tests): if not fuzzing.is_fuzzable(test): continue - for wast, asserts in support.split_wast(test): + for wast, _asserts in support.split_wast(test): if not wast: continue support.write_wast(temp_wasm, wast) diff --git a/scripts/clusterfuzz/embed_wasms.py b/scripts/clusterfuzz/embed_wasms.py index fac00a83d8b..84ce6805370 100644 --- a/scripts/clusterfuzz/embed_wasms.py +++ b/scripts/clusterfuzz/embed_wasms.py @@ -54,7 +54,7 @@ wasm_index = 0 -def replace_wasm(text): +def replace_wasm(_text): global wasm_index wasm_file = in_wasms[wasm_index] wasm_index += 1 diff --git a/scripts/clusterfuzz/run.py b/scripts/clusterfuzz/run.py index c47c2e77048..7946bc00556 100755 --- a/scripts/clusterfuzz/run.py +++ b/scripts/clusterfuzz/run.py @@ -23,14 +23,13 @@ bundle_clusterfuzz.py. ''' -import os import getopt import math +import os import random import subprocess import sys - # The V8 flags we put in the "fuzzer flags" files, which tell ClusterFuzz how to # run V8. By default we apply all staging flags. FUZZER_FLAGS = '--wasm-staging --experimental-wasm-custom-descriptors' @@ -141,7 +140,7 @@ def get_wasm_contents(name, output_dir, extra_args=[]): # wasm-opt may fail to run in rare cases (when the fuzzer emits code it # detects as invalid). Just try again in such a case. - for attempt in range(0, 100): + for attempt in range(100): # Generate random data. random_size = system_random.randint(1, MAX_RANDOM_SIZE) with open(input_data_file_path, 'wb') as file: @@ -186,7 +185,7 @@ def get_wasm_contents(name, output_dir, extra_args=[]): global temp_files temp_files += [ wasm_file_path, - input_data_file_path + input_data_file_path, ] # Convert to a string, and wrap into a typed array. @@ -261,7 +260,7 @@ def get_js_file_contents(i, output_dir): 'build(secondBinary, true)', ] - for i in range(num): + for _ in range(num): choice = system_random.choice(extra_js_operations) if choice == 'CALL_EXPORTS': # The random seed can be any unsigned 32-bit number. diff --git a/scripts/foreach.py b/scripts/foreach.py index f2e4b34647c..8736c5c4657 100755 --- a/scripts/foreach.py +++ b/scripts/foreach.py @@ -15,8 +15,8 @@ # limitations under the License. import os -import sys import subprocess +import sys from test import support @@ -33,7 +33,7 @@ def main(): cmd = sys.argv[3:] returncode = 0 all_modules = open(infile).read() - for i, (module, asserts) in enumerate(support.split_wast(infile)): + for i, (module, _asserts) in enumerate(support.split_wast(infile)): tempname = tempfile + '.' + str(i) with open(tempname, 'w') as temp: print(module, file=temp) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index fa99ad077ea..b6eda7ce929 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -1,7 +1,5 @@ #!/usr/bin/python3 - -''' -Run various fuzzing operations on random inputs, using wasm-opt. See +"""Run various fuzzing operations on random inputs, using wasm-opt. See "testcase_handlers" below for the list of fuzzing operations. Usage: @@ -24,27 +22,27 @@ (that is on a fixed set of arguments to wasm-opt, though - this script covers different options being passed) -''' +""" + +# ruff: noqa: COM819, ARG002 import contextlib -import os import difflib import json import math -import shutil -import subprocess +import os import random import re +import shutil +import subprocess import sys import tarfile import time import traceback +from datetime import datetime, timedelta, timezone from os.path import abspath -from test import fuzzing -from test import shared -from test import support - +from test import fuzzing, shared, support assert sys.version_info >= (3, 10), 'requires Python 3.10' @@ -144,7 +142,7 @@ def randomize_feature_opts(): FEATURE_OPTS.append(possible) if possible in IMPLIED_FEATURE_OPTS: FEATURE_OPTS.extend(IMPLIED_FEATURE_OPTS[possible]) - else: + elif random.random() < 0.9: # 2/3 of the remaining 90% use them all. This is useful to maximize # coverage, as enabling more features enables more optimizations and # code paths, and also allows all initial contents to run. @@ -154,11 +152,10 @@ def randomize_feature_opts(): # Same with strings. Relaxed SIMD's nondeterminism disables much but not # all of our V8 fuzzing, so avoid it too. Stack Switching, as well, is # not yet ready in V8. - if random.random() < 0.9: - FEATURE_OPTS.append('--disable-shared-everything') - FEATURE_OPTS.append('--disable-strings') - FEATURE_OPTS.append('--disable-relaxed-simd') - FEATURE_OPTS.append('--disable-stack-switching') + FEATURE_OPTS.append('--disable-shared-everything') + FEATURE_OPTS.append('--disable-strings') + FEATURE_OPTS.append('--disable-relaxed-simd') + FEATURE_OPTS.append('--disable-stack-switching') print('randomized feature opts:', '\n ' + '\n '.join(FEATURE_OPTS)) @@ -264,7 +261,6 @@ def auto_select_recent_initial_contents(): # commit time of HEAD. The reason we use the commit time of HEAD instead # of the current system time is to make the results deterministic given # the Binaryen HEAD commit. - from datetime import datetime, timedelta, timezone head_ts_str = run(['git', 'log', '-1', '--format=%cd', '--date=raw'], silent=True).split()[0] head_dt = datetime.utcfromtimestamp(int(head_ts_str)) @@ -277,9 +273,9 @@ def auto_select_recent_initial_contents(): # (wat extension is also included) p = re.compile(r'^[AM]\stest' + os.sep + r'(.*\.(wat|wast))$') matches = [p.match(e) for e in log] - auto_set = set([match.group(1) for match in matches if match]) + auto_set = {match.group(1) for match in matches if match} auto_set = auto_set.difference(set(FIXED_IMPORTANT_INITIAL_CONTENTS)) - return sorted(list(auto_set)) + return sorted(auto_set) def is_git_repo(): try: @@ -348,7 +344,7 @@ def pick_initial_contents(): if len(split_parts) > 1: index = random.randint(0, len(split_parts) - 1) chosen = split_parts[index] - module, asserts = chosen + module, _asserts = chosen if not module: # there is no module in this choice (just asserts), ignore it print('initial contents has no module') @@ -356,7 +352,7 @@ def pick_initial_contents(): test_name = abspath('initial.wat') with open(test_name, 'w') as f: f.write(module) - print(' picked submodule %d from multi-module wast' % index) + print(f' picked submodule {index} from multi-module wast') global FEATURE_OPTS FEATURE_OPTS += [ @@ -452,15 +448,12 @@ def get_export_from_call_line(call_line): # compare two strings, strictly def compare(x, y, context, verbose=True): - if x != y and x != IGNORE and y != IGNORE: + if x != y and IGNORE not in (x, y): message = ''.join([a + '\n' for a in difflib.unified_diff(x.splitlines(), y.splitlines(), fromfile='expected', tofile='actual')]) if verbose: - raise Exception(context + " comparison error, expected to have '%s' == '%s', diff:\n\n%s" % ( - x, y, - message - )) + raise Exception(f"{context} comparison error, expected to have '{x}' == '{y}', diff:\n\n{message}") else: - raise Exception(context + "\nDiff:\n\n%s" % (message)) + raise Exception(f"{context}\nDiff:\n\n{message}") # converts a possibly-signed integer to an unsigned integer @@ -582,14 +575,14 @@ def fix_double(x): def fix_spec_output(out): out = fix_output(out) # spec shows a pointer when it traps, remove that - out = '\n'.join(map(lambda x: x if 'runtime trap' not in x else x[x.find('runtime trap'):], out.splitlines())) + out = '\n'.join(ln if 'runtime trap' not in ln else ln[ln.find('runtime trap'):] for ln in out.splitlines()) # https://github.com/WebAssembly/spec/issues/543 , float consts are messed up - out = '\n'.join(map(lambda x: x if 'f32' not in x and 'f64' not in x else '', out.splitlines())) + out = '\n'.join(ln if 'f32' not in ln and 'f64' not in ln else '' for ln in out.splitlines()) return out ignored_vm_runs = 0 -ignored_vm_run_reasons = dict() +ignored_vm_run_reasons = {} # Notes a VM run that we ignore, and the reason for it (for metrics purposes). @@ -784,7 +777,7 @@ class CompareVMs(TestCaseHandler): frequency = 1 def __init__(self): - super(CompareVMs, self).__init__() + super().__init__() class BinaryenInterpreter: name = 'binaryen interpreter' @@ -856,7 +849,7 @@ class D8Liftoff(D8): name = 'd8_liftoff' def run(self, wasm): - return super(D8Liftoff, self).run(wasm, extra_d8_flags=V8_LIFTOFF_ARGS) + return super().run(wasm, extra_d8_flags=V8_LIFTOFF_ARGS) class D8Turboshaft(D8): name = 'd8_turboshaft' @@ -865,7 +858,7 @@ def run(self, wasm): flags = ['--no-liftoff'] if random.random() < 0.5: flags += ['--no-wasm-generic-wrapper'] - return super(D8Turboshaft, self).run(wasm, extra_d8_flags=flags) + return super().run(wasm, extra_d8_flags=flags) class Wasm2C: name = 'wasm2c' @@ -915,7 +908,7 @@ class Wasm2C2Wasm(Wasm2C): name = 'wasm2c2wasm' def __init__(self): - super(Wasm2C2Wasm, self).__init__() + super().__init__() self.has_emcc = shared.which('emcc') is not None @@ -951,7 +944,7 @@ def can_run(self, wasm): return False # prefer not to run if the wasm is very large, as it can OOM # the JS engine. - return super(Wasm2C2Wasm, self).can_run(wasm) and self.has_emcc and \ + return super().can_run(wasm) and self.has_emcc and \ os.path.getsize(wasm) <= INPUT_SIZE_MEAN def can_compare_to_other(self, other): @@ -1007,7 +1000,7 @@ def run_vms(self, wasm): # compare between the vms on this specific input num_vms = len(relevant_vms) - for i in range(0, num_vms): + for i in range(num_vms): for j in range(i + 1, num_vms): vm1 = relevant_vms[i] vm2 = relevant_vms[j] @@ -1036,8 +1029,8 @@ def handle_pair(self, input, before_wasm, after_wasm, opts): if (b1 != b2): run([in_bin('wasm-dis'), abspath('b1.wasm'), '-o', abspath('b1.wat')] + FEATURE_OPTS) run([in_bin('wasm-dis'), abspath('b2.wasm'), '-o', abspath('b2.wat')] + FEATURE_OPTS) - t1 = open(abspath('b1.wat'), 'r').read() - t2 = open(abspath('b2.wat'), 'r').read() + t1 = open(abspath('b1.wat')).read() + t2 = open(abspath('b2.wat')).read() compare(t1, t2, 'Output must be deterministic.', verbose=False) @@ -1243,12 +1236,12 @@ def filter_exports(wasm, output, keep, keep_defaults=True): graph = [{ 'name': 'outside', 'reaches': [f'export-{export}' for export in keep], - 'root': True + 'root': True, }] for export in keep: graph.append({ 'name': f'export-{export}', - 'export': export + 'export': export, }) with open('graph.json', 'w') as f: @@ -1741,7 +1734,7 @@ def handle_pair(self, input, before_wasm, after_wasm, opts): cmd = [shared.V8] # The flags are given in the flags file - we do *not* use our normal # flags here! - with open(flags_file, 'r') as f: + with open(flags_file) as f: flags = f.read() cmd += flags.split(' ') # Get V8's extra fuzzing flags, the same as the ClusterFuzz runner does @@ -2372,7 +2365,7 @@ def test_one(random_input, given_wasm): # on them in the same amount of time. NUM_PAIR_HANDLERS = 3 used_handlers = set() - for i in range(NUM_PAIR_HANDLERS): + for _ in range(NUM_PAIR_HANDLERS): testcase_handler = random.choice(filtered_handlers) if testcase_handler in used_handlers: continue @@ -2393,7 +2386,7 @@ def write_commands(commands, filename): with open(filename, 'w') as f: f.write('set -e\n') for command in commands: - f.write('echo "%s"\n' % command) + f.write(f'echo "{command}"\n') pre = 'BINARYEN_PASS_DEBUG=%s ' % (os.environ.get('BINARYEN_PASS_DEBUG') or '0') f.write(pre + command + ' &> /dev/null\n') f.write('echo "ok"\n') @@ -2712,7 +2705,7 @@ def get_random_opts(): (We can't automatically reduce this testcase since we can only run the reducer on valid wasm files.) ================================================================================ - ''' % {'seed': seed}) +''') break # show some useful info about filing a bug and reducing the # testcase (to make reduction simple, save "original.wasm" on @@ -2724,23 +2717,30 @@ def get_random_opts(): auto_init = '' if not shared.options.auto_initial_contents: auto_init = '--no-auto-initial-contents' - with open('reduce.sh', 'w') as reduce_sh: - reduce_sh.write('''\ + wasm_opt = in_bin('wasm-opt') + binaryen_bin = shared.options.binaryen_bin + temp_wasm = abspath('t.wasm') + working_wasm = abspath('w.wasm') + wasm_reduce = in_bin('wasm-reduce') + reduce_sh = abspath('reduce.sh') + features = ' '.join(FEATURE_OPTS) + with open('reduce.sh', 'w') as f: + f.write(f'''\ # check the input is even a valid wasm file echo "The following value should be 0:" -%(wasm_opt)s %(features)s %(temp_wasm)s +{wasm_opt} {features} {temp_wasm} echo " " $? echo "The following value should be >0:" if [ -z "$BINARYEN_FIRST_WASM" ]; then # run the command normally - ./scripts/fuzz_opt.py %(auto_init)s --binaryen-bin %(bin)s %(seed)d %(temp_wasm)s > o 2> e + ./scripts/fuzz_opt.py {auto_init} --binaryen-bin {binaryen_bin} {seed} {temp_wasm} > o 2> e else # BINARYEN_FIRST_WASM was provided so we should actually reduce the *second* # file. pass the first one in as the main file, and use the env var for the # second. - BINARYEN_SECOND_WASM=%(temp_wasm)s ./scripts/fuzz_opt.py %(auto_init)s --binaryen-bin %(bin)s %(seed)d $BINARYEN_FIRST_WASM > o 2> e + BINARYEN_SECOND_WASM={temp_wasm} ./scripts/fuzz_opt.py {auto_init} --binaryen-bin {binaryen_bin} {seed} $BINARYEN_FIRST_WASM > o 2> e fi echo " " $? @@ -2760,38 +2760,31 @@ def get_random_opts(): # To do a "dry run" of what the reducer will do, copy the original file to the # test file that this script will run on, # -# cp %(original_wasm)s %(temp_wasm)s +# cp {original_wasm} {temp_wasm} # # and then run # -# bash %(reduce_sh)s +# bash {reduce_sh} # # You may also need to add --timeout 5 or such if the testcase is a slow one. # # If the testcase handler uses a second wasm file, you may be able to reduce it # using BINARYEN_SECOND_WASM. # - ''' % {'wasm_opt': in_bin('wasm-opt'), - 'bin': shared.options.binaryen_bin, - 'seed': seed, - 'auto_init': auto_init, - 'original_wasm': original_wasm, - 'temp_wasm': abspath('t.wasm'), - 'features': ' '.join(FEATURE_OPTS), - 'reduce_sh': abspath('reduce.sh')}) - - print('''\ +''') + + print(f'''\ ================================================================================ You found a bug! Please report it with - seed: %(seed)d + seed: {seed} and the exact version of Binaryen you found it on, plus the exact Python version (hopefully deterministic random numbers will be identical). -You can run that testcase again with "fuzz_opt.py %(seed)d" +You can run that testcase again with "fuzz_opt.py {seed}" -The initial wasm file used here is saved as %(original_wasm)s +The initial wasm file used here is saved as {original_wasm} You can reduce the testcase by running this now: @@ -2799,7 +2792,7 @@ def get_random_opts(): vvvv -%(wasm_reduce)s %(features)s %(original_wasm)s '--command=bash %(reduce_sh)s' -t %(temp_wasm)s -w %(working_wasm)s +{wasm_reduce} {features} {original_wasm} '--command=bash {reduce_sh}' -t {temp_wasm} -w {working_wasm} ^^^^ @@ -2819,18 +2812,12 @@ def get_random_opts(): the wasm for fuzzing in each iteration, by adding BINARYEN_TRUST_GIVEN_WASM=1 in the env.) -You can also read "%(reduce_sh)s" which has been filled out for you and includes +You can also read "{reduce_sh}" which has been filled out for you and includes docs and suggestions. -After reduction, the reduced file will be in %(working_wasm)s +After reduction, the reduced file will be in {working_wasm} ================================================================================ - ''' % {'seed': seed, - 'original_wasm': original_wasm, - 'temp_wasm': abspath('t.wasm'), - 'working_wasm': abspath('w.wasm'), - 'wasm_reduce': in_bin('wasm-reduce'), - 'reduce_sh': abspath('reduce.sh'), - 'features': ' '.join(FEATURE_OPTS)}) +''') break if given_seed is not None: break @@ -2841,8 +2828,8 @@ def get_random_opts(): if given_seed is not None: if not given_seed_error: - print('(finished running seed %d without error)' % given_seed) + print(f'(finished running seed {given_seed} without error)') sys.exit(0) else: - print('(finished running seed %d, see error above)' % given_seed) + print(f'(finished running seed {given_seed}, see error above)') sys.exit(given_seed_error) diff --git a/scripts/fuzz_passes.py b/scripts/fuzz_passes.py index f9ee85a1d65..528de33e0b6 100755 --- a/scripts/fuzz_passes.py +++ b/scripts/fuzz_passes.py @@ -25,7 +25,6 @@ Other parameters after the first are used when calling the program. ''' -from __future__ import print_function import os import random diff --git a/scripts/fuzz_passes_wast.py b/scripts/fuzz_passes_wast.py index 0e2ea29525f..19c76d33410 100755 --- a/scripts/fuzz_passes_wast.py +++ b/scripts/fuzz_passes_wast.py @@ -22,7 +22,6 @@ Usage: Provide the filename of the wast. ''' -from __future__ import print_function import os import random diff --git a/scripts/fuzz_relooper.py b/scripts/fuzz_relooper.py index fe600baade4..7ee6525b160 100755 --- a/scripts/fuzz_relooper.py +++ b/scripts/fuzz_relooper.py @@ -18,7 +18,7 @@ This fuzzes the relooper using the C API. ''' -from __future__ import print_function +# ruff: noqa: UP031 import difflib import os @@ -69,10 +69,10 @@ def random_code(): return random.randint(1, code_max) for i in range(num): - b = set([]) + b = set() bs = random.randint(1, max(1, round(density * random.random() * (num - 1)))) - for j in range(bs): + for _ in range(bs): b.add(random.randint(1, num - 1)) b = list(b) defaults[i] = random.choice(b) @@ -83,12 +83,9 @@ def random_code(): print(counter, ':', num, density, optimize, code_likelihood, code_max, max_printed, ', seed =', seed) counter += 1 - for temp in ['fuzz.wasm', 'fuzz.wast', 'fast.txt', 'fuzz.slow.js', - 'fuzz.c']: - try: + for temp in ['fuzz.wasm', 'fuzz.wast', 'fast.txt', 'fuzz.slow.js', 'fuzz.c']: + if os.path.exists(temp): os.unlink(temp) - except OSError: - pass # parts entry = ''' diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index 0ac80c64e31..ba7d150a442 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -16,7 +16,7 @@ import sys -if sys.version_info < (3, 10): +if sys.version_info < (3, 10): # noqa: UP036 print("python 3.10 required") sys.exit(1) @@ -776,7 +776,7 @@ def instruction_parser(): printer = CodePrinter() printer.print_line("auto op = *keyword;") - printer.print_line("char buf[{}] = {{}};".format(inst_length + 1)) + printer.print_line(f"char buf[{inst_length + 1}] = {{}};") printer.print_line("// Ensure we do not copy more than the buffer can hold") printer.print_line("if (op.size() >= sizeof(buf)) {") printer.print_line(" goto parse_error;") @@ -788,16 +788,16 @@ def print_leaf(expr, inst): expr = expr.replace("()", "(ctx, pos, annotations)") else: expr = expr.replace("(", "(ctx, pos, annotations, ") - printer.print_line("if (op == \"{inst}\"sv) {{".format(inst=inst)) + printer.print_line(f"if (op == \"{inst}\"sv) {{") with printer.indent(): - printer.print_line("CHECK_ERR({expr});".format(expr=expr)) + printer.print_line(f"CHECK_ERR({expr});") printer.print_line("return Ok{};") printer.print_line("}") printer.print_line("goto parse_error;") def emit(node, idx=0): assert node.children - printer.print_line("switch (buf[{}]) {{".format(idx)) + printer.print_line(f"switch (buf[{idx}]) {{") with printer.indent(): if node.expr: printer.print_line("case '\\0':") @@ -806,13 +806,13 @@ def emit(node, idx=0): children = sorted(node.children.items(), key=lambda pair: pair[0]) for prefix, child in children: if child.children: - printer.print_line("case '{}': {{".format(prefix[0])) + printer.print_line(f"case '{prefix[0]}': {{") with printer.indent(): emit(child, idx + len(prefix)) printer.print_line("}") else: assert child.expr - printer.print_line("case '{}':".format(prefix[0])) + printer.print_line(f"case '{prefix[0]}':") with printer.indent(): print_leaf(child.expr, child.inst) printer.print_line("default: goto parse_error;") diff --git a/scripts/not.py b/scripts/not.py index 98898f451e3..a45d18de437 100755 --- a/scripts/not.py +++ b/scripts/not.py @@ -14,8 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import subprocess +import sys # Emulate the `not` tool from LLVM's test infrastructure for use with lit and diff --git a/scripts/port_passes_tests_to_lit.py b/scripts/port_passes_tests_to_lit.py index 6e82c455136..ea1dabeebbc 100755 --- a/scripts/port_passes_tests_to_lit.py +++ b/scripts/port_passes_tests_to_lit.py @@ -22,7 +22,6 @@ import subprocess import sys - script_dir = os.path.dirname(__file__) test_dir = os.path.join(os.path.dirname(script_dir), 'test') @@ -70,7 +69,7 @@ def port_test(args, test): notice = (';; NOTE: This test was ported using' ' port_passes_tests_to_lit.py and could be cleaned up.') - with open(test, 'r') as src_file: + with open(test) as src_file: with open(dest, 'w') as dest_file: print(notice, file=dest_file) print('', file=dest_file) @@ -87,7 +86,7 @@ def port_test(args, test): if not args.no_delete: for f in glob.glob(test.replace('.wast', '.*')): # Do not delete binary tests with the same name - if f.endswith('.wasm') or f.endswith('.bin.txt'): + if f.endswith(('.wasm', '.bin.txt')): continue os.remove(f) if args.git_add: diff --git a/scripts/test/binaryenjs.py b/scripts/test/binaryenjs.py index 392e9df59dc..4e102030492 100644 --- a/scripts/test/binaryenjs.py +++ b/scripts/test/binaryenjs.py @@ -15,24 +15,23 @@ import os import subprocess -from . import shared -from . import support +from . import shared, support def make_js_test_header(binaryen_js): # common wrapper code for JS tests, waiting for binaryen.js to become ready # and providing common utility used by all tests: - return ''' -import Binaryen from "%s"; + return f''' +import Binaryen from "{binaryen_js}"; var binaryen = await Binaryen() // avoid stdout/stderr ordering issues in some js shells - use just stdout console.warn = console.error = console.log; -function assert(x) { +function assert(x) {{ if (!x) throw Error('Test assertion failed'); -} -''' % binaryen_js +}} +''' def make_js_test(input_js_file, binaryen_js): diff --git a/scripts/test/fuzzing.py b/scripts/test/fuzzing.py index d5bf11a9cb3..9c0125a9206 100644 --- a/scripts/test/fuzzing.py +++ b/scripts/test/fuzzing.py @@ -14,7 +14,6 @@ import os - # Tests that the fuzzers should not operate on. unfuzzable = [ # Float16 is still experimental. diff --git a/scripts/test/generate_lld_tests.py b/scripts/test/generate_lld_tests.py index 254d73349bc..3593931548a 100755 --- a/scripts/test/generate_lld_tests.py +++ b/scripts/test/generate_lld_tests.py @@ -14,12 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function import os import sys import shared + import support @@ -57,7 +57,7 @@ def generate_wat_files(llvm_bin, emscripten_sysroot): '-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', - '-Xclang', '-I%s/include' % emscripten_sysroot, + '-Xclang', f'-I{emscripten_sysroot}/include' '-O1', ] @@ -79,11 +79,10 @@ def generate_wat_files(llvm_bin, emscripten_sysroot): compile_cmd.append('-fvisibility=default') link_cmd.append('-shared') link_cmd.append('--experimental-pic') + elif 'reserved_func_ptr' in src_file: + link_cmd.append('--entry=__main_argc_argv') else: - if 'reserved_func_ptr' in src_file: - link_cmd.append('--entry=__main_argc_argv') - else: - link_cmd.append('--entry=main') + link_cmd.append('--entry=main') if is_64: compile_cmd.append('--target=wasm64-emscripten') diff --git a/scripts/test/lld.py b/scripts/test/lld.py index 91c7e57d671..6f4b2be803b 100644 --- a/scripts/test/lld.py +++ b/scripts/test/lld.py @@ -13,8 +13,8 @@ # limitations under the License. import os -from . import shared -from . import support + +from . import shared, support def args_for_finalize(filename): diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 6de9e5dd266..526b125c182 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -12,17 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function import argparse import difflib import fnmatch import glob import os -from pathlib import Path import shutil +import stat import subprocess import sys +from pathlib import Path # The C++ standard whose features are required to build Binaryen. # Keep in sync with CMakeLists.txt CXX_STANDARD @@ -175,7 +175,7 @@ def is_exe(fpath): # Prefer tools installed using third_party/setup.py os.path.join(options.binaryen_root, 'third_party', 'mozjs'), os.path.join(options.binaryen_root, 'third_party', 'v8'), - os.path.join(options.binaryen_root, 'third_party', 'wabt', 'bin') + os.path.join(options.binaryen_root, 'third_party', 'wabt', 'bin'), ] + os.environ['PATH'].split(os.pathsep) for path in paths: path = path.strip('"') @@ -288,7 +288,6 @@ def delete_from_orbit(filename): if not os.path.exists(filename): return try: - import stat os.chmod(filename, os.stat(filename).st_mode | stat.S_IWRITE) def remove_readonly_and_try_again(func, path, exc_info): @@ -296,16 +295,16 @@ def remove_readonly_and_try_again(func, path, exc_info): os.chmod(path, os.stat(path).st_mode | stat.S_IWRITE) func(path) else: - raise + raise exc_info[1] shutil.rmtree(filename, onerror=remove_readonly_and_try_again) except OSError: pass -def run_process(cmd, check=True, input=None, decode_output=True, *args, **kw): +def run_process(cmd, check=True, input=None, decode_output=True, *args, **kwargs): if input and type(input) is str: input = bytes(input, 'utf-8') - ret = subprocess.run(cmd, check=check, input=input, *args, **kw) + ret = subprocess.run(cmd, *args, check=check, input=input, **kwargs) if decode_output and ret.stdout is not None: ret.stdout = ret.stdout.decode('utf-8') if ret.stderr is not None: @@ -329,7 +328,7 @@ def fail(actual, expected, fromfile='expected'): expected.split('\n'), actual.split('\n'), fromfile=fromfile, tofile='actual') diff_str = ''.join([a.rstrip() + '\n' for a in diff_lines])[:] - fail_with_error("incorrect output, diff:\n\n%s" % diff_str) + fail_with_error(f'incorrect output, diff:\n\n{diff_str}') def fail_if_not_identical(actual, expected, fromfile='expected'): @@ -503,7 +502,7 @@ def _can_run_spec_test(test): def binary_format_check(wast, verify_final_result=True, wasm_as_args=['-g'], - binary_suffix='.fromBinary', base_name=None, stdout=None, stderr=None): + binary_suffix='.fromBinary', base_name=None, stdout=None): # checks we can convert the wast to binary and back as_file = f"{base_name}-a.wasm" if base_name is not None else "a.wasm" @@ -545,9 +544,8 @@ def with_pass_debug(check): finally: if old_pass_debug is not None: os.environ['BINARYEN_PASS_DEBUG'] = old_pass_debug - else: - if 'BINARYEN_PASS_DEBUG' in os.environ: - del os.environ['BINARYEN_PASS_DEBUG'] + elif 'BINARYEN_PASS_DEBUG' in os.environ: + del os.environ['BINARYEN_PASS_DEBUG'] # checks if we are on windows, and if so logs out that a test is being skipped, @@ -555,7 +553,7 @@ def with_pass_debug(check): # windows, so that we can easily find which tests are skipped. def skip_if_on_windows(name): if get_platform() == 'windows': - print('skipping test "%s" on windows' % name) + print(f'skipping test "{name}" on windows') return True return False diff --git a/scripts/test/support.py b/scripts/test/support.py index ed15c819edf..a8926d8c658 100644 --- a/scripts/test/support.py +++ b/scripts/test/support.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import io import filecmp +import io import os import re import shutil @@ -103,7 +103,7 @@ def split_wast(wastFile): wast = None if not wastFile.endswith('.wasm'): try: - wast = open(wastFile, 'r').read() + wast = open(wastFile).read() except Exception: pass diff --git a/scripts/test/wasm2js.py b/scripts/test/wasm2js.py index 3c70c061609..3a45da7a9ab 100644 --- a/scripts/test/wasm2js.py +++ b/scripts/test/wasm2js.py @@ -15,8 +15,7 @@ import os import subprocess -from . import shared -from . import support +from . import shared, support basic_tests = shared.get_tests(os.path.join(shared.options.binaryen_test, 'lit', 'basic')) # memory64 is not supported in wasm2js yet (but may be with BigInt eventually). @@ -40,9 +39,8 @@ def check_for_stale_files(): return # TODO(sbc): Generalize and apply other test suites - all_tests = [] - for t in basic_tests + spec_tests + wasm2js_tests: - all_tests.append(os.path.basename(os.path.splitext(t)[0])) + all_tests = basic_tests + spec_tests + wasm2js_tests + all_tests = [os.path.basename(os.path.splitext(t)[0]) for t in all_tests] all_files = os.listdir(shared.get_test_dir('wasm2js')) for f in all_files: @@ -50,7 +48,7 @@ def check_for_stale_files(): if prefix in [t.split('.')[0] for t in assert_tests]: continue if prefix not in all_tests: - shared.fail_with_error('orphan test output: %s' % f) + shared.fail_with_error(f'orphan test output: {f}') def test_wasm2js_output(): diff --git a/scripts/test/wasm_opt.py b/scripts/test/wasm_opt.py index e5f4cdac836..3c97104f03a 100644 --- a/scripts/test/wasm_opt.py +++ b/scripts/test/wasm_opt.py @@ -16,8 +16,7 @@ import shutil import subprocess -from . import shared -from . import support +from . import shared, support def test_wasm_opt(): diff --git a/scripts/update_help_checks.py b/scripts/update_help_checks.py index 1756a0686d4..6acaf9ee126 100755 --- a/scripts/update_help_checks.py +++ b/scripts/update_help_checks.py @@ -19,7 +19,7 @@ import os import subprocess -import test.shared as shared +from test import shared script_dir = os.path.dirname(__file__) root_dir = os.path.dirname(script_dir) diff --git a/scripts/update_lit_checks.py b/scripts/update_lit_checks.py index 753b967ca41..b641fc78bff 100755 --- a/scripts/update_lit_checks.py +++ b/scripts/update_lit_checks.py @@ -235,9 +235,7 @@ def update_test(args, test, lines, tmp): command_output = get_command_output(args, output_kind, test, lines, tmp) - prefixes = set(prefix - for module_output in command_output - for prefix in module_output.keys()) + prefixes = {prefix for module_output in command_output for prefix in module_output.keys()} check_line_re = re.compile(r'^\s*;;\s*(' + '|'.join(prefixes) + r')(?:-NEXT|-LABEL|-NOT)?:.*$') @@ -269,8 +267,7 @@ def emit_checks(indent, prefix, lines): def pad(line): return line if not line or line.startswith(' ') else ' ' + line output_lines.append(f'{indent};; {prefix}: {pad(lines[0])}') - for line in lines[1:]: - output_lines.append(f'{indent};; {prefix}-NEXT:{pad(line)}') + output_lines.extend(f'{indent};; {prefix}-NEXT:{pad(line)}' for line in lines[1:]) input_modules = [m.split('\n') for m in split_modules('\n'.join(lines))] if len(input_modules) > len(command_output): @@ -301,7 +298,7 @@ def pad(line): # name, emit all the items up to and including the matching # item has_item = False - for kind_name, lines in items: + for kind_name, _lines in items: if name and (kind, name) == kind_name: has_item = True break diff --git a/test/unit/test_asyncify.py b/test/unit/test_asyncify.py index 301b91d00b7..3217eb4b21a 100644 --- a/test/unit/test_asyncify.py +++ b/test/unit/test_asyncify.py @@ -3,6 +3,7 @@ import tempfile from scripts.test import shared + from . import utils @@ -13,7 +14,7 @@ def test(args): shared.run_process(shared.WASM_OPT + args + [self.input_path('asyncify-sleep.wat'), '--asyncify', '-o', 'a.wasm']) shared.run_process(shared.WASM_OPT + args + [self.input_path('asyncify-coroutine.wat'), '--asyncify', '-o', 'b.wasm']) shared.run_process(shared.WASM_OPT + args + [self.input_path('asyncify-stackOverflow.wat'), '--asyncify', '-o', 'c.wasm']) - print(' file size: %d' % os.path.getsize('a.wasm')) + print(f' file size: {os.path.getsize("a.wasm")}') if shared.NODEJS: shared.run_process([shared.NODEJS, self.input_path('asyncify.js')], capture_output=True) @@ -29,7 +30,7 @@ def test(input_file): shared.run_process(shared.WASM_OPT + [input_file, '--asyncify', '-o', 'a.wasm']) shared.run_process(shared.WASM_DIS + ['a.wasm', '-o', 'a.wat']) output = shared.run_process(shared.WASM_SHELL + ['a.wat'], capture_output=True).stdout - with open(self.input_path('asyncify-pure.txt'), 'r') as f: + with open(self.input_path('asyncify-pure.txt')) as f: self.assert_equal_ignoring_line_endings(f.read(), output) # test wat input @@ -67,7 +68,7 @@ def test(list_name): args = shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '--asyncify', '--pass-arg=asyncify-onlylist@main', - '--pass-arg=asyncify-%slist@main' % list_name] + f'--pass-arg=asyncify-{list_name}list@main'] proc = shared.run_process(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) self.assertNotEqual(proc.returncode, 0, 'must error on using both lists at once') self.assertIn('It makes no sense to use both an asyncify only-list together with another list', proc.stdout) @@ -92,7 +93,7 @@ def test(args): temp = tempfile.NamedTemporaryFile().name with open(temp, 'w') as f: f.write('env.sleep') - response = test(['--pass-arg=asyncify-imports@@%s' % temp]) + response = test([f'--pass-arg=asyncify-imports@@{temp}']) self.assertEqual(normal, response) without = test(['--pass-arg=asyncify-imports@without.anything']) self.assertNotEqual(normal, without) diff --git a/test/unit/test_cluster_fuzz.py b/test/unit/test_cluster_fuzz.py index 8fca3be80a9..d1ffc10253c 100644 --- a/test/unit/test_cluster_fuzz.py +++ b/test/unit/test_cluster_fuzz.py @@ -10,6 +10,7 @@ import unittest from scripts.test import shared + from . import utils @@ -78,7 +79,7 @@ def generate_testcases(self, N, testcase_dir): self.assertEqual(proc.stdout.count('Created testcase:'), N) # We should have actually created them. - for i in range(0, N + 2): + for i in range(N + 2): fuzz_file = os.path.join(testcase_dir, f'fuzz-binaryen-{i}.js') flags_file = os.path.join(testcase_dir, f'flags-binaryen-{i}.js') # We actually emit the range [1, N], so 0 or N+1 should not exist. @@ -135,7 +136,7 @@ def test_fuzz_passes(self): # probability then something is very wrong, and we'd like to see # errors.) seen_num_passes = set() - for i in range(100): + for _ in range(100): os.environ['BINARYEN_PASS_DEBUG'] = '1' try: proc = self.generate_testcases(N, temp_dir.name) diff --git a/test/unit/test_dwarf.py b/test/unit/test_dwarf.py index 809c4af05dc..69367650000 100644 --- a/test/unit/test_dwarf.py +++ b/test/unit/test_dwarf.py @@ -2,6 +2,7 @@ import subprocess from scripts.test import shared + from . import utils diff --git a/test/unit/test_features.py b/test/unit/test_features.py index 2647ff84717..f33328cb488 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -1,6 +1,7 @@ import os from scripts.test import shared + from . import utils diff --git a/test/unit/test_finalize.py b/test/unit/test_finalize.py index 6b173f6c625..7bb5f980484 100644 --- a/test/unit/test_finalize.py +++ b/test/unit/test_finalize.py @@ -1,4 +1,5 @@ from scripts.test import shared + from . import utils @@ -6,7 +7,7 @@ class EmscriptenFinalizeTest(utils.BinaryenTestCase): def do_output_test(self, args): # without any output file specified, don't error, don't write the wasm p = shared.run_process(shared.WASM_EMSCRIPTEN_FINALIZE + [ - self.input_path('empty_lld.wat') + self.input_path('empty_lld.wat'), ] + args, capture_output=True) return p.stdout diff --git a/test/unit/test_fuzz_empty_data.py b/test/unit/test_fuzz_empty_data.py index 3206fcead0a..6265aac7a11 100644 --- a/test/unit/test_fuzz_empty_data.py +++ b/test/unit/test_fuzz_empty_data.py @@ -1,6 +1,8 @@ import os import tempfile + from scripts.test import shared + from . import utils diff --git a/test/unit/test_initial_fuzz.py b/test/unit/test_initial_fuzz.py index 2ddc298846b..d96bd7b27cd 100644 --- a/test/unit/test_initial_fuzz.py +++ b/test/unit/test_initial_fuzz.py @@ -1,5 +1,7 @@ import subprocess + from scripts.test import shared + from . import utils diff --git a/test/unit/test_memory_packing.py b/test/unit/test_memory_packing.py index e2468e689e0..13b9d5ec347 100644 --- a/test/unit/test_memory_packing.py +++ b/test/unit/test_memory_packing.py @@ -1,6 +1,7 @@ import os from scripts.test import shared + from . import utils """Test that MemoryPacking correctly respects the web limitations by not @@ -10,12 +11,12 @@ class MemoryPackingTest(utils.BinaryenTestCase): def test_large_segment(self): data = '"' + (('A' + ('\\00' * 9)) * 100001) + '"' - module = ''' + module = f''' (module (memory 256 256) - (data $d (i32.const 0) %s) + (data $d (i32.const 0) {data}) ) - ''' % data + ''' opts = ['--memory-packing', '--disable-bulk-memory', '--print', '-o', os.devnull] p = shared.run_process(shared.WASM_OPT + opts, input=module, @@ -24,15 +25,15 @@ def test_large_segment(self): '(data $d (i32.const 0) "A")', '(data $d.1 (i32.const 10) "A")', '(data $d.99998 (i32.const 999980) "A")', - '(data $d.99999 (i32.const 999990) "A' + ('\\00' * 9) + 'A")' + '(data $d.99999 (i32.const 999990) "A' + ('\\00' * 9) + 'A")', ] self.assertEqual(p.returncode, 0) for line in output: self.assertIn(line, p.stdout) def test_large_segment_unmergeable(self): - data = '\n'.join('(data (i32.const %i) "A")' % i for i in range(100001)) - module = '(module (memory 256 256) %s)' % data + data = '\n'.join(f'(data (i32.const {i}) "A")' for i in range(100001)) + module = f'(module (memory 256 256) {data})' opts = ['--memory-packing', '--enable-bulk-memory', '--print', '-o', os.devnull] p = shared.run_process(shared.WASM_OPT + opts, input=module, diff --git a/test/unit/test_passes.py b/test/unit/test_passes.py index a8a87c8819b..b98dd1dcdde 100644 --- a/test/unit/test_passes.py +++ b/test/unit/test_passes.py @@ -1,7 +1,9 @@ import os import re import subprocess + from scripts.test import shared + from . import utils diff --git a/test/unit/test_reduce.py b/test/unit/test_reduce.py index 0abba604f06..d1c7094259a 100644 --- a/test/unit/test_reduce.py +++ b/test/unit/test_reduce.py @@ -1,6 +1,7 @@ import subprocess from scripts.test import shared + from . import utils diff --git a/test/unit/test_stack_ir.py b/test/unit/test_stack_ir.py index 191d7eaec29..d672e83ed69 100644 --- a/test/unit/test_stack_ir.py +++ b/test/unit/test_stack_ir.py @@ -1,5 +1,7 @@ import os + from scripts.test import shared + from . import utils diff --git a/test/unit/test_symbolmap.py b/test/unit/test_symbolmap.py index 59ce1847e1e..f21226bb0dd 100644 --- a/test/unit/test_symbolmap.py +++ b/test/unit/test_symbolmap.py @@ -1,4 +1,5 @@ from scripts.test import shared + from . import utils diff --git a/test/unit/test_tail_call_type.py b/test/unit/test_tail_call_type.py index 1221dd0a710..10bd273f02b 100644 --- a/test/unit/test_tail_call_type.py +++ b/test/unit/test_tail_call_type.py @@ -1,6 +1,7 @@ import os from scripts.test import shared + from . import utils diff --git a/test/unit/test_warnings.py b/test/unit/test_warnings.py index cb912f42c16..444989bfaad 100644 --- a/test/unit/test_warnings.py +++ b/test/unit/test_warnings.py @@ -1,26 +1,31 @@ import subprocess from scripts.test import shared + from . import utils +def run(cmd): + return shared.run_process(cmd, stderr=subprocess.PIPE).stderr + + class WarningsText(utils.BinaryenTestCase): def test_warn_on_no_passes(self): - err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-o', 'a.wasm'], stderr=subprocess.PIPE).stderr + err = run(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-o', 'a.wasm']) self.assertIn('warning: no passes specified, not doing any work', err) def test_warn_on_no_output(self): - err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-O1'], stderr=subprocess.PIPE).stderr + err = run(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-O1']) self.assertIn('warning: no output file specified, not emitting output', err) def test_quiet_suppresses_warnings(self): - err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-q'], stderr=subprocess.PIPE).stderr + err = run(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '-q']) self.assertNotIn('warning', err) def test_no_warn_on_print(self): - err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '--print'], stderr=subprocess.PIPE).stderr + err = run(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '--print']) self.assertNotIn('warning: no output file specified, not emitting output', err) def test_no_warn_on_print_function_map(self): - err = shared.run_process(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '--print-function-map'], stderr=subprocess.PIPE).stderr + err = run(shared.WASM_OPT + [self.input_path('asyncify-pure.wat'), '--print-function-map']) self.assertNotIn('warning: no output file specified, not emitting output', err) diff --git a/test/unit/test_web_limitations.py b/test/unit/test_web_limitations.py index 921e02e95bd..9f74814770b 100644 --- a/test/unit/test_web_limitations.py +++ b/test/unit/test_web_limitations.py @@ -1,6 +1,7 @@ import os from scripts.test import shared + from . import utils @@ -10,12 +11,12 @@ def test_many_params(self): disallow.""" params = '(param i32) ' * 1001 - module = ''' + module = f''' (module - (func $foo %s + (func $foo {params} ) ) - ''' % params + ''' p = shared.run_process(shared.WASM_OPT + ['-o', os.devnull], input=module, capture_output=True) self.assertIn('Some VMs may not accept this binary because it has a large number of parameters in function foo.', @@ -26,12 +27,12 @@ def test_many_locals(self): disallow.""" params = '(local i32) ' * 50_001 - module = ''' + module = f''' (module - (func $foo %s + (func $foo {params} ) ) - ''' % params + ''' p = shared.run_process(shared.WASM_OPT + ['-o', os.devnull], input=module, capture_output=True) self.assertIn('Some VMs may not accept this binary because it has a large number of locals in function foo.',