1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  * 
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  * 
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  * 
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  * 
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * JDK-8141702: Add support for Symbol property keys
  26  *
  27  * @test
  28  * @run
  29  * @option --language=es6
  30  */
  31 
  32 Assert.assertTrue(typeof Symbol === 'function');
  33 Assert.assertTrue(typeof Symbol() === 'symbol');
  34 
  35 Assert.assertTrue(Symbol().toString() === 'Symbol()');
  36 Assert.assertTrue(Symbol('foo').toString() === 'Symbol(foo)');
  37 Assert.assertTrue(Symbol(1).toString() === 'Symbol(1)');
  38 Assert.assertTrue(Symbol(true).toString() === 'Symbol(true)');
  39 Assert.assertTrue(Symbol([1, 2, 3]).toString() === 'Symbol(1,2,3)');
  40 Assert.assertTrue(Symbol(null).toString() === 'Symbol(null)');
  41 Assert.assertTrue(Symbol(undefined).toString() === 'Symbol()');
  42 
  43 const s1 = Symbol();
  44 const s2 = Symbol("s2");
  45 Assert.assertFalse(s1 instanceof Symbol); // not an object
  46 
  47 let obj = {};
  48 obj['foo'] = 'foo';
  49 obj[s1] = s1;
  50 obj['bar'] = 'bar';
  51 obj[1] = 1;
  52 obj[s2] = s2;
  53 
  54 Assert.assertTrue(obj['foo'] === 'foo');
  55 Assert.assertTrue(obj[s1] === s1);
  56 Assert.assertTrue(obj['bar'] === 'bar');
  57 Assert.assertTrue(obj[1] === 1);
  58 Assert.assertTrue(obj[s2] === s2);
  59 
  60 const expectedNames = ['1', 'foo', 'bar'];
  61 const expectedSymbols = [s1, s2];
  62 const actualNames = Object.getOwnPropertyNames(obj);
  63 let actualSymbols = Object.getOwnPropertySymbols(obj);
  64 Assert.assertTrue(expectedNames.length == actualNames.length);
  65 Assert.assertTrue(expectedSymbols.length == actualSymbols.length);
  66 
  67 for (let key in expectedNames) {
  68     Assert.assertTrue(expectedNames[key] === actualNames[key]);
  69 }
  70 for (let key in expectedSymbols) {
  71     Assert.assertTrue(expectedSymbols[key] === actualSymbols[key]);
  72 }
  73 
  74 // Delete
  75 Assert.assertTrue(delete obj[s1]);
  76 Assert.assertTrue(Object.getOwnPropertySymbols(obj).length === 1);
  77 Assert.assertTrue(Object.getOwnPropertySymbols(obj)[0] === s2);
  78 
  79 // Object.defineProperty
  80 Object.defineProperty(obj, s1, {value : 'hello'});
  81 Assert.assertTrue(obj[s1] === 'hello');
  82 actualSymbols = Object.getOwnPropertySymbols(obj);
  83 Assert.assertTrue(Object.getOwnPropertySymbols(obj).length === 2);
  84 Assert.assertTrue(Object.getOwnPropertySymbols(obj)[1] === s1);
  85 
  86 // Symbol called as constructor
  87 try {
  88     new Symbol();
  89     Assert.fail("Symbol invoked as constructor");
  90 } catch (e) {
  91     if (e.name !== "TypeError" || e.message !== "Symbol is not a constructor.") {
  92         Assert.fail("Unexpected error: " + e);
  93     }
  94 }
  95 
  96 // Implicit conversion to string or number should throw
  97 try {
  98     ' ' + s1;
  99     Assert.fail("Symbol converted to string");
 100 } catch (e) {
 101     if (e.name !== "TypeError" || e.message !== "Can not convert Symbol value to string.") {
 102         Assert.fail("Unexpected error: " + e);
 103     }
 104 }
 105 
 106 try {
 107     4 * s1;
 108     Assert.fail("Symbol converted to number");
 109 } catch (e) {
 110     if (e.name !== "TypeError" || e.message !== "Can not convert Symbol value to number.") {
 111         Assert.fail("Unexpected error: " + e);
 112     }
 113 }
 114 
 115 // Symbol.for and Symbol.keyFor
 116 
 117 const uncached = Symbol('foo');
 118 const cached = Symbol.for('foo');
 119 
 120 Assert.assertTrue(uncached !== cached);
 121 Assert.assertTrue(Symbol.keyFor(uncached) === undefined);
 122 Assert.assertTrue(Symbol.keyFor(cached) === 'foo');
 123 Assert.assertTrue(cached === Symbol.for('foo'));
 124 Assert.assertTrue(cached === Symbol.for('f' + 'oo'));
 125 
 126 // JDK-8147008: Make sure symbols are handled by primitive linker
 127 Symbol.prototype.foo = 123;
 128 Symbol.prototype[s2] = s2;
 129 Assert.assertEquals(s1.foo, 123);
 130 Assert.assertEquals(s2[s2], s2);
 131 
 132 // Object wrapper
 133 
 134 const o = Object(s1);
 135 obj = {};
 136 obj[s1] = "s1";
 137 Assert.assertTrue(o == s1);
 138 Assert.assertTrue(o !== s1);
 139 Assert.assertTrue(typeof o === 'object');
 140 Assert.assertTrue(o instanceof Symbol);
 141 Assert.assertTrue(obj[o] == 's1');
 142 Assert.assertTrue(o in obj);
 143 Assert.assertEquals(o.foo, 123);
 144 Assert.assertEquals(o[s2], s2);
 145 
 146 // various non-strict comparisons that should fail
 147 
 148 Assert.assertFalse(0 == Symbol());
 149 Assert.assertFalse(1 == Symbol(1));
 150 Assert.assertFalse(null == Symbol());
 151 Assert.assertFalse(undefined == Symbol);
 152 Assert.assertFalse('Symbol()' == Symbol());
 153 Assert.assertFalse('Symbol(foo)' == Symbol('foo'));
 154