Skip to content

Commit

Permalink
add finalizer_order test
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinEady committed Jun 15, 2024
1 parent 61cd1ec commit 83af80c
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 0 deletions.
8 changes: 8 additions & 0 deletions test/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Object InitEnvMiscellaneous(Env env);
#if defined(NODE_ADDON_API_ENABLE_MAYBE)
Object InitMaybeCheck(Env env);
#endif
Object InitFinalizerOrder(Env env);

Object Init(Env env, Object exports) {
#if (NAPI_VERSION > 5)
Expand Down Expand Up @@ -186,6 +187,13 @@ Object Init(Env env, Object exports) {
#if defined(NODE_ADDON_API_ENABLE_MAYBE)
exports.Set("maybe_check", InitMaybeCheck(env));
#endif

exports.Set("finalizer_order", InitFinalizerOrder(env));

exports.Set(
"isExperimental",
Napi::Boolean::New(env, NAPI_VERSION == NAPI_VERSION_EXPERIMENTAL));

return exports;
}

Expand Down
1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
'error.cc',
'error_handling_for_primitives.cc',
'external.cc',
'finalizer_order.cc',
'function.cc',
'function_reference.cc',
'handlescope.cc',
Expand Down
99 changes: 99 additions & 0 deletions test/finalizer_order.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include <napi.h>

namespace {
class Test : public Napi::ObjectWrap<Test> {
public:
Test(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Test>(info) {
nogcFinalizerCalled = false;
gcFinalizerCalled = false;

if (info.Length() > 0) {
finalizeCb_ = Napi::Persistent(info[0].As<Napi::Function>());
}
}

static void Initialize(Napi::Env env, Napi::Object exports) {
exports.Set("Test",
DefineClass(env,
"Test",
{
StaticAccessor("isNogcFinalizerCalled",
&IsNogcFinalizerCalled,
nullptr,
napi_default),
StaticAccessor("isGcFinalizerCalled",
&IsGcFinalizerCalled,
nullptr,
napi_default),
}));
}

void Finalize(Napi::NogcEnv /*env*/) { nogcFinalizerCalled = true; }

void Finalize(Napi::Env /*env*/) {
gcFinalizerCalled = true;
if (!finalizeCb_.IsEmpty()) {
finalizeCb_.Call({});
}
}

static Napi::Value IsNogcFinalizerCalled(const Napi::CallbackInfo& info) {
return Napi::Boolean::New(info.Env(), nogcFinalizerCalled);
}

static Napi::Value IsGcFinalizerCalled(const Napi::CallbackInfo& info) {
return Napi::Boolean::New(info.Env(), gcFinalizerCalled);
}

private:
Napi::FunctionReference finalizeCb_;

static bool nogcFinalizerCalled;
static bool gcFinalizerCalled;
};

bool Test::nogcFinalizerCalled = false;
bool Test::gcFinalizerCalled = false;

bool externalNogcFinalizerCalled = false;
bool externalGcFinalizerCalled = false;

Napi::Value CreateExternalNogc(const Napi::CallbackInfo& info) {
externalNogcFinalizerCalled = false;
return Napi::External<int>::New(
info.Env(), new int(1), [](Napi::NogcEnv /*env*/, int* data) {
externalNogcFinalizerCalled = true;
delete data;
});
}

Napi::Value CreateExternalGc(const Napi::CallbackInfo& info) {
externalGcFinalizerCalled = false;
return Napi::External<int>::New(
info.Env(), new int(1), [](Napi::Env /*env*/, int* data) {
externalGcFinalizerCalled = true;
delete data;
});
}

Napi::Value IsExternalNogcFinalizerCalled(const Napi::CallbackInfo& info) {
return Napi::Boolean::New(info.Env(), externalNogcFinalizerCalled);
}

Napi::Value IsExternalGcFinalizerCalled(const Napi::CallbackInfo& info) {
return Napi::Boolean::New(info.Env(), externalGcFinalizerCalled);
}

} // namespace

Napi::Object InitFinalizerOrder(Napi::Env env) {
Napi::Object exports = Napi::Object::New(env);
Test::Initialize(env, exports);
exports["CreateExternalNogc"] = Napi::Function::New(env, CreateExternalNogc);
exports["CreateExternalGc"] = Napi::Function::New(env, CreateExternalGc);
exports["isExternalNogcFinalizerCalled"] =
Napi::Function::New(env, IsExternalNogcFinalizerCalled);
exports["isExternalGcFinalizerCalled"] =
Napi::Function::New(env, IsExternalGcFinalizerCalled);
return exports;
}
66 changes: 66 additions & 0 deletions test/finalizer_order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use strict';

/* eslint-disable no-unused-vars */

const assert = require('assert');
const testUtil = require('./testUtil');

module.exports = require('./common').runTest(test);

function test (binding) {
const { isExperimental } = binding;

let isCallbackCalled = false;

return testUtil.runGCTests([
'Finalizer Order - ObjectWrap',
() => {
let test = new binding.finalizer_order.Test(() => { isCallbackCalled = true; });
test = null;

global.gc();

if (isExperimental) {
assert.strictEqual(binding.finalizer_order.Test.isNogcFinalizerCalled, true, 'Expected nogc finalizer to be called [before ticking]');
assert.strictEqual(binding.finalizer_order.Test.isGcFinalizerCalled, false, 'Expected gc finalizer to not be called [before ticking]');
assert.strictEqual(isCallbackCalled, false, 'Expected callback not be called [before ticking]');
} else {
assert.strictEqual(binding.finalizer_order.Test.isNogcFinalizerCalled, false, 'Expected nogc finalizer to not be called [before ticking]');
assert.strictEqual(binding.finalizer_order.Test.isGcFinalizerCalled, false, 'Expected gc finalizer to not be called [before ticking]');
assert.strictEqual(isCallbackCalled, false, 'Expected callback not be called [before ticking]');
}
},
() => {
assert.strictEqual(binding.finalizer_order.Test.isNogcFinalizerCalled, true, 'Expected nogc finalizer to be called [after ticking]');
assert.strictEqual(binding.finalizer_order.Test.isGcFinalizerCalled, true, 'Expected gc finalizer to be called [after ticking]');
assert.strictEqual(isCallbackCalled, true, 'Expected callback to be called [after ticking]');
},

'Finalizer Order - External with Nogc Finalizer',
() => {
let ext = new binding.finalizer_order.CreateExternalNogc();
ext = null;
global.gc();

if (isExperimental) {
assert.strictEqual(binding.finalizer_order.isExternalNogcFinalizerCalled(), true, 'Expected External nogc finalizer to be called [before ticking]');
} else {
assert.strictEqual(binding.finalizer_order.isExternalNogcFinalizerCalled(), false, 'Expected External nogc finalizer to not be called [before ticking]');
}
},
() => {
assert.strictEqual(binding.finalizer_order.isExternalNogcFinalizerCalled(), true, 'Expected External nogc finalizer to be called [after ticking]');
},

'Finalizer Order - External with Gc Finalizer',
() => {
let ext = new binding.finalizer_order.CreateExternalGc();
ext = null;
global.gc();
assert.strictEqual(binding.finalizer_order.isExternalGcFinalizerCalled(), false, 'Expected External gc finalizer to not be called [before ticking]');
},
() => {
assert.strictEqual(binding.finalizer_order.isExternalGcFinalizerCalled(), true, 'Expected External gc finalizer to be called [after ticking]');
}
]);
}

0 comments on commit 83af80c

Please sign in to comment.