• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../../common');
3const assert = require('assert');
4
5// Testing api calls for objects
6const test_object = require(`./build/${common.buildType}/test_object`);
7
8
9const object = {
10  hello: 'world',
11  array: [
12    1, 94, 'str', 12.321, { test: 'obj in arr' },
13  ],
14  newObject: {
15    test: 'obj in obj'
16  }
17};
18
19assert.strictEqual(test_object.Get(object, 'hello'), 'world');
20assert.strictEqual(test_object.GetNamed(object, 'hello'), 'world');
21assert.deepStrictEqual(test_object.Get(object, 'array'),
22                       [ 1, 94, 'str', 12.321, { test: 'obj in arr' } ]);
23assert.deepStrictEqual(test_object.Get(object, 'newObject'),
24                       { test: 'obj in obj' });
25
26assert(test_object.Has(object, 'hello'));
27assert(test_object.HasNamed(object, 'hello'));
28assert(test_object.Has(object, 'array'));
29assert(test_object.Has(object, 'newObject'));
30
31const newObject = test_object.New();
32assert(test_object.Has(newObject, 'test_number'));
33assert.strictEqual(newObject.test_number, 987654321);
34assert.strictEqual(newObject.test_string, 'test string');
35
36{
37  // Verify that napi_get_property() walks the prototype chain.
38  function MyObject() {
39    this.foo = 42;
40    this.bar = 43;
41  }
42
43  MyObject.prototype.bar = 44;
44  MyObject.prototype.baz = 45;
45
46  const obj = new MyObject();
47
48  assert.strictEqual(test_object.Get(obj, 'foo'), 42);
49  assert.strictEqual(test_object.Get(obj, 'bar'), 43);
50  assert.strictEqual(test_object.Get(obj, 'baz'), 45);
51  assert.strictEqual(test_object.Get(obj, 'toString'),
52                     Object.prototype.toString);
53}
54
55{
56  // Verify that napi_has_own_property() fails if property is not a name.
57  [true, false, null, undefined, {}, [], 0, 1, () => {}].forEach((value) => {
58    assert.throws(() => {
59      test_object.HasOwn({}, value);
60    }, /^Error: A string or symbol was expected$/);
61  });
62}
63
64{
65  // Verify that napi_has_own_property() does not walk the prototype chain.
66  const symbol1 = Symbol();
67  const symbol2 = Symbol();
68
69  function MyObject() {
70    this.foo = 42;
71    this.bar = 43;
72    this[symbol1] = 44;
73  }
74
75  MyObject.prototype.bar = 45;
76  MyObject.prototype.baz = 46;
77  MyObject.prototype[symbol2] = 47;
78
79  const obj = new MyObject();
80
81  assert.strictEqual(test_object.HasOwn(obj, 'foo'), true);
82  assert.strictEqual(test_object.HasOwn(obj, 'bar'), true);
83  assert.strictEqual(test_object.HasOwn(obj, symbol1), true);
84  assert.strictEqual(test_object.HasOwn(obj, 'baz'), false);
85  assert.strictEqual(test_object.HasOwn(obj, 'toString'), false);
86  assert.strictEqual(test_object.HasOwn(obj, symbol2), false);
87}
88
89{
90  // test_object.Inflate increases all properties by 1
91  const cube = {
92    x: 10,
93    y: 10,
94    z: 10
95  };
96
97  assert.deepStrictEqual(test_object.Inflate(cube), { x: 11, y: 11, z: 11 });
98  assert.deepStrictEqual(test_object.Inflate(cube), { x: 12, y: 12, z: 12 });
99  assert.deepStrictEqual(test_object.Inflate(cube), { x: 13, y: 13, z: 13 });
100  cube.t = 13;
101  assert.deepStrictEqual(
102    test_object.Inflate(cube), { x: 14, y: 14, z: 14, t: 14 });
103
104  const sym1 = Symbol('1');
105  const sym2 = Symbol('2');
106  const sym3 = Symbol('3');
107  const sym4 = Symbol('4');
108  const object2 = {
109    [sym1]: '@@iterator',
110    [sym2]: sym3
111  };
112
113  assert(test_object.Has(object2, sym1));
114  assert(test_object.Has(object2, sym2));
115  assert.strictEqual(test_object.Get(object2, sym1), '@@iterator');
116  assert.strictEqual(test_object.Get(object2, sym2), sym3);
117  assert(test_object.Set(object2, 'string', 'value'));
118  assert(test_object.SetNamed(object2, 'named_string', 'value'));
119  assert(test_object.Set(object2, sym4, 123));
120  assert(test_object.Has(object2, 'string'));
121  assert(test_object.HasNamed(object2, 'named_string'));
122  assert(test_object.Has(object2, sym4));
123  assert.strictEqual(test_object.Get(object2, 'string'), 'value');
124  assert.strictEqual(test_object.Get(object2, sym4), 123);
125}
126
127{
128  // Wrap a pointer in a JS object, then verify the pointer can be unwrapped.
129  const wrapper = {};
130  test_object.Wrap(wrapper);
131
132  assert(test_object.Unwrap(wrapper));
133}
134
135{
136  // Verify that wrapping doesn't break an object's prototype chain.
137  const wrapper = {};
138  const protoA = { protoA: true };
139  Object.setPrototypeOf(wrapper, protoA);
140  test_object.Wrap(wrapper);
141
142  assert(test_object.Unwrap(wrapper));
143  assert(wrapper.protoA);
144}
145
146{
147  // Verify the pointer can be unwrapped after inserting in the prototype chain.
148  const wrapper = {};
149  const protoA = { protoA: true };
150  Object.setPrototypeOf(wrapper, protoA);
151  test_object.Wrap(wrapper);
152
153  const protoB = { protoB: true };
154  Object.setPrototypeOf(protoB, Object.getPrototypeOf(wrapper));
155  Object.setPrototypeOf(wrapper, protoB);
156
157  assert(test_object.Unwrap(wrapper));
158  assert(wrapper.protoA, true);
159  assert(wrapper.protoB, true);
160}
161
162{
163  // Verify that objects can be type-tagged and type-tag-checked.
164  const obj1 = test_object.TypeTaggedInstance(0);
165  const obj2 = test_object.TypeTaggedInstance(1);
166
167  // Verify that type tags are correctly accepted.
168  assert.strictEqual(test_object.CheckTypeTag(0, obj1), true);
169  assert.strictEqual(test_object.CheckTypeTag(1, obj2), true);
170
171  // Verify that wrongly tagged objects are rejected.
172  assert.strictEqual(test_object.CheckTypeTag(0, obj2), false);
173  assert.strictEqual(test_object.CheckTypeTag(1, obj1), false);
174
175  // Verify that untagged objects are rejected.
176  assert.strictEqual(test_object.CheckTypeTag(0, {}), false);
177  assert.strictEqual(test_object.CheckTypeTag(1, {}), false);
178}
179
180{
181  // Verify that normal and nonexistent properties can be deleted.
182  const sym = Symbol();
183  const obj = { foo: 'bar', [sym]: 'baz' };
184
185  assert.strictEqual('foo' in obj, true);
186  assert.strictEqual(sym in obj, true);
187  assert.strictEqual('does_not_exist' in obj, false);
188  assert.strictEqual(test_object.Delete(obj, 'foo'), true);
189  assert.strictEqual('foo' in obj, false);
190  assert.strictEqual(sym in obj, true);
191  assert.strictEqual('does_not_exist' in obj, false);
192  assert.strictEqual(test_object.Delete(obj, sym), true);
193  assert.strictEqual('foo' in obj, false);
194  assert.strictEqual(sym in obj, false);
195  assert.strictEqual('does_not_exist' in obj, false);
196}
197
198{
199  // Verify that non-configurable properties are not deleted.
200  const obj = {};
201
202  Object.defineProperty(obj, 'foo', { configurable: false });
203  assert.strictEqual(test_object.Delete(obj, 'foo'), false);
204  assert.strictEqual('foo' in obj, true);
205}
206
207{
208  // Verify that prototype properties are not deleted.
209  function Foo() {
210    this.foo = 'bar';
211  }
212
213  Foo.prototype.foo = 'baz';
214
215  const obj = new Foo();
216
217  assert.strictEqual(obj.foo, 'bar');
218  assert.strictEqual(test_object.Delete(obj, 'foo'), true);
219  assert.strictEqual(obj.foo, 'baz');
220  assert.strictEqual(test_object.Delete(obj, 'foo'), true);
221  assert.strictEqual(obj.foo, 'baz');
222}
223
224{
225  // Verify that napi_get_property_names gets the right set of property names,
226  // i.e.: includes prototypes, only enumerable properties, skips symbols,
227  // and includes indices and converts them to strings.
228
229  const object = Object.create({
230    inherited: 1
231  });
232
233  const fooSymbol = Symbol('foo');
234
235  object.normal = 2;
236  object[fooSymbol] = 3;
237  Object.defineProperty(object, 'unenumerable', {
238    value: 4,
239    enumerable: false,
240    writable: true,
241    configurable: true
242  });
243  object[5] = 5;
244
245  assert.deepStrictEqual(test_object.GetPropertyNames(object),
246                         ['5', 'normal', 'inherited']);
247
248  assert.deepStrictEqual(test_object.GetSymbolNames(object),
249                         [fooSymbol]);
250}
251
252// Verify that passing NULL to napi_set_property() results in the correct
253// error.
254assert.deepStrictEqual(test_object.TestSetProperty(), {
255  envIsNull: 'Invalid argument',
256  objectIsNull: 'Invalid argument',
257  keyIsNull: 'Invalid argument',
258  valueIsNull: 'Invalid argument'
259});
260
261// Verify that passing NULL to napi_has_property() results in the correct
262// error.
263assert.deepStrictEqual(test_object.TestHasProperty(), {
264  envIsNull: 'Invalid argument',
265  objectIsNull: 'Invalid argument',
266  keyIsNull: 'Invalid argument',
267  resultIsNull: 'Invalid argument'
268});
269
270// Verify that passing NULL to napi_get_property() results in the correct
271// error.
272assert.deepStrictEqual(test_object.TestGetProperty(), {
273  envIsNull: 'Invalid argument',
274  objectIsNull: 'Invalid argument',
275  keyIsNull: 'Invalid argument',
276  resultIsNull: 'Invalid argument'
277});
278
279{
280  const obj = { x: 'a', y: 'b', z: 'c' };
281
282  test_object.TestSeal(obj);
283
284  assert.strictEqual(Object.isSealed(obj), true);
285
286  assert.throws(() => {
287    obj.w = 'd';
288  }, /Cannot add property w, object is not extensible/);
289
290  assert.throws(() => {
291    delete obj.x;
292  }, /Cannot delete property 'x' of #<Object>/);
293
294  // Sealed objects allow updating existing properties,
295  // so this should not throw.
296  obj.x = 'd';
297}
298
299{
300  const obj = { x: 10, y: 10, z: 10 };
301
302  test_object.TestFreeze(obj);
303
304  assert.strictEqual(Object.isFrozen(obj), true);
305
306  assert.throws(() => {
307    obj.x = 10;
308  }, /Cannot assign to read only property 'x' of object '#<Object>/);
309
310  assert.throws(() => {
311    obj.w = 15;
312  }, /Cannot add property w, object is not extensible/);
313
314  assert.throws(() => {
315    delete obj.x;
316  }, /Cannot delete property 'x' of #<Object>/);
317}
318