// Tests for wasm exception proposal JS API features.
load(libdir + "eqArrayHelper.js" );
// WebAssembly.Tag tests.
assertErrorMessage(
() => WebAssembly.Tag(),
TypeError,
/calling a builtin Tag constructor without new is forbidden/
);
assertErrorMessage(
() => new WebAssembly.Tag(),
TypeError,
/At least 1 argument required/
);
assertErrorMessage(
() => new WebAssembly.Tag(3 ),
TypeError,
/first argument must be a tag descriptor/
);
assertErrorMessage(
() => new WebAssembly.Tag({ parameters: ["foobar" ] }),
TypeError,
/bad value type/
);
new WebAssembly.Tag({ parameters: [] });
new WebAssembly.Tag({ parameters: ["i32" ] });
new WebAssembly.Tag({ parameters: ["i32" , "externref" ] });
wasmEvalText(`(module (import "m" "e" (tag)))`, {
m: { e: new WebAssembly.Tag({ parameters: [] }) },
});
wasmEvalText(`(module (import "m" "e" (tag (param i32))))`, {
m: { e: new WebAssembly.Tag({ parameters: ["i32" ] }) },
});
wasmEvalText(`(module (import "m" "e" (tag (param i32 i64))))`, {
m: { e: new WebAssembly.Tag({ parameters: ["i32" , "i64" ] }) },
});
assertErrorMessage(
() =>
wasmEvalText(`(module (import "m" "e" (tag (param i32))))`, {
m: { e: new WebAssembly.Tag({ parameters: [] }) },
}),
WebAssembly.LinkError,
/imported tag 'm.e' signature mismatch/
);
assertErrorMessage(
() =>
wasmEvalText(`(module (import "m" "e" (tag (param))))`, {
m: { e: new WebAssembly.Tag({ parameters: ["i32" ] }) },
}),
WebAssembly.LinkError,
/imported tag 'm.e' signature mismatch/
);
// Test WebAssembly.Tag methods.
// TODO: add runtime detection for js-types
// {
// let params = [
// [],
// ["i32"],
// ["i32", "i64"],
// ["f32", "externref"],
// ["i32", "i64", "f32", "f64"],
// ];
// for (const arg of params) {
// const tag = new WebAssembly.Tag({ parameters: arg });
// assertEqArray(tag.type().parameters, arg);
// }
// }
// WebAssembly.Exception tests.
assertErrorMessage(
() => WebAssembly.Exception(),
TypeError,
/calling a builtin Exception constructor without new is forbidden/
);
assertErrorMessage(
() => new WebAssembly.Exception(),
TypeError,
/At least 2 arguments required/
);
assertErrorMessage(
() => new WebAssembly.Exception(3 , []),
TypeError,
/first argument must be a WebAssembly.Tag/
);
const { tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9 } = wasmEvalText(
`(module
(tag (export "tag1" ) (param))
(tag (export "tag2" ) (param i32))
(tag (export "tag3" ) (param i32 f32))
(tag (export "tag4" ) (param i32 externref i32))
(tag (export "tag5" ) (param i32 externref i32 externref))
(tag (export "tag6" ) (param funcref))
(tag (export "tag7" ) (param i64))
(tag (export "tag8" ) (param i32 f64))
(tag (export "tag9" ) (param externref funcref)))`
).exports;
new WebAssembly.Exception(tag1, []);
new WebAssembly.Exception(tag2, [3 ]);
new WebAssembly.Exception(tag3, [3 , 5 .5 ]);
new WebAssembly.Exception(tag4, [3 , "foo" , 4 ]);
new WebAssembly.Exception(tag5, [3 , "foo" , 4 , "bar" ]);
assertErrorMessage(
() => new WebAssembly.Exception(tag2, []),
TypeError,
/expected 1 values but got 0 /
);
assertErrorMessage(
() => new WebAssembly.Exception(tag2, [3 n]),
TypeError,
/can't convert BigInt to number/
);
assertErrorMessage(
() => new WebAssembly.Exception(tag6, [undefined]),
TypeError,
/can only pass WebAssembly exported functions to funcref/
);
assertErrorMessage(
() => new WebAssembly.Exception(tag7, [undefined]),
TypeError,
/can't convert undefined to BigInt/
);
assertErrorMessage(
() => new WebAssembly.Exception(tag7, {}),
TypeError,
/\({}\) is not iterable/
);
assertErrorMessage(
() => new WebAssembly.Exception(tag7, 1 ),
TypeError,
/second argument must be an object/
);
// Test Exception methods.
{
const exn1 = new WebAssembly.Exception(tag1, []);
assertEq(exn1.is(tag1), true );
assertEq(exn1.is(tag2), false );
assertErrorMessage(
() => exn1.is(),
TypeError,
/At least 1 argument required/
);
assertErrorMessage(
() => exn1.is(5 ),
TypeError,
/first argument must be a WebAssembly.Tag/
);
const exn2 = new WebAssembly.Exception(tag2, [3 ]);
assertEq(exn2.getArg(tag2, 0 ), 3 );
assertEq(new WebAssembly.Exception(tag2, [undefined]).getArg(tag2, 0 ), 0 );
const exn4 = new WebAssembly.Exception(tag4, [3 , "foo" , 4 ]);
assertEq(exn4.getArg(tag4, 0 ), 3 );
assertEq(exn4.getArg(tag4, 1 ), "foo" );
assertEq(exn4.getArg(tag4, 2 ), 4 );
const exn5 = new WebAssembly.Exception(tag5, [3 , "foo" , 4 , "bar" ]);
assertEq(exn5.getArg(tag5, 3 ), "bar" );
const { funcref } = wasmEvalText(
`(module (func (export "funcref" )))`
).exports;
const exn9 = new WebAssembly.Exception(tag9, ["foo" , funcref]);
assertEq(exn9.getArg(tag9, 0 ), "foo" );
assertEq(exn9.getArg(tag9, 1 ), funcref);
assertErrorMessage(
() => exn2.getArg(),
TypeError,
/At least 2 arguments required/
);
assertErrorMessage(
() => exn2.getArg(5 , 0 ),
TypeError,
/first argument must be a WebAssembly.Tag/
);
assertErrorMessage(
() => exn2.getArg(tag2, "foo" ),
TypeError,
/bad Exception getArg index/
);
assertErrorMessage(
() => exn2.getArg(tag2, 10 ),
RangeError,
/bad Exception getArg index/
);
}
// Test throwing a JS constructed exception to Wasm.
assertEq(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32)
try (result i32)
call $f
(i32.const 0 )
catch $exn
end))`,
{
m: {
exn: tag2,
f: () => {
throw new WebAssembly.Exception(tag2, [42 ]);
},
},
}
).exports.f(),
42
);
assertEqArray(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32 f32)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32 f32)
try (result i32 f32)
call $f
(i32.const 0 )
(f32.const 0 )
catch $exn
end))`,
{
m: {
exn: tag3,
f: () => {
throw new WebAssembly.Exception(tag3, [42 , 5 .5 ]);
},
},
}
).exports.f(),
[42 , 5 .5 ]
);
assertEqArray(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32 f64)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32 f64)
try (result i32 f64)
call $f
(i32.const 0 )
(f64.const 0 )
catch $exn
end))`,
{
m: {
exn: tag8,
f: () => {
throw new WebAssembly.Exception(tag8, [9999 , 9999 ]);
},
},
}
).exports.f(),
[9999 , 9999 ]
);
assertEqArray(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32 externref i32)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32 externref i32)
try (result i32 externref i32)
call $f
(i32.const 0 )
(ref.null extern)
(i32.const 0 )
catch $exn
end))`,
{
m: {
exn: tag4,
f: () => {
throw new WebAssembly.Exception(tag4, [42 , "foo" , 42 ]);
},
},
}
).exports.f(),
[42 , "foo" , 42 ]
);
assertEqArray(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32 externref i32 externref)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32 externref i32 externref)
try (result i32 externref i32 externref)
call $f
(i32.const 0 )
(ref.null extern)
(i32.const 0 )
(ref.null extern)
catch $exn
end))`,
{
m: {
exn: tag5,
f: () => {
throw new WebAssembly.Exception(tag5, [42 , "foo" , 42 , "bar" ]);
},
},
}
).exports.f(),
[42 , "foo" , 42 , "bar" ]
);
{
const { funcref } = wasmEvalText(
`(module (func (export "funcref" )))`
).exports;
assertEqArray(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param externref funcref)))
(import "m" "f" (func $f))
(func (export "f" ) (result externref funcref)
try (result externref funcref)
call $f
(ref.null extern)
(ref.null func)
catch $exn
end))`,
{
m: {
exn: tag9,
f: () => {
throw new WebAssembly.Exception(tag9, ["foo" , funcref]);
},
},
}
).exports.f(),
["foo" , funcref]
);
}
assertEq(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn))
(import "m" "f" (func $f))
(func (export "f" ) (result i32)
try (result i32)
call $f
(i32.const 0 )
catch $exn
(i32.const 0 )
catch_all
(i32.const 1 )
end))`,
{
m: {
exn: tag1,
f: () => {
throw new WebAssembly.Exception(tag2, [42 ]);
},
},
}
).exports.f(),
1
);
{
const exn = new WebAssembly.Tag({ parameters: ["i32" ] });
assertEq(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32)
try (result i32)
call $f
(i32.const 0 )
catch $exn
end))`,
{
m: {
exn,
f: () => {
throw new WebAssembly.Exception(exn, [42 ]);
},
},
}
).exports.f(),
42
);
}
{
const exn1 = new WebAssembly.Tag({ parameters: ["i32" ] });
const exn2 = new WebAssembly.Tag({ parameters: ["i32" ] });
assertEq(
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32)))
(import "m" "f" (func $f))
(func (export "f" ) (result i32)
try (result i32)
call $f
(i32.const 0 )
catch $exn
catch_all
(i32.const 1 )
end))`,
{
m: {
exn: exn1,
f: () => {
throw new WebAssembly.Exception(exn2, [42 ]);
},
},
}
).exports.f(),
1
);
}
// Test `getArg` on a Wasm-thrown exception.
assertEq(
(() => {
try {
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32 f64)))
(func (export "f" )
(i32.const 9999 )
(f64.const 9999 )
throw $exn))`,
{ m: { exn: tag8 } }
).exports.f();
} catch (exn) {
return exn.getArg(tag8, 1 );
}
})(),
9999
);
assertEqArray(
(() => {
try {
wasmEvalText(
`(module
(import "m" "exn" (tag $exn (param i32 externref i32 externref)))
(func (export "f" ) (param externref externref)
(i32.const 1 )
(local.get 0 )
(i32.const 2 )
(local.get 1 )
throw $exn))`,
{ m: { exn: tag5 } }
).exports.f("foo" , "bar" );
} catch (exn) {
return [
exn.getArg(tag5, 0 ),
exn.getArg(tag5, 1 ),
exn.getArg(tag5, 2 ),
exn.getArg(tag5, 3 ),
];
}
})(),
[1 , "foo" , 2 , "bar" ]
);
Messung V0.5 in Prozent C=97 H=96 G=96
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland