blob: 7686f6ca38e7643fbfafb37f05bc97abfd363ba8 [file] [log] [blame]
Ben Murdoch014dc512016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code must retain the above copyright
8// notice, this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright
10// notice, this list of conditions and the following disclaimer in the
11// documentation and/or other materials provided with the distribution.
12//
13// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16// DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
Ben Murdoch014dc512016-03-22 12:00:34 +000024description('Tests for ES6 class name semantics in class statements and expressions');
25
26function runTestShouldBe(statement, result) {
27 shouldBe(statement, result);
28 shouldBe("'use strict'; " + statement, result);
29}
30
31function runTestShouldBeTrue(statement) {
32 shouldBeTrue(statement);
33 shouldBeTrue("'use strict'; " + statement);
34}
35
36function runTestShouldThrow(statement) {
37 shouldThrow(statement);
38 shouldThrow("'use strict'; " + statement);
39}
40
41function runTestShouldNotThrow(statement) {
42 shouldNotThrow(statement);
43 shouldNotThrow("'use strict'; " + statement);
44}
45
46// Class statement. Class name added to global scope. Class name is available inside class scope and in global scope.
47debug('Class statement');
48runTestShouldThrow("A");
49runTestShouldThrow("class {}");
50runTestShouldThrow("class { constructor() {} }");
51runTestShouldNotThrow("class A { constructor() {} }");
52runTestShouldBe("class A { constructor() {} }; A.toString()", "'class A { constructor() {} }'");
53runTestShouldBeTrue("class A { constructor() {} }; (new A) instanceof A");
54runTestShouldBe("class A { constructor() { this.base = A; } }; (new A).base.toString()", "'class A { constructor() { this.base = A; } }'");
55runTestShouldNotThrow("class A { constructor() {} }; class B extends A {};");
56runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() {} }; B.toString()", "'class B extends A { constructor() {} }'");
57runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof A");
58runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof B");
59runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString()", "'class A { constructor() {} }'");
60runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).derived.toString()", "'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'");
61
62// Class expression. Class name not added to scope. Class name is available inside class scope.
63debug(''); debug('Class expression');
64runTestShouldThrow("A");
65runTestShouldNotThrow("(class {})");
66runTestShouldNotThrow("(class { constructor(){} })");
67runTestShouldBe("typeof (class {})", '"function"');
68runTestShouldNotThrow("(class A {})");
69runTestShouldBe("typeof (class A {})", '"function"');
70runTestShouldThrow("(class A {}); A");
71runTestShouldNotThrow("new (class A {})");
72runTestShouldBe("typeof (new (class A {}))", '"object"');
73runTestShouldNotThrow("(new (class A { constructor() { this.base = A; } })).base");
74runTestShouldBe("(new (class A { constructor() { this.base = A; } })).base.toString()", '"class A { constructor() { this.base = A; } }"');
75runTestShouldNotThrow("class A {}; (class B extends A {})");
76runTestShouldThrow("class A {}; (class B extends A {}); B");
77runTestShouldNotThrow("class A {}; new (class B extends A {})");
78runTestShouldNotThrow("class A {}; new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })");
79runTestShouldBeTrue("class A {}; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })) instanceof A");
80runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString()", "'class A { constructor() {} }'");
81runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).derived.toString()", "'class B extends A { constructor() { super(); this.base = A; this.derived = B; } }'");
82
83// Assignment of a class expression to a variable. Variable name available in scope, class name is not. Class name is available inside class scope.
84debug(''); debug('Class expression assignment to variable');
85runTestShouldThrow("A");
86runTestShouldNotThrow("var VarA = class {}");
87runTestShouldBe("var VarA = class { constructor() {} }; VarA.toString()", "'class { constructor() {} }'");
88runTestShouldThrow("VarA");
89runTestShouldNotThrow("var VarA = class A { constructor() {} }");
90runTestShouldBe("var VarA = class A { constructor() {} }; VarA.toString()", "'class A { constructor() {} }'");
91runTestShouldThrow("var VarA = class A { constructor() {} }; A.toString()");
92runTestShouldBeTrue("var VarA = class A { constructor() {} }; (new VarA) instanceof VarA");
93runTestShouldBe("var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString()", "'class A { constructor() { this.base = A; } }'");
94runTestShouldNotThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} };");
95runTestShouldThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; B");
96runTestShouldBe("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString()", "'class B extends VarA { constructor() {} }'");
97runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarA");
98runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarB");
99runTestShouldBeTrue("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");
100runTestShouldBeTrue("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");
101runTestShouldBeTrue("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");
102
103// FIXME: Class statement binding should be like `let`, not `var`.
104debug(''); debug('Class statement binding in other circumstances');
105runTestShouldThrow("var result = A; result");
106runTestShouldThrow("var result = A; class A {}; result");
107runTestShouldThrow("class A { constructor() { A = 1; } }; new A");
108runTestShouldBe("class A { constructor() { } }; A = 1; A", "1");
109runTestShouldNotThrow("class A {}; var result = A; result");
110shouldBe("eval('var Foo = 10'); Foo", "10");
111shouldThrow("'use strict'; eval('var Foo = 10'); Foo");
112shouldBe("eval('class Bar { constructor() {} }; Bar.toString()')", "'class Bar { constructor() {} }'");
113shouldThrow("'use strict'; eval('class Bar { constructor() {} }'); Bar.toString()");