Skip to content

Commit

Permalink
src: add additional tests for Function
Browse files Browse the repository at this point in the history
PR-URL: nodejs/node-addon-api#928
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: NickNaso <nicoladelgobbo@gmail.com>
  • Loading branch information
Marlyfleitas committed Mar 15, 2021
1 parent 44c1e33 commit 0bf9127
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 9 deletions.
126 changes: 124 additions & 2 deletions test/function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ namespace {

int testData = 1;

Boolean EmptyConstructor(const CallbackInfo& info) {
auto env = info.Env();
bool isEmpty = info[0].As<Boolean>();
Function function = isEmpty ? Function() : Function(env, Object::New(env));
return Boolean::New(env, function.IsEmpty());
}

void VoidCallback(const CallbackInfo& info) {
auto env = info.Env();
Object obj = info[0].As<Object>();
Expand Down Expand Up @@ -45,8 +52,9 @@ Value ValueCallbackWithData(const CallbackInfo& info) {
}

Value CallWithArgs(const CallbackInfo& info) {
Function func = info[0].As<Function>();
return func({ info[1], info[2], info[3] });
Function func = info[0].As<Function>();
return func.Call(
std::initializer_list<napi_value>{info[1], info[2], info[3]});
}

Value CallWithVector(const CallbackInfo& info) {
Expand All @@ -59,6 +67,27 @@ Value CallWithVector(const CallbackInfo& info) {
return func.Call(args);
}

Value CallWithCStyleArray(const CallbackInfo& info) {
Function func = info[0].As<Function>();
std::vector<napi_value> args;
args.reserve(3);
args.push_back(info[1]);
args.push_back(info[2]);
args.push_back(info[3]);
return func.Call(args.size(), args.data());
}

Value CallWithReceiverAndCStyleArray(const CallbackInfo& info) {
Function func = info[0].As<Function>();
Value receiver = info[1];
std::vector<napi_value> args;
args.reserve(3);
args.push_back(info[2]);
args.push_back(info[3]);
args.push_back(info[4]);
return func.Call(receiver, args.size(), args.data());
}

Value CallWithReceiverAndArgs(const CallbackInfo& info) {
Function func = info[0].As<Function>();
Value receiver = info[1];
Expand Down Expand Up @@ -96,17 +125,81 @@ Value CallConstructorWithVector(const CallbackInfo& info) {
return func.New(args);
}

Value CallConstructorWithCStyleArray(const CallbackInfo& info) {
Function func = info[0].As<Function>();
std::vector<napi_value> args;
args.reserve(3);
args.push_back(info[1]);
args.push_back(info[2]);
args.push_back(info[3]);
return func.New(args.size(), args.data());
}

void IsConstructCall(const CallbackInfo& info) {
Function callback = info[0].As<Function>();
bool isConstructCall = info.IsConstructCall();
callback({Napi::Boolean::New(info.Env(), isConstructCall)});
}

void MakeCallbackWithArgs(const CallbackInfo& info) {
Env env = info.Env();
Function callback = info[0].As<Function>();
Object resource = info[1].As<Object>();

AsyncContext context(env, "async_context_test", resource);

callback.MakeCallback(
resource,
std::initializer_list<napi_value>{info[2], info[3], info[4]},
context);
}

void MakeCallbackWithVector(const CallbackInfo& info) {
Env env = info.Env();
Function callback = info[0].As<Function>();
Object resource = info[1].As<Object>();

AsyncContext context(env, "async_context_test", resource);

std::vector<napi_value> args;
args.reserve(3);
args.push_back(info[2]);
args.push_back(info[3]);
args.push_back(info[4]);
callback.MakeCallback(resource, args, context);
}

void MakeCallbackWithCStyleArray(const CallbackInfo& info) {
Env env = info.Env();
Function callback = info[0].As<Function>();
Object resource = info[1].As<Object>();

AsyncContext context(env, "async_context_test", resource);

std::vector<napi_value> args;
args.reserve(3);
args.push_back(info[2]);
args.push_back(info[3]);
args.push_back(info[4]);
callback.MakeCallback(resource, args.size(), args.data(), context);
}

void MakeCallbackWithInvalidReceiver(const CallbackInfo& info) {
Function callback = info[0].As<Function>();
callback.MakeCallback(Value(), std::initializer_list<napi_value>{});
}

Value CallWithFunctionOperator(const CallbackInfo& info) {
Function func = info[0].As<Function>();
return func({info[1], info[2], info[3]});
}

} // end anonymous namespace

Object InitFunction(Env env) {
Object result = Object::New(env);
Object exports = Object::New(env);
exports["emptyConstructor"] = Function::New(env, EmptyConstructor);
exports["voidCallback"] = Function::New(env, VoidCallback, "voidCallback");
exports["valueCallback"] = Function::New(env, ValueCallback, std::string("valueCallback"));
exports["voidCallbackWithData"] =
Expand All @@ -115,15 +208,30 @@ Object InitFunction(Env env) {
Function::New(env, ValueCallbackWithData, nullptr, &testData);
exports["callWithArgs"] = Function::New(env, CallWithArgs);
exports["callWithVector"] = Function::New(env, CallWithVector);
exports["callWithCStyleArray"] = Function::New(env, CallWithCStyleArray);
exports["callWithReceiverAndCStyleArray"] =
Function::New(env, CallWithReceiverAndCStyleArray);
exports["callWithReceiverAndArgs"] = Function::New(env, CallWithReceiverAndArgs);
exports["callWithReceiverAndVector"] = Function::New(env, CallWithReceiverAndVector);
exports["callWithInvalidReceiver"] = Function::New(env, CallWithInvalidReceiver);
exports["callConstructorWithArgs"] = Function::New(env, CallConstructorWithArgs);
exports["callConstructorWithVector"] = Function::New(env, CallConstructorWithVector);
exports["callConstructorWithCStyleArray"] =
Function::New(env, CallConstructorWithCStyleArray);
exports["isConstructCall"] = Function::New(env, IsConstructCall);
exports["makeCallbackWithArgs"] = Function::New(env, MakeCallbackWithArgs);
exports["makeCallbackWithVector"] =
Function::New(env, MakeCallbackWithVector);
exports["makeCallbackWithCStyleArray"] =
Function::New(env, MakeCallbackWithCStyleArray);
exports["makeCallbackWithInvalidReceiver"] =
Function::New(env, MakeCallbackWithInvalidReceiver);
exports["callWithFunctionOperator"] =
Function::New(env, CallWithFunctionOperator);
result["plain"] = exports;

exports = Object::New(env);
exports["emptyConstructor"] = Function::New(env, EmptyConstructor);
exports["voidCallback"] = Function::New<VoidCallback>(env, "voidCallback");
exports["valueCallback"] =
Function::New<ValueCallback>(env, std::string("valueCallback"));
Expand All @@ -133,6 +241,9 @@ Object InitFunction(Env env) {
Function::New<ValueCallbackWithData>(env, nullptr, &testData);
exports["callWithArgs"] = Function::New<CallWithArgs>(env);
exports["callWithVector"] = Function::New<CallWithVector>(env);
exports["callWithCStyleArray"] = Function::New<CallWithCStyleArray>(env);
exports["callWithReceiverAndCStyleArray"] =
Function::New<CallWithReceiverAndCStyleArray>(env);
exports["callWithReceiverAndArgs"] =
Function::New<CallWithReceiverAndArgs>(env);
exports["callWithReceiverAndVector"] =
Expand All @@ -143,7 +254,18 @@ Object InitFunction(Env env) {
Function::New<CallConstructorWithArgs>(env);
exports["callConstructorWithVector"] =
Function::New<CallConstructorWithVector>(env);
exports["callConstructorWithCStyleArray"] =
Function::New<CallConstructorWithCStyleArray>(env);
exports["isConstructCall"] = Function::New<IsConstructCall>(env);
exports["makeCallbackWithArgs"] = Function::New<MakeCallbackWithArgs>(env);
exports["makeCallbackWithVector"] =
Function::New<MakeCallbackWithVector>(env);
exports["makeCallbackWithCStyleArray"] =
Function::New<MakeCallbackWithCStyleArray>(env);
exports["makeCallbackWithInvalidReceiver"] =
Function::New<MakeCallbackWithInvalidReceiver>(env);
exports["callWithFunctionOperator"] =
Function::New<CallWithFunctionOperator>(env);
result["templated"] = exports;
return result;
}
51 changes: 44 additions & 7 deletions test/function.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ test(require(`./build/${buildType}/binding.node`).function.templated);
test(require(`./build/${buildType}/binding_noexcept.node`).function.templated);

function test(binding) {
assert.strictEqual(binding.emptyConstructor(true), true);
assert.strictEqual(binding.emptyConstructor(false), false);

let obj = {};
assert.deepStrictEqual(binding.voidCallback(obj), undefined);
assert.deepStrictEqual(obj, { "foo": "bar" });
Expand All @@ -26,26 +29,50 @@ function test(binding) {
args = [].slice.call(arguments);
}

function makeCallbackTestFunction(receiver, expectedOne, expectedTwo, expectedThree) {
return function callback(one, two, three) {
assert.strictEqual(this, receiver);
assert.strictEqual(one, expectedOne);
assert.strictEqual(two, expectedTwo);
assert.strictEqual(three, expectedThree);
}
}

ret = 4;
assert.equal(binding.callWithArgs(testFunction, 1, 2, 3), 4);
assert.strictEqual(binding.callWithArgs(testFunction, 1, 2, 3), 4);
assert.strictEqual(receiver, undefined);
assert.deepStrictEqual(args, [ 1, 2, 3 ]);

ret = 5;
assert.equal(binding.callWithVector(testFunction, 2, 3, 4), 5);
assert.strictEqual(binding.callWithVector(testFunction, 2, 3, 4), 5);
assert.strictEqual(receiver, undefined);
assert.deepStrictEqual(args, [ 2, 3, 4 ]);

ret = 6;
assert.equal(binding.callWithReceiverAndArgs(testFunction, obj, 3, 4, 5), 6);
assert.strictEqual(binding.callWithReceiverAndArgs(testFunction, obj, 3, 4, 5), 6);
assert.deepStrictEqual(receiver, obj);
assert.deepStrictEqual(args, [ 3, 4, 5 ]);

ret = 7;
assert.equal(binding.callWithReceiverAndVector(testFunction, obj, 4, 5, 6), 7);
assert.strictEqual(binding.callWithReceiverAndVector(testFunction, obj, 4, 5, 6), 7);
assert.deepStrictEqual(receiver, obj);
assert.deepStrictEqual(args, [ 4, 5, 6 ]);

ret = 8;
assert.strictEqual(binding.callWithCStyleArray(testFunction, 5, 6, 7), ret);
assert.deepStrictEqual(receiver, undefined);
assert.deepStrictEqual(args, [ 5, 6, 7 ]);

ret = 9;
assert.strictEqual(binding.callWithReceiverAndCStyleArray(testFunction, obj, 6, 7, 8), ret);
assert.deepStrictEqual(receiver, obj);
assert.deepStrictEqual(args, [ 6, 7, 8 ]);

ret = 10;
assert.strictEqual(binding.callWithFunctionOperator(testFunction, 7, 8, 9), ret);
assert.strictEqual(receiver, undefined);
assert.deepStrictEqual(args, [ 7, 8, 9 ]);

assert.throws(() => {
binding.callWithInvalidReceiver();
}, /Invalid (pointer passed as )?argument/);
Expand All @@ -58,20 +85,30 @@ function test(binding) {
assert(obj instanceof testConstructor);
assert.deepStrictEqual(args, [ 6, 7, 8 ]);

obj = binding.callConstructorWithCStyleArray(testConstructor, 7, 8, 9);
assert(obj instanceof testConstructor);
assert.deepStrictEqual(args, [ 7, 8, 9 ]);

obj = {};
assert.deepStrictEqual(binding.voidCallbackWithData(obj), undefined);
assert.deepStrictEqual(obj, { "foo": "bar", "data": 1 });

assert.deepStrictEqual(binding.valueCallbackWithData(), { "foo": "bar", "data": 1 });

assert.equal(binding.voidCallback.name, 'voidCallback');
assert.equal(binding.valueCallback.name, 'valueCallback');
assert.strictEqual(binding.voidCallback.name, 'voidCallback');
assert.strictEqual(binding.valueCallback.name, 'valueCallback');

let testConstructCall = undefined;
binding.isConstructCall((result) => { testConstructCall = result; });
assert.ok(!testConstructCall);
new binding.isConstructCall((result) => { testConstructCall = result; });
assert.ok(testConstructCall);

// TODO: Function::MakeCallback tests
obj = {};
binding.makeCallbackWithArgs(makeCallbackTestFunction(obj, "1", "2", "3"), obj, "1", "2", "3");
binding.makeCallbackWithVector(makeCallbackTestFunction(obj, 4, 5, 6), obj, 4, 5, 6);
binding.makeCallbackWithCStyleArray(makeCallbackTestFunction(obj, 7, 8, 9), obj, 7, 8, 9);
assert.throws(() => {
binding.makeCallbackWithInvalidReceiver(() => {});
});
}

0 comments on commit 0bf9127

Please sign in to comment.