Skip to content

Add wast source information to JS-converted test cases #1919

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: wasm-3.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 28 additions & 23 deletions interpreter/script/js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function register(name, instance) {
registry[name] = instance.exports;
}

function module(bytes, valid = true) {
function module(bytes, loc, valid = true) {
let buffer = new ArrayBuffer(bytes.length);
let view = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; ++i) {
Expand Down Expand Up @@ -92,8 +92,8 @@ function run(action) {
action();
}

function assert_malformed(bytes) {
try { module(bytes, false) } catch (e) {
function assert_malformed(bytes, loc) {
try { module(bytes, loc, false) } catch (e) {
if (e instanceof WebAssembly.CompileError) return;
}
throw new Error("Wasm decoding failure expected");
Expand All @@ -103,8 +103,8 @@ function assert_malformed_custom(bytes) {
return;
}

function assert_invalid(bytes) {
try { module(bytes, false) } catch (e) {
function assert_invalid(bytes, loc) {
try { module(bytes, loc, false) } catch (e) {
if (e instanceof WebAssembly.CompileError) return;
}
throw new Error("Wasm validation failure expected");
Expand All @@ -128,7 +128,7 @@ function assert_uninstantiable(mod) {
throw new Error("Wasm trap expected");
}

function assert_trap(action) {
function assert_trap(action, loc) {
try { action() } catch (e) {
if (e instanceof WebAssembly.RuntimeError) return;
}
Expand All @@ -150,7 +150,7 @@ function assert_exhaustion(action) {
throw new Error("Wasm resource exhaustion expected");
}

function assert_return(action, ...expected) {
function assert_return(action, loc, ...expected) {
let actual = action();
if (actual === undefined) {
actual = [];
Expand Down Expand Up @@ -749,7 +749,7 @@ let rec of_definition def =
let of_wrapper env x_opt name wrap_action wrap_assertion at =
let x = of_inst_opt env x_opt in
let bs = wrap name wrap_action wrap_assertion at in
"call(instance(module(" ^ of_bytes bs ^ "), " ^
"call(instance(module(" ^ of_bytes bs ^ ", \"wrapper\"), " ^
"exports(" ^ x ^ ")), " ^ " \"run\", [])"

let of_action env act =
Expand All @@ -775,45 +775,50 @@ let of_action env act =
| _ -> None
)

let of_assertion' env act name args wrapper_opt =
let of_assertion' env act loc name args wrapper_opt =
let act_js, act_wrapper_opt = of_action env act in
let js = name ^ "(() => " ^ act_js ^ String.concat ", " ("" :: args) ^ ")" in
let js = name ^ "(() => " ^ act_js ^ loc ^ String.concat ", " ("" :: args) ^ ")" in
match act_wrapper_opt with
| None -> js ^ ";"
| Some (act_wrapper, out) ->
let run_name, wrapper =
match wrapper_opt with
| None -> name, run
| Some wrapper -> "run", wrapper
in run_name ^ "(() => " ^ act_wrapper (wrapper out) act.at ^ "); // " ^ js
in run_name ^ "(() => " ^ act_wrapper (wrapper out) act.at ^ loc ^ "); // " ^ js

let of_assertion env ass =
let loc = Filename.basename ass.at.left.file ^
":" ^ string_of_int ass.at.left.line in
let loc_as_arg = ", \"" ^ String.escaped loc ^ "\"" in
match ass.it with
| AssertMalformed (def, _) ->
"assert_malformed(" ^ of_definition def ^ ");"
"assert_malformed(" ^ of_definition def ^ loc_as_arg ^ ");"
| AssertMalformedCustom (def, _) ->
"assert_malformed_custom(" ^ of_definition def ^ ");"
"assert_malformed_custom(" ^ of_definition def ^ loc_as_arg ^ ");"
| AssertInvalid (def, _) ->
"assert_invalid(" ^ of_definition def ^ ");"
"assert_invalid(" ^ of_definition def ^ loc_as_arg ^ ");"
| AssertInvalidCustom (def, _) ->
"assert_invalid_custom(" ^ of_definition def ^ ");"
"assert_invalid_custom(" ^ of_definition def ^ loc_as_arg ^ ");"
| AssertUnlinkable (x_opt, _) ->
"assert_unlinkable(" ^ of_mod_opt env x_opt ^ ");"
| AssertUninstantiable (x_opt, _) ->
"assert_uninstantiable(" ^ of_mod_opt env x_opt ^ ");"
| AssertReturn (act, ress) ->
of_assertion' env act "assert_return" (List.map of_result ress)
of_assertion' env act loc_as_arg "assert_return" (List.map of_result ress)
(Some (assert_return ress))
| AssertTrap (act, _) ->
of_assertion' env act "assert_trap" [] None
of_assertion' env act loc_as_arg "assert_trap" [] None
| AssertExhaustion (act, _) ->
of_assertion' env act "assert_exhaustion" [] None
of_assertion' env act loc_as_arg "assert_exhaustion" [] None
| AssertException act ->
of_assertion' env act "assert_exception" [] None
of_assertion' env act loc_as_arg "assert_exception" [] None

let of_command env cmd =
"\n// " ^ Filename.basename cmd.at.left.file ^
":" ^ string_of_int cmd.at.left.line ^ "\n" ^
let loc = String.escaped (Filename.basename cmd.at.left.file ^
":" ^ string_of_int cmd.at.left.line) in
let loc_as_arg = ", \"" ^ loc ^ "\"" in
"\n// " ^ loc ^ "\n" ^
match cmd.it with
| Module (x_opt, def) ->
let rec unquote def =
Expand All @@ -823,7 +828,7 @@ let of_command env cmd =
| Quoted (_, s) ->
unquote (snd (Parse.Module.parse_string ~offset:s.at s.it))
in bind_mod env x_opt (unquote def);
"let " ^ current_mod env ^ " = module(" ^ of_definition def ^ ");\n" ^
"let " ^ current_mod env ^ " = module(" ^ of_definition def ^ loc_as_arg ^ ");\n" ^
(if x_opt = None then "" else
"let " ^ of_mod_opt env x_opt ^ " = " ^ current_mod env ^ ";\n")
| Instance (x1_opt, x2_opt) ->
Expand All @@ -835,7 +840,7 @@ let of_command env cmd =
| Register (name, x_opt) ->
"register(" ^ of_name name ^ ", " ^ of_inst_opt env x_opt ^ ")\n"
| Action act ->
of_assertion' env act "run" [] None ^ "\n"
of_assertion' env act loc_as_arg "run" [] None ^ "\n"
| Assertion ass ->
of_assertion env ass ^ "\n"
| Meta _ -> assert false
Expand Down
32 changes: 17 additions & 15 deletions test/harness/async_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ function binary(bytes) {
/**
* Returns a compiled module, or throws if there was an error at compilation.
*/
function module(bytes, valid = true) {
const test = valid
? "Test that WebAssembly compilation succeeds"
: "Test that WebAssembly compilation fails";
function module(bytes, source, valid = true) {
const test = `${ valid ? "Test that WebAssembly compilation succeeds" :
"Test that WebAssembly compilation fails"} (${source})`;

const loc = new Error().stack.toString().replace("Error", "");
let buffer = binary(bytes);
let validated = WebAssembly.validate(buffer);
Expand All @@ -167,6 +167,7 @@ function module(bytes, valid = true) {
uniqueTest(_ => {
assert_true(valid, loc);
}, test);
module.source = source;
return module;
},
error => {
Expand All @@ -181,26 +182,27 @@ function module(bytes, valid = true) {
return chain;
}

function assert_invalid(bytes) {
module(bytes, EXPECT_INVALID);
function assert_invalid(bytes, source) {
module(bytes, source, EXPECT_INVALID);
}

const assert_malformed = assert_invalid;

function assert_invalid_custom(bytes) {
module(bytes);
function assert_invalid_custom(bytes, source) {
module(bytes, source);
}

const assert_malformed_custom = assert_invalid_custom;

function instance(module, imports, valid = true) {
const test = valid
let test = valid
? "Test that WebAssembly instantiation succeeds"
: "Test that WebAssembly instantiation fails";
const loc = new Error().stack.toString().replace("Error", "");
chain = Promise.all([module, imports, chain])
.then(values => {
let imports = values[1] ? values[1] : registry;
test += ` (${values[0].source})`;
return WebAssembly.instantiate(values[0], imports);
})
.then(
Expand Down Expand Up @@ -235,8 +237,8 @@ function call(instance, name, args) {
});
}

function run(action) {
const test = "Run a WebAssembly test without special assertions";
function run(action, source) {
const test = `Run a WebAssembly test without special assertions (${source})`;
const loc = new Error().stack.toString().replace("Error", "");
chain = Promise.all([chain, action()])
.then(
Expand All @@ -256,8 +258,8 @@ function run(action) {
.catch(_ => {});
}

function assert_trap(action) {
const test = "Test that a WebAssembly code traps";
function assert_trap(action, source) {
const test = `Test that a WebAssembly code traps (${source})`;
const loc = new Error().stack.toString().replace("Error", "");
chain = Promise.all([chain, action()])
.then(
Expand All @@ -279,8 +281,8 @@ function assert_trap(action) {
.catch(_ => {});
}

function assert_return(action, ...expected) {
const test = "Test that a WebAssembly code returns a specific result";
function assert_return(action, source, ...expected) {
const test = `Test that a WebAssembly code returns a specific result (${source})`;
const loc = new Error().stack.toString().replace("Error", "");
chain = Promise.all([action(), chain])
.then(
Expand Down
33 changes: 17 additions & 16 deletions test/harness/sync_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function binary(bytes) {
/**
* Returns a compiled module, or throws if there was an error at compilation.
*/
function module(bytes, valid = true) {
function module(bytes, source, valid = true) {
let buffer = binary(bytes);
let validated;

Expand All @@ -176,6 +176,7 @@ function module(bytes, valid = true) {
let module;
try {
module = new WebAssembly.Module(buffer);
module.source = source;
} catch(e) {
if (valid)
throw new Error('WebAssembly.Module ctor unexpectedly throws ${typeof e}: ${e}${e.stack}');
Expand All @@ -189,32 +190,32 @@ function uniqueTest(func, desc) {
test(func, testNum() + desc);
}

function assert_invalid(bytes) {
function assert_invalid(bytes, source) {
uniqueTest(() => {
try {
module(bytes, /* valid */ false);
module(bytes, source, /* valid */ false);
throw new Error('did not fail');
} catch(e) {
assert_true(e instanceof WebAssembly.CompileError, "expected invalid failure:");
}
}, "A wast module that should be invalid or malformed.");
}, `A wast module that should be invalid or malformed. (${source})`);
}

const assert_malformed = assert_invalid;

function assert_invalid_custom(bytes) {
function assert_invalid_custom(bytes, source) {
uniqueTest(() => {
try {
module(bytes, /* valid */ true);
module(bytes, source, /* valid */ true);
} catch(e) {
throw new Error('failed on custom section error');
}
}, "A wast module that should have an invalid or malformed custom section.");
}, `A wast module that should have an invalid or malformed custom section. (${source})`);
}

const assert_malformed_custom = assert_invalid_custom;

function instance(mod, imports = registry, valid = true) {
function instance(module, imports = registry, valid = true) {
if (imports instanceof Result) {
if (imports.isError())
return imports;
Expand All @@ -225,7 +226,7 @@ function instance(mod, imports = registry, valid = true) {

let i;
try {
i = new WebAssembly.Instance(mod, imports);
i = new WebAssembly.Instance(module, imports);
} catch(e) {
err = e;
}
Expand All @@ -234,7 +235,7 @@ function instance(mod, imports = registry, valid = true) {
uniqueTest(() => {
let instantiated = err === null;
assert_true(instantiated, err);
}, "module successfully instantiated");
}, `module successfully instantiated (${module.source})`);
}

return err !== null ? ErrorResult(err) : ValueResult(i);
Expand Down Expand Up @@ -285,15 +286,15 @@ function exports(instance) {
return ValueResult({ module: instance.value.exports, spectest: registry.spectest });
}

function run(action) {
function run(action, source) {
let result = action();

_assert(result instanceof Result);

uniqueTest(() => {
if (result.isError())
throw result.value;
}, "A wast test that runs without any special assertion.");
}, `A wast test that runs without any special assertion. (${source})`);
}

function assert_unlinkable(bytes) {
Expand Down Expand Up @@ -324,7 +325,7 @@ function assert_uninstantiable(bytes) {
}, "A wast module that is uninstantiable.");
}

function assert_trap(action) {
function assert_trap(action, source) {
let result = action();

_assert(result instanceof Result);
Expand All @@ -335,7 +336,7 @@ function assert_trap(action) {
let e = result.value;
assert_true(e instanceof WebAssembly.RuntimeError, `expected runtime error, observed ${e}:`);
}
}, "A wast module that must trap at runtime.");
}, `A wast module that must trap at runtime. (${source})`);
}

let StackOverflow;
Expand All @@ -355,7 +356,7 @@ function assert_exhaustion(action) {
}, "A wast module that must exhaust the stack space.");
}

function assert_return(action, ...expected) {
function assert_return(action, source, ...expected) {
let result = action();
_assert(result instanceof Result);

Expand Down Expand Up @@ -408,7 +409,7 @@ function assert_return(action, ...expected) {
assert_equals(actual[i], expected[i]);
}
}
}, "A wast module that must return a particular value.");
}, `A wast module that must return a particular value. (${source})`);
}

function assert_return_nan(action) {
Expand Down