diff --git a/test/binding.gyp b/test/binding.gyp index fc5b5c2c8..c9f82ee20 100644 --- a/test/binding.gyp +++ b/test/binding.gyp @@ -35,6 +35,7 @@ 'object/has_property.cc', 'object/object.cc', 'object/set_property.cc', + 'object/subscript_operator.cc', 'promise.cc', 'run_script.cc', 'threadsafe_function/threadsafe_function_ctx.cc', diff --git a/test/object/get_property.js b/test/object/get_property.js index 7ec9b119e..8028165c3 100644 --- a/test/object/get_property.js +++ b/test/object/get_property.js @@ -12,19 +12,27 @@ function test(binding) { assert.strictEqual(nativeGetProperty(obj, 'test'), 1); } + function testShouldReturnUndefinedIfKeyIsNotPresent(nativeGetProperty) { + const obj = { }; + assert.strictEqual(nativeGetProperty(obj, 'test'), undefined); + } + function testShouldThrowErrorIfKeyIsInvalid(nativeGetProperty) { assert.throws(() => { nativeGetProperty(undefined, 'test'); }, /Cannot convert undefined or null to object/); } - testGetProperty(binding.object.getPropertyWithNapiValue); - testGetProperty(binding.object.getPropertyWithNapiWrapperValue); - testGetProperty(binding.object.getPropertyWithCStyleString); - testGetProperty(binding.object.getPropertyWithCppStyleString); + const nativeFunctions = [ + binding.object.getPropertyWithNapiValue, + binding.object.getPropertyWithNapiWrapperValue, + binding.object.getPropertyWithCStyleString, + binding.object.getPropertyWithCppStyleString + ]; - testShouldThrowErrorIfKeyIsInvalid(binding.object.getPropertyWithNapiValue); - testShouldThrowErrorIfKeyIsInvalid(binding.object.getPropertyWithNapiWrapperValue); - testShouldThrowErrorIfKeyIsInvalid(binding.object.getPropertyWithCStyleString); - testShouldThrowErrorIfKeyIsInvalid(binding.object.getPropertyWithCppStyleString); + nativeFunctions.forEach((nativeFunction) => { + testGetProperty(nativeFunction); + testShouldReturnUndefinedIfKeyIsNotPresent(nativeFunction); + testShouldThrowErrorIfKeyIsInvalid(nativeFunction); + }); } diff --git a/test/object/object.cc b/test/object/object.cc index 2c0ce420b..b2f6b5f95 100644 --- a/test/object/object.cc +++ b/test/object/object.cc @@ -36,6 +36,14 @@ Value HasPropertyWithCppStyleString(const CallbackInfo& info); Value AddFinalizer(const CallbackInfo& info); Value AddFinalizerWithHint(const CallbackInfo& info); +// Native wrappers for testing Object::operator [] +Value SubscriptGetWithCStyleString(const CallbackInfo& info); +Value SubscriptGetWithCppStyleString(const CallbackInfo& info); +Value SubscriptGetAtIndex(const CallbackInfo& info); +void SubscriptSetWithCStyleString(const CallbackInfo& info); +void SubscriptSetWithCppStyleString(const CallbackInfo& info); +void SubscriptSetAtIndex(const CallbackInfo& info); + static bool testValue = true; // Used to test void* Data() integrity struct UserDataHolder { @@ -69,6 +77,19 @@ Value TestFunctionWithUserData(const CallbackInfo& info) { return Number::New(info.Env(), holder->value); } +Value EmptyConstructor(const CallbackInfo& info) { + auto env = info.Env(); + bool isEmpty = info[0].As(); + Object object = isEmpty ? Object() : Object(env, Object::New(env)); + return Boolean::New(env, object.IsEmpty()); +} + +Value ConstructorFromObject(const CallbackInfo& info) { + auto env = info.Env(); + Object object = info[0].As(); + return Object(env, object); +} + Array GetPropertyNames(const CallbackInfo& info) { Object obj = info[0].As(); Array arr = obj.GetPropertyNames(); @@ -228,9 +249,18 @@ Value CreateObjectUsingMagic(const CallbackInfo& info) { return obj; } +Value InstanceOf(const CallbackInfo& info) { + Object obj = info[0].As(); + Function constructor = info[1].As(); + return Boolean::New(info.Env(), obj.InstanceOf(constructor)); +} + Object InitObject(Env env) { Object exports = Object::New(env); + exports["emptyConstructor"] = Function::New(env, EmptyConstructor); + exports["constructorFromObject"] = Function::New(env, ConstructorFromObject); + exports["GetPropertyNames"] = Function::New(env, GetPropertyNames); exports["defineProperties"] = Function::New(env, DefineProperties); exports["defineValueProperty"] = Function::New(env, DefineValueProperty); @@ -265,5 +295,18 @@ Object InitObject(Env env) { exports["addFinalizer"] = Function::New(env, AddFinalizer); exports["addFinalizerWithHint"] = Function::New(env, AddFinalizerWithHint); + exports["instanceOf"] = Function::New(env, InstanceOf); + + exports["subscriptGetWithCStyleString"] = + Function::New(env, SubscriptGetWithCStyleString); + exports["subscriptGetWithCppStyleString"] = + Function::New(env, SubscriptGetWithCppStyleString); + exports["subscriptGetAtIndex"] = Function::New(env, SubscriptGetAtIndex); + exports["subscriptSetWithCStyleString"] = + Function::New(env, SubscriptSetWithCStyleString); + exports["subscriptSetWithCppStyleString"] = + Function::New(env, SubscriptSetWithCppStyleString); + exports["subscriptSetAtIndex"] = Function::New(env, SubscriptSetAtIndex); + return exports; } diff --git a/test/object/object.js b/test/object/object.js index 8741e27f1..4b6f72fc7 100644 --- a/test/object/object.js +++ b/test/object/object.js @@ -102,6 +102,17 @@ function test(binding) { testDefineProperties('string'); testDefineProperties('value'); + { + assert.strictEqual(binding.object.emptyConstructor(true), true); + assert.strictEqual(binding.object.emptyConstructor(false), false); + } + + { + const expected = { 'one': 1, 'two': 2, 'three': 3 }; + const actual = binding.object.constructorFromObject(expected); + assert.deepStrictEqual(actual, expected); + } + { const obj = {}; const testSym = Symbol(); @@ -110,9 +121,10 @@ function test(binding) { } { - const obj = {'one': 1, 'two': 2, 'three': 3}; + const testSym = Symbol(); + const obj = { 'one': 1, 'two': 2, 'three': 3, [testSym]: 4 }; var arr = binding.object.GetPropertyNames(obj); - assert.deepStrictEqual(arr, ['one', 'two', 'three']) + assert.deepStrictEqual(arr, ['one', 'two', 'three']); } { @@ -136,4 +148,13 @@ function test(binding) { circular2: magicObject }); } + + { + function Ctor() {}; + + assert.strictEqual(binding.object.instanceOf(new Ctor(), Ctor), true); + assert.strictEqual(binding.object.instanceOf(new Ctor(), Object), true); + assert.strictEqual(binding.object.instanceOf({}, Ctor), false); + assert.strictEqual(binding.object.instanceOf(null, Ctor), false); + } } diff --git a/test/object/subscript_operator.cc b/test/object/subscript_operator.cc new file mode 100644 index 000000000..3af39fc54 --- /dev/null +++ b/test/object/subscript_operator.cc @@ -0,0 +1,42 @@ +#include "napi.h" + +using namespace Napi; + +Value SubscriptGetWithCStyleString(const CallbackInfo& info) { + Object obj = info[0].As(); + String jsKey = info[1].As(); + return obj[jsKey.Utf8Value().c_str()]; +} + +Value SubscriptGetWithCppStyleString(const CallbackInfo& info) { + Object obj = info[0].As(); + String jsKey = info[1].As(); + return obj[jsKey.Utf8Value()]; +} + +Value SubscriptGetAtIndex(const CallbackInfo& info) { + Object obj = info[0].As(); + uint32_t index = info[1].As(); + return obj[index]; +} + +void SubscriptSetWithCStyleString(const CallbackInfo& info) { + Object obj = info[0].As(); + String jsKey = info[1].As(); + Value value = info[2]; + obj[jsKey.Utf8Value().c_str()] = value; +} + +void SubscriptSetWithCppStyleString(const CallbackInfo& info) { + Object obj = info[0].As(); + String jsKey = info[1].As(); + Value value = info[2]; + obj[jsKey.Utf8Value()] = value; +} + +void SubscriptSetAtIndex(const CallbackInfo& info) { + Object obj = info[0].As(); + uint32_t index = info[1].As(); + Value value = info[2]; + obj[index] = value; +} diff --git a/test/object/subscript_operator.js b/test/object/subscript_operator.js new file mode 100644 index 000000000..21a6ee891 --- /dev/null +++ b/test/object/subscript_operator.js @@ -0,0 +1,19 @@ +'use strict'; + +const buildType = process.config.target_defaults.default_configuration; +const assert = require('assert'); + +test(require(`../build/${buildType}/binding.node`)); +test(require(`../build/${buildType}/binding_noexcept.node`)); + +function test(binding) { + function testProperty(obj, key, value, nativeGetProperty, nativeSetProperty) { + nativeSetProperty(obj, key, value); + assert.strictEqual(nativeGetProperty(obj, key), value); + } + + testProperty({}, 'key', 'value', binding.object.subscriptGetWithCStyleString, binding.object.subscriptSetWithCStyleString); + testProperty({ key: 'override me' }, 'key', 'value', binding.object.subscriptGetWithCppStyleString, binding.object.subscriptSetWithCppStyleString); + testProperty({}, 0, 'value', binding.object.subscriptGetAtIndex, binding.object.subscriptSetAtIndex); + testProperty({ key: 'override me' }, 0, 'value', binding.object.subscriptGetAtIndex, binding.object.subscriptSetAtIndex); +}