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
5// Flags: --harmony-tostring --harmony-proxies
6
7var global = this;
8
9var funs = {
10  Object:   [ Object ],
11  Function: [ Function ],
12  Array:    [ Array ],
13  String:   [ String ],
14  Boolean:  [ Boolean ],
15  Number:   [ Number ],
16  Date:     [ Date ],
17  RegExp:   [ RegExp ],
18  Error:    [ Error, TypeError, RangeError, SyntaxError, ReferenceError,
19              EvalError, URIError ]
20}
21for (f in funs) {
22  for (i in funs[f]) {
23    assertEquals("[object " + f + "]",
24                 Object.prototype.toString.call(new funs[f][i]),
25                 funs[f][i]);
26    assertEquals("[object Function]",
27                 Object.prototype.toString.call(funs[f][i]),
28                 funs[f][i]);
29  }
30}
31
32function testToStringTag(className) {
33  // Using builtin toStringTags
34  var obj = {};
35  obj[Symbol.toStringTag] = className;
36  assertEquals("[object " + className + "]",
37               Object.prototype.toString.call(obj));
38
39  // Getter throws
40  obj = {};
41  Object.defineProperty(obj, Symbol.toStringTag, {
42    get: function() { throw className; }
43  });
44  assertThrowsEquals(function() {
45    Object.prototype.toString.call(obj);
46  }, className);
47
48  // Getter does not throw
49  obj = {};
50  Object.defineProperty(obj, Symbol.toStringTag, {
51    get: function() { return className; }
52  });
53  assertEquals("[object " + className + "]",
54               Object.prototype.toString.call(obj));
55
56  // Custom, non-builtin toStringTags
57  obj = {};
58  obj[Symbol.toStringTag] = "X" + className;
59  assertEquals("[object X" + className + "]",
60               Object.prototype.toString.call(obj));
61
62  // With getter
63  obj = {};
64  Object.defineProperty(obj, Symbol.toStringTag, {
65    get: function() { return "X" + className; }
66  });
67  assertEquals("[object X" + className + "]",
68               Object.prototype.toString.call(obj));
69
70  // Undefined toStringTag should return [object className]
71  var obj = className === "Arguments" ?
72      (function() { return arguments; })() : new global[className];
73  obj[Symbol.toStringTag] = undefined;
74  assertEquals("[object " + className + "]",
75               Object.prototype.toString.call(obj));
76
77  // With getter
78  var obj = className === "Arguments" ?
79      (function() { return arguments; })() : new global[className];
80  Object.defineProperty(obj, Symbol.toStringTag, {
81    get: function() { return undefined; }
82  });
83  assertEquals("[object " + className + "]",
84               Object.prototype.toString.call(obj));
85}
86
87[
88  "Arguments",
89  "Array",
90  "Boolean",
91  "Date",
92  "Error",
93  "Function",
94  "Number",
95  "RegExp",
96  "String"
97].forEach(testToStringTag);
98
99function testToStringTagNonString(value) {
100  var obj = {};
101  obj[Symbol.toStringTag] = value;
102  assertEquals("[object Object]", Object.prototype.toString.call(obj));
103
104  // With getter
105  obj = {};
106  Object.defineProperty(obj, Symbol.toStringTag, {
107    get: function() { return value; }
108  });
109  assertEquals("[object Object]", Object.prototype.toString.call(obj));
110}
111
112[
113  null,
114  function() {},
115  [],
116  {},
117  /regexp/,
118  42,
119  Symbol("sym"),
120  new Date(),
121  (function() { return arguments; })(),
122  true,
123  new Error("oops"),
124  new String("str")
125].forEach(testToStringTagNonString);
126
127function testObjectToStringPropertyDesc() {
128  var desc = Object.getOwnPropertyDescriptor(Object.prototype, "toString");
129  assertTrue(desc.writable);
130  assertFalse(desc.enumerable);
131  assertTrue(desc.configurable);
132}
133testObjectToStringPropertyDesc();
134
135function testObjectToStringOwnNonStringValue() {
136  var obj = Object.defineProperty({}, Symbol.toStringTag, { value: 1 });
137  assertEquals("[object Object]", ({}).toString.call(obj));
138}
139testObjectToStringOwnNonStringValue();
140
141
142// Proxies
143
144function assertTag(tag, obj) {
145  assertEquals("[object " + tag + "]", Object.prototype.toString.call(obj));
146}
147
148assertTag("Object", new Proxy({}, {}));
149assertTag("Array", new Proxy([], {}));
150assertTag("Function", new Proxy(() => 42, {}));
151assertTag("Foo", new Proxy(() => 42, {get() {return "Foo"}}));
152assertTag("Function", new Proxy(() => 42, {get() {return 666}}));
153
154revocable = Proxy.revocable([], {});
155revocable.revoke();
156assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
157
158handler = {};
159revocable = Proxy.revocable([], handler);
160handler.get = () => revocable.revoke();
161assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
162