summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/ShadowRealms
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/tests/non262/ShadowRealms
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--js/src/tests/non262/ShadowRealms/ccw-2.js22
-rw-r--r--js/src/tests/non262/ShadowRealms/ccw.js33
-rw-r--r--js/src/tests/non262/ShadowRealms/error.js102
-rw-r--r--js/src/tests/non262/ShadowRealms/function-copy-name-and-length-fails-error-realm.js27
-rw-r--r--js/src/tests/non262/ShadowRealms/function-return.js73
-rw-r--r--js/src/tests/non262/ShadowRealms/interrupt-request.js16
-rw-r--r--js/src/tests/non262/ShadowRealms/syntax-error.js33
-rw-r--r--js/src/tests/non262/ShadowRealms/unwrap-wrap-with-proto.js12
8 files changed, 318 insertions, 0 deletions
diff --git a/js/src/tests/non262/ShadowRealms/ccw-2.js b/js/src/tests/non262/ShadowRealms/ccw-2.js
new file mode 100644
index 0000000000..5a60341a65
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/ccw-2.js
@@ -0,0 +1,22 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+var g = newGlobal({newCompartment: true});
+
+var sr = new ShadowRealm();
+
+var f = sr.evaluate(`
+ var wrappedCCW;
+ (f => { wrappedCCW = f; });
+`);
+
+f(g.evaluate(`x => x()`));
+
+var h = sr.evaluate(`
+ // Pass an object from the ShadowRealm's compartment to the CCW function.
+ wrappedCCW(() => { return "ok"; })
+`);
+
+assertEq(h, "ok");
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/ShadowRealms/ccw.js b/js/src/tests/non262/ShadowRealms/ccw.js
new file mode 100644
index 0000000000..7596f15823
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/ccw.js
@@ -0,0 +1,33 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+var g = newGlobal({ newCompartment: true });
+
+var sr = g.evaluate(`new ShadowRealm()`);
+
+
+// sr should be a CCW to a ShadowRealm.
+ShadowRealm.prototype.evaluate.call(sr, "var x = 10");
+assertEq(sr.evaluate("x"), 10);
+
+// wrappedf should *not* be a CCW, because we're using this realm's ShadowRealm.prototype.evaluate,
+// and so the active realm when invoking will be this current realm.
+//
+// However, the target function (wrappedf's f) comes from another compartment, and will have to be a CCW.
+var wrappedf = ShadowRealm.prototype.evaluate.call(sr, "function f() { return 10; }; f");
+assertEq(wrappedf(), 10);
+
+var evaluate_from_other_realm = g.evaluate('ShadowRealm.prototype.evaluate');
+
+// wrappedb should be a CCW, since the callee of the .call comes from the other
+// compartment.
+var wrappedb = evaluate_from_other_realm.call(sr, "function b() { return 12; }; b");
+assertEq(wrappedb(), 12);
+
+nukeAllCCWs()
+// This throws, but the dead object message is lost and replaced with the wrapped function
+// object message.
+assertThrowsInstanceOf(() => wrappedf(), TypeError);
+assertThrowsInstanceOf(() => wrappedb(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true); \ No newline at end of file
diff --git a/js/src/tests/non262/ShadowRealms/error.js b/js/src/tests/non262/ShadowRealms/error.js
new file mode 100644
index 0000000000..0d0a559b28
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/error.js
@@ -0,0 +1,102 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+let sr = new ShadowRealm();
+
+try {
+ sr.evaluate("throw new Error('hi')");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/Error: hi/.test(e.message), true, "Should have included information from thrown error");
+}
+
+try {
+ sr.evaluate("throw new Error('∂å∂')");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/Error: ∂å∂/.test(e.message), true, "Should have included information from thrown error, UTF-8 Pass through.");
+}
+
+try {
+ sr.evaluate("throw {name: 'Hello', message: 'goodbye'}");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/uncaught exception: Object/.test(e.message), true, "Should get generic fillin message, non-string");
+}
+
+try {
+ sr.evaluate("throw {name: 10, message: 11}");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/uncaught exception: Object/.test(e.message), true, "Should get generic fillin message, non-string");
+}
+
+
+try {
+ sr.evaluate("throw { get name() { return 'holy'; }, get message() { return 'smokes' } }");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/uncaught exception: Object/.test(e.message), true, "Should get generic error message, getters");
+}
+
+// Wrapped Functions
+try {
+ var wrapped = sr.evaluate("() => { throw new Error('hi') }");
+ assertEq(!!wrapped, true, "Wrapped created");
+ wrapped();
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/Error: hi/.test(e.message), true, "Should have included information from thrown error");
+}
+
+try {
+ var wrapped = sr.evaluate("() => { throw new Error('∂å∂') } ");
+ assertEq(!!wrapped, true, "Wrapped created");
+ wrapped();
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/Error: ∂å∂/.test(e.message), true, "Should have included information from thrown error, UTF-8 Pass through.");
+}
+
+try {
+ var wrapped = sr.evaluate("() => { throw {name: 'Hello', message: 'goodbye'} } ");
+ assertEq(!!wrapped, true, "Wrapped created");
+ wrapped();
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/uncaught exception: Object/.test(e.message), true, "Should get generic error message");
+}
+
+try {
+ var wrapped = sr.evaluate("() => { throw {name: 10, message: 11} } ");
+ assertEq(!!wrapped, true, "Wrapped created");
+ wrapped();
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ print(e.message)
+ assertEq(/uncaught exception: Object/.test(e.message), true, "Should get generic error message");
+}
+
+
+try {
+ var wrapped = sr.evaluate("() => { throw { get name() { return 'holy'; }, get message() { return 'smokes' } } } ");
+ assertEq(!!wrapped, true, "Wrapped created");
+ wrapped();
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof TypeError, true, "Correct type of error")
+ assertEq(/uncaught exception: Object/.test(e.message), true, "Should get generic error message");
+}
+
+
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true); \ No newline at end of file
diff --git a/js/src/tests/non262/ShadowRealms/function-copy-name-and-length-fails-error-realm.js b/js/src/tests/non262/ShadowRealms/function-copy-name-and-length-fails-error-realm.js
new file mode 100644
index 0000000000..23040c9fb3
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/function-copy-name-and-length-fails-error-realm.js
@@ -0,0 +1,27 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+var sr = new ShadowRealm();
+
+var id = sr.evaluate(`x => x()`);
+
+// |id| is a Function from the current realm and _not_ from ShadowRealm.
+assertEq(id instanceof Function, true);
+
+function f() {
+ return 1;
+}
+
+// Smoke test: Ensure calling |f| through the ShadowRealm works correctly.
+assertEq(id(f), 1);
+
+// Add an accessor for "name" which throws. This will lead to throwing an
+// exception in CopyNameAndLength. The thrown exception should be from the
+// realm of |id|, i.e. the current realm.
+Object.defineProperty(f, "name", {
+ get() { throw new Error; }
+});
+
+assertThrowsInstanceOf(() => id(f), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/ShadowRealms/function-return.js b/js/src/tests/non262/ShadowRealms/function-return.js
new file mode 100644
index 0000000000..d0853bcbb3
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/function-return.js
@@ -0,0 +1,73 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+// The output of Function.prototype.toString must match the |NativeFunction| production.
+// https://tc39.es/ecma262/#sec-function.prototype.tostring
+//
+// NativeFunction :
+// function NativeFunctionAccessor? PropertyName[~Yield, ~Await]? ( FormalParameters[~Yield, ~Await] ) { [ native code ] }
+//
+// NativeFunctionAccessor :
+// get
+// set
+
+function assertMatchesNativeFunction(f) {
+ var source = f.toString();
+
+ // Starts with "function".
+ assertEq(/^function\b/.test(source), true);
+
+ // Remove the optional |NativeFunctionAccessor| part.
+ var nativeAccesorRe = /^(?<start>\s*function)(?<accessor>\s+[gs]et)(?<end>\s+[^(].*)$/;
+ var match = nativeAccesorRe.exec(source);
+ if (match) {
+ source = match.groups.start + match.groups.end;
+ }
+
+ // The body must include the string "[native code".
+ var closeCurly = source.lastIndexOf("}");
+ var openCurly = source.lastIndexOf("{");
+ assertEq(openCurly < closeCurly, true);
+
+ var body = source.slice(openCurly + 1, closeCurly);
+ assertEq(/^\s*\[native code\]\s*$/.test(body), true);
+
+ // Verify |PropertyName| and |FormalParameters| are syntactically correct by parsing the source
+ // code. But we first need to replace the "[native code]" substring.
+ source = source.slice(0, openCurly) + "{}";
+
+ // Also prepend "void" to parse the function source code as a FunctionExpression, because we
+ // don't necessarily have a name part.
+ source = "void " + source;
+
+ try {
+ Function(source);
+ } catch {
+ assertEq(true, false, `${source} doesn't match NativeFunction`);
+ }
+}
+
+let sr = new ShadowRealm();
+var f = sr.evaluate("function f() { }; f");
+
+assertMatchesNativeFunction(f);
+
+f.name = "koala"
+assertMatchesNativeFunction(f);
+
+Object.defineProperty(f, "name", { writable: true, value: "koala" });
+assertMatchesNativeFunction(f);
+
+f.name = "panda"
+assertMatchesNativeFunction(f);
+
+f.name = "has whitespace, therefore shouldn't match the PropertyName production";
+assertMatchesNativeFunction(f);
+
+f.name = 123;
+assertMatchesNativeFunction(f);
+
+Object.defineProperty(f, "name", { get() { throw new Error("unexpected side-effect"); } });
+assertMatchesNativeFunction(f);
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/ShadowRealms/interrupt-request.js b/js/src/tests/non262/ShadowRealms/interrupt-request.js
new file mode 100644
index 0000000000..160a861135
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/interrupt-request.js
@@ -0,0 +1,16 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+// Request interrupt from shadow realm evaluation.
+
+expectExitCode(6);
+
+new ShadowRealm().evaluate(`
+ (interruptIf => {
+ interruptIf(true);
+
+ for (;;) {} // Wait for interrupt.
+ });
+`)(interruptIf);
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);
diff --git a/js/src/tests/non262/ShadowRealms/syntax-error.js b/js/src/tests/non262/ShadowRealms/syntax-error.js
new file mode 100644
index 0000000000..8cae199f50
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/syntax-error.js
@@ -0,0 +1,33 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+let sr = new ShadowRealm();
+
+try {
+ sr.evaluate("var x /");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof SyntaxError, true, "Same Global Error")
+ assertEq(/unterminated regular expression literal/.test(e.message), true, "Should have reported a sensible error message");
+}
+
+try {
+ sr.evaluate("var x =");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof SyntaxError, true, "Same Global Error")
+ assertEq(/expected expression/.test(e.message), true, "Should have reported a sensible error message");
+}
+
+
+try {
+ sr.evaluate("#x in this");
+ assertEq(true, false, "Should have thrown");
+} catch (e) {
+ assertEq(e instanceof SyntaxError, true, "Same Global Error")
+ assertEq(/reference to undeclared private field or method/.test(e.message), true, "Should have reported a sensible error message");
+}
+
+
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true); \ No newline at end of file
diff --git a/js/src/tests/non262/ShadowRealms/unwrap-wrap-with-proto.js b/js/src/tests/non262/ShadowRealms/unwrap-wrap-with-proto.js
new file mode 100644
index 0000000000..f4e07e67b5
--- /dev/null
+++ b/js/src/tests/non262/ShadowRealms/unwrap-wrap-with-proto.js
@@ -0,0 +1,12 @@
+// |reftest| shell-option(--enable-shadow-realms) skip-if(!xulRuntime.shell)
+
+var sr = new ShadowRealm();
+
+var w = wrapWithProto(sr, null);
+
+var r = ShadowRealm.prototype.evaluate.call(w, `"ok"`);
+
+assertEq(r, "ok");
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);