Bug 1141863 - Tests. (r=jorendorff)
authorEric Faust <efaustbmo@gmail.com>
Thu, 08 Oct 2015 17:01:49 -0700
changeset 267014 b5a67fbf08051b7961cef6b9a8c8835fd3f87f50
parent 267013 f6598d998f3ef5f1f07ece07ad2da6188de7d0f8
child 267015 82b5260c2eb347df1ee16823b50a808d4c23f54e
push id29504
push usercbook@mozilla.com
push dateFri, 09 Oct 2015 09:43:23 +0000
treeherdermozilla-central@d01dd42e654b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1141863
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1141863 - Tests. (r=jorendorff)
js/src/tests/ecma_6/Class/superCallBadDynamicSuperClass.js
js/src/tests/ecma_6/Class/superCallBadNewTargetPrototype.js
js/src/tests/ecma_6/Class/superCallBaseInvoked.js
js/src/tests/ecma_6/Class/superCallIllegal.js
js/src/tests/ecma_6/Class/superCallInvalidBase.js
js/src/tests/ecma_6/Class/superCallOrder.js
js/src/tests/ecma_6/Class/superCallProperBase.js
js/src/tests/ecma_6/Class/superCallSpreadCall.js
js/src/tests/ecma_6/Class/superCallThisInit.js
js/src/tests/js1_8_5/reflect-parse/classes.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallBadDynamicSuperClass.js
@@ -0,0 +1,17 @@
+var test = `
+
+class base { constructor() { } }
+
+class inst extends base { constructor() { super(); } }
+
+Object.setPrototypeOf(inst, Math.sin);
+
+assertThrowsInstanceOf(() => new inst(), TypeError);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallBadNewTargetPrototype.js
@@ -0,0 +1,30 @@
+var test = `
+
+class base { constructor() { } }
+
+// lies and the lying liars who tell them
+function lies() { }
+lies.prototype = 4;
+
+assertThrowsInstanceOf(()=>Reflect.consruct(base, [], lies), TypeError);
+
+// lie a slightly different way
+function get(target, property, receiver) {
+    if (property === "prototype")
+        return 42;
+    return Reflect.get(target, property, receiver);
+}
+
+class inst extends base {
+    constructor() { super(); }
+}
+
+assertThrowsInstanceOf(()=>new new Proxy(inst, {get})(), TypeError);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallBaseInvoked.js
@@ -0,0 +1,53 @@
+var test = `
+
+function testBase(base) {
+    class instance extends base {
+        constructor(inst, one) {
+            super(inst, one);
+        }
+    }
+
+    let inst = new instance(instance, 1);
+    assertEq(Object.getPrototypeOf(inst), instance.prototype);
+    assertEq(inst.calledBase, true);
+}
+
+class base {
+    // Base class must be [[Construct]]ed, as you cannot [[Call]] a class
+    // constructor
+    constructor(nt, one) {
+        assertEq(new.target, nt);
+
+        // Check argument ordering
+        assertEq(one, 1);
+        this.calledBase = true;
+    }
+}
+
+testBase(base);
+testBase(class extends base {
+             constructor(nt, one) {
+                 // Every step of the way, new.target and args should be right
+                 assertEq(new.target, nt);
+                 assertEq(one, 1);
+                 super(nt, one);
+             }
+         });
+function baseFunc(nt, one) {
+    assertEq(new.target, nt);
+    assertEq(one, 1);
+    this.calledBase = true;
+}
+
+testBase(baseFunc);
+testBase(new Proxy(baseFunc, {}));
+
+// Object will have to wait for fixed builtins.
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallIllegal.js
@@ -0,0 +1,7 @@
+// super() invalid outside derived class constructors, including in dynamic
+// functions and eval
+assertThrowsInstanceOf(() => new Function("super();"), SyntaxError);
+assertThrowsInstanceOf(() => eval("super()"), SyntaxError);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallInvalidBase.js
@@ -0,0 +1,15 @@
+var test = `
+
+class instance extends null {
+    constructor() { super(); }
+}
+
+assertThrowsInstanceOf(() => new instance(), TypeError);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallOrder.js
@@ -0,0 +1,33 @@
+var test = `
+
+function base() { }
+
+class beforeSwizzle extends base {
+    constructor() {
+        super(Object.setPrototypeOf(beforeSwizzle, null));
+    }
+}
+
+new beforeSwizzle();
+
+// Again, testing both dynamic prototype dispatch, and that we get the function
+// before evaluating args
+class beforeThrow extends base {
+    constructor() {
+        function thrower() { throw new Error(); }
+        super(thrower());
+    }
+}
+
+Object.setPrototypeOf(beforeThrow, Math.sin);
+
+// Will throw that Math.sin is not a constructor before evaluating the args
+assertThrowsInstanceOf(() => new beforeThrow(), TypeError);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallProperBase.js
@@ -0,0 +1,33 @@
+var test = `
+
+class base1 {
+    constructor() {
+        this.base = 1;
+    }
+}
+
+class base2 {
+    constructor() {
+        this.base = 2;
+    }
+}
+
+class inst extends base1 {
+    constructor() {
+        super();
+    }
+}
+
+assertEq(new inst().base, 1);
+
+Object.setPrototypeOf(inst, base2);
+
+assertEq(new inst().base, 2);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallSpreadCall.js
@@ -0,0 +1,34 @@
+var test = `
+
+class base {
+    constructor(a, b, c) {
+        assertEq(a, 1);
+        assertEq(b, 2);
+        assertEq(c, 3);
+        this.calledBase = true;
+    }
+}
+
+class test extends base {
+    constructor(arr) {
+        super(...arr);
+    }
+}
+
+assertEq(new test([1,2,3]).calledBase, true);
+
+class testRest extends base {
+   constructor(...args) {
+       super(...args);
+   }
+}
+
+assertEq(new testRest(1,2,3).calledBase, true);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/superCallThisInit.js
@@ -0,0 +1,52 @@
+var test = `
+
+function base() { this.prop = 42; }
+
+class testInitialize extends base {
+    constructor() {
+        // A poor man's assertThrowsInstanceOf, as arrow functions are currently
+        // disabled in this context
+        try {
+            this;
+            throw new Error();
+        } catch (e if e instanceof ReferenceError) { }
+        super();
+        assertEq(this.prop, 42);
+    }
+}
+assertEq(new testInitialize().prop, 42);
+
+// super() twice is a no-go.
+class willThrow extends base {
+    constructor() {
+        super();
+        super();
+    }
+}
+assertThrowsInstanceOf(()=>new willThrow(), ReferenceError);
+
+// This is determined at runtime, not the syntax level.
+class willStillThrow extends base {
+    constructor() {
+        for (let i = 0; i < 3; i++) {
+            super();
+        }
+    }
+}
+assertThrowsInstanceOf(()=>new willStillThrow(), ReferenceError);
+
+class canCatchThrow extends base {
+    constructor() {
+        super();
+        try { super(); } catch(e) { }
+    }
+}
+assertEq(new canCatchThrow().prop, 42);
+
+`;
+
+if (classesEnabled())
+    eval(test);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
--- a/js/src/tests/js1_8_5/reflect-parse/classes.js
+++ b/js/src/tests/js1_8_5/reflect-parse/classes.js
@@ -20,39 +20,40 @@ function testClasses() {
         return methodMaker(methodName, args.map(ident), blockStmt(body));
     }
 
     function simpleMethod(id, kind, generator, args=[], isStatic=false) {
         return classMethod(ident(id),
                            methodFun(id, kind, generator, args),
                            kind, isStatic);
     }
-    function ctorWithName(id) {
+    function ctorWithName(id, body = []) {
         return classMethod(ident("constructor"),
-                           methodFun(id, "method", false, []),
+                           methodFun(id, "method", false, [], body),
                            "method", false);
     }
     function emptyCPNMethod(id, isStatic) {
         return classMethod(computedName(lit(id)),
                            funExpr(null, [], blockStmt([])),
                            "method", isStatic);
     }
 
     function assertClassExpr(str, methods, heritage=null, name=null) {
         let template = classExpr(name, heritage, methods);
         assertExpr("(" + str + ")", template);
     }
+
     // FunctionExpression of constructor has class name as its id.
     // FIXME: Implement ES6 function "name" property semantics (bug 883377).
     let ctorPlaceholder = {};
-    function assertClass(str, methods, heritage=null) {
+    function assertClass(str, methods, heritage=null, constructorBody=[]) {
         let namelessStr = str.replace("NAME", "");
         let namedStr = str.replace("NAME", "Foo");
-        let namedCtor = ctorWithName("Foo");
-        let namelessCtor = ctorWithName(null);
+        let namedCtor = ctorWithName("Foo", constructorBody);
+        let namelessCtor = ctorWithName(null, constructorBody);
         let namelessMethods = methods.map(x => x == ctorPlaceholder ? namelessCtor : x);
         let namedMethods = methods.map(x => x == ctorPlaceholder ? namedCtor : x);
         assertClassExpr(namelessStr, namelessMethods, heritage);
         assertClassExpr(namedStr, namedMethods, heritage, ident("Foo"));
 
         let template = classStmt(ident("Foo"), heritage, namedMethods);
         assertStmt(namedStr, template);
     }
@@ -438,33 +439,45 @@ function testClasses() {
     assertClassError("class NAME { constructor() { super; } }", SyntaxError);
 
     /* SuperCall */
 
     // SuperCall is invalid outside derived class constructors.
     assertError("super()", SyntaxError);
     assertError("(function() { super(); })", SyntaxError);
 
+    // SuperCall is invalid in generator comprehensions, even inside derived
+    // class constructors
+    assertError("(super() for (x in y))", SyntaxError);
+    assertClassError("class NAME { constructor() { (super() for (x in y))", SyntaxError);
+
+
     // Even in class constructors
     assertClassError("class NAME { constructor() { super(); } }", SyntaxError);
 
     function superConstructor(args) {
         return classMethod(ident("constructor"),
-                           methodFun("constructor", "method", false,
+                           methodFun("NAME", "method", false,
                                      [], [exprStmt(superCallExpr(args))]),
                            "method", false);
     }
 
+    function superCallBody(args) {
+        return [exprStmt(superCallExpr(args))];
+    }
+
     // SuperCall works with various argument configurations.
     assertClass("class NAME extends null { constructor() { super() } }",
-                [superConstructor([])], lit(null));
+                [ctorPlaceholder], lit(null), superCallBody([]));
     assertClass("class NAME extends null { constructor() { super(1) } }",
-                [superConstructor([lit(1)])], lit(null));
+                [ctorPlaceholder], lit(null), superCallBody([lit(1)]));
+    assertClass("class NAME extends null { constructor() { super(1, a) } }",
+                [ctorPlaceholder], lit(null), superCallBody([lit(1), ident("a")]));
     assertClass("class NAME extends null { constructor() { super(...[]) } }",
-                [superConstructor([spread(arrExpr([]))])], lit(null));
+                [ctorPlaceholder], lit(null), superCallBody([spread(arrExpr([]))]));
 
     /* EOF */
     // Clipped classes should throw a syntax error
     assertClassError("class NAME {", SyntaxError);
     assertClassError("class NAME {;", SyntaxError);
     assertClassError("class NAME { constructor", SyntaxError);
     assertClassError("class NAME { constructor(", SyntaxError);
     assertClassError("class NAME { constructor()", SyntaxError);