1// Flags: --expose-internals
2'use strict';
3
4require('../common');
5const assert = require('assert');
6const util = require('util');
7const { internalBinding } = require('internal/test/binding');
8const processUtil = internalBinding('util');
9const opts = { showProxy: true };
10
11let proxyObj;
12let called = false;
13const target = {
14  [util.inspect.custom](depth, { showProxy }) {
15    if (showProxy === false) {
16      called = true;
17      if (proxyObj !== this) {
18        throw new Error('Failed');
19      }
20    }
21    return [1, 2, 3];
22  }
23};
24const handler = {
25  getPrototypeOf() { throw new Error('getPrototypeOf'); },
26  setPrototypeOf() { throw new Error('setPrototypeOf'); },
27  isExtensible() { throw new Error('isExtensible'); },
28  preventExtensions() { throw new Error('preventExtensions'); },
29  getOwnPropertyDescriptor() { throw new Error('getOwnPropertyDescriptor'); },
30  defineProperty() { throw new Error('defineProperty'); },
31  has() { throw new Error('has'); },
32  get() { throw new Error('get'); },
33  set() { throw new Error('set'); },
34  deleteProperty() { throw new Error('deleteProperty'); },
35  ownKeys() { throw new Error('ownKeys'); },
36  apply() { throw new Error('apply'); },
37  construct() { throw new Error('construct'); }
38};
39proxyObj = new Proxy(target, handler);
40
41// Inspecting the proxy should not actually walk it's properties
42util.inspect(proxyObj, opts);
43
44// Make sure inspecting object does not trigger any proxy traps.
45util.format('%s', proxyObj);
46
47// getProxyDetails is an internal method, not intended for public use.
48// This is here to test that the internals are working correctly.
49let details = processUtil.getProxyDetails(proxyObj, true);
50assert.strictEqual(target, details[0]);
51assert.strictEqual(handler, details[1]);
52
53details = processUtil.getProxyDetails(proxyObj);
54assert.strictEqual(target, details[0]);
55assert.strictEqual(handler, details[1]);
56
57details = processUtil.getProxyDetails(proxyObj, false);
58assert.strictEqual(target, details);
59
60details = processUtil.getProxyDetails({}, true);
61assert.strictEqual(details, undefined);
62
63const r = Proxy.revocable({}, {});
64r.revoke();
65
66details = processUtil.getProxyDetails(r.proxy, true);
67assert.strictEqual(details[0], null);
68assert.strictEqual(details[1], null);
69
70details = processUtil.getProxyDetails(r.proxy, false);
71assert.strictEqual(details, null);
72
73assert.strictEqual(util.inspect(r.proxy), '<Revoked Proxy>');
74assert.strictEqual(
75  util.inspect(r, { showProxy: true }),
76  '{ proxy: <Revoked Proxy>, revoke: [Function (anonymous)] }',
77);
78
79assert.strictEqual(util.format('%s', r.proxy), '<Revoked Proxy>');
80
81assert.strictEqual(
82  util.inspect(proxyObj, opts),
83  'Proxy [\n' +
84  '  [ 1, 2, 3 ],\n' +
85  '  {\n' +
86  '    getPrototypeOf: [Function: getPrototypeOf],\n' +
87  '    setPrototypeOf: [Function: setPrototypeOf],\n' +
88  '    isExtensible: [Function: isExtensible],\n' +
89  '    preventExtensions: [Function: preventExtensions],\n' +
90  '    getOwnPropertyDescriptor: [Function: getOwnPropertyDescriptor],\n' +
91  '    defineProperty: [Function: defineProperty],\n' +
92  '    has: [Function: has],\n' +
93  '    get: [Function: get],\n' +
94  '    set: [Function: set],\n' +
95  '    deleteProperty: [Function: deleteProperty],\n' +
96  '    ownKeys: [Function: ownKeys],\n' +
97  '    apply: [Function: apply],\n' +
98  '    construct: [Function: construct]\n' +
99  '  }\n' +
100  ']'
101);
102
103// Using getProxyDetails with non-proxy returns undefined
104assert.strictEqual(processUtil.getProxyDetails({}), undefined);
105
106// Inspecting a proxy without the showProxy option set to true should not
107// trigger any proxy handlers.
108assert.strictEqual(util.inspect(proxyObj), '[ 1, 2, 3 ]');
109assert(called);
110
111// Yo dawg, I heard you liked Proxy so I put a Proxy
112// inside your Proxy that proxies your Proxy's Proxy.
113const proxy1 = new Proxy({}, {});
114const proxy2 = new Proxy(proxy1, {});
115const proxy3 = new Proxy(proxy2, proxy1);
116const proxy4 = new Proxy(proxy1, proxy2);
117const proxy5 = new Proxy(proxy3, proxy4);
118const proxy6 = new Proxy(proxy5, proxy5);
119const expected0 = '{}';
120const expected1 = 'Proxy [ {}, {} ]';
121const expected2 = 'Proxy [ Proxy [ {}, {} ], {} ]';
122const expected3 = 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]';
123const expected4 = 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]';
124const expected5 = 'Proxy [\n  ' +
125                  'Proxy [ Proxy [ Proxy [Array], {} ], Proxy [ {}, {} ] ],\n' +
126                  '  Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [Array], {} ] ]' +
127                  '\n]';
128const expected6 = 'Proxy [\n' +
129                  '  Proxy [\n' +
130                  '    Proxy [ Proxy [Array], Proxy [Array] ],\n' +
131                  '    Proxy [ Proxy [Array], Proxy [Array] ]\n' +
132                  '  ],\n' +
133                  '  Proxy [\n' +
134                  '    Proxy [ Proxy [Array], Proxy [Array] ],\n' +
135                  '    Proxy [ Proxy [Array], Proxy [Array] ]\n' +
136                  '  ]\n' +
137                  ']';
138assert.strictEqual(
139  util.inspect(proxy1, { showProxy: 1, depth: null }),
140  expected1);
141assert.strictEqual(util.inspect(proxy2, opts), expected2);
142assert.strictEqual(util.inspect(proxy3, opts), expected3);
143assert.strictEqual(util.inspect(proxy4, opts), expected4);
144assert.strictEqual(util.inspect(proxy5, opts), expected5);
145assert.strictEqual(util.inspect(proxy6, opts), expected6);
146assert.strictEqual(util.inspect(proxy1), expected0);
147assert.strictEqual(util.inspect(proxy2), expected0);
148assert.strictEqual(util.inspect(proxy3), expected0);
149assert.strictEqual(util.inspect(proxy4), expected0);
150assert.strictEqual(util.inspect(proxy5), expected0);
151assert.strictEqual(util.inspect(proxy6), expected0);
152
153// Just for fun, let's create a Proxy using Arrays.
154const proxy7 = new Proxy([], []);
155const expected7 = 'Proxy [ [], [] ]';
156assert.strictEqual(util.inspect(proxy7, opts), expected7);
157assert.strictEqual(util.inspect(proxy7), '[]');
158
159// Now we're just getting silly, right?
160const proxy8 = new Proxy(Date, []);
161const proxy9 = new Proxy(Date, String);
162const expected8 = 'Proxy [ [Function: Date], [] ]';
163const expected9 = 'Proxy [ [Function: Date], [Function: String] ]';
164assert.strictEqual(util.inspect(proxy8, opts), expected8);
165assert.strictEqual(util.inspect(proxy9, opts), expected9);
166assert.strictEqual(util.inspect(proxy8), '[Function: Date]');
167assert.strictEqual(util.inspect(proxy9), '[Function: Date]');
168
169const proxy10 = new Proxy(() => {}, {});
170const proxy11 = new Proxy(() => {}, {
171  get() {
172    return proxy11;
173  },
174  apply() {
175    return proxy11;
176  }
177});
178const expected10 = '[Function (anonymous)]';
179const expected11 = '[Function (anonymous)]';
180assert.strictEqual(util.inspect(proxy10), expected10);
181assert.strictEqual(util.inspect(proxy11), expected11);
182