diff options
Diffstat (limited to 'js/src/tests/non262/PrivateName')
22 files changed, 759 insertions, 0 deletions
diff --git a/js/src/tests/non262/PrivateName/browser.js b/js/src/tests/non262/PrivateName/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/PrivateName/browser.js diff --git a/js/src/tests/non262/PrivateName/constructor-args.js b/js/src/tests/non262/PrivateName/constructor-args.js new file mode 100644 index 0000000000..970d809921 --- /dev/null +++ b/js/src/tests/non262/PrivateName/constructor-args.js @@ -0,0 +1,23 @@ +class A { + #x = "hello"; + constructor(o = this.#x) { + this.value = o; + } +}; + +var a = new A; +assertEq(a.value, "hello"); + + +class B extends A { + constructor() { + // Cannot access 'this' until super() called. + super(); + assertEq("value" in this, true); + assertEq(this.value, "hello"); + } +} + +var b = new B; + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/error-locations.js b/js/src/tests/non262/PrivateName/error-locations.js new file mode 100644 index 0000000000..e91815ea81 --- /dev/null +++ b/js/src/tests/non262/PrivateName/error-locations.js @@ -0,0 +1,34 @@ +// |reftest| +function assertLineAndColumn(str, line, column) { + try { + eval(str); + throw 'didn\'t syntaxerror, bad.' + } catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.lineNumber, line); + assertEq(e.columnNumber, column); + } +} + +assertLineAndColumn(`class A { g() { return this.#x; }}`, 1, 29); +// Make sure we're reporting the first error, if there are multiple, in class +// exit context; +assertLineAndColumn( + `class A { g() { return this.#x; } y() { return this.#z + this.#y; } }`, + 1, 29); +assertLineAndColumn(`this.#x`, 1, 6); +// Make sure we're reporting the first error, if there are multiple, in +// non-class context; +assertLineAndColumn(`this.#x; this.#y; this.#z`, 1, 6); + +assertLineAndColumn( + `class A { +g() { return this.#x; }}`, + 2, 19); +assertLineAndColumn( + `class A { + +g() { return this.#x; } y() { return this.#y; }}`, + 3, 19); + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/error-outside-class.js b/js/src/tests/non262/PrivateName/error-outside-class.js new file mode 100644 index 0000000000..8ddb380872 --- /dev/null +++ b/js/src/tests/non262/PrivateName/error-outside-class.js @@ -0,0 +1,13 @@ + +// Can't reference a private field without an object +assertThrowsInstanceOf(() => eval('#x'), SyntaxError); + +// Can't reference a private field without an enclosing class +assertThrowsInstanceOf(() => eval('this.#x'), SyntaxError); + +// Can't reference a private field in a random function outside a class context +assertThrowsInstanceOf( + () => eval('function foo() { return this.#x'), SyntaxError); + + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/home-object-when-preceded-by-computed-key.js b/js/src/tests/non262/PrivateName/home-object-when-preceded-by-computed-key.js new file mode 100644 index 0000000000..ef53a1304b --- /dev/null +++ b/js/src/tests/non262/PrivateName/home-object-when-preceded-by-computed-key.js @@ -0,0 +1,34 @@ +class Base { + m() { return "pass"; } + static m() { return "fail"; } +} + +var key = { + toString() { + return "computed"; + } +}; + +let obj1 = new class extends Base { + [key]() {} + + // Private method with a directly preceding method using a computed key led + // to assigning the wrong home object. + #m() { return super.m(); } + m() { return this.#m(); } +}; + +assertEq(obj1.m(), "pass"); + +let obj2 = new class extends Base { + // Same test as above, but this time preceded by a static method. + static [key]() {} + + #m() { return super.m(); } + m() { return this.#m(); } +}; + +assertEq(obj2.m(), "pass"); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/illegal-delete.js b/js/src/tests/non262/PrivateName/illegal-delete.js new file mode 100644 index 0000000000..464b7dd685 --- /dev/null +++ b/js/src/tests/non262/PrivateName/illegal-delete.js @@ -0,0 +1,94 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs newGlobal() + +class A { + #x = {a: 1}; + b = null; + es(s) { + eval(s); + } +} + +var a = new A; +a.b = new A; + +assertThrowsInstanceOf(() => a.es('delete this.#x'), SyntaxError); +assertThrowsInstanceOf(() => a.es('delete (this.#x)'), SyntaxError); +assertThrowsInstanceOf(() => a.es('delete this?.#x'), SyntaxError); +assertThrowsInstanceOf(() => a.es('delete this?.b.#x'), SyntaxError); +// Should be OK +a.es('delete (0, this.#x.a)') +a.es('delete this?.b.#x.a') + + +// Make sure the above works in a different context, with emphasis on +// lazy/syntax parsing. +function eval_and_report(str) { + var classTest = ` + class B { + #x = {a: 1}; + b = null; + test() { + ${str}; + } + } + var b = new B; + b.b = new B; + b.test(); + `; + + var str = ` + function f(run) { + if (run) { + ${classTest} + } + } + f(run)`; + + + var throws = []; + // Evalutate in a new global; has the advantage that it makes successes + // idempotent. + var g = newGlobal(); + g.run = false; + + try { + // The idea is that this is a full parse + evaluate(classTest, {global: g}); + } catch (e) { + throws.push(e); + } + + try { + // The idea is this is a lazy parse; however, fields currently + // disable lazy parsing, so right now + evaluate(str, {global: g}); + } catch (e) { + throws.push(e); + } + + return throws; +} + +function assertSyntaxError(str) { + var exceptions = eval_and_report(str); + assertEq(exceptions.length, 2); + for (var e of exceptions) { + assertEq(/SyntaxError/.test(e.name), true); + } +} + +function assertNoSyntaxError(str) { + var exceptions = eval_and_report(str); + assertEq(exceptions.length, 0); +} + +assertSyntaxError('delete this.#x'); +assertSyntaxError('delete (this.#x)'); +assertSyntaxError('delete this?.#x'); +assertSyntaxError('delete this?.b.#x'); +// Should be OK +assertNoSyntaxError('delete (0, this.#x.a)') +assertNoSyntaxError('delete this?.b.#x.a') + + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/illegal-in-class-context.js b/js/src/tests/non262/PrivateName/illegal-in-class-context.js new file mode 100644 index 0000000000..85b34563ec --- /dev/null +++ b/js/src/tests/non262/PrivateName/illegal-in-class-context.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!xulRuntime.shell) + +assertThrowsInstanceOf(() => eval(`class A { #x; #x; }`), SyntaxError); + +// No computed private fields +assertThrowsInstanceOf( + () => eval(`var x = "foo"; class A { #[x] = 20; }`), SyntaxError); + +function assertThrowsWithMessage(f, msg) { + var fullmsg; + try { + f(); + } catch (exc) { + if (exc.message.normalize() === msg.normalize()) + return; + + fullmsg = `Assertion failed: expected message '${msg}', got '${exc.message}'`; + } + + if (fullmsg === undefined) + fullmsg = `Assertion failed: expected exception, no exception thrown`; + + throw new Error(fullmsg); +} + +assertThrowsWithMessage(() => eval(`class A { #x; h(o) { return !#x; }}`), + "invalid use of private name in unary expression without object reference"); +assertThrowsWithMessage(() => eval(`class A { #x; h(o) { return 1 + #x in o; }}`), + "invalid use of private name due to operator precedence"); + + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/illegal-in-identifier-context.js b/js/src/tests/non262/PrivateName/illegal-in-identifier-context.js new file mode 100644 index 0000000000..e7e232bf69 --- /dev/null +++ b/js/src/tests/non262/PrivateName/illegal-in-identifier-context.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!xulRuntime.shell) + +// Private names can't appear in contexts where plain identifiers are expected. + +// Private names as binding identifiers. +assertThrowsInstanceOf(() => eval(`var #a;`), SyntaxError); +assertThrowsInstanceOf(() => eval(`let #a;`), SyntaxError); +assertThrowsInstanceOf(() => eval(`const #a = 0;`), SyntaxError); +assertThrowsInstanceOf(() => eval(`function #a(){}`), SyntaxError); +assertThrowsInstanceOf(() => eval(`function f(#a){}`), SyntaxError); + +// With escape sequences (leading and non-leading case). +assertThrowsInstanceOf(() => eval(String.raw`var #\u0061;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`var #a\u0061;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`let #\u0061;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`let #a\u0061;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`const #\u0061 = 0;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`const #a\u0061 = 0;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`function #\u0061(){}`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`function #a\u0061(){}`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`function f(#\u0061){}`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`function f(#a\u0061){}`), SyntaxError); + + +// Private names as label identifiers. +assertThrowsInstanceOf(() => eval(`#a: ;`), SyntaxError); + +// With escape sequences (leading and non-leading case). +assertThrowsInstanceOf(() => eval(String.raw`#\u0061: ;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`#a\u0061: ;`), SyntaxError); + + +// Private names as identifier references. +assertThrowsInstanceOf(() => eval(`#a = 0;`), SyntaxError); +assertThrowsInstanceOf(() => eval(`typeof #a;`), SyntaxError); + +// With escape sequences (leading and non-leading case). +assertThrowsInstanceOf(() => eval(String.raw`#\u0061 = 0;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`#a\u0061 = 0;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`typeof #\u0061;`), SyntaxError); +assertThrowsInstanceOf(() => eval(String.raw`typeof #a\u0061;`), SyntaxError); + + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/illegal-in-object-context.js b/js/src/tests/non262/PrivateName/illegal-in-object-context.js new file mode 100644 index 0000000000..9cc1488376 --- /dev/null +++ b/js/src/tests/non262/PrivateName/illegal-in-object-context.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!xulRuntime.shell) + +// Private names aren't valid in object literals. + +assertThrowsInstanceOf(() => eval(`var o = {#a: 0};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {#a};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {#a(){}};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {get #a(){}};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {set #a(v){}};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {*#a(v){}};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {async #a(v){}};`), SyntaxError); +assertThrowsInstanceOf(() => eval(`var o = {async *#a(v){}};`), SyntaxError); + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/lexical-presence.js b/js/src/tests/non262/PrivateName/lexical-presence.js new file mode 100644 index 0000000000..ce8588a0f1 --- /dev/null +++ b/js/src/tests/non262/PrivateName/lexical-presence.js @@ -0,0 +1,55 @@ +// |reftest| + +// Verify that private fields are enabled. +class A { + #x; +}; + +function assertThrowsSyntaxError(str) { + assertThrowsInstanceOf(() => eval(str), SyntaxError); // Direct Eval + assertThrowsInstanceOf(() => (1, eval)(str), SyntaxError); // Indirect Eval + assertThrowsInstanceOf(() => Function(str), SyntaxError); // Function +} + +assertThrowsSyntaxError(` + class B { + g() { + return this.#x; + } + }; +`); + +assertThrowsSyntaxError(` +with (new class A { #x; }) { + class B { + #y; + constructor() { return this.#x; } + } + } +`); + +// Make sure we don't create a generic binding for #x. +with (new class { + #x = 12; +}) { + assertEq('#x' in this, false); +} + +// Try to fetch a non-existing field using different +// compilation contexts +function assertNonExisting(fetchCode) { + source = `var X = class { + b() { + ${fetchCode} + } + } + var a = new X; + a.b()` + assertThrowsInstanceOf(() => eval(source), SyntaxError); +} + +assertNonExisting(`return eval("this.#x")"`); +assertNonExisting(`return (1,eval)("this.#x")`); +assertNonExisting(`var f = Function("this.#x"); return f();`); + +if (typeof reportCompare === 'function') reportCompare(0, 0);
\ No newline at end of file diff --git a/js/src/tests/non262/PrivateName/modify-non-extensible.js b/js/src/tests/non262/PrivateName/modify-non-extensible.js new file mode 100644 index 0000000000..7e9af31895 --- /dev/null +++ b/js/src/tests/non262/PrivateName/modify-non-extensible.js @@ -0,0 +1,75 @@ +// |reftest| + +// Returns the argument in the constructor to allow stamping private fields into +// arbitrary objects. +class OverrideBase { + constructor(o) { + return o; + } +}; + +class A extends OverrideBase { + #a = 1; + g() { + return this.#a + } + + static gs(o) { + return o.#a; + } + static inca(obj) { + obj.#a++; + } +} + +var obj = {}; +Object.seal(obj); +new A(obj); // Add #a to obj, but not g. +assertEq('g' in obj, false); +assertEq(A.gs(obj), 1); +A.inca(obj); +assertEq(A.gs(obj), 2); + +// Ensure that the object remains non-extensible +obj.h = 'hi' +assertEq('h' in obj, false); + + +Object.freeze(obj); +A.inca(obj); // Despite being frozen, private names are modifiable. +assertEq(A.gs(obj), 3); +assertEq(Object.isFrozen(obj), true); + +var proxy = new Proxy({}, {}); +assertEq(Object.isFrozen(proxy), false); + +new A(proxy); +assertEq(A.gs(proxy), 1); + +// Note: this doesn't exercise the non-native object +// path in TestIntegrityLevel like you might expect. +// +// For that see below. +Object.freeze(proxy); +assertEq(Object.isFrozen(proxy), true); + +A.inca(proxy); +assertEq(A.gs(proxy), 2) + +var target = { a: 10 }; +Object.freeze(target); +new A(target); +assertEq(Object.isFrozen(target), true) + +var getOwnKeys = []; +var proxy = new Proxy(target, { + getOwnPropertyDescriptor: function (target, key) { + getOwnKeys.push(key); + return Reflect.getOwnPropertyDescriptor(target, key); + }, +}); + +Object.isFrozen(proxy); +assertEq(getOwnKeys.length, 1); + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/names.js b/js/src/tests/non262/PrivateName/names.js new file mode 100644 index 0000000000..39d5128b2e --- /dev/null +++ b/js/src/tests/non262/PrivateName/names.js @@ -0,0 +1,30 @@ +// |reftest| +var C = class { + static #field = () => 'Test262'; + static field = () => 'Test262'; + #instance = () => 'Test262'; + instance = () => 'Test262'; + + static accessPrivateField() { + return this.#field; + } + + accessPrivateInstanceField() { + return this.#instance; + } + + static accessField() { + return this.field; + } + + accessInstanceField() { + return this.instance; + } +} +assertEq(C.accessPrivateField().name, '#field') +assertEq(C.accessField().name, 'field'); +var c = new C; +assertEq(c.accessPrivateInstanceField().name, '#instance'); +assertEq(c.accessInstanceField().name, 'instance'); + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/nested-class-name-used.js b/js/src/tests/non262/PrivateName/nested-class-name-used.js new file mode 100644 index 0000000000..416a1aff36 --- /dev/null +++ b/js/src/tests/non262/PrivateName/nested-class-name-used.js @@ -0,0 +1,32 @@ +// |reftest| +// AllPrivateIdentifiersValid uses only lexical string names, not +// the dynamic private names; which means the below is not a syntax +// error but is instead a TypeError on access. + +class A { + #x = 10; + f() { + class B { + g() { + return this.#x; // note: #x isn't declared in this class, but + // the enclosing. + } + }; + this.y = new B; + } + constructor() { + this.f(); + } + g() { + return this.y.g(); + } +}; + +a = new A; +try { + a.g(); +} catch (e) { + assertEq(e instanceof TypeError, true); +} + +if (typeof reportCompare === 'function') reportCompare(0, 0);
\ No newline at end of file diff --git a/js/src/tests/non262/PrivateName/not-iterable.js b/js/src/tests/non262/PrivateName/not-iterable.js new file mode 100644 index 0000000000..0e9a76f569 --- /dev/null +++ b/js/src/tests/non262/PrivateName/not-iterable.js @@ -0,0 +1,39 @@ +// |reftest| +// +// Ensure PrivateNames aren't iterable. + +class O { + #x = 123; + gx() { + return this.#x; + } +} +var o = new O; + +assertEq(o.gx(), 123); + +assertEq(Object.keys(o).length, 0); +assertEq(Object.getOwnPropertyNames(o).length, 0); +assertEq(Object.getOwnPropertySymbols(o).length, 0); +assertEq(Reflect.ownKeys(o).length, 0); + +var forIn = []; +for (var pk in o) { + forIn.push(pk); +} +assertEq(forIn.length, 0); + +// Proxy case +var proxy = new Proxy(o, {}); +assertEq(Object.keys(proxy).length, 0); +assertEq(Object.getOwnPropertyNames(proxy).length, 0); +assertEq(Object.getOwnPropertySymbols(proxy).length, 0); +assertEq(Reflect.ownKeys(proxy).length, 0); + +for (var pk in proxy) { + forIn.push(pk); +} +assertEq(forIn.length, 0); + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/parse-utf8-non-ascii-identifier.js b/js/src/tests/non262/PrivateName/parse-utf8-non-ascii-identifier.js new file mode 100644 index 0000000000..7f4b15f2dc --- /dev/null +++ b/js/src/tests/non262/PrivateName/parse-utf8-non-ascii-identifier.js @@ -0,0 +1,22 @@ +// Test that non-ASCII identifier names are correctly parsed in the Utf-8 parser. + +// Utf-8 encoding for U+05EF is (0xD7 0xAF), the first code unit isn't a valid +// Ascii ID_START code unit. +class NonAscii { + // U+05EF HEBREW YOD TRIANGLE + #ׯ; +} + +// Also check using Unicode escapes works. +class NonAsciiUnicodeEscape1 { + // U+05EF HEBREW YOD TRIANGLE + #\u05ef; +} + +class NonAsciiUnicodeEscape2 { + // U+05EF HEBREW YOD TRIANGLE + #\u{5ef}; +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/prototype-proxy.js b/js/src/tests/non262/PrivateName/prototype-proxy.js new file mode 100644 index 0000000000..55c8abab13 --- /dev/null +++ b/js/src/tests/non262/PrivateName/prototype-proxy.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!this.hasOwnProperty("wrapWithProto")) + +const o0 = {}; +const v2 = new Proxy(o0, o0); + +// v8 is a forwarding proxy with "prototype" behaviour; +// see the comment for mHasPrototype on BaseProxyHandler +// in Proxy.h. +// +// Private Fields don't interact with the hasPrototype +// behaviour (to minimize the overhead, and since private +// fields are always own properties). +const v8 = this.wrapWithProto(v2, {}); +function f9(a10) { + return v8; +} +class C11 extends f9 { + #b = 12; + static { + const v13 = new this(); + + const val = v8.#b; // Get + assertEq(val, 12); + + v8.#b = 0; // Set + assertEq(v8.#b, 0); + + assertEq(#b in v8, true); // HasOwn. + } +} + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/proxy-1.js b/js/src/tests/non262/PrivateName/proxy-1.js new file mode 100644 index 0000000000..21f8f0ef08 --- /dev/null +++ b/js/src/tests/non262/PrivateName/proxy-1.js @@ -0,0 +1,21 @@ +// |reftest| + +class A { + #x = 10; + g() { + return this.#x; + } +}; + +var p = new Proxy(new A, {}); +var completed = false; +try { + p.g(); + completed = true; +} catch (e) { + assertEq(e instanceof TypeError, true); +} +assertEq(completed, false); + + +if (typeof reportCompare === 'function') reportCompare(0, 0); diff --git a/js/src/tests/non262/PrivateName/proxy-ccw.js b/js/src/tests/non262/PrivateName/proxy-ccw.js new file mode 100644 index 0000000000..94778489b6 --- /dev/null +++ b/js/src/tests/non262/PrivateName/proxy-ccw.js @@ -0,0 +1,66 @@ +// |reftest| + +// Validate CCWs and proxies +class Base { + constructor(o) { + return o; + } +} + +class A extends Base { + x1 = 12; + #x = 10; + static gx(o) { + return o.#x; + } + static sx(o, x) { + o.#x = x; + } + static hasx(o) { + try { + o.#x; + return true; + } catch { + return false; + } + } +} + + +var g = newGlobal({newCompartment: true}); +g.A = A; + +// cross_compartment_target is a cross compartment wrapper to an empty object. +var cross_compartment_target = g.eval('this.x = {}; this.x'); + +// #x gets stamped into the target of the CCW. +new A(cross_compartment_target); +assertEq(A.hasx(cross_compartment_target), true); + +// Can we update and read from this compartment? +assertEq(A.gx(cross_compartment_target), 10); +var o = {test: 12}; +A.sx(cross_compartment_target, o); +assertEq(A.gx(cross_compartment_target), o); + +// Can we read and update from the other compartment? +assertEq(g.eval('this.A.gx(this.x)'), o); +var y = g.eval('this.y = {test: 13}; this.A.sx(this.x, this.y); this.y'); +assertEq(g.eval('this.A.gx(this.x)'), y); +assertEq(A.gx(cross_compartment_target), y); + + +if (typeof nukeCCW === 'function') { + // Nuke the CCW. Now things should throw. + nukeCCW(cross_compartment_target); + var threw = true; + try { + A.gx(cross_compartment_target); + threw = false; + } catch (e) { + } + assertEq(threw, true); +} + + +if (typeof reportCompare === 'function') reportCompare(0, 0);
\ No newline at end of file diff --git a/js/src/tests/non262/PrivateName/proxy-init-set.js b/js/src/tests/non262/PrivateName/proxy-init-set.js new file mode 100644 index 0000000000..bc78f50a09 --- /dev/null +++ b/js/src/tests/non262/PrivateName/proxy-init-set.js @@ -0,0 +1,74 @@ +// |reftest| +// Ensure that the distinction between Proxy Init and Proxy Set holds + +function assertThrowsTypeError(f) { + var type; + try { + f(); + } catch (ex) { + type = ex.name; + } + assertEq(type, 'TypeError'); +} + + + +var target = {}; +var p1 = new Proxy(target, {}); +var p2 = new Proxy(target, {}); + +class Base { + constructor(o) { + return o; + } +} + +class A extends Base { + #field = 10; + static gf(o) { + return o.#field; + } + static sf(o) { + o.#field = 15; + } +} + +class B extends Base { + #field = 25; + static gf(o) { + return o.#field; + } + static sf(o) { + o.#field = 20; + } +} + +// Verify field handling on the proxy we install it on. +new A(p1); +assertEq(A.gf(p1), 10); +A.sf(p1) +assertEq(A.gf(p1), 15); + +// Despite P1 being stamped with A's field, it shouldn't +// be sufficient to set B's field. +assertThrowsTypeError(() => B.sf(p1)); +assertThrowsTypeError(() => B.gf(p1)); +assertThrowsTypeError(() => B.sf(p1)); +new B(p1); +assertEq(B.gf(p1), 25); +B.sf(p1); +assertEq(B.gf(p1), 20); + +// A's field should't be on the target +assertThrowsTypeError(() => A.gf(target)); + +// Can't set the field, doesn't exist +assertThrowsTypeError(() => A.sf(p2)); + +// Definitely can't get the field, doesn't exist. +assertThrowsTypeError(() => A.gf(p2)); + +// Still should't be on the target. +assertThrowsTypeError(() => A.gf(target)); + +if (typeof reportCompare === 'function') reportCompare(0, 0);
\ No newline at end of file diff --git a/js/src/tests/non262/PrivateName/read-private-eval.js b/js/src/tests/non262/PrivateName/read-private-eval.js new file mode 100644 index 0000000000..2c68e1c5d2 --- /dev/null +++ b/js/src/tests/non262/PrivateName/read-private-eval.js @@ -0,0 +1,13 @@ +// |reftest| + +class A { + #x = 14; + g() { + return eval('this.#x'); + } +} + +a = new A; +assertEq(a.g(), 14); + +if (typeof reportCompare === 'function') reportCompare(0, 0);
\ No newline at end of file diff --git a/js/src/tests/non262/PrivateName/shell.js b/js/src/tests/non262/PrivateName/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/PrivateName/shell.js diff --git a/js/src/tests/non262/PrivateName/unicode-names.js b/js/src/tests/non262/PrivateName/unicode-names.js new file mode 100644 index 0000000000..ff8d1fa2ff --- /dev/null +++ b/js/src/tests/non262/PrivateName/unicode-names.js @@ -0,0 +1,11 @@ +// |reftest| skip-if(!xulRuntime.shell) + +source = `class A { + // Ensure this name parses. Failure would be an InternalError: Buffer too + // small + #℘; +}`; + +Function(source); + +if (typeof reportCompare === 'function') reportCompare(0, 0);
\ No newline at end of file |