summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorLuke Wilde <lukew@serenityos.org>2022-04-10 00:56:04 +0100
committerLinus Groh <mail@linusgroh.de>2022-04-11 21:23:36 +0100
commit7798821f5ba4e574d5049f2182c90d229d7923c1 (patch)
treeb210da495362c41d199d80b529909c5932840837 /Userland
parent34f902fb524808b308efe4568ff5a026d2cb4884 (diff)
downloadserenity-7798821f5ba4e574d5049f2182c90d229d7923c1.zip
LibJS: Add tests for the new steps added to PerformEval
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-inheritance.js250
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-private-fields.js37
-rw-r--r--Userland/Libraries/LibJS/Tests/classes/class-public-fields.js37
-rw-r--r--Userland/Libraries/LibJS/Tests/functions/function-new-target.js36
-rw-r--r--Userland/Libraries/LibJS/Tests/return.js28
5 files changed, 388 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js b/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js
index 336e2b729b..3ec85ec3ee 100644
--- a/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js
+++ b/Userland/Libraries/LibJS/Tests/classes/class-inheritance.js
@@ -199,3 +199,253 @@ test("Issue #8574, super property access before super() call", () => {
}).toThrowWithMessage(ReferenceError, "|this| has not been initialized");
expect(hit).toBeTrue();
});
+
+test("can access super via direct eval", () => {
+ let superCalled = false;
+ const aObject = { a: 1 };
+ const bObject = { b: 2 };
+
+ class A {
+ constructor() {
+ superCalled = true;
+ }
+
+ foo() {
+ return aObject;
+ }
+
+ bar() {
+ return bObject;
+ }
+ }
+
+ class B extends A {
+ constructor() {
+ eval("super()");
+ }
+ }
+
+ expect(() => {
+ new B();
+ }).not.toThrow();
+
+ expect(superCalled).toBeTrue();
+ superCalled = false;
+
+ class C extends A {
+ constructor() {
+ eval("super()");
+ return eval("super.foo()");
+ }
+ }
+
+ expect(() => {
+ new C();
+ }).not.toThrow();
+
+ expect(superCalled).toBeTrue();
+ superCalled = false;
+
+ expect(new C()).toBe(aObject);
+
+ expect(superCalled).toBeTrue();
+ superCalled = false;
+
+ class D extends A {
+ constructor() {
+ eval("super()");
+ return eval("super['bar']()");
+ }
+ }
+
+ expect(() => {
+ new D();
+ }).not.toThrow();
+
+ expect(superCalled).toBeTrue();
+ superCalled = false;
+
+ expect(new D()).toBe(bObject);
+
+ expect(superCalled).toBeTrue();
+});
+
+test("cannot access super via indirect eval", () => {
+ const indirect = eval;
+ let superCalled = false;
+
+ const aObject = { a: 1 };
+ const bObject = { b: 1 };
+
+ class A {
+ constructor() {
+ superCalled = true;
+ this.a = aObject;
+ this.c = bObject;
+ }
+ }
+
+ class B extends A {
+ constructor() {
+ indirect("super()");
+ }
+ }
+
+ expect(() => {
+ new B();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(superCalled).toBeFalse();
+
+ class C extends A {
+ constructor() {
+ super();
+ return indirect("super.a");
+ }
+ }
+
+ expect(() => {
+ new C();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(superCalled).toBeTrue();
+ superCalled = false;
+
+ class D extends A {
+ constructor() {
+ super();
+ return indirect("super['b']");
+ }
+ }
+
+ expect(() => {
+ new D();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(superCalled).toBeTrue();
+});
+
+test("super outside of derived class fails to parse", () => {
+ expect("super").not.toEval();
+ expect("super()").not.toEval();
+ expect("super.a").not.toEval();
+ expect("super['b']").not.toEval();
+ expect("function a() { super }").not.toEval();
+ expect("function a() { super() }").not.toEval();
+ expect("function a() { super.a }").not.toEval();
+ expect("function a() { super['b'] }").not.toEval();
+ expect("() => { super }").not.toEval();
+ expect("() => { super() }").not.toEval();
+ expect("() => { super.a }").not.toEval();
+ expect("() => { super['b'] }").not.toEval();
+ expect("class A { constructor() { super } }").not.toEval();
+ expect("class A { constructor() { super() } }").not.toEval();
+
+ expect(() => {
+ eval("super");
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ eval("super()");
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ eval("super.a");
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ eval("super['b']");
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ function a() {
+ eval("super");
+ }
+
+ expect(() => {
+ a();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ new a();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ function b() {
+ eval("super()");
+ }
+
+ expect(() => {
+ b();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ new b();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ function c() {
+ eval("super.a");
+ }
+
+ expect(() => {
+ c();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ new c();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ function d() {
+ eval("super['b']");
+ }
+
+ expect(() => {
+ d();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ expect(() => {
+ new d();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ const e = () => eval("super");
+
+ expect(() => {
+ e();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ const f = () => eval("super()");
+
+ expect(() => {
+ f();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ const g = () => eval("super.a");
+
+ expect(() => {
+ g();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ const h = () => eval("super['b']");
+
+ expect(() => {
+ h();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ class I {
+ constructor() {
+ eval("super");
+ }
+ }
+
+ expect(() => {
+ new I();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+
+ class J {
+ constructor() {
+ eval("super()");
+ }
+ }
+
+ expect(() => {
+ new J();
+ }).toThrowWithMessage(SyntaxError, "'super' keyword unexpected here");
+});
diff --git a/Userland/Libraries/LibJS/Tests/classes/class-private-fields.js b/Userland/Libraries/LibJS/Tests/classes/class-private-fields.js
index 2eebaa6245..a00dd74235 100644
--- a/Userland/Libraries/LibJS/Tests/classes/class-private-fields.js
+++ b/Userland/Libraries/LibJS/Tests/classes/class-private-fields.js
@@ -111,3 +111,40 @@ test("private identifier not followed by 'in' throws", () => {
test("cannot have static and non static field with the same description", () => {
expect("class A { static #simple; #simple; }").not.toEval();
});
+
+test("'arguments' is not allowed in class field initializer", () => {
+ expect("class A { #a = arguments; }").not.toEval();
+ expect("class B { static #b = arguments; }").not.toEval();
+
+ class C {
+ #c = eval("arguments");
+ }
+
+ expect(() => {
+ new C();
+ }).toThrowWithMessage(SyntaxError, "'arguments' is not allowed in class field initializer");
+
+ expect(() => {
+ class D {
+ static #d = eval("arguments");
+ }
+ }).toThrowWithMessage(SyntaxError, "'arguments' is not allowed in class field initializer");
+});
+
+test("using 'arguments' via indirect eval throws at runtime instead of parse time", () => {
+ const indirect = eval;
+
+ class A {
+ #a = indirect("arguments");
+ }
+
+ expect(() => {
+ new A();
+ }).toThrowWithMessage(ReferenceError, "'arguments' is not defined");
+
+ expect(() => {
+ class B {
+ static #b = indirect("arguments");
+ }
+ }).toThrowWithMessage(ReferenceError, "'arguments' is not defined");
+});
diff --git a/Userland/Libraries/LibJS/Tests/classes/class-public-fields.js b/Userland/Libraries/LibJS/Tests/classes/class-public-fields.js
index 4bc405e362..da76f4cf80 100644
--- a/Userland/Libraries/LibJS/Tests/classes/class-public-fields.js
+++ b/Userland/Libraries/LibJS/Tests/classes/class-public-fields.js
@@ -86,6 +86,43 @@ test("with super class", () => {
expect(b.super_field).toBe(4);
});
+test("'arguments' is not allowed in class field initializer", () => {
+ expect("class A { a = arguments; }").not.toEval();
+ expect("class B { static b = arguments; }").not.toEval();
+
+ class C {
+ c = eval("arguments");
+ }
+
+ expect(() => {
+ new C();
+ }).toThrowWithMessage(SyntaxError, "'arguments' is not allowed in class field initializer");
+
+ expect(() => {
+ class D {
+ static d = eval("arguments");
+ }
+ }).toThrowWithMessage(SyntaxError, "'arguments' is not allowed in class field initializer");
+});
+
+test("using 'arguments' via indirect eval throws at runtime instead of parse time", () => {
+ const indirect = eval;
+
+ class A {
+ a = indirect("arguments");
+ }
+
+ expect(() => {
+ new A();
+ }).toThrowWithMessage(ReferenceError, "'arguments' is not defined");
+
+ expect(() => {
+ class B {
+ static b = indirect("arguments");
+ }
+ }).toThrowWithMessage(ReferenceError, "'arguments' is not defined");
+});
+
describe("class fields with a 'special' name", () => {
test("static", () => {
class A {
diff --git a/Userland/Libraries/LibJS/Tests/functions/function-new-target.js b/Userland/Libraries/LibJS/Tests/functions/function-new-target.js
index 9eb7659391..bd3369ff21 100644
--- a/Userland/Libraries/LibJS/Tests/functions/function-new-target.js
+++ b/Userland/Libraries/LibJS/Tests/functions/function-new-target.js
@@ -20,6 +20,42 @@ test("basic functionality", () => {
expect(new baz().newTarget).toEqual(baz);
});
+test("retrieving new.target from direct eval", () => {
+ function foo() {
+ return eval("new.target");
+ }
+
+ let result;
+
+ expect(() => {
+ result = foo();
+ }).not.toThrowWithMessage(SyntaxError, "'new.target' not allowed outside of a function");
+
+ expect(result).toBe(undefined);
+
+ expect(() => {
+ result = new foo();
+ }).not.toThrowWithMessage(SyntaxError, "'new.target' not allowed outside of a function");
+
+ expect(result).toBe(foo);
+});
+
+test("cannot retrieve new.target from indirect eval", () => {
+ const indirect = eval;
+
+ function foo() {
+ return indirect("new.target");
+ }
+
+ expect(() => {
+ foo();
+ }).toThrowWithMessage(SyntaxError, "'new.target' not allowed outside of a function");
+
+ expect(() => {
+ new foo();
+ }).toThrowWithMessage(SyntaxError, "'new.target' not allowed outside of a function");
+});
+
test("syntax error outside of function", () => {
expect("new.target").not.toEval();
});
diff --git a/Userland/Libraries/LibJS/Tests/return.js b/Userland/Libraries/LibJS/Tests/return.js
index 2c5b8683f6..fdde273be4 100644
--- a/Userland/Libraries/LibJS/Tests/return.js
+++ b/Userland/Libraries/LibJS/Tests/return.js
@@ -51,3 +51,31 @@ describe("returning from loops", () => {
expect(foo()).toBe(10);
});
});
+
+test("cannot use return in eval", () => {
+ const indirect = eval;
+
+ expect(() => {
+ eval("return 1;");
+ }).toThrowWithMessage(SyntaxError, "'return' not allowed outside of a function");
+
+ expect(() => {
+ indirect("return 1;");
+ }).toThrowWithMessage(SyntaxError, "'return' not allowed outside of a function");
+
+ function foo() {
+ eval("return 1;");
+ }
+
+ expect(() => {
+ foo();
+ }).toThrowWithMessage(SyntaxError, "'return' not allowed outside of a function");
+
+ function bar() {
+ indirect("return 1;");
+ }
+
+ expect(() => {
+ bar();
+ }).toThrowWithMessage(SyntaxError, "'return' not allowed outside of a function");
+});