summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/PrivateName
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/PrivateName')
-rw-r--r--js/src/tests/non262/PrivateName/browser.js0
-rw-r--r--js/src/tests/non262/PrivateName/error-locations.js35
-rw-r--r--js/src/tests/non262/PrivateName/error-outside-class.js13
-rw-r--r--js/src/tests/non262/PrivateName/illegal-delete.js94
-rw-r--r--js/src/tests/non262/PrivateName/illegal-in-class-context.js24
-rw-r--r--js/src/tests/non262/PrivateName/illegal-in-identifier-context.js45
-rw-r--r--js/src/tests/non262/PrivateName/illegal-in-object-context.js14
-rw-r--r--js/src/tests/non262/PrivateName/lexical-presence.js55
-rw-r--r--js/src/tests/non262/PrivateName/modify-non-extensible.js42
-rw-r--r--js/src/tests/non262/PrivateName/names.js31
-rw-r--r--js/src/tests/non262/PrivateName/nested-class-name-used.js33
-rw-r--r--js/src/tests/non262/PrivateName/not-iterable.js39
-rw-r--r--js/src/tests/non262/PrivateName/proxy-1.js21
-rw-r--r--js/src/tests/non262/PrivateName/proxy-ccw.js66
-rw-r--r--js/src/tests/non262/PrivateName/proxy-init-set.js75
-rw-r--r--js/src/tests/non262/PrivateName/read-private-eval.js13
-rw-r--r--js/src/tests/non262/PrivateName/shell.js0
-rw-r--r--js/src/tests/non262/PrivateName/unicode-names.js16
18 files changed, 616 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/error-locations.js b/js/src/tests/non262/PrivateName/error-locations.js
new file mode 100644
index 0000000000..fb54faaefa
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/error-locations.js
@@ -0,0 +1,35 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+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, 28);
+// 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, 28);
+assertLineAndColumn(`this.#x`, 1, 5);
+// Make sure we're reporting the first error, if there are multiple, in
+// non-class context;
+assertLineAndColumn(`this.#x; this.#y; this.#z`, 1, 5);
+
+assertLineAndColumn(
+ `class A {
+g() { return this.#x; }}`,
+ 2, 18);
+assertLineAndColumn(
+ `class A {
+
+g() { return this.#x; } y() { return this.#y; }}`,
+ 3, 18);
+
+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/illegal-delete.js b/js/src/tests/non262/PrivateName/illegal-delete.js
new file mode 100644
index 0000000000..84d527a378
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/illegal-delete.js
@@ -0,0 +1,94 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+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..3012e4bfe9
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/illegal-in-class-context.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+// Are private fields enabled?
+let privateFields = false;
+try {
+ Function('class C { #x; }');
+ privateFields = true;
+} catch (exc) {
+ assertEq(exc instanceof SyntaxError, true);
+}
+
+if (!privateFields) {
+ assertThrowsInstanceOf(() => eval(`class A { #x }`), SyntaxError);
+ assertThrowsInstanceOf(() => eval(`class A { #x=10 }`), SyntaxError);
+} else {
+ assertThrowsInstanceOf(() => eval(`class A { #x; #x; }`), SyntaxError);
+}
+
+// No computed private fields
+assertThrowsInstanceOf(
+ () => eval(`var x = "foo"; class A { #[x] = 20; }`), SyntaxError);
+
+
+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..4ec5c310c4
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/lexical-presence.js
@@ -0,0 +1,55 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+// 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..b57f82b38e
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/modify-non-extensible.js
@@ -0,0 +1,42 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+// 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);
+
+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..f71f1ac19d
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/names.js
@@ -0,0 +1,31 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+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..cc1a77f375
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/nested-class-name-used.js
@@ -0,0 +1,33 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+// 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..59c6169079
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/not-iterable.js
@@ -0,0 +1,39 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+//
+// 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/proxy-1.js b/js/src/tests/non262/PrivateName/proxy-1.js
new file mode 100644
index 0000000000..5a70841450
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/proxy-1.js
@@ -0,0 +1,21 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+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..e68426b93d
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/proxy-ccw.js
@@ -0,0 +1,66 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+// 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..0d94ec0492
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/proxy-init-set.js
@@ -0,0 +1,75 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-options
+
+// 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..1f96f2ac5c
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/read-private-eval.js
@@ -0,0 +1,13 @@
+// |reftest| shell-option(--enable-private-fields) skip-if(!xulRuntime.shell) -- requires shell-option
+
+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..25eeffff4a
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/unicode-names.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+source = `class A {
+ // Ensure this name parses. Failure would be an InternalError: Buffer too
+ // small
+ #℘;
+}`;
+
+try {
+ Function(source);
+} catch (e) {
+ assertEq(getRealmConfiguration()['privateFields'], false);
+ assertEq(e instanceof SyntaxError, true);
+}
+
+if (typeof reportCompare === 'function') reportCompare(0, 0); \ No newline at end of file