// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flags: --allow-natives-syntax (function TestSuperNamedLoads() { function Base() { } function fBase() { } Base.prototype = { f() { return "Base " + this.toString(); }, x: 15, toString() { return "this is Base"; } }; function Derived() { this.derivedDataProperty = "xxx"; } Derived.prototype = { __proto__: Base.prototype, toString() { return "this is Derived"; }, x: 27, f() { assertEquals("Base this is Derived", super.f()); var a = super.x; assertEquals(15, a); assertEquals(15, super.x); assertEquals(27, this.x); return "Derived"; } }; assertEquals("Base this is Base", new Base().f()); assertEquals("Derived", new Derived().f()); }()); (function TestSuperKeyedLoads() { 'use strict'; var x = 'x'; var derivedDataProperty = 'derivedDataProperty'; var f = 'f'; class Base { f() { return "Base " + this.toString(); } toString() { return "this is Base"; } } Base.prototype[x] = 15; function Derived() { this[derivedDataProperty] = "xxx"; } Derived.prototype = { __proto__: Base.prototype, toString() { return "this is Derived"; }, x: 27, f() { assertEquals("Base this is Derived", super[f]()); var a = super[x]; assertEquals(15, a); assertEquals(15, super[x]); assertEquals(27, this[x]); return "Derived"; } }; assertEquals("Base this is Base", new Base().f()); assertEquals("Derived", new Derived().f()); }()); (function TestSuperKeywordNonMethod() { 'use strict'; class C { f() { super.unknown(); } } assertThrows(function() { new C().f(); }, TypeError); }()); (function TestGetter() { function Base() {} var derived; Base.prototype = { constructor: Base, get x() { assertSame(this, derived); return this._x; }, _x: 'base' }; function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 'derived', testGetter() { return super.x; }, testGetterStrict() { 'use strict'; return super.x; } }; derived = new Derived(); assertEquals('derived', derived.testGetter()); derived = new Derived(); assertEquals('derived', derived.testGetterStrict()); }()); (function TestGetterKeyed() { var x = 'x'; function Base() {} var derived; Base.prototype = { constructor: Base, get x() { assertSame(this, derived); return this._x; }, _x: 'base' }; function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 'derived', testGetter() { return super[x]; }, testGetterStrict() { 'use strict'; return super[x]; }, testGetterWithToString() { var toStringCalled; var o = { toString: function() { toStringCalled++; return 'x'; } }; toStringCalled = 0; assertEquals('derived', super[o]); assertEquals(1, toStringCalled); var eToThrow = new Error(); var oThrowsInToString = { toString: function() { throw eToThrow; } }; var ex = null; try { super[oThrowsInToString]; } catch(e) { ex = e } assertEquals(eToThrow, ex); var oReturnsNumericString = { toString: function() { return "1"; } }; assertEquals(undefined, super[oReturnsNumericString]); assertEquals(undefined, super[1]); } }; derived = new Derived(); assertEquals('derived', derived.testGetter()); derived = new Derived(); assertEquals('derived', derived.testGetterStrict()); derived = new Derived(); derived.testGetterWithToString(); }()); (function TestGetterNumericKeyed() { var x = 42; function Base() {} var derived; Base.prototype = { constructor: Base, _x: 'base' }; Object.defineProperty(Base.prototype, x, { get: function() { assertSame(this, derived); return this._x; }}); function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 'derived', testGetter() { return super[x]; }, testGetterStrict() { 'use strict'; return super[x]; }, testGetterWithToString() { var toStringCalled; var o = { toString: function() { toStringCalled++; return '42'; } }; toStringCalled = 0; assertEquals('derived', super[o]); assertEquals(1, toStringCalled); var eToThrow = new Error(); var oThrowsInToString = { toString: function() { throw eToThrow; } }; var ex = null; try { super[oThrowsInToString]; } catch(e) { ex = e } assertEquals(eToThrow, ex); var oReturnsNumericString = { toString: function() { return "42"; } }; assertEquals('derived', super[oReturnsNumericString]); assertEquals('derived', super[42]); } }; derived = new Derived(); assertEquals('derived', derived.testGetter()); derived = new Derived(); assertEquals('derived', derived.testGetterStrict()); derived = new Derived(); derived.testGetterWithToString(); }()); (function TestSetter() { function Base() {} Base.prototype = { constructor: Base, get x() { return this._x; }, set x(v) { this._x = v; }, _x: 'base' }; function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 'derived', testSetter() { assertEquals('foobar', super.x = 'foobar'); assertEquals('foobarabc', super.x += 'abc'); }, testSetterStrict() { 'use strict'; assertEquals('foobar', super.x = 'foobar'); assertEquals('foobarabc', super.x += 'abc'); } }; var d = new Derived(); d.testSetter(); assertEquals('base', Base.prototype._x); assertEquals('foobarabc', d._x); d._x = ''; d.testSetterStrict(); assertEquals('base', Base.prototype._x); assertEquals('foobarabc', d._x); }()); (function TestSetterNumericKeyed() { var x = 42; function Base() {} Base.prototype = { constructor: Base, _x: 'base' }; Object.defineProperty(Base.prototype, x, { get: function() { return this._x; }, set: function(v) { this._x = v; } }); function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 'derived', testSetter() { assertEquals('foobar', super[x] = 'foobar'); assertEquals('foobarabc', super[x] += 'abc'); }, testSetterStrict() { 'use strict'; assertEquals('foobar', super[x] = 'foobar'); assertEquals('foobarabc', super[x] += 'abc'); }, testSetterWithToString() { var toStringCalled; var o = { toString: function() { toStringCalled++; return x; } }; toStringCalled = 0; super[o] = 'set'; assertEquals(1, toStringCalled); assertEquals('set', this._x); var eToThrow = new Error(); var oThrowsInToString = { toString: function() { throw eToThrow; } }; var ex = null; try { super[oThrowsInToString] = 'xyz'; } catch(e) { ex = e } assertEquals(eToThrow, ex); assertEquals('set', this._x); } }; var d = new Derived(); d.testSetter(); assertEquals('base', Base.prototype._x); assertEquals('foobarabc', d._x); d._x = ''; d.testSetterStrict(); assertEquals('base', Base.prototype._x); assertEquals('foobarabc', d._x); d = new Derived(); d.testSetterWithToString(); }()); (function TestSetterKeyed() { var x = 'x'; function Base() {} Base.prototype = { constructor: Base, get x() { return this._x; }, set x(v) { this._x = v; }, _x: 'base' }; function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 'derived', testSetter() { assertEquals('foobar', super[x] = 'foobar'); assertEquals('foobarabc', super[x] += 'abc'); }, testSetterStrict() { 'use strict'; assertEquals('foobar', super[x] = 'foobar'); assertEquals('foobarabc', super[x] += 'abc'); }, testSetterWithToString() { var toStringCalled; var o = { toString: function() { toStringCalled++; return 'x'; } }; toStringCalled = 0; super[o] = 'set'; assertEquals(1, toStringCalled); assertEquals('set', this._x); var eToThrow = new Error(); var oThrowsInToString = { toString: function() { throw eToThrow; } }; var ex = null; try { super[oThrowsInToString] = 'xyz'; } catch(e) { ex = e } assertEquals(eToThrow, ex); assertEquals('set', this._x); var oReturnsNumericString = { toString: function() { return "1"; } }; assertEquals('abc', super[oReturnsNumericString] = 'abc'); assertEquals('set', this._x); assertEquals(10, super[1] = 10); } }; var d = new Derived(); d.testSetter(); assertEquals('base', Base.prototype._x); assertEquals('foobarabc', d._x); d._x = ''; d.testSetterStrict(); assertEquals('base', Base.prototype._x); assertEquals('foobarabc', d._x); d = new Derived(); d.testSetterWithToString(); }()); (function TestSetterDataProperties() { function Base() {} Base.prototype = { constructor: Base, x: 'x from Base' }; function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testSetter() { assertEquals('x from Base', super.x); super.x = 'data property'; assertEquals('x from Base', super.x); assertEquals('data property', this.x); } }; new Derived().testSetter(); }()); (function TestKeyedSetterDataProperties() { var x = 'x'; function Base() {} Base.prototype = { constructor: Base, x: 'x from Base' }; function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testSetter() { assertEquals('x from Base', super[x]); super[x] = 'data property'; assertEquals('x from Base', super[x]); assertEquals('data property', this[x]); } }; new Derived().testSetter(); }()); (function TestKeyedNumericSetterDataProperties() { var x = 42; function Base() {} Base.prototype = { constructor: Base, 42: 'x from Base' }; function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testSetter() { assertEquals('x from Base', super[x]); super[x] = 'data property'; assertEquals('x from Base', super[x]); assertEquals('data property', this[x]); } }; new Derived().testSetter(); }()); (function TestAccessorsOnPrimitives() { var getCalled = 0; var setCalled = 0; function Base() {} Base.prototype = { constructor: Base, get x() { getCalled++; return 1; }, set x(v) { setCalled++; return v; }, }; function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testSetter() { setCalled = 0; getCalled = 0; assertEquals('object', typeof this); assertInstanceof(this, Number) assertEquals(42, this.valueOf()); assertEquals(1, super.x); assertEquals(1, getCalled); assertEquals(0, setCalled); assertEquals(5, super.x = 5); assertEquals(1, getCalled); assertEquals(1, setCalled); assertEquals(6, super.x += 5); assertEquals(2, getCalled); assertEquals(2, setCalled); super.newProperty = 15; assertEquals(15, this.newProperty); assertEquals(undefined, super.newProperty); }, testSetterStrict() { 'use strict'; getCalled = 0; setCalled = 0; assertTrue(42 === this); assertEquals(1, super.x); assertEquals(1, getCalled); assertEquals(0, setCalled); assertEquals(5, super.x = 5); assertEquals(1, getCalled); assertEquals(1, setCalled); assertEquals(6, super.x += 5); assertEquals(2, getCalled); assertEquals(2, setCalled); var ex; try { super.newProperty = 15; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); } } Derived.prototype.testSetter.call(42); Derived.prototype.testSetterStrict.call(42); function DerivedFromString() {} DerivedFromString.prototype = { __proto__: String.prototype, f() { 'use strict'; assertTrue(42 === this); assertEquals(String.prototype.toString, super.toString); var ex; try { super.toString(); } catch(e) { ex = e; } assertInstanceof(ex, TypeError); } }; DerivedFromString.prototype.f.call(42); }()); (function TestKeyedAccessorsOnPrimitives() { var x = 'x'; var newProperty = 'newProperty'; var toString = 'toString'; var getCalled = 0; var setCalled = 0; function Base() {} Base.prototype = { constructor: Base, get x() { getCalled++; return 1; }, set x(v) { setCalled++; return v; }, }; function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testSetter() { setCalled = 0; getCalled = 0; assertEquals('object', typeof this); assertInstanceof(this, Number) assertEquals(42, this.valueOf()); assertEquals(1, super[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); assertEquals(5, super[x] = 5); assertEquals(1, getCalled); assertEquals(1, setCalled); assertEquals(6, super[x] += 5); assertEquals(2, getCalled); assertEquals(2, setCalled); super[newProperty] = 15; assertEquals(15, this[newProperty]); assertEquals(undefined, super[newProperty]); }, testSetterStrict() { 'use strict'; getCalled = 0; setCalled = 0; assertTrue(42 === this); assertEquals(1, super[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); assertEquals(5, super[x] = 5); assertEquals(1, getCalled); assertEquals(1, setCalled); assertEquals(6, super[x] += 5); assertEquals(2, getCalled); assertEquals(2, setCalled); var ex; try { super[newProperty] = 15; } catch (e) { ex = e; } assertInstanceof(ex,TypeError); } }; Derived.prototype.testSetter.call(42); Derived.prototype.testSetterStrict.call(42); function DerivedFromString() {} DerivedFromString.prototype = { __proto__: String.prototype, f() { 'use strict'; assertTrue(42 === this); assertEquals(String.prototype.toString, super[toString]); var ex; try { super[toString](); } catch(e) { ex = e; } assertInstanceof(ex, TypeError); } }; DerivedFromString.prototype.f.call(42); }()); (function TestNumericKeyedAccessorsOnPrimitives() { var x = 42; var newProperty = 43; var getCalled = 0; var setCalled = 0; function Base() {} Base.prototype = { constructor: Base, }; Object.defineProperty(Base.prototype, x, { get: function() { getCalled++; return 1; }, set: function(v) { setCalled++; return v; } }); function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testSetter() { setCalled = 0; getCalled = 0; assertEquals('object', typeof this); assertInstanceof(this, Number) assertEquals(42, this.valueOf()); assertEquals(1, super[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); assertEquals(5, super[x] = 5); assertEquals(1, getCalled); assertEquals(1, setCalled); assertEquals(6, super[x] += 5); assertEquals(2, getCalled); assertEquals(2, setCalled); super[newProperty] = 15; assertEquals(15, this[newProperty]); assertEquals(undefined, super[newProperty]); }, testSetterStrict() { 'use strict'; getCalled = 0; setCalled = 0; assertTrue(42 === this); assertEquals(1, super[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); assertEquals(5, super[x] = 5); assertEquals(1, getCalled); assertEquals(1, setCalled); assertEquals(6, super[x] += 5); assertEquals(2, getCalled); assertEquals(2, setCalled); var ex; try { super[newProperty] = 15; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); } }; Derived.prototype.testSetter.call(42); Derived.prototype.testSetterStrict.call(42); }()); (function TestKeyedNumericSetterOnExotics() { function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, callSetterOnArray() { super[42] = 1; }, callStrictSetterOnString() { 'use strict'; assertEquals('string', typeof this); assertTrue('abcdef' === this); var ex = null; try { super[5] = 'q'; } catch(e) { ex = e; } assertInstanceof(ex, TypeError); ex = null; try { super[1024] = 'q'; } catch(e) { ex = e; } assertInstanceof(ex, TypeError); } }; var x = []; assertEquals(0, x.length); Derived.prototype.callSetterOnArray.call(x); assertEquals(43, x.length); assertEquals(1, x[42]); var s = 'abcdef'; Derived.prototype.callStrictSetterOnString.call(s) }()); (function TestSetterUndefinedProperties() { function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(undefined, super.x); assertEquals(undefined, this.x); super.x = 10; assertEquals(10, this.x); assertEquals(undefined, super.x); }, mStrict() { 'use strict'; assertEquals(undefined, super.x); assertEquals(undefined, this.x); super.x = 10; assertEquals(10, this.x); assertEquals(undefined, super.x); } }; var d = new Derived(); d.mSloppy(); assertEquals(10, d.x); var d1 = new Derived(); d1.mStrict(); assertEquals(10, d.x); }()); (function TestKeyedSetterUndefinedProperties() { var x = 'x'; function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(undefined, super[x]); assertEquals(undefined, this[x]); super[x] = 10; assertEquals(10, this[x]); assertEquals(undefined, super[x]); }, mStrict() { 'use strict'; assertEquals(undefined, super[x]); assertEquals(undefined, this[x]); super[x] = 10; assertEquals(10, this[x]); assertEquals(undefined, super[x]); } }; var d = new Derived(); d.mSloppy(); assertEquals(10, d.x); var d1 = new Derived(); d1.mStrict(); assertEquals(10, d.x); }()); (function TestKeyedNumericSetterUndefinedProperties() { var x = 42; function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(undefined, super[x]); assertEquals(undefined, this[x]); super[x] = 10; assertEquals(10, this[x]); assertEquals(undefined, super[x]); }, mStrict() { 'use strict'; assertEquals(undefined, super[x]); assertEquals(undefined, this[x]); super[x] = 10; assertEquals(10, this[x]); assertEquals(undefined, super[x]); } }; var d = new Derived(); d.mSloppy(); assertEquals(10, d[x]); var d1 = new Derived(); d1.mStrict(); assertEquals(10, d[x]); }()); (function TestSetterCreatingOwnPropertiesReconfigurable() { function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(42, this.ownReadOnly); super.ownReadOnly = 55; assertSame(undefined, super.ownReadOnly); assertEquals(42, this.ownReadOnly); assertFalse(Base.prototype.hasOwnProperty('ownReadOnly')); assertEquals(15, this.ownReadonlyAccessor); super.ownReadonlyAccessor = 25; assertSame(undefined, super.ownReadonlyAccessor); assertEquals(15, this.ownReadonlyAccessor); assertFalse(Base.prototype.hasOwnProperty('ownReadonlyAccessor')); super.ownSetter = 35; assertSame(undefined, super.ownSetter); var descr = Object.getOwnPropertyDescriptor(this, 'ownSetter'); assertTrue('set' in descr); assertFalse(Base.prototype.hasOwnProperty('ownSetter')); }, mStrict() { 'use strict'; assertEquals(42, this.ownReadOnly); assertThrows(() => {super.ownReadOnly = 55}, TypeError); assertSame(undefined, super.ownReadOnly); assertEquals(42, this.ownReadOnly); assertFalse(Base.prototype.hasOwnProperty('ownReadOnly')); assertEquals(15, this.ownReadonlyAccessor); assertThrows(() => {super.ownReadonlyAccessor = 25}, TypeError); assertSame(undefined, super.ownReadonlyAccessor); assertEquals(15, this.ownReadonlyAccessor); assertFalse(Base.prototype.hasOwnProperty('ownReadonlyAccessor')); assertThrows(() => {super.ownSetter = 35}, TypeError); assertSame(undefined, super.ownSetter); var descr = Object.getOwnPropertyDescriptor(this, 'ownSetter'); assertTrue('set' in descr); assertFalse(Base.prototype.hasOwnProperty('ownSetter')); }, }; var d = new Derived(); Object.defineProperty(d, 'ownReadOnly', { value: 42, writable: false, configurable: true }); Object.defineProperty(d, 'ownSetter', { set: function() { assertUnreachable(); }, configurable: true }); Object.defineProperty(d, 'ownReadonlyAccessor', { get: function() { return 15; }, configurable: true }); d.mSloppy(); var d = new Derived(); Object.defineProperty(d, 'ownReadOnly', { value: 42, writable: false, configurable: true }); Object.defineProperty(d, 'ownSetter', { set: function() { assertUnreachable(); }, configurable: true }); Object.defineProperty(d, 'ownReadonlyAccessor', { get: function() { return 15; }, configurable: true }); d.mStrict(); }()); (function TestSetterCreatingOwnPropertiesNonConfigurable() { function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(42, this.ownReadOnly); super.ownReadOnly = 55; assertEquals(42, this.ownReadOnly); var descr = Object.getOwnPropertyDescriptor(this, 'ownReadOnly'); assertEquals(42, descr.value); assertFalse(descr.configurable); assertFalse(descr.enumerable); assertFalse(descr.writable); assertFalse(Base.prototype.hasOwnProperty('ownReadOnly')); assertEquals(15, this.ownReadonlyAccessor); super.ownReadonlyAccessor = 25; assertSame(undefined, super.ownReadonlyAccessor); assertEquals(15, this.ownReadonlyAccessor); var descr = Object.getOwnPropertyDescriptor(this, 'ownReadonlyAccessor'); assertFalse(descr.configurable); assertFalse(descr.enumerable); assertFalse(Base.prototype.hasOwnProperty('ownReadonlyAccessor')); super.ownSetter = 35; var descr = Object.getOwnPropertyDescriptor(this, 'ownSetter'); assertFalse(descr.configurable); assertFalse(descr.enumerable); assertFalse(Base.prototype.hasOwnProperty('ownSetter')); }, mStrict() { 'use strict'; var ex; assertEquals(42, this.ownReadOnly); try { super.ownReadOnly = 55; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals( "Cannot assign to read only property 'ownReadOnly' of object '#'", ex.message); assertEquals(42, this.ownReadOnly); ex = null; assertEquals(15, this.ownReadonlyAccessor); try { super.ownReadonlyAccessor = 25; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals('Cannot redefine property: ownReadonlyAccessor', ex.message); assertEquals(15, this.ownReadonlyAccessor); ex = null; try { super.ownSetter = 35; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals('Cannot redefine property: ownSetter', ex.message); } }; var d = new Derived(); Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false }); Object.defineProperty(d, 'ownSetter', { set : function() { assertUnreachable(); } }); Object.defineProperty(d, 'ownReadonlyAccessor', { get : function() { return 15; }}); d.mSloppy(); d.mStrict(); }()); (function TestSetterInForIn() { var setCalled = 0; var getCalled = 0; function Base() {} Base.prototype = { constructor: Base, get x() { getCalled++; return 1; }, set x(v) { setCalled++; this.x_.push(v); }, }; function Derived() { this.x_ = []; } Derived.prototype = { __proto__: Base.prototype, constructor: Derived, testIter() { setCalled = 0; getCalled = 0; for (super.x in [1,2,3]) {} assertEquals(0, getCalled); assertEquals(3, setCalled); assertEquals(["0", "1", "2"], this.x_); }, testIterKeyed() { setCalled = 0; getCalled = 0; for (super[x] in [1,2,3]) {} assertEquals(0, getCalled); assertEquals(3, setCalled); assertEquals(["0","1","2"], this.x_); this.x_ = []; setCalled = 0; getCalled = 0; var toStringCalled = 0; var o = {toString: function () { toStringCalled++; return x }}; for (super[o] in [1,2,3]) {} assertEquals(0, getCalled); assertEquals(3, setCalled); assertEquals(3, toStringCalled); assertEquals(["0","1","2"], this.x_); } }; new Derived().testIter(); var x = 'x'; new Derived().testIterKeyed(); }()); function TestKeyedSetterCreatingOwnPropertiesReconfigurable(ownReadOnly, ownReadonlyAccessor, ownSetter) { function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(42, this[ownReadOnly]); super[ownReadOnly] = 55; assertSame(undefined, super[ownReadOnly]); assertEquals(42, this[ownReadOnly]); assertFalse(Base.prototype.hasOwnProperty(ownReadOnly)); assertEquals(15, this[ownReadonlyAccessor]); super[ownReadonlyAccessor] = 25; assertSame(undefined, super[ownReadonlyAccessor]); assertEquals(15, this[ownReadonlyAccessor]); assertFalse(Base.prototype.hasOwnProperty(ownReadonlyAccessor)); super[ownSetter] = 35; assertSame(undefined, super[ownSetter]); var descr = Object.getOwnPropertyDescriptor(this, ownSetter); assertTrue('set' in descr); assertFalse(Base.prototype.hasOwnProperty(ownSetter)); }, mStrict() { 'use strict'; assertEquals(42, this[ownReadOnly]); assertThrows(() => {super[ownReadOnly] = 55}, TypeError); assertSame(undefined, super[ownReadOnly]); assertEquals(42, this[ownReadOnly]); assertFalse(Base.prototype.hasOwnProperty(ownReadOnly)); assertEquals(15, this[ownReadonlyAccessor]); assertThrows(() => {super[ownReadonlyAccessor] = 25}, TypeError); assertSame(undefined, super[ownReadonlyAccessor]); assertEquals(15, this[ownReadonlyAccessor]); assertFalse(Base.prototype.hasOwnProperty(ownReadonlyAccessor)); assertThrows(() => {super[ownSetter] = 35}, TypeError); assertSame(undefined, super[ownSetter]); var descr = Object.getOwnPropertyDescriptor(this, ownSetter); assertTrue('set' in descr); assertFalse(Base.prototype.hasOwnProperty(ownSetter)); }, }; var d = new Derived(); Object.defineProperty(d, ownReadOnly, { value: 42, writable: false, configurable: true }); Object.defineProperty(d, ownSetter, { set: function() { assertUnreachable(); }, configurable: true }); Object.defineProperty(d, ownReadonlyAccessor, { get: function() { return 15; }, configurable: true }); d.mSloppy(); var d = new Derived(); Object.defineProperty(d, ownReadOnly, { value: 42, writable: false, configurable: true }); Object.defineProperty(d, ownSetter, { set: function() { assertUnreachable(); }, configurable: true }); Object.defineProperty(d, ownReadonlyAccessor, { get: function() { return 15; }, configurable: true }); d.mStrict(); } TestKeyedSetterCreatingOwnPropertiesReconfigurable('ownReadOnly', 'ownReadonlyAccessor', 'ownSetter'); TestKeyedSetterCreatingOwnPropertiesReconfigurable(42, 43, 44); function TestKeyedSetterCreatingOwnPropertiesNonConfigurable( ownReadOnly, ownReadonlyAccessor, ownSetter) { function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mSloppy() { assertEquals(42, this[ownReadOnly]); super[ownReadOnly] = 55; assertEquals(42, this[ownReadOnly]); var descr = Object.getOwnPropertyDescriptor(this, ownReadOnly); assertEquals(42, descr.value); assertFalse(descr.configurable); assertFalse(descr.enumerable); assertFalse(descr.writable); assertFalse(Base.prototype.hasOwnProperty(ownReadOnly)); assertEquals(15, this[ownReadonlyAccessor]); super[ownReadonlyAccessor] = 25; assertSame(undefined, super[ownReadonlyAccessor]); assertEquals(15, this[ownReadonlyAccessor]); var descr = Object.getOwnPropertyDescriptor(this, ownReadonlyAccessor); assertFalse(descr.configurable); assertFalse(descr.enumerable); assertFalse(Base.prototype.hasOwnProperty(ownReadonlyAccessor)); super[ownSetter] = 35; var descr = Object.getOwnPropertyDescriptor(this, ownSetter); assertFalse(descr.configurable); assertFalse(descr.enumerable); assertFalse(Base.prototype.hasOwnProperty(ownSetter)); }, mStrict() { 'use strict'; var ex; assertEquals(42, this[ownReadOnly]); try { super[ownReadOnly] = 55; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals( "Cannot assign to read only property '" + ownReadOnly + "' of object '#'", ex.message); assertEquals(42, this[ownReadOnly]); ex = null; assertEquals(15, this[ownReadonlyAccessor]); try { super[ownReadonlyAccessor] = 25; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals('Cannot redefine property: ' + ownReadonlyAccessor, ex.message); assertEquals(15, this[ownReadonlyAccessor]); ex = null; try { super[ownSetter] = 35; } catch (e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals('Cannot redefine property: ' + ownSetter, ex.message); } }; var d = new Derived(); Object.defineProperty(d, ownReadOnly, { value : 42, writable : false }); Object.defineProperty(d, ownSetter, { set : function() { assertUnreachable(); } }); Object.defineProperty(d, ownReadonlyAccessor, { get : function() { return 15; }}); d.mSloppy(); d.mStrict(); } TestKeyedSetterCreatingOwnPropertiesNonConfigurable('ownReadOnly', 'ownReadonlyAccessor', 'ownSetter'); TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); (function TestSetterNoProtoWalk() { function Base() {} function Derived() {} var getCalled; var setCalled; Derived.prototype = { __proto__: Base.prototype, get x() { getCalled++; return 42; }, set x(v) { setCalled++; }, mSloppy() { setCalled = 0; getCalled = 0; assertEquals(42, this.x); assertEquals(1, getCalled); assertEquals(0, setCalled); getCalled = 0; setCalled = 0; this.x = 43; assertEquals(0, getCalled); assertEquals(1, setCalled); getCalled = 0; setCalled = 0; super.x = 15; assertEquals(0, setCalled); assertEquals(0, getCalled); assertEquals(15, this.x); assertEquals(0, getCalled); assertEquals(0, setCalled); }, mStrict() { 'use strict'; setCalled = 0; getCalled = 0; assertEquals(42, this.x); assertEquals(1, getCalled); assertEquals(0, setCalled); getCalled = 0; setCalled = 0; this.x = 43; assertEquals(0, getCalled); assertEquals(1, setCalled); getCalled = 0; setCalled = 0; super.x = 15; assertEquals(0, setCalled); assertEquals(0, getCalled); assertEquals(15, this.x); assertEquals(0, getCalled); assertEquals(0, setCalled); } }; new Derived().mSloppy(); new Derived().mStrict(); }()); (function TestKeyedSetterNoProtoWalk() { var x = 'x'; function Base() {} function Derived() {} var getCalled; var setCalled; Derived.prototype = { __proto__: Base.prototype, get x() { getCalled++; return 42; }, set x(v) { setCalled++; }, mSloppy() { setCalled = 0; getCalled = 0; assertEquals(42, this[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); getCalled = 0; setCalled = 0; this[x] = 43; assertEquals(0, getCalled); assertEquals(1, setCalled); getCalled = 0; setCalled = 0; super[x] = 15; assertEquals(0, setCalled); assertEquals(0, getCalled); assertEquals(15, this[x]); assertEquals(0, getCalled); assertEquals(0, setCalled); }, mStrict() { 'use strict'; setCalled = 0; getCalled = 0; assertEquals(42, this[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); getCalled = 0; setCalled = 0; this[x] = 43; assertEquals(0, getCalled); assertEquals(1, setCalled); getCalled = 0; setCalled = 0; super[x] = 15; assertEquals(0, setCalled); assertEquals(0, getCalled); assertEquals(15, this[x]); assertEquals(0, getCalled); assertEquals(0, setCalled); } }; new Derived().mSloppy(); new Derived().mStrict(); }()); (function TestKeyedNumericSetterNoProtoWalk() { var x = 42; function Base() {} function Derived() {} var getCalled; var setCalled; Derived.prototype = { __proto__: Base.prototype, mSloppy() { setCalled = 0; getCalled = 0; assertEquals(42, this[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); getCalled = 0; setCalled = 0; this[x] = 43; assertEquals(0, getCalled); assertEquals(1, setCalled); getCalled = 0; setCalled = 0; super[x] = 15; assertEquals(0, setCalled); assertEquals(0, getCalled); assertEquals(15, this[x]); assertEquals(0, getCalled); assertEquals(0, setCalled); }, mStrict() { 'use strict'; setCalled = 0; getCalled = 0; assertEquals(42, this[x]); assertEquals(1, getCalled); assertEquals(0, setCalled); getCalled = 0; setCalled = 0; this[x] = 43; assertEquals(0, getCalled); assertEquals(1, setCalled); getCalled = 0; setCalled = 0; super[x] = 15; assertEquals(0, setCalled); assertEquals(0, getCalled); assertEquals(15, this[x]); assertEquals(0, getCalled); assertEquals(0, setCalled); } }; Object.defineProperty(Derived.prototype, x, { get: function() { getCalled++; return 42; }, set: function(v) { setCalled++; } }); new Derived().mSloppy(); new Derived().mStrict(); }()); (function TestSetterDoesNotReconfigure() { function Base() {} function Derived() {} Derived.prototype = { __proto__: Derived.prototype, mStrict(){ 'use strict'; super.nonEnumConfig = 5; var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig'); assertEquals(5, d1.value); assertTrue(d1.configurable); assertFalse(d1.enumerable); super.nonEnumNonConfig = 5; var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig'); assertEquals(5, d1.value); assertFalse(d1.configurable); assertFalse(d1.enumerable); }, mSloppy(){ super.nonEnumConfig = 42; var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig'); assertEquals(42, d1.value); assertTrue(d1.configurable); assertFalse(d1.enumerable); super.nonEnumNonConfig = 42; var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig'); assertEquals(42, d1.value); assertFalse(d1.configurable); assertFalse(d1.enumerable); } }; var d = new Derived(); Object.defineProperty(d, 'nonEnumConfig', { value : 0, enumerable : false, configurable : true, writable : true }); Object.defineProperty(d, 'nonEnumNonConfig', { value : 0, enumerable : false, configurable : false, writable : true }); d.mStrict(); d.mSloppy(); }()); (function TestKeyedSetterDoesNotReconfigure() { var nonEnumConfig = 'nonEnumConfig'; var nonEnumNonConfig = 'nonEnumNonConfig'; function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mStrict(){ 'use strict'; super[nonEnumConfig] = 5; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig); assertEquals(5, d1.value); assertTrue(d1.configurable); assertFalse(d1.enumerable); super[nonEnumNonConfig] = 5; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig); assertEquals(5, d1.value); assertFalse(d1.configurable); assertFalse(d1.enumerable); }, mSloppy(){ super[nonEnumConfig] = 42; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig); assertEquals(42, d1.value); assertTrue(d1.configurable); assertFalse(d1.enumerable); super[nonEnumNonConfig] = 42; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig); assertEquals(42, d1.value); assertFalse(d1.configurable); assertFalse(d1.enumerable); } }; var d = new Derived(); Object.defineProperty(d, nonEnumConfig, { value : 0, enumerable : false, configurable : true, writable : true }); Object.defineProperty(d, nonEnumNonConfig, { value : 0, enumerable : false, configurable : false, writable : true }); d.mStrict(); d.mSloppy(); }()); (function TestKeyedNumericSetterDoesNotReconfigure() { var nonEnumConfig = 42; var nonEnumNonConfig = 43; function Base() {} function Derived() {} Derived.prototype = { __proto__: Base.prototype, mStrict(){ 'use strict'; super[nonEnumConfig] = 5; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig); assertEquals(5, d1.value); assertTrue(d1.configurable); assertFalse(d1.enumerable); super[nonEnumNonConfig] = 5; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig); assertEquals(5, d1.value); assertFalse(d1.configurable); assertFalse(d1.enumerable); }, mSloppy(){ super[nonEnumConfig] = 42; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig); assertEquals(42, d1.value); assertTrue(d1.configurable); assertFalse(d1.enumerable); super[nonEnumNonConfig] = 42; var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig); assertEquals(42, d1.value); assertFalse(d1.configurable); assertFalse(d1.enumerable); } }; var d = new Derived(); Object.defineProperty(d, nonEnumConfig, { value : 0, enumerable : false, configurable : true, writable : true }); Object.defineProperty(d, nonEnumNonConfig, { value : 0, enumerable : false, configurable : false, writable : true }); d.mStrict(); d.mSloppy(); }()); (function TestCountOperations() { function Base() {} Base.prototype = { constructor: Base, get x() { return this._x; }, set x(v) { this._x = v; }, _x: 1 }; function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 2, testCounts() { assertEquals(2, this._x); assertEquals(2, super.x); super.x++; assertEquals(3, super.x); ++super.x; assertEquals(4, super.x); assertEquals(4, super.x++); assertEquals(5, super.x); assertEquals(6, ++super.x); assertEquals(6, super.x); assertEquals(6, this._x); super.x--; assertEquals(5, super.x); --super.x; assertEquals(4, super.x); assertEquals(4, super.x--); assertEquals(3, super.x); assertEquals(2, --super.x); assertEquals(2, super.x); assertEquals(2, this._x); } }; new Derived().testCounts(); }()); (function TestKeyedCountOperations() { var x = 'x'; function Base() {} Base.prototype = { constructor: Base, get x() { return this._x; }, set x(v) { this._x = v; }, _x: 1 }; function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 2, testCounts() { assertEquals(2, this._x); assertEquals(2, super[x]); super[x]++; assertEquals(3, super[x]); ++super[x]; assertEquals(4, super[x]); assertEquals(4, super[x]++); assertEquals(5, super[x]); assertEquals(6, ++super[x]); assertEquals(6, super[x]); assertEquals(6, this._x); super[x]--; assertEquals(5, super[x]); --super[x]; assertEquals(4, super[x]); assertEquals(4, super[x]--); assertEquals(3, super[x]); assertEquals(2, --super[x]); assertEquals(2, super[x]); assertEquals(2, this._x); } }; new Derived().testCounts(); }()); (function TestKeyedNumericCountOperations() { var x = 42; function Base() {} Base.prototype = { constructor: Base, _x: 1 }; Object.defineProperty(Base.prototype, x, { get: function() { return this._x; }, set: function(v) { this._x = v;; } }); function Derived() {} Derived.__proto__ = Base; Derived.prototype = { __proto__: Base.prototype, constructor: Derived, _x: 2, testCounts() { assertEquals(2, this._x); assertEquals(2, super[x]); super[x]++; assertEquals(3, super[x]); ++super[x]; assertEquals(4, super[x]); assertEquals(4, super[x]++); assertEquals(5, super[x]); assertEquals(6, ++super[x]); assertEquals(6, super[x]); assertEquals(6, this._x); super[x]--; assertEquals(5, super[x]); --super[x]; assertEquals(4, super[x]); assertEquals(4, super[x]--); assertEquals(3, super[x]); assertEquals(2, --super[x]); assertEquals(2, super[x]); assertEquals(2, this._x); } }; new Derived().testCounts(); }()); (function TestSetterSuperNonWritable() { function Base() {} Object.defineProperty(Base.prototype, 'x', { value : 27, writable: false }); function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, mSloppy() { assertEquals(27, super.x); assertEquals(27, this.x); super.x = 10; assertEquals(27, super.x); assertEquals(27, this.x); }, mStrict() { 'use strict'; assertEquals(27, super.x); assertEquals(27, this.x); var ex = null; try { super.x = 10; } catch(e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals(27, super.x); assertEquals(27, this.x); } }; new Derived().mSloppy(); new Derived().mStrict(); }()); (function TestSetterKeyedSuperNonWritable() { var x = 'xyz'; function Base() {} Object.defineProperty(Base.prototype, x, { value : 27, writable: false }); function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, mSloppy() { assertEquals(27, super[x]); assertEquals(27, this[x]); super[x] = 10; assertEquals(27, super[x]); assertEquals(27, this[x]); }, mStrict() { 'use strict'; assertEquals(27, super[x]); assertEquals(27, this[x]); var ex = null; try { super[x] = 10; } catch(e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals(27, super[x]); assertEquals(27, this[x]); } }; new Derived().mSloppy(); new Derived().mStrict(); }()); (function TestSetterKeyedNumericSuperNonWritable() { var x = 42; function Base() {} Object.defineProperty(Base.prototype, x, { value : 27, writable: false }); function Derived() {} Derived.prototype = { __proto__: Base.prototype, constructor: Derived, mSloppy() { assertEquals(27, super[x]); assertEquals(27, this[x]); super[x] = 10; assertEquals(27, super[x]); assertEquals(27, this[x]); }, mStrict() { 'use strict'; assertEquals(27, super[x]); assertEquals(27, this[x]); var ex = null; try { super[x] = 10; } catch(e) { ex = e; } assertInstanceof(ex, TypeError); assertEquals(27, super[x]); assertEquals(27, this[x]); } }; new Derived().mSloppy(); new Derived().mStrict(); }()); (function TestSuperCall() { 'use strict'; var baseCalled = 0; var derivedCalled = 0; var derivedDerivedCalled = 0; class Base { constructor() { baseCalled++; } } class Derived extends Base { constructor() { let r = super(); assertEquals(this, r); derivedCalled++; } } assertEquals(Base, Base.prototype.constructor); assertEquals(Base.prototype, Derived.prototype.__proto__); baseCalled = 0; derivedCalled = 0; new Derived(); assertEquals(1, baseCalled); assertEquals(1, derivedCalled); class DerivedDerived extends Derived { constructor() { let r = super(); assertEquals(this, r); derivedDerivedCalled++; } } baseCalled = 0; derivedCalled = 0; derivedDerivedCalled = 0; new DerivedDerived(); assertEquals(1, baseCalled); assertEquals(1, derivedCalled); assertEquals(1, derivedDerivedCalled); class Base2 { constructor(v) { this.fromBase = v; } } class Derived2 extends Base2 { constructor(v1, v2) { let r = super(v1); assertEquals(this, r); this.fromDerived = v2; } } var d = new Derived2("base", "derived"); assertEquals("base", d.fromBase); assertEquals("derived", d.fromDerived); var calls = 0; class G { constructor() { calls++; } } class F extends Object { constructor() { super(); } } F.__proto__ = G; new F(); assertEquals(1, calls); F.__proto__ = function() {}; new F(); assertEquals(1, calls); }()); (function TestExtendsObject() { 'use strict'; class F extends Object { } var f = new F(42); assertInstanceof(f, F); assertInstanceof(f, Object); }()); (function TestSuperCallErrorCases() { 'use strict'; class T extends Object { constructor() { super(); } } T.__proto__ = null; assertThrows(function() { new T(); }, TypeError); }()); (function TestSuperPropertyInEval() { 'use strict'; let y = 3; class Base { m() { return 1; } get x() { return 2; } } class Derived extends Base { evalM() { assertEquals(1, eval('super.m()')); } evalX() { assertEquals(2, eval('super.x')); } globalEval1() { assertThrows('super.x', SyntaxError); assertThrows('super.m()', SyntaxError); } globalEval2() { super.x; assertThrows('super.x', SyntaxError); assertThrows('super.m()', SyntaxError); } } let d = new Derived(); d.globalEval1(); d.globalEval2(); d.evalM(); d.evalX(); })(); (function TestSuperPropertyInArrow() { 'use strict'; let y = 3; class Base { m() { return 1; } get x() { return 2; } } class Derived extends Base { arrow() { assertSame(super.x, (() => super.x)()); assertSame(super.m(), (() => super.m())()); return (() => super.m())(); } } let d = new Derived(); assertSame(1, d.arrow()); })(); (function TestSuperInOtherScopes() { var p = {x: 99}; var o0 = {__proto__: p, f() { return eval("'use strict'; super.x") }}; assertEquals(p.x, o0.f()); var o1 = {__proto__: p, f() { with ({}) return super.x }}; assertEquals(p.x, o1.f()); var o2 = {__proto__: p, f({a}) { return super.x }}; assertEquals(p.x, o2.f({})); var o3 = {__proto__: p, f(...a) { return super.x }}; assertEquals(p.x, o3.f()); var o4 = {__proto__: p, f() { 'use strict'; { let x; return super.x } }}; assertEquals(p.x, o4.f()); })(); (function TestSuperCallInOtherScopes() { class C {constructor() { this.x = 99 }} class D0 extends C {constructor() { eval("'use strict'; super()") }} assertEquals(99, (new D0).x); class D2 extends C {constructor({a}) { super() }} assertEquals(99, (new D2({})).x); class D3 extends C {constructor(...a) { super() }} assertEquals(99, (new D3()).x); class D4 extends C {constructor() { { let x; super() } }} assertEquals(99, (new D4).x); })(); (function TestSuperCallInEval() { 'use strict'; class Base { constructor(x) { this.x = x; } } class Derived extends Base { constructor(x) { let r = eval('super(x)'); assertEquals(this, r); } } let d = new Derived(42); assertSame(42, d.x); })(); (function TestSuperCallInArrow() { 'use strict'; class Base { constructor(x) { this.x = x; } } class Derived extends Base { constructor(x) { let r = (() => super(x))(); assertEquals(this, r); } } let d = new Derived(42); assertSame(42, d.x); })(); (function TestSuperCallEscapes() { 'use strict'; class Base { constructor(x) { this.x = x; } } let f; class Derived extends Base { constructor() { f = () => super(2); } } assertThrows(function() { new Derived(); }, ReferenceError); let o = f(); assertEquals(2, o.x); assertInstanceof(o, Derived); assertThrows(function() { f(); }, ReferenceError); })(); (function TestSuperCallInLoop() { 'use strict'; class Base { constructor(x) { this.x = x; } } class Derived extends Base { constructor(x, n) { for (var i = 0; i < n; ++i) { super(x); } } } let o = new Derived(23, 1); assertEquals(23, o.x); assertInstanceof(o, Derived); assertThrows("new Derived(42, 0)", ReferenceError); assertThrows("new Derived(65, 2)", ReferenceError); })(); (function TestSuperCallReentrant() { 'use strict'; class Base { constructor(fun) { this.x = fun(); } } class Derived extends Base { constructor(x) { let f = () => super(() => x) super(f); } } assertThrows("new Derived(23)", ReferenceError); })(); (function TestSuperCallSpreadInEval() { 'use strict'; class Base { constructor(x) { this.x = x; } } class Derived extends Base { constructor(x) { let r = eval('super(...[x])'); assertEquals(this, r); } } let d = new Derived(42); assertSame(42, d.x); })(); (function TestSuperCallSpreadInArrow() { 'use strict'; class Base { constructor(x) { this.x = x; } } class Derived extends Base { constructor(x) { let r = (() => super(...[x]))(); assertEquals(this, r); } } let d = new Derived(42); assertSame(42, d.x); })(); (function TestNullSuperPropertyLoad() { var obj = { __proto__: null, named() { return super.x }, keyed() { return super[5] } }; assertThrows(obj.named, TypeError); assertThrows(obj.keyed, TypeError); class C extends null { named() { return super.x } keyed() { return super[5] } } assertThrows(C.prototype.named, TypeError); assertThrows(C.prototype.keyed, TypeError); })(); (function TestNullSuperPropertyStore() { var obj = { __proto__: null, named() { super.x = 42 }, keyed() { super[5] = 42 } }; assertThrows(obj.named, TypeError); assertThrows(obj.keyed, TypeError); class C extends null { named() { super.x = 42 } keyed() { super[5] = 42 } } assertThrows(C.prototype.named, TypeError); assertThrows(C.prototype.keyed, TypeError); })();