From b11bdd4022d2238f1473ca3c3ffba5779180c6a6 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Mon, 23 Dec 2024 16:28:53 -0700 Subject: [PATCH] LibWeb: Import WPT tests for WebAssembly.Global There's one failing due to the constructor object not having the name "Global" vs "WebAssembly.Global". This also doesn't include the tentative test for the type property. --- .../wasm/jsapi/global/constructor.any.txt | 66 +++++++ .../wasm/jsapi/global/toString.any.txt | 7 + .../wasm/jsapi/global/value-get-set.any.txt | 73 ++++++++ .../wasm/jsapi/global/valueOf.any.txt | 7 + .../wasm/jsapi/global/constructor.any.html | 15 ++ .../wasm/jsapi/global/constructor.any.js | 171 ++++++++++++++++++ .../wasm/jsapi/global/toString.any.html | 15 ++ .../wasm/jsapi/global/toString.any.js | 17 ++ .../wasm/jsapi/global/value-get-set.any.html | 15 ++ .../wasm/jsapi/global/value-get-set.any.js | 152 ++++++++++++++++ .../wasm/jsapi/global/valueOf.any.html | 15 ++ .../wasm/jsapi/global/valueOf.any.js | 28 +++ 12 files changed, 581 insertions(+) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/constructor.any.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/toString.any.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/value-get-set.any.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/valueOf.any.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.js create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.js create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.js create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.js diff --git a/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/constructor.any.txt b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/constructor.any.txt new file mode 100644 index 00000000000..c0e668496f5 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/constructor.any.txt @@ -0,0 +1,66 @@ +Harness status: OK + +Found 60 tests + +59 Pass +1 Fail +Fail name +Pass length +Pass No arguments +Pass Calling +Pass Order of evaluation +Pass Invalid descriptor argument +Pass Invalid type argument +Pass Construct v128 global +Pass i64 with default +Pass Default value for type i32 +Pass Explicit value undefined for type i32 +Pass Explicit value null for type i32 +Pass Explicit value true for type i32 +Pass Explicit value false for type i32 +Pass Explicit value 2 for type i32 +Pass Explicit value "3" for type i32 +Pass Explicit value object with toString returning string for type i32 +Pass Explicit value object with valueOf returning string for type i32 +Pass Explicit value object with toString returning number for type i32 +Pass Explicit value object with valueOf returning number for type i32 +Pass BigInt value for type i32 +Pass Default value for type f32 +Pass Explicit value undefined for type f32 +Pass Explicit value null for type f32 +Pass Explicit value true for type f32 +Pass Explicit value false for type f32 +Pass Explicit value 2 for type f32 +Pass Explicit value "3" for type f32 +Pass Explicit value object with toString returning string for type f32 +Pass Explicit value object with valueOf returning string for type f32 +Pass Explicit value object with toString returning number for type f32 +Pass Explicit value object with valueOf returning number for type f32 +Pass BigInt value for type f32 +Pass Default value for type f64 +Pass Explicit value undefined for type f64 +Pass Explicit value null for type f64 +Pass Explicit value true for type f64 +Pass Explicit value false for type f64 +Pass Explicit value 2 for type f64 +Pass Explicit value "3" for type f64 +Pass Explicit value object with toString returning string for type f64 +Pass Explicit value object with valueOf returning string for type f64 +Pass Explicit value object with toString returning number for type f64 +Pass Explicit value object with valueOf returning number for type f64 +Pass BigInt value for type f64 +Pass Explicit value undefined for type i64 +Pass Explicit value true for type i64 +Pass Explicit value false for type i64 +Pass Explicit value "3" for type i64 +Pass Explicit value bigint "123" for type i64 +Pass Explicit value object with toString returning string for type i64 +Pass Explicit value object with valueOf returning string for type i64 +Pass Explicit value object with toString returning bigint for type i64 +Pass Explicit value object with valueOf returning bigint for type i64 +Pass Pass non-bigint as i64 Global value: null +Pass Pass non-bigint as i64 Global value: 666 +Pass Pass non-bigint as i64 Global value: object "5" +Pass Pass non-bigint as i64 Global value: object "[object Object]" +Pass Pass non-bigint as i64 Global value: symbol "Symbol()" +Pass Stray argument \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/toString.any.txt b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/toString.any.txt new file mode 100644 index 00000000000..4579025e851 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/toString.any.txt @@ -0,0 +1,7 @@ +Harness status: OK + +Found 2 tests + +2 Pass +Pass Object.prototype.toString on an Global +Pass @@toStringTag exists on the prototype with the appropriate descriptor \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/value-get-set.any.txt b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/value-get-set.any.txt new file mode 100644 index 00000000000..990ab31da3f --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/value-get-set.any.txt @@ -0,0 +1,73 @@ +Harness status: OK + +Found 68 tests + +68 Pass +Pass Branding +Pass Immutable i32 (missing) +Pass Immutable i32 with ToNumber side-effects (missing) +Pass Immutable i32 (undefined) +Pass Immutable i32 with ToNumber side-effects (undefined) +Pass Immutable i32 (null) +Pass Immutable i32 with ToNumber side-effects (null) +Pass Immutable i32 (false) +Pass Immutable i32 with ToNumber side-effects (false) +Pass Immutable i32 (empty string) +Pass Immutable i32 with ToNumber side-effects (empty string) +Pass Immutable i32 (zero) +Pass Immutable i32 with ToNumber side-effects (zero) +Pass Mutable i32 (true) +Pass Mutable i32 (one) +Pass Mutable i32 (string) +Pass Mutable i32 (true on prototype) +Pass Immutable i64 (missing) +Pass Immutable i64 with ToNumber side-effects (missing) +Pass Immutable i64 (undefined) +Pass Immutable i64 with ToNumber side-effects (undefined) +Pass Immutable i64 (null) +Pass Immutable i64 with ToNumber side-effects (null) +Pass Immutable i64 (false) +Pass Immutable i64 with ToNumber side-effects (false) +Pass Immutable i64 (empty string) +Pass Immutable i64 with ToNumber side-effects (empty string) +Pass Immutable i64 (zero) +Pass Immutable i64 with ToNumber side-effects (zero) +Pass Mutable i64 (true) +Pass Mutable i64 (one) +Pass Mutable i64 (string) +Pass Mutable i64 (true on prototype) +Pass Immutable f32 (missing) +Pass Immutable f32 with ToNumber side-effects (missing) +Pass Immutable f32 (undefined) +Pass Immutable f32 with ToNumber side-effects (undefined) +Pass Immutable f32 (null) +Pass Immutable f32 with ToNumber side-effects (null) +Pass Immutable f32 (false) +Pass Immutable f32 with ToNumber side-effects (false) +Pass Immutable f32 (empty string) +Pass Immutable f32 with ToNumber side-effects (empty string) +Pass Immutable f32 (zero) +Pass Immutable f32 with ToNumber side-effects (zero) +Pass Mutable f32 (true) +Pass Mutable f32 (one) +Pass Mutable f32 (string) +Pass Mutable f32 (true on prototype) +Pass Immutable f64 (missing) +Pass Immutable f64 with ToNumber side-effects (missing) +Pass Immutable f64 (undefined) +Pass Immutable f64 with ToNumber side-effects (undefined) +Pass Immutable f64 (null) +Pass Immutable f64 with ToNumber side-effects (null) +Pass Immutable f64 (false) +Pass Immutable f64 with ToNumber side-effects (false) +Pass Immutable f64 (empty string) +Pass Immutable f64 with ToNumber side-effects (empty string) +Pass Immutable f64 (zero) +Pass Immutable f64 with ToNumber side-effects (zero) +Pass Mutable f64 (true) +Pass Mutable f64 (one) +Pass Mutable f64 (string) +Pass Mutable f64 (true on prototype) +Pass i64 mutability +Pass Calling setter without argument +Pass Stray argument \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/valueOf.any.txt b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/valueOf.any.txt new file mode 100644 index 00000000000..f7b5c500043 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/wasm/jsapi/global/valueOf.any.txt @@ -0,0 +1,7 @@ +Harness status: OK + +Found 2 tests + +2 Pass +Pass Branding +Pass Stray argument \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.html b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.html new file mode 100644 index 00000000000..e0b55ba5522 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.html @@ -0,0 +1,15 @@ + + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.js b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.js new file mode 100644 index 00000000000..f83f77a5c3e --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/constructor.any.js @@ -0,0 +1,171 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm +// META: script=/wasm/jsapi/assertions.js + +function assert_Global(actual, expected) { + assert_equals(Object.getPrototypeOf(actual), WebAssembly.Global.prototype, + "prototype"); + assert_true(Object.isExtensible(actual), "extensible"); + + assert_equals(actual.value, expected, "value"); + assert_equals(actual.valueOf(), expected, "valueOf"); +} + +test(() => { + assert_function_name(WebAssembly.Global, "Global", "WebAssembly.Global"); +}, "name"); + +test(() => { + assert_function_length(WebAssembly.Global, 1, "WebAssembly.Global"); +}, "length"); + +test(() => { + assert_throws_js(TypeError, () => new WebAssembly.Global()); +}, "No arguments"); + +test(() => { + const argument = { "value": "i32" }; + assert_throws_js(TypeError, () => WebAssembly.Global(argument)); +}, "Calling"); + +test(() => { + const order = []; + + new WebAssembly.Global({ + get value() { + order.push("descriptor value"); + return { + toString() { + order.push("descriptor value toString"); + return "f64"; + }, + }; + }, + + get mutable() { + order.push("descriptor mutable"); + return false; + }, + }, { + valueOf() { + order.push("value valueOf()"); + } + }); + + assert_array_equals(order, [ + "descriptor mutable", + "descriptor value", + "descriptor value toString", + "value valueOf()", + ]); +}, "Order of evaluation"); + +test(() => { + const invalidArguments = [ + undefined, + null, + false, + true, + "", + "test", + Symbol(), + 1, + NaN, + {}, + ]; + for (const invalidArgument of invalidArguments) { + assert_throws_js(TypeError, + () => new WebAssembly.Global(invalidArgument), + `new Global(${format_value(invalidArgument)})`); + } +}, "Invalid descriptor argument"); + +test(() => { + const invalidTypes = ["i16", "i128", "f16", "f128", "u32", "u64", "i32\0"]; + for (const value of invalidTypes) { + const argument = { value }; + assert_throws_js(TypeError, () => new WebAssembly.Global(argument)); + } +}, "Invalid type argument"); + +test(() => { + const argument = { "value": "v128" }; + assert_throws_js(TypeError, () => new WebAssembly.Global(argument)); +}, "Construct v128 global"); + +test(() => { + const argument = { "value": "i64" }; + const global = new WebAssembly.Global(argument); + assert_Global(global, 0n); +}, "i64 with default"); + +for (const type of ["i32", "f32", "f64"]) { + test(() => { + const argument = { "value": type }; + const global = new WebAssembly.Global(argument); + assert_Global(global, 0); + }, `Default value for type ${type}`); + + const valueArguments = [ + [undefined, 0], + [null, 0], + [true, 1], + [false, 0], + [2, 2], + ["3", 3], + [{ toString() { return "5" } }, 5, "object with toString returning string"], + [{ valueOf() { return "8" } }, 8, "object with valueOf returning string"], + [{ toString() { return 6 } }, 6, "object with toString returning number"], + [{ valueOf() { return 9 } }, 9, "object with valueOf returning number"], + ]; + for (const [value, expected, name = format_value(value)] of valueArguments) { + test(() => { + const argument = { "value": type }; + const global = new WebAssembly.Global(argument, value); + assert_Global(global, expected); + }, `Explicit value ${name} for type ${type}`); + } + + test(() => { + const argument = { "value": type }; + assert_throws_js(TypeError, () => new WebAssembly.Global(argument, 0n)); + }, `BigInt value for type ${type}`); +} + +const valueArguments = [ + [undefined, 0n], + [true, 1n], + [false, 0n], + ["3", 3n], + [123n, 123n], + [{ toString() { return "5" } }, 5n, "object with toString returning string"], + [{ valueOf() { return "8" } }, 8n, "object with valueOf returning string"], + [{ toString() { return 6n } }, 6n, "object with toString returning bigint"], + [{ valueOf() { return 9n } }, 9n, "object with valueOf returning bigint"], +]; +for (const [value, expected, name = format_value(value)] of valueArguments) { + test(() => { + const argument = { "value": "i64" }; + const global = new WebAssembly.Global(argument, value); + assert_Global(global, expected); + }, `Explicit value ${name} for type i64`); +} + +const invalidBigints = [ + null, + 666, + { toString() { return 5 } }, + { valueOf() { return 8 } }, + Symbol(), +]; +for (const invalidBigint of invalidBigints) { + test(() => { + var argument = { "value": "i64" }; + assert_throws_js(TypeError, () => new WebAssembly.Global(argument, invalidBigint)); + }, `Pass non-bigint as i64 Global value: ${format_value(invalidBigint)}`); +} + +test(() => { + const argument = { "value": "i32" }; + const global = new WebAssembly.Global(argument, 0, {}); + assert_Global(global, 0); +}, "Stray argument"); diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.html b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.html new file mode 100644 index 00000000000..6c093d5e39c --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.html @@ -0,0 +1,15 @@ + + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.js b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.js new file mode 100644 index 00000000000..b308498982e --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/toString.any.js @@ -0,0 +1,17 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +test(() => { + const argument = { "value": "i32" }; + const global = new WebAssembly.Global(argument); + assert_class_string(global, "WebAssembly.Global"); +}, "Object.prototype.toString on an Global"); + +test(() => { + assert_own_property(WebAssembly.Global.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "WebAssembly.Global", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.html b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.html new file mode 100644 index 00000000000..bc314d10a2f --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.html @@ -0,0 +1,15 @@ + + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.js b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.js new file mode 100644 index 00000000000..bee5581f418 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/value-get-set.any.js @@ -0,0 +1,152 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +test(() => { + const thisValues = [ + undefined, + null, + true, + "", + Symbol(), + 1, + {}, + WebAssembly.Global, + WebAssembly.Global.prototype, + ]; + + const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value"); + assert_equals(typeof desc, "object"); + + const getter = desc.get; + assert_equals(typeof getter, "function"); + + const setter = desc.set; + assert_equals(typeof setter, "function"); + + for (const thisValue of thisValues) { + assert_throws_js(TypeError, () => getter.call(thisValue), `getter with this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => setter.call(thisValue, 1), `setter with this=${format_value(thisValue)}`); + } +}, "Branding"); + +for (const type of ["i32", "i64", "f32", "f64"]) { + const [initial, value, invalid] = type === "i64" ? [0n, 1n, 2] : [0, 1, 2n]; + const immutableOptions = [ + [{}, "missing"], + [{ "mutable": undefined }, "undefined"], + [{ "mutable": null }, "null"], + [{ "mutable": false }, "false"], + [{ "mutable": "" }, "empty string"], + [{ "mutable": 0 }, "zero"], + ]; + for (const [opts, name] of immutableOptions) { + test(() => { + opts.value = type; + const global = new WebAssembly.Global(opts); + assert_equals(global.value, initial, "initial value"); + assert_equals(global.valueOf(), initial, "initial valueOf"); + + assert_throws_js(TypeError, () => global.value = value); + + assert_equals(global.value, initial, "post-set value"); + assert_equals(global.valueOf(), initial, "post-set valueOf"); + }, `Immutable ${type} (${name})`); + + test(t => { + opts.value = type; + const global = new WebAssembly.Global(opts); + assert_equals(global.value, initial, "initial value"); + assert_equals(global.valueOf(), initial, "initial valueOf"); + + const value = { + valueOf: t.unreached_func("should not call valueOf"), + toString: t.unreached_func("should not call toString"), + }; + assert_throws_js(TypeError, () => global.value = value); + + assert_equals(global.value, initial, "post-set value"); + assert_equals(global.valueOf(), initial, "post-set valueOf"); + }, `Immutable ${type} with ToNumber side-effects (${name})`); + } + + const mutableOptions = [ + [{ "mutable": true }, "true"], + [{ "mutable": 1 }, "one"], + [{ "mutable": "x" }, "string"], + [Object.create({ "mutable": true }), "true on prototype"], + ]; + for (const [opts, name] of mutableOptions) { + test(() => { + opts.value = type; + const global = new WebAssembly.Global(opts); + assert_equals(global.value, initial, "initial value"); + assert_equals(global.valueOf(), initial, "initial valueOf"); + + global.value = value; + + assert_throws_js(TypeError, () => global.value = invalid); + + assert_equals(global.value, value, "post-set value"); + assert_equals(global.valueOf(), value, "post-set valueOf"); + }, `Mutable ${type} (${name})`); + } +} + +test(() => { + const argument = { "value": "i64", "mutable": true }; + const global = new WebAssembly.Global(argument); + + assert_equals(global.value, 0n, "initial value using ToJSValue"); + + const valid = [ + [123n, 123n], + [2n ** 63n, - (2n ** 63n)], + [true, 1n], + [false, 0n], + ["456", 456n], + ]; + for (const [input, output] of valid) { + global.value = input; + assert_equals(global.valueOf(), output, "post-set valueOf"); + } + + const invalid = [ + undefined, + null, + 0, + 1, + 4.2, + Symbol(), + ]; + for (const input of invalid) { + assert_throws_js(TypeError, () => global.value = input); + } +}, "i64 mutability"); + +test(() => { + const argument = { "value": "i32", "mutable": true }; + const global = new WebAssembly.Global(argument); + const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value"); + assert_equals(typeof desc, "object"); + + const setter = desc.set; + assert_equals(typeof setter, "function"); + + assert_throws_js(TypeError, () => setter.call(global)); +}, "Calling setter without argument"); + +test(() => { + const argument = { "value": "i32", "mutable": true }; + const global = new WebAssembly.Global(argument); + const desc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, "value"); + assert_equals(typeof desc, "object"); + + const getter = desc.get; + assert_equals(typeof getter, "function"); + + const setter = desc.set; + assert_equals(typeof setter, "function"); + + assert_equals(getter.call(global, {}), 0); + assert_equals(setter.call(global, 1, {}), undefined); + assert_equals(global.value, 1); +}, "Stray argument"); diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.html b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.html new file mode 100644 index 00000000000..2c31ed88cc2 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.html @@ -0,0 +1,15 @@ + + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.js b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.js new file mode 100644 index 00000000000..5bcb1718258 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/wasm/jsapi/global/valueOf.any.js @@ -0,0 +1,28 @@ +// META: global=window,dedicatedworker,jsshell,shadowrealm + +test(() => { + const argument = { "value": "i32" }; + const thisValues = [ + undefined, + null, + true, + "", + Symbol(), + 1, + {}, + WebAssembly.Global, + WebAssembly.Global.prototype, + ]; + + const fn = WebAssembly.Global.prototype.valueOf; + + for (const thisValue of thisValues) { + assert_throws_js(TypeError, () => fn.call(thisValue), `this=${format_value(thisValue)}`); + } +}, "Branding"); + +test(() => { + const argument = { "value": "i32" }; + const global = new WebAssembly.Global(argument, 0); + assert_equals(global.valueOf({}), 0); +}, "Stray argument");