1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5var global = this; 6 7var funs = { 8 Object: [ Object ], 9 Function: [ Function ], 10 Array: [ Array ], 11 String: [ String ], 12 Boolean: [ Boolean ], 13 Number: [ Number ], 14 Date: [ Date ], 15 RegExp: [ RegExp ], 16 Error: [ Error, TypeError, RangeError, SyntaxError, ReferenceError, 17 EvalError, URIError ] 18}; 19for (var f in funs) { 20 for (var i in funs[f]) { 21 22 assertEquals("[object " + f + "]", 23 Object.prototype.toString.call(new funs[f][i]), 24 funs[f][i]); 25 assertEquals("[object Function]", 26 Object.prototype.toString.call(funs[f][i]), 27 funs[f][i]); 28 } 29} 30 31function testToStringTag(className) { 32 // Using builtin toStringTags 33 var obj = {}; 34 obj[Symbol.toStringTag] = className; 35 assertEquals("[object " + className + "]", 36 Object.prototype.toString.call(obj)); 37 38 // Getter throws 39 obj = {}; 40 Object.defineProperty(obj, Symbol.toStringTag, { 41 get: function() { throw className; } 42 }); 43 assertThrowsEquals(function() { 44 Object.prototype.toString.call(obj); 45 }, className); 46 47 // Getter does not throw 48 obj = {}; 49 Object.defineProperty(obj, Symbol.toStringTag, { 50 get: function() { return className; } 51 }); 52 assertEquals("[object " + className + "]", 53 Object.prototype.toString.call(obj)); 54 55 // Custom, non-builtin toStringTags 56 obj = {}; 57 obj[Symbol.toStringTag] = "X" + className; 58 assertEquals("[object X" + className + "]", 59 Object.prototype.toString.call(obj)); 60 61 // With getter 62 obj = {}; 63 Object.defineProperty(obj, Symbol.toStringTag, { 64 get: function() { return "X" + className; } 65 }); 66 assertEquals("[object X" + className + "]", 67 Object.prototype.toString.call(obj)); 68 69 // Undefined toStringTag should return [object className] 70 var obj = className === "Arguments" ? 71 (function() { return arguments; })() : new global[className]; 72 obj[Symbol.toStringTag] = undefined; 73 assertEquals("[object " + className + "]", 74 Object.prototype.toString.call(obj)); 75 76 // With getter 77 var obj = className === "Arguments" ? 78 (function() { return arguments; })() : new global[className]; 79 Object.defineProperty(obj, Symbol.toStringTag, { 80 get: function() { return undefined; } 81 }); 82 assertEquals("[object " + className + "]", 83 Object.prototype.toString.call(obj)); 84} 85 86[ 87 "Arguments", 88 "Array", 89 "Boolean", 90 "Date", 91 "Error", 92 "Function", 93 "Number", 94 "RegExp", 95 "String" 96].forEach(testToStringTag); 97 98function testToStringTagNonString(value) { 99 var obj = {}; 100 obj[Symbol.toStringTag] = value; 101 assertEquals("[object Object]", Object.prototype.toString.call(obj)); 102 103 // With getter 104 obj = {}; 105 Object.defineProperty(obj, Symbol.toStringTag, { 106 get: function() { return value; } 107 }); 108 assertEquals("[object Object]", Object.prototype.toString.call(obj)); 109} 110 111[ 112 null, 113 function() {}, 114 [], 115 {}, 116 /regexp/, 117 42, 118 Symbol("sym"), 119 new Date(), 120 (function() { return arguments; })(), 121 true, 122 new Error("oops"), 123 new String("str") 124].forEach(testToStringTagNonString); 125 126function testObjectToStringPropertyDesc() { 127 var desc = Object.getOwnPropertyDescriptor(Object.prototype, "toString"); 128 assertTrue(desc.writable); 129 assertFalse(desc.enumerable); 130 assertTrue(desc.configurable); 131} 132testObjectToStringPropertyDesc(); 133 134function testObjectToStringOnNonStringValue(obj) { 135 Object.defineProperty(obj, Symbol.toStringTag, { value: 1 }); 136 assertEquals("[object Object]", ({}).toString.call(obj)); 137} 138testObjectToStringOnNonStringValue({}); 139 140 141// Proxies 142 143function assertTag(tag, obj) { 144 assertEquals("[object " + tag + "]", Object.prototype.toString.call(obj)); 145} 146 147assertTag("Object", new Proxy({}, {})); 148assertTag("Array", new Proxy([], {})); 149assertTag("Function", new Proxy(() => 42, {})); 150assertTag("Foo", new Proxy(() => 42, {get() {return "Foo"}})); 151assertTag("Function", new Proxy(() => 42, {get() {return 666}})); 152 153var revocable = Proxy.revocable([], {}); 154revocable.revoke(); 155assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError); 156 157var handler = {}; 158revocable = Proxy.revocable([], handler); 159// The first get() call, i.e., toString() revokes the proxy 160handler.get = () => revocable.revoke(); 161assertEquals("[object Array]", Object.prototype.toString.call(revocable.proxy)); 162assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError); 163 164revocable = Proxy.revocable([], handler); 165handler.get = () => {revocable.revoke(); return "value";}; 166assertEquals("[object value]", Object.prototype.toString.call(revocable.proxy)); 167assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError); 168 169 170revocable = Proxy.revocable(function() {}, handler); 171handler.get = () => revocable.revoke(); 172assertEquals("[object Function]", Object.prototype.toString.call(revocable.proxy)); 173assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError); 174 175function* gen() { yield 1; } 176 177assertTag("GeneratorFunction", gen); 178Object.defineProperty(gen, Symbol.toStringTag, {writable: true}); 179gen[Symbol.toStringTag] = "different string"; 180assertTag("different string", gen); 181gen[Symbol.toStringTag] = 1; 182assertTag("Function", gen); 183 184function overwriteToStringTagWithNonStringValue(tag, obj) { 185 assertTag(tag, obj); 186 187 Object.defineProperty(obj, Symbol.toStringTag, { 188 configurable: true, 189 value: "different string" 190 }); 191 assertTag("different string", obj); 192 193 testObjectToStringOnNonStringValue(obj); 194} 195 196overwriteToStringTagWithNonStringValue("global", global); 197overwriteToStringTagWithNonStringValue("Generator", gen()); 198 199var arrayBuffer = new ArrayBuffer(); 200overwriteToStringTagWithNonStringValue("ArrayBuffer", arrayBuffer); 201overwriteToStringTagWithNonStringValue("DataView", new DataView(arrayBuffer)); 202 203overwriteToStringTagWithNonStringValue("Int8Array", new Int8Array()); 204overwriteToStringTagWithNonStringValue("Uint8Array", new Uint8Array()); 205overwriteToStringTagWithNonStringValue("Uint8ClampedArray", 206 new Uint8ClampedArray()); 207overwriteToStringTagWithNonStringValue("Int16Array", new Int16Array()); 208overwriteToStringTagWithNonStringValue("Uint16Array", new Uint16Array()); 209overwriteToStringTagWithNonStringValue("Int32Array", new Int32Array()); 210overwriteToStringTagWithNonStringValue("Uint32Array", new Uint32Array()); 211overwriteToStringTagWithNonStringValue("Float32Array", new Float32Array()); 212overwriteToStringTagWithNonStringValue("Float64Array", new Float64Array()); 213 214var set = new Set(); 215var map = new Map(); 216 217overwriteToStringTagWithNonStringValue("Set", set); 218overwriteToStringTagWithNonStringValue("Map", map); 219 220overwriteToStringTagWithNonStringValue("Set Iterator", set[Symbol.iterator]()); 221overwriteToStringTagWithNonStringValue("Map Iterator", map[Symbol.iterator]()); 222 223overwriteToStringTagWithNonStringValue("WeakSet", new WeakSet()); 224overwriteToStringTagWithNonStringValue("WeakMap", new WeakMap()); 225 226overwriteToStringTagWithNonStringValue("Promise", new Promise(function() {})); 227