Skip to content

Commit 83af80c

Browse files
committed
add finalizer_order test
1 parent 61cd1ec commit 83af80c

File tree

4 files changed

+174
-0
lines changed

4 files changed

+174
-0
lines changed

test/binding.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ Object InitEnvMiscellaneous(Env env);
8686
#if defined(NODE_ADDON_API_ENABLE_MAYBE)
8787
Object InitMaybeCheck(Env env);
8888
#endif
89+
Object InitFinalizerOrder(Env env);
8990

9091
Object Init(Env env, Object exports) {
9192
#if (NAPI_VERSION > 5)
@@ -186,6 +187,13 @@ Object Init(Env env, Object exports) {
186187
#if defined(NODE_ADDON_API_ENABLE_MAYBE)
187188
exports.Set("maybe_check", InitMaybeCheck(env));
188189
#endif
190+
191+
exports.Set("finalizer_order", InitFinalizerOrder(env));
192+
193+
exports.Set(
194+
"isExperimental",
195+
Napi::Boolean::New(env, NAPI_VERSION == NAPI_VERSION_EXPERIMENTAL));
196+
189197
return exports;
190198
}
191199

test/binding.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
'error.cc',
3131
'error_handling_for_primitives.cc',
3232
'external.cc',
33+
'finalizer_order.cc',
3334
'function.cc',
3435
'function_reference.cc',
3536
'handlescope.cc',

test/finalizer_order.cc

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include <napi.h>
2+
3+
namespace {
4+
class Test : public Napi::ObjectWrap<Test> {
5+
public:
6+
Test(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Test>(info) {
7+
nogcFinalizerCalled = false;
8+
gcFinalizerCalled = false;
9+
10+
if (info.Length() > 0) {
11+
finalizeCb_ = Napi::Persistent(info[0].As<Napi::Function>());
12+
}
13+
}
14+
15+
static void Initialize(Napi::Env env, Napi::Object exports) {
16+
exports.Set("Test",
17+
DefineClass(env,
18+
"Test",
19+
{
20+
StaticAccessor("isNogcFinalizerCalled",
21+
&IsNogcFinalizerCalled,
22+
nullptr,
23+
napi_default),
24+
StaticAccessor("isGcFinalizerCalled",
25+
&IsGcFinalizerCalled,
26+
nullptr,
27+
napi_default),
28+
}));
29+
}
30+
31+
void Finalize(Napi::NogcEnv /*env*/) { nogcFinalizerCalled = true; }
32+
33+
void Finalize(Napi::Env /*env*/) {
34+
gcFinalizerCalled = true;
35+
if (!finalizeCb_.IsEmpty()) {
36+
finalizeCb_.Call({});
37+
}
38+
}
39+
40+
static Napi::Value IsNogcFinalizerCalled(const Napi::CallbackInfo& info) {
41+
return Napi::Boolean::New(info.Env(), nogcFinalizerCalled);
42+
}
43+
44+
static Napi::Value IsGcFinalizerCalled(const Napi::CallbackInfo& info) {
45+
return Napi::Boolean::New(info.Env(), gcFinalizerCalled);
46+
}
47+
48+
private:
49+
Napi::FunctionReference finalizeCb_;
50+
51+
static bool nogcFinalizerCalled;
52+
static bool gcFinalizerCalled;
53+
};
54+
55+
bool Test::nogcFinalizerCalled = false;
56+
bool Test::gcFinalizerCalled = false;
57+
58+
bool externalNogcFinalizerCalled = false;
59+
bool externalGcFinalizerCalled = false;
60+
61+
Napi::Value CreateExternalNogc(const Napi::CallbackInfo& info) {
62+
externalNogcFinalizerCalled = false;
63+
return Napi::External<int>::New(
64+
info.Env(), new int(1), [](Napi::NogcEnv /*env*/, int* data) {
65+
externalNogcFinalizerCalled = true;
66+
delete data;
67+
});
68+
}
69+
70+
Napi::Value CreateExternalGc(const Napi::CallbackInfo& info) {
71+
externalGcFinalizerCalled = false;
72+
return Napi::External<int>::New(
73+
info.Env(), new int(1), [](Napi::Env /*env*/, int* data) {
74+
externalGcFinalizerCalled = true;
75+
delete data;
76+
});
77+
}
78+
79+
Napi::Value IsExternalNogcFinalizerCalled(const Napi::CallbackInfo& info) {
80+
return Napi::Boolean::New(info.Env(), externalNogcFinalizerCalled);
81+
}
82+
83+
Napi::Value IsExternalGcFinalizerCalled(const Napi::CallbackInfo& info) {
84+
return Napi::Boolean::New(info.Env(), externalGcFinalizerCalled);
85+
}
86+
87+
} // namespace
88+
89+
Napi::Object InitFinalizerOrder(Napi::Env env) {
90+
Napi::Object exports = Napi::Object::New(env);
91+
Test::Initialize(env, exports);
92+
exports["CreateExternalNogc"] = Napi::Function::New(env, CreateExternalNogc);
93+
exports["CreateExternalGc"] = Napi::Function::New(env, CreateExternalGc);
94+
exports["isExternalNogcFinalizerCalled"] =
95+
Napi::Function::New(env, IsExternalNogcFinalizerCalled);
96+
exports["isExternalGcFinalizerCalled"] =
97+
Napi::Function::New(env, IsExternalGcFinalizerCalled);
98+
return exports;
99+
}

test/finalizer_order.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict';
2+
3+
/* eslint-disable no-unused-vars */
4+
5+
const assert = require('assert');
6+
const testUtil = require('./testUtil');
7+
8+
module.exports = require('./common').runTest(test);
9+
10+
function test (binding) {
11+
const { isExperimental } = binding;
12+
13+
let isCallbackCalled = false;
14+
15+
return testUtil.runGCTests([
16+
'Finalizer Order - ObjectWrap',
17+
() => {
18+
let test = new binding.finalizer_order.Test(() => { isCallbackCalled = true; });
19+
test = null;
20+
21+
global.gc();
22+
23+
if (isExperimental) {
24+
assert.strictEqual(binding.finalizer_order.Test.isNogcFinalizerCalled, true, 'Expected nogc finalizer to be called [before ticking]');
25+
assert.strictEqual(binding.finalizer_order.Test.isGcFinalizerCalled, false, 'Expected gc finalizer to not be called [before ticking]');
26+
assert.strictEqual(isCallbackCalled, false, 'Expected callback not be called [before ticking]');
27+
} else {
28+
assert.strictEqual(binding.finalizer_order.Test.isNogcFinalizerCalled, false, 'Expected nogc finalizer to not be called [before ticking]');
29+
assert.strictEqual(binding.finalizer_order.Test.isGcFinalizerCalled, false, 'Expected gc finalizer to not be called [before ticking]');
30+
assert.strictEqual(isCallbackCalled, false, 'Expected callback not be called [before ticking]');
31+
}
32+
},
33+
() => {
34+
assert.strictEqual(binding.finalizer_order.Test.isNogcFinalizerCalled, true, 'Expected nogc finalizer to be called [after ticking]');
35+
assert.strictEqual(binding.finalizer_order.Test.isGcFinalizerCalled, true, 'Expected gc finalizer to be called [after ticking]');
36+
assert.strictEqual(isCallbackCalled, true, 'Expected callback to be called [after ticking]');
37+
},
38+
39+
'Finalizer Order - External with Nogc Finalizer',
40+
() => {
41+
let ext = new binding.finalizer_order.CreateExternalNogc();
42+
ext = null;
43+
global.gc();
44+
45+
if (isExperimental) {
46+
assert.strictEqual(binding.finalizer_order.isExternalNogcFinalizerCalled(), true, 'Expected External nogc finalizer to be called [before ticking]');
47+
} else {
48+
assert.strictEqual(binding.finalizer_order.isExternalNogcFinalizerCalled(), false, 'Expected External nogc finalizer to not be called [before ticking]');
49+
}
50+
},
51+
() => {
52+
assert.strictEqual(binding.finalizer_order.isExternalNogcFinalizerCalled(), true, 'Expected External nogc finalizer to be called [after ticking]');
53+
},
54+
55+
'Finalizer Order - External with Gc Finalizer',
56+
() => {
57+
let ext = new binding.finalizer_order.CreateExternalGc();
58+
ext = null;
59+
global.gc();
60+
assert.strictEqual(binding.finalizer_order.isExternalGcFinalizerCalled(), false, 'Expected External gc finalizer to not be called [before ticking]');
61+
},
62+
() => {
63+
assert.strictEqual(binding.finalizer_order.isExternalGcFinalizerCalled(), true, 'Expected External gc finalizer to be called [after ticking]');
64+
}
65+
]);
66+
}

0 commit comments

Comments
 (0)