// 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. 'use strict'; function ID(x) { return x; } (function TestClassMethodString() { class C { a() { return 'A'} ['b']() { return 'B'; } c() { return 'C'; } [ID('d')]() { return 'D'; } } assertEquals('A', new C().a()); assertEquals('B', new C().b()); assertEquals('C', new C().c()); assertEquals('D', new C().d()); assertArrayEquals([], Object.keys(C.prototype)); assertArrayEquals(['constructor', 'a', 'b', 'c', 'd'], Object.getOwnPropertyNames(C.prototype)); })(); (function TestClassMethodNumber() { class C { a() { return 'A'; } [1]() { return 'B'; } c() { return 'C'; } [ID(2)]() { return 'D'; } } assertEquals('A', new C().a()); assertEquals('B', new C()[1]()); assertEquals('C', new C().c()); assertEquals('D', new C()[2]()); // Array indexes first. assertArrayEquals([], Object.keys(C.prototype)); assertArrayEquals(['1', '2', 'constructor', 'a', 'c'], Object.getOwnPropertyNames(C.prototype)); })(); (function TestClassMethodSymbol() { var sym1 = Symbol(); var sym2 = Symbol(); class C { a() { return 'A'; } [sym1]() { return 'B'; } c() { return 'C'; } [ID(sym2)]() { return 'D'; } } assertEquals('A', new C().a()); assertEquals('B', new C()[sym1]()); assertEquals('C', new C().c()); assertEquals('D', new C()[sym2]()); assertArrayEquals([], Object.keys(C.prototype)); assertArrayEquals(['constructor', 'a', 'c'], Object.getOwnPropertyNames(C.prototype)); assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C.prototype)); })(); (function TestStaticClassMethodString() { class C { static a() { return 'A'} static ['b']() { return 'B'; } static c() { return 'C'; } static ['d']() { return 'D'; } } assertEquals('A', C.a()); assertEquals('B', C.b()); assertEquals('C', C.c()); assertEquals('D', C.d()); assertArrayEquals([], Object.keys(C)); // TODO(arv): It is not clear that we are adding the "standard" properties // in the right order. As far as I can tell the spec adds them in alphabetical // order. assertArrayEquals(['length', 'prototype', 'a', 'b', 'c', 'd', 'name'], Object.getOwnPropertyNames(C)); })(); (function TestStaticClassMethodNumber() { class C { static a() { return 'A'; } static [1]() { return 'B'; } static c() { return 'C'; } static [2]() { return 'D'; } } assertEquals('A', C.a()); assertEquals('B', C[1]()); assertEquals('C', C.c()); assertEquals('D', C[2]()); // Array indexes first. assertArrayEquals([], Object.keys(C)); assertArrayEquals(['1', '2', 'length', 'prototype', 'a', 'c', 'name'], Object.getOwnPropertyNames(C)); })(); (function TestStaticClassMethodSymbol() { var sym1 = Symbol(); var sym2 = Symbol(); class C { static a() { return 'A'; } static [sym1]() { return 'B'; } static c() { return 'C'; } static [sym2]() { return 'D'; } } assertEquals('A', C.a()); assertEquals('B', C[sym1]()); assertEquals('C', C.c()); assertEquals('D', C[sym2]()); assertArrayEquals([], Object.keys(C)); assertArrayEquals(['length', 'prototype', 'a', 'c', 'name'], Object.getOwnPropertyNames(C)); assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C)); })(); function assertIteratorResult(value, done, result) { assertEquals({ value: value, done: done}, result); } (function TestGeneratorComputedName() { class C { *['a']() { yield 1; yield 2; } } var iter = new C().a(); assertIteratorResult(1, false, iter.next()); assertIteratorResult(2, false, iter.next()); assertIteratorResult(undefined, true, iter.next()); assertArrayEquals([], Object.keys(C.prototype)); assertArrayEquals(['constructor', 'a'], Object.getOwnPropertyNames(C.prototype)); })(); (function TestToNameSideEffects() { var counter = 0; var key1 = { toString: function() { assertEquals(0, counter++); return 'b'; } }; var key2 = { toString: function() { assertEquals(1, counter++); return 'd'; } }; class C { a() { return 'A'; } [key1]() { return 'B'; } c() { return 'C'; } [key2]() { return 'D'; } } assertEquals(2, counter); assertEquals('A', new C().a()); assertEquals('B', new C().b()); assertEquals('C', new C().c()); assertEquals('D', new C().d()); assertArrayEquals([], Object.keys(C.prototype)); assertArrayEquals(['constructor', 'a', 'b', 'c', 'd'], Object.getOwnPropertyNames(C.prototype)); })(); (function TestToNameSideEffectsNumbers() { var counter = 0; var key1 = { valueOf: function() { assertEquals(0, counter++); return 1; }, toString: null }; var key2 = { valueOf: function() { assertEquals(1, counter++); return 2; }, toString: null }; class C { a() { return 'A'; } [key1]() { return 'B'; } c() { return 'C'; } [key2]() { return 'D'; } } assertEquals(2, counter); assertEquals('A', new C().a()); assertEquals('B', new C()[1]()); assertEquals('C', new C().c()); assertEquals('D', new C()[2]()); // Array indexes first. assertArrayEquals([], Object.keys(C.prototype)); assertArrayEquals(['1', '2', 'constructor', 'a', 'c'], Object.getOwnPropertyNames(C.prototype)); })(); (function TestLength() { class C { static ['length']() { return 42; } } assertEquals(42, C.length()); class C1 { static get ['length']() { return 'A'; } } assertEquals('A', C1.length); class C2 { static get length() { assertUnreachable(); } static get ['length']() { return 'B'; } } assertEquals('B', C2.length); class C3 { static get length() { assertUnreachable(); } static get ['length']() { assertUnreachable(); } static get ['length']() { return 'C'; } } assertEquals('C', C3.length); class C4 { static get ['length']() { assertUnreachable(); } static get length() { return 'D'; } } assertEquals('D', C4.length); })(); (function TestGetter() { class C { get ['a']() { return 'A'; } } assertEquals('A', new C().a); class C2 { get b() { assertUnreachable(); } get ['b']() { return 'B'; } } assertEquals('B', new C2().b); class C3 { get c() { assertUnreachable(); } get ['c']() { assertUnreachable(); } get ['c']() { return 'C'; } } assertEquals('C', new C3().c); class C4 { get ['d']() { assertUnreachable(); } get d() { return 'D'; } } assertEquals('D', new C4().d); })(); (function TestSetter() { var calls = 0; class C { set ['a'](_) { calls++; } } new C().a = 'A'; assertEquals(1, calls); calls = 0; class C2 { set b(_) { assertUnreachable(); } set ['b'](_) { calls++; } } new C2().b = 'B'; assertEquals(1, calls); calls = 0; class C3 { set c(_) { assertUnreachable() } set ['c'](_) { assertUnreachable() } set ['c'](_) { calls++ } } new C3().c = 'C'; assertEquals(1, calls); calls = 0; class C4 { set ['d'](_) { assertUnreachable() } set d(_) { calls++ } } new C4().d = 'D'; assertEquals(1, calls); })(); (function TestPrototype() { assertThrows(function() { class C { static ['prototype']() { return 1; } } }, TypeError); assertThrows(function() { class C2 { static get ['prototype']() { return 2; } } }, TypeError); assertThrows(function() { class C3 { static set ['prototype'](x) { assertEquals(3, x); } } }, TypeError); assertThrows(function() { class C4 { static *['prototype']() { yield 1; yield 2; } } }, TypeError); })(); (function TestPrototypeConcat() { assertThrows(function() { class C { static ['pro' + 'tot' + 'ype']() { return 1; } } }, TypeError); assertThrows(function() { class C2 { static get ['pro' + 'tot' + 'ype']() { return 2; } } }, TypeError); assertThrows(function() { class C3 { static set ['pro' + 'tot' + 'ype'](x) { assertEquals(3, x); } } }, TypeError); assertThrows(function() { class C4 { static *['pro' + 'tot' + 'ype']() { yield 1; yield 2; } } }, TypeError); })(); (function TestConstructor() { // Normally a constructor property is not allowed. class C { ['constructor']() { return 1; } } assertTrue(C !== C.prototype.constructor); assertEquals(1, new C().constructor()); class C2 { get ['constructor']() { return 2; } } assertEquals(2, new C2().constructor); var calls = 0; class C3 { set ['constructor'](x) { assertEquals(3, x); calls++; } } new C3().constructor = 3; assertEquals(1, calls); class C4 { *['constructor']() { yield 1; yield 2; } } var iter = new C4().constructor(); assertIteratorResult(1, false, iter.next()); assertIteratorResult(2, false, iter.next()); assertIteratorResult(undefined, true, iter.next()); })(); (function TestExceptionInName() { function MyError() {}; function throwMyError() { throw new MyError(); } assertThrows(function() { class C { [throwMyError()]() {} } }, MyError); assertThrows(function() { class C { get [throwMyError()]() { return 42; } } }, MyError); assertThrows(function() { class C { set [throwMyError()](_) { } } }, MyError); })(); (function TestTdzName() { assertThrows(function() { class C { [C]() {} } }, ReferenceError); assertThrows(function() { class C { get [C]() { return 42; } } }, ReferenceError); assertThrows(function() { class C { set [C](_) { } } }, ReferenceError); })();