mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 18:57:42 +00:00
LibJS: Add tests for the new steps added to PerformEval
This commit is contained in:
parent
34f902fb52
commit
7798821f5b
5 changed files with 388 additions and 0 deletions
|
@ -199,3 +199,253 @@ test("Issue #8574, super property access before super() call", () => {
|
||||||
}).toThrowWithMessage(ReferenceError, "|this| has not been initialized");
|
}).toThrowWithMessage(ReferenceError, "|this| has not been initialized");
|
||||||
expect(hit).toBeTrue();
|
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");
|
||||||
|
});
|
||||||
|
|
|
@ -111,3 +111,40 @@ test("private identifier not followed by 'in' throws", () => {
|
||||||
test("cannot have static and non static field with the same description", () => {
|
test("cannot have static and non static field with the same description", () => {
|
||||||
expect("class A { static #simple; #simple; }").not.toEval();
|
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");
|
||||||
|
});
|
||||||
|
|
|
@ -86,6 +86,43 @@ test("with super class", () => {
|
||||||
expect(b.super_field).toBe(4);
|
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", () => {
|
describe("class fields with a 'special' name", () => {
|
||||||
test("static", () => {
|
test("static", () => {
|
||||||
class A {
|
class A {
|
||||||
|
|
|
@ -20,6 +20,42 @@ test("basic functionality", () => {
|
||||||
expect(new baz().newTarget).toEqual(baz);
|
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", () => {
|
test("syntax error outside of function", () => {
|
||||||
expect("new.target").not.toEval();
|
expect("new.target").not.toEval();
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,3 +51,31 @@ describe("returning from loops", () => {
|
||||||
expect(foo()).toBe(10);
|
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");
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue