Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function tests #928

Merged
merged 11 commits into from
Mar 15, 2021
Merged
133 changes: 131 additions & 2 deletions test/function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ namespace {

int testData = 1;

Boolean EmptyConstructor(const CallbackInfo& info) {
JoseExposito marked this conversation as resolved.
Show resolved Hide resolved
auto env = info.Env();
Function function = Function();
return Boolean::New(env, function.IsEmpty());
}

Boolean NonEmptyConstructor(const CallbackInfo& info) {
auto env = info.Env();
Function 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 +57,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 +72,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 +130,82 @@ 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["nonEmptyConstructor"] = Function::New(env, NonEmptyConstructor);
exports["voidCallback"] = Function::New(env, VoidCallback, "voidCallback");
exports["valueCallback"] = Function::New(env, ValueCallback, std::string("valueCallback"));
exports["voidCallbackWithData"] =
Expand All @@ -115,15 +214,31 @@ 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["nonEmptyConstructor"] = Function::New(env, NonEmptyConstructor);
exports["voidCallback"] = Function::New<VoidCallback>(env, "voidCallback");
exports["valueCallback"] =
Function::New<ValueCallback>(env, std::string("valueCallback"));
Expand All @@ -133,6 +248,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 +261,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);
assert.strictEqual(binding.nonEmptyConstructor(), true);

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(() => {});
});
}