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