Skip to content

Commit 04b26a9

Browse files
JckXiamhdawson
authored andcommitted
test: add first set of func Ref tests
PR-URL: #1035 Reviewed-By: Michael Dawson <[email protected] Reviewed-By: Kevin Eady <[email protected]>
1 parent 4663453 commit 04b26a9

File tree

2 files changed

+314
-6
lines changed

2 files changed

+314
-6
lines changed

test/function_reference.cc

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,163 @@
33

44
using namespace Napi;
55

6+
class FuncRefObject : public Napi::ObjectWrap<FuncRefObject> {
7+
public:
8+
FuncRefObject(const Napi::CallbackInfo& info)
9+
: Napi::ObjectWrap<FuncRefObject>(info) {
10+
Napi::Env env = info.Env();
11+
int argLen = info.Length();
12+
if (argLen <= 0 || !info[0].IsNumber()) {
13+
Napi::TypeError::New(env, "First param should be a number")
14+
.ThrowAsJavaScriptException();
15+
return;
16+
}
17+
Napi::Number value = info[0].As<Napi::Number>();
18+
this->_value = value.Int32Value();
19+
}
20+
21+
Napi::Value GetValue(const Napi::CallbackInfo& info) {
22+
int value = this->_value;
23+
return Napi::Number::New(info.Env(), value);
24+
}
25+
26+
private:
27+
int _value;
28+
};
29+
630
namespace {
31+
32+
Value ConstructRefFromExisitingRef(const CallbackInfo& info) {
33+
HandleScope scope(info.Env());
34+
FunctionReference ref;
35+
FunctionReference movedRef;
36+
ref.Reset(info[0].As<Function>());
37+
movedRef = std::move(ref);
38+
39+
return MaybeUnwrap(movedRef({}));
40+
}
41+
42+
Value CallWithVectorArgs(const CallbackInfo& info) {
43+
HandleScope scope(info.Env());
44+
std::vector<napi_value> newVec;
45+
FunctionReference ref;
46+
ref.Reset(info[0].As<Function>());
47+
48+
for (int i = 1; i < (int)info.Length(); i++) {
49+
newVec.push_back(info[i]);
50+
}
51+
return MaybeUnwrap(ref.Call(newVec));
52+
}
53+
54+
Value CallWithInitList(const CallbackInfo& info) {
55+
HandleScope scope(info.Env());
56+
FunctionReference ref;
57+
ref.Reset(info[0].As<Function>());
58+
59+
return MaybeUnwrap(ref.Call({info[1], info[2], info[3]}));
60+
}
61+
62+
Value CallWithRecvInitList(const CallbackInfo& info) {
63+
HandleScope scope(info.Env());
64+
FunctionReference ref;
65+
ref.Reset(info[0].As<Function>());
66+
67+
return MaybeUnwrap(ref.Call(info[1], {info[2], info[3], info[4]}));
68+
}
69+
70+
Value CallWithRecvVector(const CallbackInfo& info) {
71+
HandleScope scope(info.Env());
72+
FunctionReference ref;
73+
std::vector<napi_value> newVec;
74+
ref.Reset(info[0].As<Function>());
75+
76+
for (int i = 2; i < (int)info.Length(); i++) {
77+
newVec.push_back(info[i]);
78+
}
79+
return MaybeUnwrap(ref.Call(info[1], newVec));
80+
}
81+
82+
Value CallWithRecvArgc(const CallbackInfo& info) {
83+
HandleScope scope(info.Env());
84+
FunctionReference ref;
85+
int argLength = info.Length() - 2;
86+
napi_value* args = new napi_value[argLength];
87+
ref.Reset(info[0].As<Function>());
88+
89+
int argIdx = 0;
90+
for (int i = 2; i < (int)info.Length(); i++, argIdx++) {
91+
args[argIdx] = info[i];
92+
}
93+
94+
return MaybeUnwrap(ref.Call(info[1], argLength, args));
95+
}
96+
97+
Value MakeAsyncCallbackWithInitList(const Napi::CallbackInfo& info) {
98+
Napi::FunctionReference ref;
99+
ref.Reset(info[0].As<Function>());
100+
101+
Napi::AsyncContext context(info.Env(), "func_ref_resources", {});
102+
103+
return MaybeUnwrap(
104+
ref.MakeCallback(Napi::Object::New(info.Env()), {}, context));
105+
}
106+
107+
Value MakeAsyncCallbackWithVector(const Napi::CallbackInfo& info) {
108+
Napi::FunctionReference ref;
109+
ref.Reset(info[0].As<Function>());
110+
std::vector<napi_value> newVec;
111+
Napi::AsyncContext context(info.Env(), "func_ref_resources", {});
112+
113+
for (int i = 1; i < (int)info.Length(); i++) {
114+
newVec.push_back(info[i]);
115+
}
116+
117+
return MaybeUnwrap(
118+
ref.MakeCallback(Napi::Object::New(info.Env()), newVec, context));
119+
}
120+
121+
Value MakeAsyncCallbackWithArgv(const Napi::CallbackInfo& info) {
122+
Napi::FunctionReference ref;
123+
ref.Reset(info[0].As<Function>());
124+
int argLength = info.Length() - 1;
125+
napi_value* args = new napi_value[argLength];
126+
127+
int argIdx = 0;
128+
for (int i = 1; i < (int)info.Length(); i++, argIdx++) {
129+
args[argIdx] = info[i];
130+
}
131+
132+
Napi::AsyncContext context(info.Env(), "func_ref_resources", {});
133+
return MaybeUnwrap(ref.MakeCallback(
134+
Napi::Object::New(info.Env()), argLength, args, context));
135+
}
136+
137+
Value CreateFunctionReferenceUsingNew(const Napi::CallbackInfo& info) {
138+
Napi::Function func = ObjectWrap<FuncRefObject>::DefineClass(
139+
info.Env(),
140+
"MyObject",
141+
{ObjectWrap<FuncRefObject>::InstanceMethod("getValue",
142+
&FuncRefObject::GetValue)});
143+
Napi::FunctionReference* constructor = new Napi::FunctionReference();
144+
*constructor = Napi::Persistent(func);
145+
146+
return MaybeUnwrapOr(constructor->New({info[0].As<Number>()}), Object());
147+
}
148+
149+
Value CreateFunctionReferenceUsingNewVec(const Napi::CallbackInfo& info) {
150+
Napi::Function func = ObjectWrap<FuncRefObject>::DefineClass(
151+
info.Env(),
152+
"MyObject",
153+
{ObjectWrap<FuncRefObject>::InstanceMethod("getValue",
154+
&FuncRefObject::GetValue)});
155+
Napi::FunctionReference* constructor = new Napi::FunctionReference();
156+
*constructor = Napi::Persistent(func);
157+
std::vector<napi_value> newVec;
158+
newVec.push_back(info[0]);
159+
160+
return MaybeUnwrapOr(constructor->New(newVec), Object());
161+
}
162+
7163
Value Call(const CallbackInfo& info) {
8164
HandleScope scope(info.Env());
9165
FunctionReference ref;
@@ -23,7 +179,22 @@ Value Construct(const CallbackInfo& info) {
23179

24180
Object InitFunctionReference(Env env) {
25181
Object exports = Object::New(env);
26-
182+
exports["CreateFuncRefWithNew"] =
183+
Function::New(env, CreateFunctionReferenceUsingNew);
184+
exports["CreateFuncRefWithNewVec"] =
185+
Function::New(env, CreateFunctionReferenceUsingNewVec);
186+
exports["CallWithRecvArgc"] = Function::New(env, CallWithRecvArgc);
187+
exports["CallWithRecvVector"] = Function::New(env, CallWithRecvVector);
188+
exports["CallWithRecvInitList"] = Function::New(env, CallWithRecvInitList);
189+
exports["CallWithInitList"] = Function::New(env, CallWithInitList);
190+
exports["CallWithVec"] = Function::New(env, CallWithVectorArgs);
191+
exports["ConstructWithMove"] =
192+
Function::New(env, ConstructRefFromExisitingRef);
193+
exports["AsyncCallWithInitList"] =
194+
Function::New(env, MakeAsyncCallbackWithInitList);
195+
exports["AsyncCallWithVector"] =
196+
Function::New(env, MakeAsyncCallbackWithVector);
197+
exports["AsyncCallWithArgv"] = Function::New(env, MakeAsyncCallbackWithArgv);
27198
exports["call"] = Function::New(env, Call);
28199
exports["construct"] = Function::New(env, Construct);
29200

test/function_reference.js

Lines changed: 142 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,157 @@
11
'use strict';
22

33
const assert = require('assert');
4+
const asyncHook = require('async_hooks');
45

5-
module.exports = require('./common').runTest(binding => {
6-
test(binding.functionreference);
6+
module.exports = require('./common').runTest(async (binding) => {
7+
await test(binding.functionreference);
78
});
89

9-
function test(binding) {
10+
function installAsyncHook () {
11+
let id;
12+
let destroyed;
13+
let hook;
14+
const events = [];
15+
return new Promise((resolve, reject) => {
16+
const interval = setInterval(() => {
17+
if (destroyed) {
18+
hook.disable();
19+
clearInterval(interval);
20+
resolve(events);
21+
}
22+
}, 10);
23+
24+
hook = asyncHook
25+
.createHook({
26+
init (asyncId, type, triggerAsyncId, resource) {
27+
if (id === undefined && type === 'func_ref_resources') {
28+
id = asyncId;
29+
events.push({ eventName: 'init', type, triggerAsyncId, resource });
30+
}
31+
},
32+
before (asyncId) {
33+
if (asyncId === id) {
34+
events.push({ eventName: 'before' });
35+
}
36+
},
37+
after (asyncId) {
38+
if (asyncId === id) {
39+
events.push({ eventName: 'after' });
40+
}
41+
},
42+
destroy (asyncId) {
43+
if (asyncId === id) {
44+
events.push({ eventName: 'destroy' });
45+
destroyed = true;
46+
}
47+
}
48+
})
49+
.enable();
50+
});
51+
}
52+
53+
function canConstructRefFromExistingRef (binding) {
54+
const testFunc = () => 240;
55+
assert(binding.ConstructWithMove(testFunc) === 240);
56+
}
57+
58+
function canCallFunctionWithDifferentOverloads (binding) {
59+
let outsideRef = {};
60+
const testFunc = (a, b) => a * a - b * b;
61+
const testFuncB = (a, b, c) => a + b - c * c;
62+
const testFuncC = (a, b, c) => {
63+
outsideRef.a = a;
64+
outsideRef.b = b;
65+
outsideRef.c = c;
66+
};
67+
const testFuncD = (a, b, c, d) => {
68+
outsideRef.result = a + b * c - d;
69+
return outsideRef.result;
70+
};
71+
72+
assert(binding.CallWithVec(testFunc, 5, 4) === testFunc(5, 4));
73+
assert(binding.CallWithInitList(testFuncB, 2, 4, 5) === testFuncB(2, 4, 5));
74+
75+
binding.CallWithRecvVector(testFuncC, outsideRef, 1, 2, 4);
76+
assert(outsideRef.a === 1 && outsideRef.b === 2 && outsideRef.c === 4);
77+
78+
outsideRef = {};
79+
binding.CallWithRecvInitList(testFuncC, outsideRef, 1, 2, 4);
80+
assert(outsideRef.a === 1 && outsideRef.b === 2 && outsideRef.c === 4);
81+
82+
outsideRef = {};
83+
binding.CallWithRecvArgc(testFuncD, outsideRef, 2, 4, 5, 6);
84+
assert(outsideRef.result === testFuncD(2, 4, 5, 6));
85+
}
86+
87+
async function canCallAsyncFunctionWithDifferentOverloads (binding) {
88+
const testFunc = () => 2100;
89+
const testFuncB = (a, b, c, d) => a + b + c + d;
90+
let hook = installAsyncHook();
91+
binding.AsyncCallWithInitList(testFunc);
92+
let triggerAsyncId = asyncHook.executionAsyncId();
93+
let res = await hook;
94+
assert.deepStrictEqual(res, [
95+
{
96+
eventName: 'init',
97+
type: 'func_ref_resources',
98+
triggerAsyncId: triggerAsyncId,
99+
resource: {}
100+
},
101+
{ eventName: 'before' },
102+
{ eventName: 'after' },
103+
{ eventName: 'destroy' }
104+
]);
105+
106+
hook = installAsyncHook();
107+
triggerAsyncId = asyncHook.executionAsyncId();
108+
assert(
109+
binding.AsyncCallWithVector(testFuncB, 2, 4, 5, 6) === testFuncB(2, 4, 5, 6)
110+
);
111+
res = await hook;
112+
assert.deepStrictEqual(res, [
113+
{
114+
eventName: 'init',
115+
type: 'func_ref_resources',
116+
triggerAsyncId: triggerAsyncId,
117+
resource: {}
118+
},
119+
{ eventName: 'before' },
120+
{ eventName: 'after' },
121+
{ eventName: 'destroy' }
122+
]);
123+
124+
hook = installAsyncHook();
125+
triggerAsyncId = asyncHook.executionAsyncId();
126+
assert(
127+
binding.AsyncCallWithArgv(testFuncB, 2, 4, 5, 6) === testFuncB(2, 4, 5, 6)
128+
);
129+
}
130+
async function test (binding) {
10131
const e = new Error('foobar');
11-
const functionMayThrow = () => { throw e; };
12-
const classMayThrow = class { constructor() { throw e; } };
132+
const functionMayThrow = () => {
133+
throw e;
134+
};
135+
const classMayThrow = class {
136+
constructor () {
137+
throw e;
138+
}
139+
};
140+
141+
const newRef = binding.CreateFuncRefWithNew(120);
142+
assert(newRef.getValue() === 120);
143+
144+
const newRefWithVecArg = binding.CreateFuncRefWithNewVec(80);
145+
assert(newRefWithVecArg.getValue() === 80);
13146

14147
assert.throws(() => {
15148
binding.call(functionMayThrow);
16149
}, /foobar/);
17150
assert.throws(() => {
18151
binding.construct(classMayThrow);
19152
}, /foobar/);
153+
154+
canConstructRefFromExistingRef(binding);
155+
canCallFunctionWithDifferentOverloads(binding);
156+
await canCallAsyncFunctionWithDifferentOverloads(binding);
20157
}

0 commit comments

Comments
 (0)