blob: bc7d9681f89a7aaf0f4857c5b2e4d3dd5ea554a1 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005var 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 ]
Ben Murdoch61f157c2016-09-16 13:49:30 +010018};
19for (var f in funs) {
20 for (var i in funs[f]) {
21
Emily Bernierd0a1eb72015-03-24 16:35:39 -040022 assertEquals("[object " + f + "]",
Ben Murdoch61f157c2016-09-16 13:49:30 +010023 Object.prototype.toString.call(new funs[f][i]),
24 funs[f][i]);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040025 assertEquals("[object Function]",
Ben Murdoch61f157c2016-09-16 13:49:30 +010026 Object.prototype.toString.call(funs[f][i]),
27 funs[f][i]);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028 }
29}
30
31function testToStringTag(className) {
32 // Using builtin toStringTags
33 var obj = {};
34 obj[Symbol.toStringTag] = className;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035 assertEquals("[object " + className + "]",
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 Object.prototype.toString.call(obj));
37
38 // Getter throws
39 obj = {};
40 Object.defineProperty(obj, Symbol.toStringTag, {
41 get: function() { throw className; }
42 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 assertThrowsEquals(function() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 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 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000052 assertEquals("[object " + className + "]",
Emily Bernierd0a1eb72015-03-24 16:35:39 -040053 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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 assertEquals("[object Object]", Object.prototype.toString.call(obj));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400102
103 // With getter
104 obj = {};
105 Object.defineProperty(obj, Symbol.toStringTag, {
106 get: function() { return value; }
107 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 assertEquals("[object Object]", Object.prototype.toString.call(obj));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400109}
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();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133
Ben Murdoch61f157c2016-09-16 13:49:30 +0100134function testObjectToStringOnNonStringValue(obj) {
135 Object.defineProperty(obj, Symbol.toStringTag, { value: 1 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 assertEquals("[object Object]", ({}).toString.call(obj));
137}
Ben Murdoch61f157c2016-09-16 13:49:30 +0100138testObjectToStringOnNonStringValue({});
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139
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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100153var revocable = Proxy.revocable([], {});
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154revocable.revoke();
155assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
156
Ben Murdoch61f157c2016-09-16 13:49:30 +0100157var handler = {};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158revocable = Proxy.revocable([], handler);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100159// The first get() call, i.e., toString() revokes the proxy
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160handler.get = () => revocable.revoke();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100161assertEquals("[object Array]", Object.prototype.toString.call(revocable.proxy));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100163
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() {}));