test: checks on napi factory wrap’s finalization

Fixes: https://github.com/nodejs/node/issues/22396
PR-URL: https://github.com/nodejs/node/pull/22612
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
This commit is contained in:
Lucas Woo 2018-08-31 11:57:33 +08:00 committed by Gabriel Schulhof
parent cf0e881b33
commit 1cee085367
5 changed files with 41 additions and 14 deletions

View File

@ -15,9 +15,14 @@ napi_value CreateObject(napi_env env, napi_callback_info info) {
napi_value Init(napi_env env, napi_value exports) { napi_value Init(napi_env env, napi_value exports) {
NAPI_CALL(env, MyObject::Init(env)); NAPI_CALL(env, MyObject::Init(env));
NAPI_CALL(env, napi_property_descriptor descriptors[] = {
// NOLINTNEXTLINE (readability/null_usage) DECLARE_NAPI_GETTER("finalizeCount", MyObject::GetFinalizeCount),
napi_create_function(env, "exports", -1, CreateObject, NULL, &exports)); DECLARE_NAPI_PROPERTY("createObject", CreateObject),
};
NAPI_CALL(env, napi_define_properties(
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
return exports; return exports;
} }

View File

@ -1,6 +1,8 @@
#include "myobject.h" #include "myobject.h"
#include "../common.h" #include "../common.h"
static int finalize_count = 0;
MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {}
MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); }
@ -8,10 +10,17 @@ MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); }
void MyObject::Destructor(napi_env env, void MyObject::Destructor(napi_env env,
void* nativeObject, void* nativeObject,
void* /*finalize_hint*/) { void* /*finalize_hint*/) {
++finalize_count;
MyObject* obj = static_cast<MyObject*>(nativeObject); MyObject* obj = static_cast<MyObject*>(nativeObject);
delete obj; delete obj;
} }
napi_value MyObject::GetFinalizeCount(napi_env env, napi_callback_info info) {
napi_value result;
NAPI_CALL(env, napi_create_int32(env, finalize_count, &result));
return result;
}
napi_ref MyObject::constructor; napi_ref MyObject::constructor;
napi_status MyObject::Init(napi_env env) { napi_status MyObject::Init(napi_env env) {

View File

@ -7,6 +7,7 @@ class MyObject {
public: public:
static napi_status Init(napi_env env); static napi_status Init(napi_env env);
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); static void Destructor(napi_env env, void* nativeObject, void* finalize_hint);
static napi_value GetFinalizeCount(napi_env env, napi_callback_info info);
static napi_status NewInstance(napi_env env, static napi_status NewInstance(napi_env env,
napi_value arg, napi_value arg,
napi_value* instance); napi_value* instance);

View File

@ -1,14 +1,25 @@
'use strict'; 'use strict';
// Flags: --expose-gc
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const createObject = require(`./build/${common.buildType}/binding`); const test = require(`./build/${common.buildType}/binding`);
const obj = createObject(10); assert.strictEqual(test.finalizeCount, 0);
assert.strictEqual(obj.plusOne(), 11); (() => {
assert.strictEqual(obj.plusOne(), 12); const obj = test.createObject(10);
assert.strictEqual(obj.plusOne(), 13); assert.strictEqual(obj.plusOne(), 11);
assert.strictEqual(obj.plusOne(), 12);
assert.strictEqual(obj.plusOne(), 13);
})();
global.gc();
assert.strictEqual(test.finalizeCount, 1);
const obj2 = createObject(20); (() => {
assert.strictEqual(obj2.plusOne(), 21); const obj2 = test.createObject(20);
assert.strictEqual(obj2.plusOne(), 22); assert.strictEqual(obj2.plusOne(), 21);
assert.strictEqual(obj2.plusOne(), 23); assert.strictEqual(obj2.plusOne(), 22);
assert.strictEqual(obj2.plusOne(), 23);
})();
global.gc();
assert.strictEqual(test.finalizeCount, 2);

View File

@ -6,11 +6,12 @@ const assert = require('assert');
const addon = require(`./build/${common.buildType}/binding`); const addon = require(`./build/${common.buildType}/binding`);
let obj1 = addon.createObject(10); let obj1 = addon.createObject(10);
const obj2 = addon.createObject(20); let obj2 = addon.createObject(20);
const result = addon.add(obj1, obj2); const result = addon.add(obj1, obj2);
assert.strictEqual(result, 30); assert.strictEqual(result, 30);
// Make sure the native destructor gets called. // Make sure the native destructor gets called.
obj1 = null; obj1 = null;
obj2 = null;
global.gc(); global.gc();
assert.strictEqual(addon.finalizeCount(), 1); assert.strictEqual(addon.finalizeCount(), 2);