ES6 class syntax should use block scoping
[WebKit.git] / LayoutTests / js / script-tests / class-syntax-extends.js
1
2 description('Tests for ES6 class syntax "extends"');
3
4 function shouldThrow(s, message) {
5     var threw = false;
6     try {
7         eval(s);
8     } catch(e) {
9         threw = true;
10         if (!message || e.toString() === eval(message))
11             testPassed(s + ":::" + e.toString());
12         else
13             testFailed(s);
14     }
15     if (!threw)
16         testFailed(s);
17 }
18
19 function shouldNotThrow(s) {
20     var threw = false;
21     try {
22         eval(s);
23     } catch(e) {
24         threw = true;
25     }
26     if (threw)
27         testFailed(s);
28     else
29         testPassed(s);
30 }
31
32 function shouldBe(a, b) {
33     if (eval(a) === eval(b))
34         testPassed(a + ":::" + b);
35     else
36         testFailed(a + ":::" + b);
37 }
38
39 function shouldBeTrue(s) {
40     if (eval(s) === true)
41         testPassed(s);
42     else
43         testFailed(s);
44 }
45
46 class Base {
47     constructor() { }
48     baseMethod() { return 'base'; }
49     overridenMethod() { return 'base'; }
50     static staticBaseMethod() { return 'base'; }
51     static staticOverridenMethod() { return 'base'; }
52 }
53
54 class Derived extends Base {
55     constructor() { super(); }
56     overridenMethod() { return 'derived'; }
57     static staticOverridenMethod() { return 'derived'; }
58 }
59
60 shouldBeTrue('(new Base) instanceof Base');
61 shouldBe('Object.getPrototypeOf(new Base)', 'Base.prototype');
62 shouldBeTrue('(new Derived) instanceof Derived');
63 shouldBe('Object.getPrototypeOf(new Derived)', 'Derived.prototype');
64 shouldBe('Object.getPrototypeOf(Derived.prototype)', 'Base.prototype');
65 shouldBe('(new Derived).baseMethod()', '"base"');
66 shouldBe('(new Derived).overridenMethod()', '"derived"');
67 shouldBe('Derived.staticBaseMethod()', '"base"');
68 shouldBe('Derived.staticOverridenMethod()', '"derived"');
69
70 shouldThrow('x = class extends', '"SyntaxError: Unexpected end of script"');
71 shouldThrow('x = class extends', '"SyntaxError: Unexpected end of script"');
72 shouldThrow('x = class extends Base {', '"SyntaxError: Unexpected end of script"');
73 shouldNotThrow('x = class extends Base { }');
74 shouldNotThrow('x = class extends Base { constructor() { } }');
75 shouldBe('x.__proto__', 'Base');
76 shouldBe('Object.getPrototypeOf(x)', 'Base');
77 shouldBe('x.prototype.__proto__', 'Base.prototype');
78 shouldBe('Object.getPrototypeOf(x.prototype)', 'Base.prototype');
79 shouldBe('x = class extends null { constructor() { } }; x.__proto__', 'Function.prototype');
80 shouldBe('x.__proto__', 'Function.prototype');
81 shouldThrow('x = class extends 3 { constructor() { } }; x.__proto__', '"TypeError: The superclass is not an object."');
82 shouldThrow('x = class extends "abc" { constructor() { } }; x.__proto__', '"TypeError: The superclass is not an object."');
83 shouldNotThrow('baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype');
84 shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The superclass\'s prototype is not an object."');
85 shouldNotThrow('baseWithBadPrototype.prototype = "abc"');
86 shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: The superclass\'s prototype is not an object."');
87 shouldNotThrow('baseWithBadPrototype.prototype = null; x = class extends baseWithBadPrototype { constructor() { } }');
88
89 shouldThrow('x = 1; c = class extends ++x { constructor() { } };');
90 shouldThrow('x = 1; c = class extends x++ { constructor() { } };');
91 shouldThrow('x = 1; c = class extends (++x) { constructor() { } };');
92 shouldThrow('x = 1; c = class extends (x++) { constructor() { } };');
93 shouldBe('x = 1; try { c = class extends (++x) { constructor() { } } } catch (e) { }; x', '2');
94 shouldBe('x = 1; try { c = class extends (x++) { constructor() { } } } catch (e) { }; x', '2');
95
96 shouldNotThrow('namespace = {}; namespace.A = class { }; namespace.B = class extends namespace.A { }');
97 shouldNotThrow('namespace = {}; namespace.A = class A { }; namespace.B = class B extends namespace.A { }');
98 shouldNotThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends namespace.A { constructor() { } }');
99 shouldNotThrow('namespace = {}; namespace.A = class A { constructor() { } }; namespace.B = class B extends namespace.A { constructor() { } }');
100 shouldNotThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (namespace.A) { constructor() { } }');
101 shouldNotThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends namespace["A"] { constructor() { } }');
102 shouldNotThrow('namespace = {}; namespace.A = class { constructor() { } }; function getClassA() { return namespace.A }; namespace.B = class extends getClassA() { constructor() { } }');
103 shouldNotThrow('namespace = {}; namespace.A = class { constructor() { } }; function getClass(prop) { return namespace[prop] }; namespace.B = class extends getClass("A") { constructor() { } }');
104 shouldNotThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (false||null||namespace.A) { constructor() { } }');
105 shouldThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends false||null||namespace.A { constructor() { } }');
106 shouldNotThrow('x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (x++, namespace.A) { constructor() { } };');
107 shouldThrow('x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (namespace.A, x++) { constructor() { } };');
108 shouldThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A { constructor() { } }');
109 shouldThrow('namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A() { constructor() { } }');
110 shouldBe('x = 1; namespace = {}; namespace.A = class { constructor() { } }; try { namespace.B = class extends (x++, namespace.A) { constructor() { } } } catch (e) { } x', '2');
111 shouldBe('x = 1; namespace = {}; namespace.A = class { constructor() { } }; try { namespace.B = class extends (namespace.A, x++) { constructor() { } } } catch (e) { } x', '2');
112
113 shouldBe('Object.getPrototypeOf((class { constructor () { } }).prototype)', 'Object.prototype');
114 shouldBe('Object.getPrototypeOf((class extends null { constructor () { super(); } }).prototype)', 'null');
115 shouldThrow('new (class extends undefined { constructor () { this } })', '"TypeError: The superclass is not an object."');
116 shouldThrow('x = undefined; new (class extends x { constructor () { super(); } })', '"TypeError: The superclass is not an object."');
117 shouldBeTrue ('class x {}; new (class extends null { constructor () { return new x; } }) instanceof x');
118 shouldThrow('new (class extends null { constructor () { this; } })', '"ReferenceError: Cannot access uninitialized variable."');
119 shouldThrow('new (class extends null { constructor () { super(); } })', '"TypeError: undefined is not an object (evaluating \'super()\')"');
120 shouldBe('x = {}; new (class extends null { constructor () { return x } })', 'x');
121 shouldThrow('y = 12; new (class extends null { constructor () { return y; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."');
122 shouldBeTrue ('class x {}; new (class extends null { constructor () { return new x; } }) instanceof x');
123 shouldBe('x = null; Object.getPrototypeOf((class extends x { }).prototype)', 'null');
124 shouldBeTrue('Object.prototype.isPrototypeOf(class { })');
125 shouldBeTrue('Function.prototype.isPrototypeOf(class { })');
126
127 var successfullyParsed = true;