| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- // ES6 super chain tests
- WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
- class SimpleParent {
- constructor() {
- this.foo = 'SimpleParent';
- }
- }
- let calls_to_ConstructorCountingParent = 0;
- class ConstructorCountingParent {
- constructor() {
- calls_to_ConstructorCountingParent++;
- }
- }
- class UninitializedThisReturningArgumentConstructor extends SimpleParent {
- constructor(arg) {
- return arg;
- }
- };
- class InitializedThisReturningArgumentConstructor extends SimpleParent {
- constructor(arg) {
- super();
- return arg;
- }
- };
- var tests = [
- {
- name: "Simple derived class constructor using this",
- body: function () {
- class DerivedClassUsingThis extends SimpleParent {
- constructor() {
- super();
- this.bar = "DerivedClassUsingThis";
- }
- };
- let result = new DerivedClassUsingThis();
- assert.areEqual("DerivedClassUsingThis", result.bar, "This is initialized with the return value from super()");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedClassUsingThis, "Result object is instanceof derived class");
- }
- },
- {
- name: "Simple derived class constructor using this without calling super causing use before declaration error",
- body: function () {
- class DerivedClassUsingThisIllegally extends SimpleParent {
- constructor() {
- this.bar = "DerivedClassUsingThisIllegally";
- }
- };
- assert.throws(function() { new DerivedClassUsingThisIllegally(); }, ReferenceError, "It's a ReferenceError to access 'this' without calling super", "Use before declaration");
- }
- },
- {
- name: "Simple derived class constructor using this before calling super causing use before declaration error",
- body: function () {
- class DerivedClassUsingThisIllegally extends SimpleParent {
- constructor() {
- this.bar = "DerivedClassUsingThisIllegally";
- super();
- }
- };
- assert.throws(function() { new DerivedClassUsingThisIllegally(); }, ReferenceError, "It's a ReferenceError to access 'this' without calling super", "Use before declaration");
- }
- },
- {
- name: "Simple derived class constructor using this via a lambda",
- body: function () {
- class DerivedClassUsingThisViaLambda extends SimpleParent {
- constructor() {
- var arrow = () => { this.bar = 'DerivedClassUsingThisViaLambda'; };
- super();
- arrow();
- }
- };
- let result = new DerivedClassUsingThisViaLambda();
- assert.areEqual("DerivedClassUsingThisViaLambda", result.bar, "Arrow is defined using this (before super call) and called after super call in derived constructor");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedClassUsingThisViaLambda, "Result object is instanceof derived class");
- }
- },
- {
- name: "Simple derived class constructor using this without calling super via a lambda causing use before declaration error",
- body: function () {
- class DerivedClassUsingThisIllegallyViaLambda extends SimpleParent {
- constructor() {
- var arrow = () => { this.bar = 'DerivedClassUsingThisIllegallyViaLambda'; };
- arrow();
- }
- };
- assert.throws(function() { new DerivedClassUsingThisIllegallyViaLambda(); }, ReferenceError, "It's a ReferenceError to access 'this' without calling super", "Use before declaration");
- }
- },
- {
- name: "Simple derived class constructor using this before calling super via a lambda causing use before declaration error",
- body: function () {
- class DerivedClassUsingThisIllegallyViaLambda extends SimpleParent {
- constructor() {
- var arrow = () => { this.bar = 'DerivedClassUsingThisIllegallyViaLambda'; };
- arrow();
- super();
- }
- };
- assert.throws(function() { new DerivedClassUsingThisIllegallyViaLambda(); }, ReferenceError, "It's a ReferenceError to access 'this' without calling super", "Use before declaration");
- }
- },
- {
- name: "Simple derived class constructor using this and super via a lambda",
- body: function () {
- class DerivedClassUsingThisAndSuperViaLambda extends SimpleParent {
- constructor() {
- var this_arrow = () => { this.bar = 'DerivedClassUsingThisAndSuperViaLambda'; };
- var super_arrow = () => { super(); }
- super_arrow();
- this_arrow();
- }
- };
- let result = new DerivedClassUsingThisAndSuperViaLambda();
- assert.areEqual("DerivedClassUsingThisAndSuperViaLambda", result.bar, "Arrow is defined using this (before super call) and called after super call in derived constructor");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedClassUsingThisAndSuperViaLambda, "Result object is instanceof derived class");
- }
- },
- {
- name: "Simple derived class constructor using this and super via a lambda (lambda with super call defined first)",
- body: function () {
- class DerivedClassUsingThisAndSuperViaLambda extends SimpleParent {
- constructor() {
- var super_arrow = () => { super(); }
- var this_arrow = () => { this.bar = 'DerivedClassUsingThisAndSuperViaLambda'; };
- super_arrow();
- this_arrow();
- }
- };
- let result = new DerivedClassUsingThisAndSuperViaLambda();
- assert.areEqual("DerivedClassUsingThisAndSuperViaLambda", result.bar, "Arrow is defined using this (before super call) and called after super call in derived constructor");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedClassUsingThisAndSuperViaLambda, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class constructor throws ReferenceError accessing this with no super call",
- body: function () {
- class IllegalThisAccessConstructor extends SimpleParent {
- constructor() {
- this.bar = 'something';
- }
- };
- assert.throws(function() { new IllegalThisAccessConstructor(); }, ReferenceError, "It's a ReferenceError to access 'this' without calling super", "Use before declaration");
- }
- },
- {
- name: "Derived class constructor throws ReferenceError accessing this before super call",
- body: function () {
- class IllegalThisBeforeSuperConstructor extends SimpleParent {
- constructor() {
- this.bar = 'something';
- super();
- }
- };
- assert.throws(function() { new IllegalThisBeforeSuperConstructor(); }, ReferenceError, "It's a ReferenceError to access 'this' before calling super", "Use before declaration");
- }
- },
- {
- name: "Derived class throws ReferenceError with empty constructor (implicit access of this)",
- body: function () {
- class EmptyConstructor extends SimpleParent {
- constructor() {
- // Implicitly "return this;"
- }
- };
- assert.throws(function() { new EmptyConstructor(); }, ReferenceError, "It's a ReferenceError to implicit return 'this' from class constructor without calling super", "Use before declaration");
- }
- },
- {
- name: "Derived class with default constructor returns initialized this argument",
- body: function () {
- class DefaultConstructor extends SimpleParent {
- // Implicitly
- // constructor(...args) { super(...args); }
- };
- let obj = new DefaultConstructor();
- assert.areEqual('SimpleParent', obj.foo, "Object from base constructor should have been returned.");
- assert.isTrue(obj instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(obj instanceof DefaultConstructor, "Result object is instanceof derived class");
- class DefaultConstructorReturningArgumentViaBaseClass extends UninitializedThisReturningArgumentConstructor {
- // Implicitly
- // constructor(...args) { super(...args); }
- };
- obj = new DefaultConstructorReturningArgumentViaBaseClass({ bar: 'DefaultConstructorReturningArgumentViaBaseClass' });
- assert.areEqual('DefaultConstructorReturningArgumentViaBaseClass', obj.bar, "Object from base constructor should have been returned.");
- assert.isFalse(obj instanceof UninitializedThisReturningArgumentConstructor, "Result object is not instanceof base class");
- assert.isFalse(obj instanceof DefaultConstructorReturningArgumentViaBaseClass, "Result object is not instanceof derived class");
- }
- },
- {
- name: "Derived class throws TypeError when returning non-object if this is initialized",
- body: function () {
- assert.throws(function() { new InitializedThisReturningArgumentConstructor(null); }, TypeError, "Returning null from derived constructor should throw TypeError", "Derived class constructor can return only object or undefined");
- assert.throws(function() { new InitializedThisReturningArgumentConstructor('string'); }, TypeError, "Returning 'string' from derived constructor should throw TypeError", "Derived class constructor can return only object or undefined");
- assert.throws(function() { new InitializedThisReturningArgumentConstructor(5); }, TypeError, "Returning 5 from derived constructor should throw TypeError", "Derived class constructor can return only object or undefined");
- }
- },
- {
- name: "Derived class throws TypeError when returning non-object if this is uninitialized",
- body: function () {
- assert.throws(function() { new UninitializedThisReturningArgumentConstructor(null); }, TypeError, "Returning null from derived constructor should throw TypeError", "Derived class constructor can return only object or undefined");
- assert.throws(function() { new UninitializedThisReturningArgumentConstructor('string'); }, TypeError, "Returning 'string' from derived constructor should throw TypeError", "Derived class constructor can return only object or undefined");
- assert.throws(function() { new UninitializedThisReturningArgumentConstructor(5); }, TypeError, "Returning 5 from derived constructor should throw TypeError", "Derived class constructor can return only object or undefined");
- }
- },
- {
- name: "TypeError is thrown when trying to derive from a function which is not a constructor",
- body: function () {
- assert.throws(function () { class A extends JSON { }; }, TypeError, "JSON object does not have an internal Construct slot", "Function is not a constructor");
- assert.throws(function () { class A extends Math { }; }, TypeError, "Math object does not have an internal Construct slot", "Function is not a constructor");
- function* gf(a) { yield 1 + a + this.a; }
- assert.throws(function () { class A extends gf { } }, TypeError, "Class deriving from a generator function throws TypeError", "Function is not a constructor");
- assert.throws(function () { class A extends (a) => a {} }, TypeError, "Class deriving from a lambda throws TypeError", "Function is not a constructor");
- }
- },
- {
- name: "Derived class returning undefined, returns 'this' instead",
- body: function () {
- class ImplicitReturnUndefinedNotInitializedThis extends SimpleParent {
- constructor() {
- return;
- }
- }
- assert.throws(function() { new ImplicitReturnUndefinedNotInitializedThis(); }, ReferenceError, "Derived class constructor implicitly returning undefined with no super call throws ReferenceError", "Use before declaration");
- class ExplicitReturnUndefinedNotInitializedThis extends SimpleParent {
- constructor() {
- return undefined;
- }
- }
- assert.throws(function() { new ExplicitReturnUndefinedNotInitializedThis(); }, ReferenceError, "Derived class constructor explicitly returning undefined with no super call throws ReferenceError", "Use before declaration");
- class ImplicitReturnUndefinedInitializedThis extends SimpleParent {
- constructor() {
- super();
- this.bar = 'ImplicitReturnUndefinedInitializedThis';
- return;
- }
- }
- let result = new ImplicitReturnUndefinedInitializedThis();
- assert.areEqual('SimpleParent', result.foo, "Object from base constructor should have been returned.");
- assert.areEqual('ImplicitReturnUndefinedInitializedThis', result.bar, "'this' modified in derived constructor.");
- assert.isTrue(result instanceof ImplicitReturnUndefinedInitializedThis, "Result object is instanceof derived class");
- assert.isTrue(result instanceof SimpleParent, "Result object is not instanceof base class");
- class ExplicitReturnUndefinedInitializedThis extends SimpleParent {
- constructor() {
- super();
- this.bar = 'ExplicitReturnUndefinedInitializedThis';
- return undefined;
- }
- }
- result = new ExplicitReturnUndefinedInitializedThis();
- assert.areEqual('SimpleParent', result.foo, "Object from base constructor should have been returned.");
- assert.areEqual('ExplicitReturnUndefinedInitializedThis', result.bar, "'this' modified in derived constructor.");
- assert.isTrue(result instanceof ExplicitReturnUndefinedInitializedThis, "Result object is instanceof derived class");
- assert.isTrue(result instanceof SimpleParent, "Result object is not instanceof base class");
- }
- },
- {
- name: "Derived class returns any object and avoids super call / this initialization",
- body: function () {
- let obj = new UninitializedThisReturningArgumentConstructor({ foo: 'value' });
- assert.areEqual('value', obj.foo, "We returned an object from the class constructor which didn't initialize 'this' so we should get that object back");
- }
- },
- {
- name: "Derived class throws ReferenceError with multiple calls to super ('this' is already initialized)",
- body: function () {
- // Reset call counter in parent
- calls_to_ConstructorCountingParent = 0;
- class IllegalSuperCallConstructor extends ConstructorCountingParent {
- constructor() {
- super();
- super();
- }
- };
- assert.throws(function() { new IllegalSuperCallConstructor(); }, ReferenceError, "It's a ReferenceError to call super multiple times in a derived class constructor", "Multiple calls to 'super' in a class constructor are not allowed");
- assert.areEqual(2, calls_to_ConstructorCountingParent, "We do call the super function body twice but we throw ReferenceError when trying to assign the 'this' value after the second super call");
- }
- },
- {
- name: "Derived class throws ReferenceError with multiple calls to super ('this' is already initialized) with one call in a lambda",
- body: function () {
- // Reset call counter in parent
- calls_to_ConstructorCountingParent = 0;
- class IllegalSuperCallConstructor extends ConstructorCountingParent {
- constructor() {
- let arrow = () => { super(); };
- super();
- arrow();
- }
- };
- assert.throws(function() { new IllegalSuperCallConstructor(); }, ReferenceError, "It's a ReferenceError to call super multiple times in a derived class constructor", "Multiple calls to 'super' in a class constructor are not allowed");
- assert.areEqual(2, calls_to_ConstructorCountingParent, "We do call the super function body twice but we throw ReferenceError when trying to assign the 'this' value after the second super call");
- }
- },
- {
- name: "Derived class throws ReferenceError with multiple calls to super ('this' is already initialized) with multiple calls in lambdas",
- body: function () {
- // Reset call counter in parent
- calls_to_ConstructorCountingParent = 0;
- class IllegalSuperCallConstructor extends ConstructorCountingParent {
- constructor() {
- let arrow = () => { super(); };
- let arrow2 = () => { super(); };
- arrow();
- arrow2();
- }
- };
- assert.throws(function() { new IllegalSuperCallConstructor(); }, ReferenceError, "It's a ReferenceError to call super multiple times in a derived class constructor", "Multiple calls to 'super' in a class constructor are not allowed");
- assert.areEqual(2, calls_to_ConstructorCountingParent, "We do call the super function body twice but we throw ReferenceError when trying to assign the 'this' value after the second super call");
- }
- },
- {
- name: "Derived class throws ReferenceError with multiple calls to super ('this' is already initialized) with multiple calls in the same lambda",
- body: function () {
- // Reset call counter in parent
- calls_to_ConstructorCountingParent = 0;
- class IllegalSuperCallConstructor extends ConstructorCountingParent {
- constructor() {
- let arrow = () => { super(); super(); };
- arrow();
- }
- };
- assert.throws(function() { new IllegalSuperCallConstructor(); }, ReferenceError, "It's a ReferenceError to call super multiple times in a derived class constructor", "Multiple calls to 'super' in a class constructor are not allowed");
- assert.areEqual(2, calls_to_ConstructorCountingParent, "We do call the super function body twice but we throw ReferenceError when trying to assign the 'this' value after the second super call");
- }
- },
- {
- name: "Derived class constructor captures this and super in a lambda but doesn't call the lambda",
- body: function () {
- class DerivedClassCapturingThisAndSuper extends SimpleParent {
- constructor() {
- let arrow = () => { this.bar = 'lambda'; super(); };
- super();
- this.bar = "DerivedClassCapturingThisAndSuper";
- }
- };
- let result = new DerivedClassCapturingThisAndSuper();
- assert.areEqual("DerivedClassCapturingThisAndSuper", result.bar, "This is initialized with the return value from super()");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedClassCapturingThisAndSuper, "Result object is instanceof derived class");
- }
- },
- {
- name: "Creating an instance of base class doesn't block new.target calculation for super chain",
- body: function () {
- let parent = new SimpleParent();
- class SimpleDerivedClass extends SimpleParent {
- constructor() {
- super();
- this.bar = "SimpleDerivedClass";
- }
- };
- let result = new SimpleDerivedClass();
- assert.isFalse(Object.hasOwnProperty(parent, 'bar'), "Parent object doesn't have derived class values");
- assert.areEqual("SimpleParent", parent.foo, "Parent class initialized the object");
- assert.isTrue(parent instanceof SimpleParent, "Parent object is instanceof base class");
- assert.isFalse(parent instanceof SimpleDerivedClass, "Parent object isn't instanceof derived class");
- assert.areEqual("SimpleDerivedClass", result.bar, "This is initialized with the return value from super()");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SimpleDerivedClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Chain of multiple derived classes",
- body: function () {
- class MiddleDerivedClass extends SimpleParent {
- constructor() {
- super();
- this.bar = "MiddleDerivedClass";
- }
- };
- class BottomDerivedClass extends MiddleDerivedClass {
- constructor() {
- super();
- this.baz = "BottomDerivedClass";
- }
- };
- let result = new BottomDerivedClass();
- assert.areEqual("BottomDerivedClass", result.baz, "This is initialized with the return value from super()");
- assert.areEqual("MiddleDerivedClass", result.bar, "This is initialized with the return value from super()");
- assert.areEqual("SimpleParent", result.foo, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof MiddleDerivedClass, "Result object is instanceof derived class");
- assert.isTrue(result instanceof BottomDerivedClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class constructor leaks lambda which performs super",
- body: function() {
- class A {
- constructor() {
- this.a = 'A';
- }
- }
- class B extends A {
- constructor() {
- super();
- this.b = 'B';
- }
- }
- class C extends B {
- constructor() {
- var s = () => { super(); this.c = 'C'; return this; };
- return s;
- }
- }
- var maker = new C();
- var result = maker();
- assert.areEqual("C", result.c, "This is initialized with the return value from super()");
- assert.areEqual("B", result.b, "This is initialized with the return value from super()");
- assert.areEqual("A", result.a, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof A, "Result object is instanceof base class");
- assert.isTrue(result instanceof B, "Result object is instanceof derived class");
- assert.isTrue(result instanceof C, "Result object is instanceof derived class");
- assert.throws(function() { var result2 = maker(); }, ReferenceError, "Calling the escaped lambda again will throw since 'this' of the parent is already initialized", "Multiple calls to 'super' in a class constructor are not allowed");
- // creating a new lambda should let us construct one more object
- maker = new C();
- result = maker();
- assert.areEqual("C", result.c, "This is initialized with the return value from super()");
- assert.areEqual("B", result.b, "This is initialized with the return value from super()");
- assert.areEqual("A", result.a, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof A, "Result object is instanceof base class");
- assert.isTrue(result instanceof B, "Result object is instanceof derived class");
- assert.isTrue(result instanceof C, "Result object is instanceof derived class");
- assert.throws(function() { var result2 = maker(); }, ReferenceError, "Calling the escaped lambda again will throw since 'this' of the parent is already initialized", "Multiple calls to 'super' in a class constructor are not allowed");
- }
- },
- {
- name: "Derived class constructor leaks lambda which performs super (lamdba comes from middle derived class)",
- body: function() {
- class A {
- constructor() {
- this.a = 'A';
- }
- }
- class B extends A {
- constructor() {
- var s = () => { super(); this.b = 'B'; return this; };
- return s;
- }
- }
- class C extends B {
- constructor() {
- super();
- }
- }
- var maker = new C();
- var result = maker();
- assert.areEqual("B", result.b, "This is initialized with the return value from super()");
- assert.areEqual("A", result.a, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof A, "Result object is instanceof base class");
- assert.isTrue(result instanceof B, "Result object is instanceof derived class");
- assert.isTrue(result instanceof C, "Result object is instanceof derived class");
- assert.throws(function() { var result2 = maker(); }, ReferenceError, "Calling the escaped lambda again will throw since 'this' of the parent is already initialized", "Multiple calls to 'super' in a class constructor are not allowed");
- // creating a new lambda should let us construct one more object
- maker = new C();
- result = maker();
- assert.areEqual("B", result.b, "This is initialized with the return value from super()");
- assert.areEqual("A", result.a, "Parent class returned the object from super to derived constructor");
- assert.isTrue(result instanceof A, "Result object is instanceof base class");
- assert.isTrue(result instanceof B, "Result object is instanceof derived class");
- assert.isTrue(result instanceof C, "Result object is instanceof derived class");
- assert.throws(function() { var result2 = maker(); }, ReferenceError, "Calling the escaped lambda again will throw since 'this' of the parent is already initialized", "Multiple calls to 'super' in a class constructor are not allowed");
- }
- },
- {
- name: "Derived class constructor leaks lambda which references 'this' in TDZ",
- body: function() {
- class A {
- constructor() {
- this.a = 'A';
- }
- }
- class B extends A {
- constructor() {
- super();
- this.b = 'B';
- }
- }
- class C extends B {
- constructor() {
- var s = () => { this.c = 'C'; super(); return this; };
- return s;
- }
- }
- var maker = new C();
- assert.throws(function() { var result = maker(); }, ReferenceError, "Calling the escaped lambda throws since 'this' is accessed before super call", "Use before declaration");
- }
- },
- {
- name: "Derived class constructor leaks lambda which references 'this' in TDZ (lamdba comes from middle derived class)",
- body: function() {
- class A {
- constructor() {
- this.a = 'A';
- }
- }
- class B extends A {
- constructor() {
- var s = () => { this.b = 'B'; super(); return this; };
- return s;
- }
- }
- class C extends B {
- constructor() {
- super();
- }
- }
- var maker = new C();
- assert.throws(function() { var result = maker(); }, ReferenceError, "Calling the escaped lambda throws since 'this' is accessed before super call", "Use before declaration");
- }
- },
- {
- name: "Derived class with null extends expression cannot be new'd",
- body: function () {
- class NullExtendsExpression extends null {
- };
- assert.throws(function() { new NullExtendsExpression(); }, TypeError, "Class that extends null throws when we attempt to call super as [[construct]]", "Function 'super' is not a constructor");
- }
- },
- {
- name: "Derived class with null extends expression can be new'd if constructor returns object",
- body: function () {
- class NullExtendsExpressionWithConstructor extends null {
- constructor(arg) {
- return arg;
- }
- };
- var result = new NullExtendsExpressionWithConstructor({foo:'value'});
- assert.areEqual('value', result.foo, "Class derived from null expression can return an object safely");
- assert.isFalse(result instanceof NullExtendsExpressionWithConstructor, "Result object is not instanceof class");
- }
- },
- {
- name: "Derived constructor with a super call that isn't executed",
- body: function () {
- let returnFalse = () => { return false; };
- class DerivedClassAccessThisImplicitReturn extends SimpleParent {
- constructor() {
- if (returnFalse()) {
- super();
- }
- this.bar = '';
- }
- };
- assert.throws(function() { new DerivedClassAccessThisImplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassImplicitReturn extends SimpleParent {
- constructor() {
- if (returnFalse()) {
- super();
- }
- }
- };
- assert.throws(function() { new DerivedClassImplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassAccessThisExplicitReturn extends SimpleParent {
- constructor() {
- if (returnFalse()) {
- super();
- }
- this.bar = '';
- return this;
- }
- };
- assert.throws(function() { new DerivedClassAccessThisExplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassExplicitReturn extends SimpleParent {
- constructor() {
- if (returnFalse()) {
- super();
- }
- return this;
- }
- };
- assert.throws(function() { new DerivedClassExplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassAccessThisViaLambdaImplicitReturn extends SimpleParent {
- constructor() {
- let arrow = () => { this.foo = ''; }
- if (returnFalse()) {
- super();
- }
- arrow();
- }
- };
- assert.throws(function() { new DerivedClassAccessThisViaLambdaImplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassAccessThisViaLambdaExplicitReturn extends SimpleParent {
- constructor() {
- let arrow = () => { this.foo = ''; }
- if (returnFalse()) {
- super();
- }
- arrow();
- return this;
- }
- };
- assert.throws(function() { new DerivedClassAccessThisViaLambdaExplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassWithThisScopeCaptureNoAccessImplicitReturn extends SimpleParent {
- constructor() {
- let arrow = () => { this.foo = ''; }
- if (returnFalse()) {
- super();
- }
- }
- };
- assert.throws(function() { new DerivedClassWithThisScopeCaptureNoAccessImplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- class DerivedClassWithThisScopeCaptureNoAccessExplicitReturn extends SimpleParent {
- constructor() {
- let arrow = () => { this.foo = ''; }
- if (returnFalse()) {
- super();
- }
- return this;
- }
- };
- assert.throws(function() { new DerivedClassWithThisScopeCaptureNoAccessExplicitReturn(); }, ReferenceError, "When super isn't called, this is undecl", "Use before declaration");
- }
- },
- {
- name: "Derived class with super call inside an eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- eval('super();');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with super call inside an eval which accesses this",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- eval('super(); this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Class derived from SimpleParent can return an object safely");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with super call inside an eval which accesses new.target",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- eval('assert.areEqual(new.target, SuperCallInEvalClass, "new.target === SuperCallInEvalClass"); super();');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with super call inside an eval which accesses new.target and this",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- eval('assert.areEqual(new.target, SuperCallInEvalClass); super(); this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with super call inside an eval access to this inside eval and constructor",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- eval('super(); this.bar = "SuperCallInEvalClass";');
- this.baz = "SuperCallInEvalClass_ctor";
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.areEqual('SuperCallInEvalClass_ctor', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_ctor'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class 'this' access inside an eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- super();
- eval('this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class 'this' access inside and outside an eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- super();
- eval('this.bar = "SuperCallInEvalClass";');
- this.baz = "SuperCallInEvalClass_ctor";
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.areEqual('SuperCallInEvalClass_ctor', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_ctor'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class super call inside an eval with an unused arrow super call",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- let arrow = () => { super(); }
- eval('super(); this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class super call inside an arrow with this access in an eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- let arrow = () => { super(); }
- arrow();
- eval('this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class super call inside an arrow accessing new.target with this access in an eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- let arrow = () => {
- assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");
- super();
- }
- arrow();
- eval('this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with arrow and eval accessing new.target, this - super in the arrow",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- let arrow = () => {
- assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");
- super();
- this.baz = "SuperCallInEvalClass_arrow";
- }
- arrow();
- eval('assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target"); this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.areEqual('SuperCallInEvalClass_arrow', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_arrow'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with arrow and eval accessing new.target, this - super in the eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- let arrow = () => {
- assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");
- this.baz = "SuperCallInEvalClass_arrow";
- }
- eval('assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target"); super(); this.bar = "SuperCallInEvalClass";');
- arrow();
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.areEqual('SuperCallInEvalClass_arrow', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_arrow'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with arrow and multiple evals accessing new.target, this - super in the eval",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- eval('assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");');
- let arrow = () => {
- assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");
- this.baz = "SuperCallInEvalClass_arrow";
- }
- eval('super();');
- arrow();
- eval('this.bar = "SuperCallInEvalClass";');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass'");
- assert.areEqual('SuperCallInEvalClass_arrow', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_arrow'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class testing all arrow/eval scenarios together",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor(callSuperInCtor, callSuperInLambda, callSuperInEval) {
- assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");
- eval('assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");');
- let arrow_pre = () => {
- assert.areEqual(SuperCallInEvalClass, new.target, "SuperCallInEvalClass === new.target");
- }
- let arrow_post = () => {
- this.baz = "SuperCallInEvalClass_arrow";
- }
- let arrow_super = () => {
- super();
- }
- arrow_pre();
- if (callSuperInCtor) {
- super();
- }
- if (callSuperInLambda) {
- arrow_super();
- }
- if (callSuperInEval) {
- eval('super();');
- }
- arrow_post();
- eval('this.bar = "SuperCallInEvalClass_eval";');
- this.bot = 'SuperCallInEvalClass_ctor';
- }
- };
- function verifyObj(result) {
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass_eval', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass_eval'");
- assert.areEqual('SuperCallInEvalClass_arrow', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_arrow'");
- assert.areEqual('SuperCallInEvalClass_ctor', result.bot, "Result object has derived field bot set to 'SuperCallInEvalClass_ctor'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- verifyObj(new SuperCallInEvalClass(true,false,false));
- verifyObj(new SuperCallInEvalClass(false,true,false));
- verifyObj(new SuperCallInEvalClass(false,false,true));
- assert.throws(function() { new SuperCallInEvalClass(false,false,false); }, ReferenceError, "Not calling super at all will cause a ReferenceError", "Use before declaration");
- assert.throws(function() { new SuperCallInEvalClass(true,true,false); }, ReferenceError, "Calling super in the ctor and a lambda throws a ReferenceError", "Multiple calls to 'super' in a class constructor are not allowed");
- assert.throws(function() { new SuperCallInEvalClass(true,false,true); }, ReferenceError, "Calling super in the ctor and eval throws a ReferenceError", "Multiple calls to 'super' in a class constructor are not allowed");
- assert.throws(function() { new SuperCallInEvalClass(false,true,true); }, ReferenceError, "Calling super in a lambda and eval throws a ReferenceError", "Multiple calls to 'super' in a class constructor are not allowed");
- }
- },
- {
- name: "Chained derived constructors performing super calls",
- body: function () {
- class DerivedClassUsingSuperInEval extends SimpleParent {
- constructor() {
- eval('super();');
- }
- };
- class DerivedClassUsingSuperInArrow extends DerivedClassUsingSuperInEval {
- constructor() {
- let arrow = () => { super(); }
- arrow();
- }
- };
- class DerivedClassUsingDefaultConstructor extends DerivedClassUsingSuperInArrow {
- }
- class BottomLevelDerivedClass extends DerivedClassUsingDefaultConstructor {
- constructor() {
- super();
- }
- };
- var result = new BottomLevelDerivedClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedClassUsingSuperInEval, "Result object is instanceof derived class");
- assert.isTrue(result instanceof DerivedClassUsingSuperInArrow, "Result object is instanceof derived class");
- assert.isTrue(result instanceof DerivedClassUsingDefaultConstructor, "Result object is instanceof derived class");
- assert.isTrue(result instanceof BottomLevelDerivedClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with nested evals performing super",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- var inner = "SuperCallInEvalClass_inner_eval";
- var outer = "SuperCallInEvalClass_outer_eval";
- eval('eval("super(); this.bar = inner;"); this.baz = outer;');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass_inner_eval', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass_inner_eval'");
- assert.areEqual('SuperCallInEvalClass_outer_eval', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_outer_eval'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with eval in arrow performing super",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- var inner = "SuperCallInEvalClass_inner_eval";
- var outer = "SuperCallInEvalClass_outer_eval";
- var arrow = () => {
- eval("super(); this.bar = inner;");
- this.baz = outer;
- };
- arrow();
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass_inner_eval', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass_inner_eval'");
- assert.areEqual('SuperCallInEvalClass_outer_eval', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_outer_eval'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with nested eval in arrow performing super",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- var inner = "SuperCallInEvalClass_inner_eval";
- var outer = "SuperCallInEvalClass_outer_eval";
- var arrow = () => {
- eval(`eval("super(); this.bar = inner;");`);
- this.baz = outer;
- };
- arrow();
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass_inner_eval', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass_inner_eval'");
- assert.areEqual('SuperCallInEvalClass_outer_eval', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_outer_eval'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with nested eval nested in arrow performing super",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- var inner = "SuperCallInEvalClass_inner_eval";
- var outer = "SuperCallInEvalClass_outer_eval";
- var arrow = () => {
- eval(`eval("super(); this.bar = inner;");`);
- this.baz = outer;
- };
- var exec_arrow = () => {
- arrow();
- };
- exec_arrow();
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass_inner_eval', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass_inner_eval'");
- assert.areEqual('SuperCallInEvalClass_outer_eval', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_outer_eval'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Derived class with nested constructor calls and arrow performing super inside eval",
- body: function () {
- class B { }
- class A extends B
- {
- constructor()
- {
- eval("(()=>{ super(); this.value = 1; class X extends Object { constructor() { eval(\"super(); this.value = 2; \"); } } var x = new X(); this.x = x;})()");
- }
- }
- var a=new A();
- assert.isTrue(a instanceof A, "object a should be instanceof derived class");
- assert.isTrue(a instanceof B, "object should be instanceof base class");
- assert.areEqual(1, a.value, "assignment to 'this' inside constructor eval nested arrow function");
- assert.areEqual(2, a.x.value, "assignment to 'this' inside nested constructor and eval");
- }
- },
- {
- name: "Derived class with arrow in eval performing super",
- body: function () {
- class SuperCallInEvalClass extends SimpleParent {
- constructor() {
- var inner = "SuperCallInEvalClass_inner_eval";
- var outer = "SuperCallInEvalClass_outer_eval";
- eval('(()=>{super(); this.bar = inner;})(); this.baz = outer;');
- }
- };
- var result = new SuperCallInEvalClass();
- assert.areEqual('SimpleParent', result.foo, "Class derived from SimpleParent has foo field set to 'SimpleParent'");
- assert.areEqual('SuperCallInEvalClass_inner_eval', result.bar, "Result object has derived field bar set to 'SuperCallInEvalClass_inner_eval'");
- assert.areEqual('SuperCallInEvalClass_outer_eval', result.baz, "Result object has derived field baz set to 'SuperCallInEvalClass_outer_eval'");
- assert.isTrue(result instanceof SimpleParent, "Result object is instanceof base class");
- assert.isTrue(result instanceof SuperCallInEvalClass, "Result object is instanceof derived class");
- }
- },
- {
- name: "Eval class hierarchy with super call",
- body: function () {
- let result = eval(`
- class EvalSimpleParent {
- constructor() {
- this.foo = "EvalSimpleParent";
- }
- };
- class EvalDerivedClass extends EvalSimpleParent {
- constructor() {
- super();
- this.bar = "EvalDerivedClass";
- }
- };
- var o = new EvalDerivedClass();
- assert.isTrue(o instanceof EvalSimpleParent, "Result object is instanceof base class");
- assert.isTrue(o instanceof EvalDerivedClass, "Result object is instanceof derived class");
- o;
- `);
- assert.areEqual('EvalSimpleParent', result.foo, "Class derived from EvalSimpleParent has foo field set to 'EvalSimpleParent'");
- assert.areEqual('EvalDerivedClass', result.bar, "Result object has derived field bar set to 'EvalDerivedClass'");
- }
- },
- {
- name: "Eval class hierarchy with super call inside arrow function",
- body: function () {
- let result = eval(`
- class EvalSimpleParent {
- constructor() {
- this.foo = "EvalSimpleParent";
- }
- };
- class EvalDerivedClass extends EvalSimpleParent {
- constructor() {
- var inner = "EvalDerivedClass_inner";
- var outer = "EvalDerivedClass_outer";
- var arrow = () => {
- super();
- this.baz = inner;
- };
- arrow();
- this.bar = outer;
- }
- };
- var o = new EvalDerivedClass();
- assert.isTrue(o instanceof EvalSimpleParent, "Result object is instanceof base class");
- assert.isTrue(o instanceof EvalDerivedClass, "Result object is instanceof derived class");
- o;
- `);
- assert.areEqual('EvalSimpleParent', result.foo, "Class derived from EvalSimpleParent has foo field set to 'EvalSimpleParent'");
- assert.areEqual('EvalDerivedClass_outer', result.bar, "Result object has derived field bar set to 'EvalDerivedClass_outer'");
- assert.areEqual('EvalDerivedClass_inner', result.baz, "Result object has derived field baz set to 'EvalDerivedClass_inner'");
- }
- },
- {
- name: "Eval class hierarchy with super call inside nested eval",
- body: function () {
- let result = eval(`
- class EvalSimpleParent {
- constructor() {
- this.foo = "EvalSimpleParent";
- }
- };
- class EvalDerivedClass extends EvalSimpleParent {
- constructor() {
- var inner = "EvalDerivedClass_inner";
- var outer = "EvalDerivedClass_outer";
- eval('super(); this.bar = inner;');
- this.baz = outer;
- }
- };
- var o = new EvalDerivedClass();
- assert.isTrue(o instanceof EvalSimpleParent, "Result object is instanceof base class");
- assert.isTrue(o instanceof EvalDerivedClass, "Result object is instanceof derived class");
- o;
- `);
- assert.areEqual('EvalSimpleParent', result.foo, "Class derived from EvalSimpleParent has foo field set to 'EvalSimpleParent'");
- assert.areEqual('EvalDerivedClass_inner', result.bar, "Result object has derived field bar set to 'EvalDerivedClass_inner'");
- assert.areEqual('EvalDerivedClass_outer', result.baz, "Result object has derived field baz set to 'EvalDerivedClass_outer'");
- }
- },
- {
- name: "Eval class hierarchy with super call inside eval inside arrow function",
- body: function () {
- let result = eval(`
- class EvalSimpleParent {
- constructor() {
- this.foo = "EvalSimpleParent";
- }
- };
- class EvalDerivedClass extends EvalSimpleParent {
- constructor() {
- var moreinner = "EvalDerivedClass_moreinner";
- var inner = "EvalDerivedClass_inner";
- var outer = "EvalDerivedClass_outer";
- var arrow = () => {
- eval('super(); this.bat = moreinner;');
- this.baz = inner;
- };
- arrow();
- this.bar = outer;
- }
- };
- var o = new EvalDerivedClass();
- assert.isTrue(o instanceof EvalSimpleParent, "Result object is instanceof base class");
- assert.isTrue(o instanceof EvalDerivedClass, "Result object is instanceof derived class");
- o;
- `);
- assert.areEqual('EvalSimpleParent', result.foo, "Class derived from EvalSimpleParent has foo field set to 'EvalSimpleParent'");
- assert.areEqual('EvalDerivedClass_outer', result.bar, "Result object has derived field bar set to 'EvalDerivedClass_outer'");
- assert.areEqual('EvalDerivedClass_inner', result.baz, "Result object has derived field baz set to 'EvalDerivedClass_inner'");
- assert.areEqual('EvalDerivedClass_moreinner', result.bat, "Result object has derived field bat set to 'EvalDerivedClass_moreinner'");
- }
- },
- {
- name: "ES5-style class as a base class - explicit return of this from base",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = "Base";
- return this;
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- super();
- this.bar = "Derived";
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "ES5-style class as a base class with the super call inside an eval - explicit return of this from base",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = "Base";
- return this;
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- eval('super();');
- this.bar = "Derived";
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "ES5-style class as a base class with the super call inside an arrow - explicit return of this from base",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = "Base";
- return this;
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- let arrow = () => { super(); };
- arrow();
- this.bar = "Derived";
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "ES5-style class as a base class - implicit return of this from base",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = "Base";
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- super();
- this.bar = "Derived";
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "ES5-style class as a base class with the super call inside an eval - implicit return of this from base",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = "Base";
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- eval('super();');
- this.bar = "Derived";
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "ES5-style class as a base class with the super call inside an arrow - implicit return of this from base",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = "Base";
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- let arrow = () => { super(); };
- arrow();
- this.bar = "Derived";
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "Function as a base class can't assign this to non-object via super call",
- body: function () {
- function BaseReturnsArgument(arg) {
- assert.areEqual(new.target, DerivedFromBase, "new.target === DerivedFromBase");
- this.foo = 'BaseReturnsArgument';
- return arg;
- }
- BaseReturnsArgument.prototype = {
- constructor: BaseReturnsArgument
- }
- class DerivedFromBase extends BaseReturnsArgument {
- constructor(arg) {
- super(arg);
- assert.isFalse(this === arg, "If base function returns non-object, 'this' is returned instead");
- this.bar = 'DerivedFromBase';
- }
- }
- function testDerivedClass(arg) {
- let result = new DerivedFromBase(arg);
- assert.isTrue(result instanceof BaseReturnsArgument, "Result object is instanceof base class");
- assert.isTrue(result instanceof DerivedFromBase, "Result object is instanceof derived class");
- assert.areEqual('BaseReturnsArgument', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('DerivedFromBase', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- testDerivedClass();
- testDerivedClass(undefined);
- testDerivedClass(null);
- testDerivedClass('string');
- testDerivedClass(5);
- testDerivedClass(Symbol());
- }
- },
- {
- name: "Function as a base class can return an object to override this",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- this.foo = 'bad';
- return { foo: 'Base' };
- }
- Base.prototype = {
- constructor: Base
- }
- class Derived extends Base {
- constructor() {
- super();
- this.bar = 'Derived';
- }
- }
- let result = new Derived();
- assert.isFalse(result instanceof Base, "Result object is instanceof base class");
- assert.isFalse(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- {
- name: "Super call with expressions in arguments",
- body: function () {
- function Base() {
- assert.areEqual(new.target, Derived, "new.target === Derived");
- assert.areEqual(3, arguments[0], 'arguments[0] === 3')
- assert.areEqual('str', arguments[1], 'arguments[1] === "str"')
- assert.areEqual(1, arguments[2], 'arguments[2] === 1')
- assert.areEqual(2, arguments[3], 'arguments[3] === 2')
- assert.areEqual(3, arguments[4], 'arguments[4] === 3')
- assert.areEqual(5, arguments.length, 'arguments.length === 5');
- this.foo = 'Base';
- }
- Base.prototype = {
- constructor: Base
- }
- function foo() { return 'str'; }
- class Derived extends Base {
- constructor() {
- super(1+2,foo(),...[1,2,3]);
- this.bar = 'Derived';
- }
- }
- let result = new Derived();
- assert.isTrue(result instanceof Base, "Result object is instanceof base class");
- assert.isTrue(result instanceof Derived, "Result object is instanceof derived class");
- assert.areEqual('Base', result.foo, "Class derived from Base has foo field set to 'Base'");
- assert.areEqual('Derived', result.bar, "Result object has derived field bar set to 'Derived'");
- }
- },
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|