• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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