Home | History | Annotate | Download | only in webkit
      1 // 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 
     24 // Flags: --harmony-sloppy
     25 
     26 description('Tests for ES6 class name semantics in class statements and expressions');
     27 
     28 function runTestShouldBe(statement, result) {
     29     shouldBe(statement, result);
     30     shouldBe("'use strict'; " + statement, result);
     31 }
     32 
     33 function runTestShouldBeTrue(statement) {
     34     shouldBeTrue(statement);
     35     shouldBeTrue("'use strict'; " + statement);
     36 }
     37 
     38 function runTestShouldThrow(statement) {
     39     shouldThrow(statement);
     40     shouldThrow("'use strict'; " + statement);
     41 }
     42 
     43 function runTestShouldNotThrow(statement) {
     44     shouldNotThrow(statement);
     45     shouldNotThrow("'use strict'; " + statement);
     46 }
     47 
     48 // Class statement. Class name added to global scope. Class name is available inside class scope and in global scope.
     49 debug('Class statement');
     50 runTestShouldThrow("A");
     51 runTestShouldThrow("class {}");
     52 runTestShouldThrow("class { constructor() {} }");
     53 runTestShouldNotThrow("class A { constructor() {} }");
     54 runTestShouldBe("class A { constructor() {} }; A.toString()", "'class A { constructor() {} }'");
     55 runTestShouldBeTrue("class A { constructor() {} }; (new A) instanceof A");
     56 runTestShouldBe("class A { constructor() { this.base = A; } }; (new A).base.toString()", "'class A { constructor() { this.base = A; } }'");
     57 runTestShouldNotThrow("class A { constructor() {} }; class B extends A {};");
     58 runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() {} }; B.toString()", "'class B extends A { constructor() {} }'");
     59 runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof A");
     60 runTestShouldBeTrue("class A { constructor() {} }; class B extends A {}; (new B) instanceof B");
     61 runTestShouldBe("class A { constructor() {} }; class B extends A { constructor() { super(); this.base = A; this.derived = B; } }; (new B).base.toString()", "'class A { constructor() {} }'");
     62 runTestShouldBe("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; } }'");
     63 
     64 // Class expression. Class name not added to scope. Class name is available inside class scope.
     65 debug(''); debug('Class expression');
     66 runTestShouldThrow("A");
     67 runTestShouldNotThrow("(class {})");
     68 runTestShouldNotThrow("(class { constructor(){} })");
     69 runTestShouldBe("typeof (class {})", '"function"');
     70 runTestShouldNotThrow("(class A {})");
     71 runTestShouldBe("typeof (class A {})", '"function"');
     72 runTestShouldThrow("(class A {}); A");
     73 runTestShouldNotThrow("new (class A {})");
     74 runTestShouldBe("typeof (new (class A {}))", '"object"');
     75 runTestShouldNotThrow("(new (class A { constructor() { this.base = A; } })).base");
     76 runTestShouldBe("(new (class A { constructor() { this.base = A; } })).base.toString()", '"class A { constructor() { this.base = A; } }"');
     77 runTestShouldNotThrow("class A {}; (class B extends A {})");
     78 runTestShouldThrow("class A {}; (class B extends A {}); B");
     79 runTestShouldNotThrow("class A {}; new (class B extends A {})");
     80 runTestShouldNotThrow("class A {}; new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })");
     81 runTestShouldBeTrue("class A {}; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })) instanceof A");
     82 runTestShouldBe("class A { constructor() {} }; (new (class B extends A { constructor() { super(); this.base = A; this.derived = B; } })).base.toString()", "'class A { constructor() {} }'");
     83 runTestShouldBe("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; } }'");
     84 
     85 // Assignment of a class expression to a variable. Variable name available in scope, class name is not. Class name is available inside class scope.
     86 debug(''); debug('Class expression assignment to variable');
     87 runTestShouldThrow("A");
     88 runTestShouldNotThrow("var VarA = class {}");
     89 runTestShouldBe("var VarA = class { constructor() {} }; VarA.toString()", "'class { constructor() {} }'");
     90 runTestShouldThrow("VarA");
     91 runTestShouldNotThrow("var VarA = class A { constructor() {} }");
     92 runTestShouldBe("var VarA = class A { constructor() {} }; VarA.toString()", "'class A { constructor() {} }'");
     93 runTestShouldThrow("var VarA = class A { constructor() {} }; A.toString()");
     94 runTestShouldBeTrue("var VarA = class A { constructor() {} }; (new VarA) instanceof VarA");
     95 runTestShouldBe("var VarA = class A { constructor() { this.base = A; } }; (new VarA).base.toString()", "'class A { constructor() { this.base = A; } }'");
     96 runTestShouldNotThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} };");
     97 runTestShouldThrow("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; B");
     98 runTestShouldBe("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { constructor() {} }; VarB.toString()", "'class B extends VarA { constructor() {} }'");
     99 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarA");
    100 runTestShouldBeTrue("var VarA = class A { constructor() {} }; var VarB = class B extends VarA { }; (new VarB) instanceof VarB");
    101 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");
    102 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");
    103 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");
    104 
    105 // FIXME: Class statement binding should be like `let`, not `var`.
    106 debug(''); debug('Class statement binding in other circumstances');
    107 runTestShouldThrow("var result = A; result");
    108 runTestShouldThrow("var result = A; class A {}; result");
    109 runTestShouldThrow("class A { constructor() { A = 1; } }; new A");
    110 runTestShouldBe("class A { constructor() { } }; A = 1; A", "1");
    111 runTestShouldNotThrow("class A {}; var result = A; result");
    112 shouldBe("eval('var Foo = 10'); Foo", "10");
    113 shouldThrow("'use strict'; eval('var Foo = 10'); Foo");
    114 shouldBe("eval('class Bar { constructor() {} }; Bar.toString()')", "'class Bar { constructor() {} }'");
    115 shouldThrow("'use strict'; eval('class Bar { constructor() {} }'); Bar.toString()");
    116