561a617bc234c63a16a632c69e54dfe4ecf36cb5
[WebKit.git] / LayoutTests / js / script-tests / class-syntax-name.js
1 description('Tests for ES6 class name semantics in class statements and expressions');
2
3 function runTestShouldBe(statement, result) {
4     shouldBe(statement, result);
5     shouldBe("'use strict'; " + statement, result);
6 }
7
8 function runTestShouldBeTrue(statement) {
9     shouldBeTrue(statement);
10     shouldBeTrue("'use strict'; " + statement);
11 }
12
13 function runTestShouldThrow(statement) {
14     shouldThrow(statement);
15     shouldThrow("'use strict'; " + statement);
16 }
17
18 function runTestShouldNotThrow(statement) {
19     shouldNotThrow(statement);
20     shouldNotThrow("'use strict'; " + statement);
21 }
22
23 // Class statement. Class name added to global scope. Class name is available inside class scope and in global scope.
24 debug('Class statement');
25 runTestShouldThrow("A");
26 runTestShouldThrow("class {}");
27 runTestShouldThrow("class { constructor() {} }");
28 runTestShouldNotThrow("class A { constructor() {} }");
29 runTestShouldBe("class A { constructor() {} }; A.toString()", "'function A() {}'");
30 runTestShouldBeTrue("class A { constructor() {} }; (new A) instanceof A");
31 runTestShouldBe("class A { constructor() { this.base = A; } }; (new A).base.toString()", "'function A() { this.base = A; }'");
32 runTestShouldNotThrow("class A { constructor() {} }; class B extends A {};");
33 runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() {} }; B.toString()", "'function B() {}'");
34 runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof A");
35 runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof B");
36 runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString()", "'function A() {}'");
37 runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString()", "'function B() { super(); this.base = A; this.derived = B; }'");
38
39 // Class expression. Class name not added to scope. Class name is available inside class scope.
40 debug(''); debug('Class expression');
41 runTestShouldThrow("A");
42 runTestShouldNotThrow("(class {})");
43 runTestShouldNotThrow("(class { constructor(){} })");
44 runTestShouldBe("typeof (class {})", '"function"');
45 runTestShouldNotThrow("(class A {})");
46 runTestShouldBe("typeof (class A {})", '"function"');
47 runTestShouldThrow("(class A {}); A");
48 runTestShouldNotThrow("new (class A {})");
49 runTestShouldBe("typeof (new (class A {}))", '"object"');
50 runTestShouldNotThrow("(new (class A { constructor() { this.base = A; } })).base");
51 runTestShouldBe("(new (class A { constructor() { this.base = A; } })).base.toString()", '"function A() { this.base = A; }"');
52 runTestShouldNotThrow("class A {}; (class B extends A {})");
53 runTestShouldThrow("class A {}; (class B extends A {}); B");
54 runTestShouldNotThrow("class A {}; new (class B extends A {})");
55 runTestShouldNotThrow("class A {}; new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })");
56 runTestShouldBeTrue("class A {}; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })) instanceof A");
57 runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString()", "'function A() {}'");
58 runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString()", "'function B() { super(); this.base = A; this.derived = B; }'");
59
60 // Assignment of a class expression to a variable. Variable name available in scope, class name is not. Class name is available inside class scope.
61 debug(''); debug('Class expression assignment to variable');
62 runTestShouldThrow("A");
63 runTestShouldNotThrow("var VarA = class {}");
64 runTestShouldBe("var VarA = class { constructor() {} }; VarA.toString()", "'function () {}'");
65 runTestShouldThrow("VarA");
66 runTestShouldNotThrow("var VarA = class A { constructor() {} }");
67 runTestShouldBe("var VarA = class A { constructor() {} }; VarA.toString()", "'function A() {}'");
68 runTestShouldThrow("var VarA = class A { constructor() {} }; A.toString()");
69 runTestShouldBeTrue("var VarA = class A { constructor() {} }; (new VarA) instanceof VarA");
70 runTestShouldBe("var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString()", "'function A() { this.base = A; }'");
71 runTestShouldNotThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} };");
72 runTestShouldThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; B");
73 runTestShouldBe("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString()", "'function B() {}'");
74 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarA");
75 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarB");
76 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() { super(); this.base = VarA; this.derived = B; this.derivedVar = VarB; } }; (new VarB).base === VarA");
77 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() { super(); this.base = VarA; this.derived = B; this.derivedVar = VarB; } }; (new VarB).derived === VarB");
78 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() { super(); this.base = VarA; this.derived = B; this.derivedVar = VarB; } }; (new VarB).derivedVar === VarB");
79
80 // FIXME: Class statement binding should be like `let`, not `var`.
81 debug(''); debug('Class statement binding in other circumstances');
82 runTestShouldThrow("var result = A; result");
83 runTestShouldThrow("var result = A; class A {}; result");
84 runTestShouldThrow("class A { constructor() { A = 1; } }; new A");
85 runTestShouldBe("class A { constructor() { } }; A = 1; A", "1");
86 runTestShouldNotThrow("class A {}; var result = A; result");
87 shouldBe("eval('var Foo = 10'); Foo", "10");
88 shouldThrow("'use strict'; eval('var Foo = 10'); Foo");
89 shouldBe("eval('class Bar { constructor() {} }'); Bar.toString()", "'function Bar() {}'");
90 shouldThrow("'use strict'; eval('class Bar { constructor() {} }'); Bar.toString()");