LibJS: Add tests for the new steps added to PerformEval

This commit is contained in:
Luke Wilde 2022-04-10 00:56:04 +01:00 committed by Linus Groh
parent 34f902fb52
commit 7798821f5b
Notes: sideshowbarker 2024-07-17 12:04:37 +09:00
5 changed files with 388 additions and 0 deletions

View file

@ -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");
});

View file

@ -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");
});

View file

@ -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 {

View file

@ -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();
});

View file

@ -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");
});