Skip to content

Commit

Permalink
test: add additional tests for Object
Browse files Browse the repository at this point in the history
Test that Object::GetPropertyNames does not
return properties whose key is a Symbol

PR-URL: nodejs/node-addon-api#923
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: NickNaso <nicoladelgobbo@gmail.com>
  • Loading branch information
Marlyfleitas committed Mar 15, 2021
1 parent 1938211 commit cad5106
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 10 deletions.
1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
24 changes: 16 additions & 8 deletions test/object/get_property.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
}
43 changes: 43 additions & 0 deletions test/object/object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<Boolean>();
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<Object>();
return Object(env, object);
}

Array GetPropertyNames(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
Array arr = obj.GetPropertyNames();
Expand Down Expand Up @@ -228,9 +249,18 @@ Value CreateObjectUsingMagic(const CallbackInfo& info) {
return obj;
}

Value InstanceOf(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
Function constructor = info[1].As<Function>();
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);
Expand Down Expand Up @@ -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;
}
25 changes: 23 additions & 2 deletions test/object/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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']);
}

{
Expand All @@ -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);
}
}
42 changes: 42 additions & 0 deletions test/object/subscript_operator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "napi.h"

using namespace Napi;

Value SubscriptGetWithCStyleString(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
String jsKey = info[1].As<String>();
return obj[jsKey.Utf8Value().c_str()];
}

Value SubscriptGetWithCppStyleString(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
String jsKey = info[1].As<String>();
return obj[jsKey.Utf8Value()];
}

Value SubscriptGetAtIndex(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
uint32_t index = info[1].As<Napi::Number>();
return obj[index];
}

void SubscriptSetWithCStyleString(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
String jsKey = info[1].As<String>();
Value value = info[2];
obj[jsKey.Utf8Value().c_str()] = value;
}

void SubscriptSetWithCppStyleString(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
String jsKey = info[1].As<String>();
Value value = info[2];
obj[jsKey.Utf8Value()] = value;
}

void SubscriptSetAtIndex(const CallbackInfo& info) {
Object obj = info[0].As<Object>();
uint32_t index = info[1].As<Napi::Number>();
Value value = info[2];
obj[index] = value;
}
19 changes: 19 additions & 0 deletions test/object/subscript_operator.js
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit cad5106

Please sign in to comment.