// This test cannot use imports because it needs to run in non-strict mode. function assert(actual, expected, message) { if (arguments.length == 1) expected = true; if (actual === expected) return; if (typeof actual == 'number' && isNaN(actual) && typeof expected == 'number' && isNaN(expected)) return; if (actual !== null && expected !== null && typeof actual == 'object' && typeof expected == 'object' && actual.toString() === expected.toString()) return; var msg = message ? " (" + message + ")" : ""; throw Error("assertion failed: got |" + actual + "|" + ", expected |" + expected + "|" + msg); } function assert_throws(expected_error, func, message) { var err = false; var msg = message ? " (" + message + ")" : ""; try { switch (typeof func) { case 'string': eval(func); break; case 'function': func(); break; } } catch(e) { err = true; if (!(e instanceof expected_error)) { throw Error(`expected ${expected_error.name}, got ${e.name}${msg}`); } } if (!err) { throw Error(`expected ${expected_error.name}${msg}`); } } /*----------------*/ function test_op1() { var r, a; r = 1 + 2; assert(r, 3, "1 + 2 === 3"); r = 1 - 2; assert(r, -1, "1 - 2 === -1"); r = -1; assert(r, -1, "-1 === -1"); r = +2; assert(r, 2, "+2 === 2"); r = 2 * 3; assert(r, 6, "2 * 3 === 6"); r = 4 / 2; assert(r, 2, "4 / 2 === 2"); r = 4 % 3; assert(r, 1, "4 % 3 === 3"); r = 4 << 2; assert(r, 16, "4 << 2 === 16"); r = 1 << 0; assert(r, 1, "1 << 0 === 1"); r = 1 << 31; assert(r, -2147483648, "1 << 31 === -2147483648"); r = 1 << 32; assert(r, 1, "1 << 32 === 1"); r = (1 << 31) < 0; assert(r, true, "(1 << 31) < 0 === true"); r = -4 >> 1; assert(r, -2, "-4 >> 1 === -2"); r = -4 >>> 1; assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe"); r = 1 & 1; assert(r, 1, "1 & 1 === 1"); r = 0 | 1; assert(r, 1, "0 | 1 === 1"); r = 1 ^ 1; assert(r, 0, "1 ^ 1 === 0"); r = ~1; assert(r, -2, "~1 === -2"); r = !1; assert(r, false, "!1 === false"); assert((1 < 2), true, "(1 < 2) === true"); assert((2 > 1), true, "(2 > 1) === true"); assert(('b' > 'a'), true, "('b' > 'a') === true"); assert(2 ** 8, 256, "2 ** 8 === 256"); } function test_cvt() { assert((NaN | 0), 0); assert((Infinity | 0), 0); assert(((-Infinity) | 0), 0); assert(("12345" | 0), 12345); assert(("0x12345" | 0), 0x12345); assert(((4294967296 * 3 - 4) | 0), -4); assert(("12345" >>> 0), 12345); assert(("0x12345" >>> 0), 0x12345); assert((NaN >>> 0), 0); assert((Infinity >>> 0), 0); assert(((-Infinity) >>> 0), 0); assert(((4294967296 * 3 - 4) >>> 0), (4294967296 - 4)); assert((19686109595169230000).toString(), "19686109595169230000"); } function test_eq() { assert(null == undefined); assert(undefined == null); assert(true == 1); assert(0 == false); assert("" == 0); assert("123" == 123); assert("122" != 123); assert((new Number(1)) == 1); assert(2 == (new Number(2))); assert((new String("abc")) == "abc"); assert({} != "abc"); } function test_inc_dec() { var a, r; a = 1; r = a++; assert(r === 1 && a === 2, true, "++"); a = 1; r = ++a; assert(r === 2 && a === 2, true, "++"); a = 1; r = a--; assert(r === 1 && a === 0, true, "--"); a = 1; r = --a; assert(r === 0 && a === 0, true, "--"); a = {x:true}; a.x++; assert(a.x, 2, "++"); a = {x:true}; a.x--; assert(a.x, 0, "--"); a = [true]; a[0]++; assert(a[0], 2, "++"); a = {x:true}; r = a.x++; assert(r === 1 && a.x === 2, true, "++"); a = {x:true}; r = a.x--; assert(r === 1 && a.x === 0, true, "--"); a = [true]; r = a[0]++; assert(r === 1 && a[0] === 2, true, "++"); a = [true]; r = a[0]--; assert(r === 1 && a[0] === 0, true, "--"); } function F(x) { this.x = x; } function test_op2() { var a, b; a = new Object; a.x = 1; assert(a.x, 1, "new"); b = new F(2); assert(b.x, 2, "new"); a = {x : 2}; assert(("x" in a), true, "in"); assert(("y" in a), false, "in"); a = {}; assert((a instanceof Object), true, "instanceof"); assert((a instanceof String), false, "instanceof"); assert((typeof 1), "number", "typeof"); assert((typeof Object), "function", "typeof"); assert((typeof null), "object", "typeof"); assert((typeof unknown_var), "undefined", "typeof"); a = {x: 1, if: 2, async: 3}; assert(a.if === 2); assert(a.async === 3); } function test_delete() { var a, err; a = {x: 1, y: 1}; assert((delete a.x), true, "delete"); assert(("x" in a), false, "delete"); /* the following are not tested by test262 */ assert(delete "abc"[100], true); err = false; try { delete null.a; } catch(e) { err = (e instanceof TypeError); } assert(err, true, "delete"); err = false; try { a = { f() { delete super.a; } }; a.f(); } catch(e) { err = (e instanceof ReferenceError); } assert(err, true, "delete"); } function test_prototype() { var f = function f() { }; assert(f.prototype.constructor, f, "prototype"); var g = function g() { }; /* QuickJS bug */ Object.defineProperty(g, "prototype", { writable: false }); assert(g.prototype.constructor, g, "prototype"); } function test_arguments() { function f2() { assert(arguments.length, 2, "arguments"); assert(arguments[0], 1, "arguments"); assert(arguments[1], 3, "arguments"); } f2(1, 3); } function test_class() { var o; class C { constructor() { this.x = 10; } f() { return 1; } static F() { return -1; } get y() { return 12; } }; class D extends C { constructor() { super(); this.z = 20; } g() { return 2; } static G() { return -2; } h() { return super.f(); } static H() { return super["F"](); } } assert(C.F(), -1); assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y"); o = new C(); assert(o.f(), 1); assert(o.x, 10); assert(D.F(), -1); assert(D.G(), -2); assert(D.H(), -1); o = new D(); assert(o.f(), 1); assert(o.g(), 2); assert(o.x, 10); assert(o.z, 20); assert(o.h(), 1); /* test class name scope */ var E1 = class E { static F() { return E; } }; assert(E1, E1.F()); class S { static x = 42; static y = S.x; static z = this.x; } assert(S.x, 42); assert(S.y, 42); assert(S.z, 42); class P { get; set; async; get = () => "123"; set = () => "456"; async = () => "789"; static() { return 42; } } assert(new P().get(), "123"); assert(new P().set(), "456"); assert(new P().async(), "789"); assert(new P().static(), 42); }; function test_template() { var a, b; b = 123; a = `abc${b}d`; assert(a, "abc123d"); a = String.raw `abc${b}d`; assert(a, "abc123d"); a = "aaa"; b = "bbb"; assert(`aaa${a, b}ccc`, "aaabbbccc"); } function test_template_skip() { var a = "Bar"; var { b = `${a + `a${a}` }baz` } = {}; assert(b, "BaraBarbaz"); } function test_object_literal() { var x = 0, get = 1, set = 2; async = 3; a = { get: 2, set: 3, async: 4, get a(){ return this.get} }; assert(JSON.stringify(a), '{"get":2,"set":3,"async":4,"a":2}'); assert(a.a, 2); a = { x, get, set, async }; assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}'); } function test_regexp_skip() { var a, b; [a, b = /abc\(/] = [1]; assert(a, 1); [a, b =/abc\(/] = [2]; assert(a, 2); } function test_labels() { do x: { break x; } while(0); if (1) x: { break x; } else x: { break x; } with ({}) x: { break x; }; while (0) x: { break x; }; } function test_destructuring() { function * g () { return 0; }; var [x] = g(); assert(x, void 0); } function test_spread() { var x; x = [1, 2, ...[3, 4]]; assert(x.toString(), "1,2,3,4"); x = [ ...[ , ] ]; assert(Object.getOwnPropertyNames(x).toString(), "0,length"); } function test_function_length() { assert( ((a, b = 1, c) => {}).length, 1); assert( (([a,b]) => {}).length, 1); assert( (({a,b}) => {}).length, 1); assert( ((c, [a,b] = 1, d) => {}).length, 1); } function test_argument_scope() { var f; var c = "global"; f = function(a = eval("var arguments")) {}; // for some reason v8 does not throw an exception here if (typeof require === 'undefined') assert_throws(SyntaxError, f); f = function(a = eval("1"), b = arguments[0]) { return b; }; assert(f(12), 12); f = function(a, b = arguments[0]) { return b; }; assert(f(12), 12); f = function(a, b = () => arguments) { return b; }; assert(f(12)()[0], 12); f = function(a = eval("1"), b = () => arguments) { return b; }; assert(f(12)()[0], 12); (function() { "use strict"; f = function(a = this) { return a; }; assert(f.call(123), 123); f = function f(a = f) { return a; }; assert(f(), f); f = function f(a = eval("f")) { return a; }; assert(f(), f); })(); f = (a = eval("var c = 1"), probe = () => c) => { var c = 2; assert(c, 2); assert(probe(), 1); } f(); f = (a = eval("var arguments = 1"), probe = () => arguments) => { var arguments = 2; assert(arguments, 2); assert(probe(), 1); } f(); f = function f(a = eval("var c = 1"), b = c, probe = () => c) { assert(b, 1); assert(c, 1); assert(probe(), 1) } f(); assert(c, "global"); f = function f(a, b = c, probe = () => c) { eval("var c = 1"); assert(c, 1); assert(b, "global"); assert(probe(), "global") } f(); assert(c, "global"); f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) { assert(probe(), 1) } f(); } function test_function_expr_name() { var f; /* non strict mode test : assignment to the function name silently fails */ f = function myfunc() { myfunc = 1; return myfunc; }; assert(f(), f); f = function myfunc() { myfunc = 1; (() => { myfunc = 1; })(); return myfunc; }; assert(f(), f); f = function myfunc() { eval("myfunc = 1"); return myfunc; }; assert(f(), f); /* strict mode test : assignment to the function name raises a TypeError exception */ f = function myfunc() { "use strict"; myfunc = 1; }; assert_throws(TypeError, f); f = function myfunc() { "use strict"; (() => { myfunc = 1; })(); }; assert_throws(TypeError, f); f = function myfunc() { "use strict"; eval("myfunc = 1"); }; assert_throws(TypeError, f); } function test_expr(expr, err) { if (err) assert_throws(err, expr, `for ${expr}`); else assert(1, eval(expr), `for ${expr}`); } function test_name(name, err) { test_expr(`(function() { return typeof ${name} ? 1 : 1; })()`); test_expr(`(function() { var ${name}; ${name} = 1; return ${name}; })()`); test_expr(`(function() { let ${name}; ${name} = 1; return ${name}; })()`, name == 'let' ? SyntaxError : undefined); test_expr(`(function() { const ${name} = 1; return ${name}; })()`, name == 'let' ? SyntaxError : undefined); test_expr(`(function(${name}) { ${name} = 1; return ${name}; })()`); test_expr(`(function({${name}}) { ${name} = 1; return ${name}; })({})`); test_expr(`(function ${name}() { return ${name} ? 1 : 0; })()`); test_expr(`"use strict"; (function() { return typeof ${name} ? 1 : 1; })()`, err); test_expr(`"use strict"; (function() { if (0) ${name} = 1; return 1; })()`, err); test_expr(`"use strict"; (function() { var x; if (0) x = ${name}; return 1; })()`, err); test_expr(`"use strict"; (function() { var ${name}; return 1; })()`, err); test_expr(`"use strict"; (function() { let ${name}; return 1; })()`, err); test_expr(`"use strict"; (function() { const ${name} = 1; return 1; })()`, err); test_expr(`"use strict"; (function() { var ${name}; ${name} = 1; return 1; })()`, err); test_expr(`"use strict"; (function() { var ${name}; ${name} = 1; return ${name}; })()`, err); test_expr(`"use strict"; (function(${name}) { return 1; })()`, err); test_expr(`"use strict"; (function({${name}}) { return 1; })({})`, err); test_expr(`"use strict"; (function ${name}() { return 1; })()`, err); test_expr(`(function() { "use strict"; return typeof ${name} ? 1 : 1; })()`, err); test_expr(`(function() { "use strict"; if (0) ${name} = 1; return 1; })()`, err); test_expr(`(function() { "use strict"; var x; if (0) x = ${name}; return 1; })()`, err); test_expr(`(function() { "use strict"; var ${name}; return 1; })()`, err); test_expr(`(function() { "use strict"; let ${name}; return 1; })()`, err); test_expr(`(function() { "use strict"; const ${name} = 1; return 1; })()`, err); test_expr(`(function() { "use strict"; var ${name}; ${name} = 1; return 1; })()`, err); test_expr(`(function() { "use strict"; var ${name}; ${name} = 1; return ${name}; })()`, err); test_expr(`(function(${name}) { "use strict"; return 1; })()`, err); test_expr(`(function({${name}}) { "use strict"; return 1; })({})`, SyntaxError); test_expr(`(function ${name}() { "use strict"; return 1; })()`, err); } function test_reserved_names() { test_name('await'); test_name('yield', SyntaxError); test_name('implements', SyntaxError); test_name('interface', SyntaxError); test_name('let', SyntaxError); test_name('package', SyntaxError); test_name('private', SyntaxError); test_name('protected', SyntaxError); test_name('public', SyntaxError); test_name('static', SyntaxError); } function test_number_literals() { assert(0.1.a, undefined); assert(0x1.a, undefined); assert(0b1.a, undefined); assert(01.a, undefined); assert(0o1.a, undefined); test_expr('0.a', SyntaxError); assert(parseInt("0_1"), 0); assert(parseInt("1_0"), 1); assert(parseInt("0_1", 8), 0); assert(parseInt("1_0", 8), 1); assert(parseFloat("0_1"), 0); assert(parseFloat("1_0"), 1); assert(1_0, 10); assert(parseInt("Infinity"), NaN); assert(parseFloat("Infinity"), Infinity); assert(parseFloat("Infinity1"), Infinity); assert(parseFloat("Infinity_"), Infinity); assert(parseFloat("Infinity."), Infinity); test_expr('0_0', SyntaxError); test_expr('00_0', SyntaxError); test_expr('01_0', SyntaxError); test_expr('08_0', SyntaxError); test_expr('09_0', SyntaxError); } function test_syntax() { assert_throws(SyntaxError, "do"); assert_throws(SyntaxError, "do;"); assert_throws(SyntaxError, "do{}"); assert_throws(SyntaxError, "if"); assert_throws(SyntaxError, "if\n"); assert_throws(SyntaxError, "if 1"); assert_throws(SyntaxError, "if \0"); assert_throws(SyntaxError, "if ;"); assert_throws(SyntaxError, "if 'abc'"); assert_throws(SyntaxError, "if `abc`"); assert_throws(SyntaxError, "if /abc/"); assert_throws(SyntaxError, "if abc"); assert_throws(SyntaxError, "if abc\u0064"); assert_throws(SyntaxError, "if abc\\u0064"); assert_throws(SyntaxError, "if \u0123"); assert_throws(SyntaxError, "if \\u0123"); } /* optional chaining tests not present in test262 */ function test_optional_chaining() { var a, z; z = null; a = { b: { c: 2 } }; assert(delete z?.b.c, true); assert(delete a?.b.c, true); assert(JSON.stringify(a), '{"b":{}}', "optional chaining delete"); a = { b: { c: 2 } }; assert(delete z?.b["c"], true); assert(delete a?.b["c"], true); assert(JSON.stringify(a), '{"b":{}}'); a = { b() { return this._b; }, _b: { c: 42 } }; assert((a?.b)().c, 42); assert((a?.["b"])().c, 42); } function test_parse_semicolon() { /* 'yield' or 'await' may not be considered as a token if the previous ';' is missing */ function *f() { function func() { } yield 1; var h = x => x + 1 yield 2; } async function g() { function func() { } await 1; var h = x => x + 1 await 2; } } test_op1(); test_cvt(); test_eq(); test_inc_dec(); test_op2(); test_delete(); test_prototype(); test_arguments(); test_class(); test_template(); test_template_skip(); test_object_literal(); test_regexp_skip(); test_labels(); test_destructuring(); test_spread(); test_function_length(); test_argument_scope(); test_function_expr_name(); test_reserved_names(); test_number_literals(); test_syntax(); test_optional_chaining(); test_parse_semicolon();