blob: 033533cf29d9b93ca3fc1e689997002697f5954f [file] [log] [blame]
#!/usr/bin/env python3
import argparse
import sys
import os
import glob
import subprocess
import shutil
import multiprocessing as mp
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
INTERPRETER_DIR = os.path.join(SCRIPT_DIR, '..', 'interpreter')
WASM_EXEC = os.path.join(INTERPRETER_DIR, 'wasm')
WAST_TESTS_DIR = os.path.join(SCRIPT_DIR, 'core')
HARNESS_DIR = os.path.join(SCRIPT_DIR, 'harness')
HARNESS_FILES = ['testharness.js', 'testharnessreport.js', 'testharness.css']
WPT_URL_PREFIX = '/resources'
# Helpers.
def run(*cmd):
return subprocess.call(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
# Preconditions.
def ensure_remove_dir(path):
if os.path.exists(path):
shutil.rmtree(path)
def ensure_empty_dir(path):
ensure_remove_dir(path)
os.mkdir(path)
def compile_wasm_interpreter():
print("Recompiling the wasm interpreter...")
result = run('make', '-C', INTERPRETER_DIR, 'clean', 'default')
if result != 0:
print("Couldn't recompile wasm spec interpreter")
sys.exit(1)
print("Done!")
def ensure_wasm_executable(path_to_wasm):
"""
Ensure we have built the wasm spec interpreter.
"""
result = run(path_to_wasm, '-v', '-e', '')
if result != 0:
print('Unable to run the wasm executable')
sys.exit(1)
# JS harness.
def convert_one_wast_file(inputs):
wast_file, js_file = inputs
print('Compiling {} to JS...'.format(wast_file))
return run(WASM_EXEC, wast_file, '-h', '-o', js_file)
def convert_wast_to_js(out_js_dir):
"""Compile all the wast files to JS and store the results in the JS dir."""
inputs = []
for wast_file in glob.glob(os.path.join(WAST_TESTS_DIR, '*.wast')):
# Don't try to compile tests that are supposed to fail.
if '.fail.' in wast_file:
continue
js_filename = os.path.basename(wast_file) + '.js'
js_file = os.path.join(out_js_dir, js_filename)
inputs.append((wast_file, js_file))
pool = mp.Pool(processes=8)
for result in pool.imap_unordered(convert_one_wast_file, inputs):
if result != 0:
print('Error when compiling {} to JS: {}', wast_file, result.stdout)
return [js_file for (wast_file, js_file) in inputs]
def copy_harness_files(out_js_dir, include_harness):
harness_dir = os.path.join(out_js_dir, 'harness')
ensure_empty_dir(harness_dir)
print('Copying JS test harness to the JS out dir...')
for js_file in glob.glob(os.path.join(HARNESS_DIR, '*')):
if os.path.basename(js_file) in HARNESS_FILES and not include_harness:
continue
shutil.copy(js_file, harness_dir)
def build_js(out_js_dir):
print('Building JS...')
convert_wast_to_js(out_js_dir)
copy_harness_files(out_js_dir, False)
print('Done building JS.')
# HTML harness.
HTML_HEADER = """<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>WebAssembly Web Platform Test</title>
</head>
<body>
<script src={WPT_PREFIX}/testharness.js></script>
<script src={WPT_PREFIX}/testharnessreport.js></script>
<script src={PREFIX}/{JS_HARNESS}></script>
<div id=log></div>
"""
HTML_BOTTOM = """
</body>
</html>
"""
def wrap_single_test(js_file):
test_func_name = os.path.basename(js_file).replace('.', '_').replace('-', '_')
content = "(function {}() {{\n".format(test_func_name)
with open(js_file, 'r') as f:
content += f.read()
content += "reinitializeRegistry();\n})();\n"
with open(js_file, 'w') as f:
f.write(content)
def build_html_js(out_dir):
ensure_empty_dir(out_dir)
copy_harness_files(out_dir, True)
tests = convert_wast_to_js(out_dir)
for js_file in tests:
wrap_single_test(js_file)
return tests
def build_html_from_js(tests, html_dir, use_sync):
for js_file in tests:
js_filename = os.path.basename(js_file)
html_filename = js_filename + '.html'
html_file = os.path.join(html_dir, html_filename)
js_harness = "sync_index.js" if use_sync else "async_index.js"
with open(html_file, 'w+') as f:
content = HTML_HEADER.replace('{PREFIX}', './js/harness') \
.replace('{WPT_PREFIX}', './js/harness') \
.replace('{JS_HARNESS}', js_harness)
content += " <script src=./js/{SCRIPT}></script>".replace('{SCRIPT}', js_filename)
content += HTML_BOTTOM
f.write(content)
def build_html(html_dir, js_dir, use_sync):
print("Building HTML tests...")
js_html_dir = os.path.join(html_dir, 'js')
tests = build_html_js(js_html_dir)
print('Building WPT tests from JS tests...')
build_html_from_js(tests, html_dir, use_sync)
print("Done building HTML tests.")
# Front page harness.
def build_front_page(out_dir, js_dir, use_sync):
print('Building front page containing all the HTML tests...')
js_out_dir = os.path.join(out_dir, 'js')
tests = build_html_js(js_out_dir)
front_page = os.path.join(out_dir, 'index.html')
js_harness = "sync_index.js" if use_sync else "async_index.js"
with open(front_page, 'w+') as f:
content = HTML_HEADER.replace('{PREFIX}', './js/harness') \
.replace('{WPT_PREFIX}', './js/harness')\
.replace('{JS_HARNESS}', js_harness)
for js_file in tests:
filename = os.path.basename(js_file)
content += " <script src=./js/{SCRIPT}></script>\n".replace('{SCRIPT}', filename)
content += HTML_BOTTOM
f.write(content)
print('Done building front page!')
# Main program.
def process_args():
parser = argparse.ArgumentParser(description="Helper tool to build the\
multi-stage cross-browser test suite for WebAssembly.")
parser.add_argument('--js',
dest="js_dir",
help="Relative path to the output directory for the pure JS tests.",
type=str)
parser.add_argument('--html',
dest="html_dir",
help="Relative path to the output directory for the Web Platform tests.",
type=str)
parser.add_argument('--front',
dest="front_dir",
help="Relative path to the output directory for the front page.",
type=str)
parser.add_argument('--dont-recompile',
action="store_const",
dest="compile",
help="Don't recompile the wasm spec interpreter (by default, it is)",
const=False,
default=True)
parser.add_argument('--use-sync',
action="store_const",
dest="use_sync",
help="Let the tests use the synchronous JS API (by default, it does not)",
const=True,
default=False)
return parser.parse_args(), parser
if __name__ == '__main__':
args, parser = process_args()
js_dir = args.js_dir
html_dir = args.html_dir
front_dir = args.front_dir
if front_dir is None and js_dir is None and html_dir is None:
print('At least one mode must be selected.\n')
parser.print_help()
sys.exit(1)
if args.compile:
compile_wasm_interpreter()
ensure_wasm_executable(WASM_EXEC)
if js_dir is not None:
ensure_empty_dir(js_dir)
build_js(js_dir)
if html_dir is not None:
ensure_empty_dir(html_dir)
build_html(html_dir, js_dir, args.use_sync)
if front_dir is not None:
ensure_empty_dir(front_dir)
build_front_page(front_dir, js_dir, args.use_sync)
print('Done!')