aboutsummaryrefslogtreecommitdiff
path: root/test/js-native-api/test_reference/test.js
diff options
context:
space:
mode:
authorGabriel Schulhof <gabriel.schulhof@intel.com>2018-11-17 12:34:54 -0800
committerGabriel Schulhof <gabriel.schulhof@intel.com>2018-12-04 13:58:17 -0800
commit938e11882b96e19b443477571455088baaa054d8 (patch)
treeeb828a60957a2881995ba9a83f44a32a18fbff16 /test/js-native-api/test_reference/test.js
parent83ee137c4565112177f22f2c735b266b22262220 (diff)
downloadandroid-node-v8-938e11882b96e19b443477571455088baaa054d8.tar.gz
android-node-v8-938e11882b96e19b443477571455088baaa054d8.tar.bz2
android-node-v8-938e11882b96e19b443477571455088baaa054d8.zip
test: partition N-API tests
Partition test/addons-napi into test/js-native-api and test/node-api to isolate the Node.js-agnostic portion of the N-API tests from the Node.js-specific portion. PR-URL: https://github.com/nodejs/node/pull/24557 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Diffstat (limited to 'test/js-native-api/test_reference/test.js')
-rw-r--r--test/js-native-api/test_reference/test.js146
1 files changed, 146 insertions, 0 deletions
diff --git a/test/js-native-api/test_reference/test.js b/test/js-native-api/test_reference/test.js
new file mode 100644
index 0000000000..389ee11d7e
--- /dev/null
+++ b/test/js-native-api/test_reference/test.js
@@ -0,0 +1,146 @@
+'use strict';
+// Flags: --expose-gc
+
+const common = require('../../common');
+const assert = require('assert');
+
+const test_reference = require(`./build/${common.buildType}/test_reference`);
+
+// This test script uses external values with finalizer callbacks
+// in order to track when values get garbage-collected. Each invocation
+// of a finalizer callback increments the finalizeCount property.
+assert.strictEqual(test_reference.finalizeCount, 0);
+
+// Run each test function in sequence,
+// with an async delay and GC call between each.
+function runTests(i, title, tests) {
+ if (tests[i]) {
+ if (typeof tests[i] === 'string') {
+ title = tests[i];
+ runTests(i + 1, title, tests);
+ } else {
+ try {
+ tests[i]();
+ } catch (e) {
+ console.error(`Test failed: ${title}`);
+ throw e;
+ }
+ setImmediate(() => {
+ global.gc();
+ runTests(i + 1, title, tests);
+ });
+ }
+ }
+}
+runTests(0, undefined, [
+
+ 'External value without a finalizer',
+ () => {
+ const value = test_reference.createExternal();
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ assert.strictEqual(typeof value, 'object');
+ test_reference.checkExternal(value);
+ },
+ () => {
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ },
+
+ 'External value with a finalizer',
+ () => {
+ const value = test_reference.createExternalWithFinalize();
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ assert.strictEqual(typeof value, 'object');
+ test_reference.checkExternal(value);
+ },
+ () => {
+ assert.strictEqual(test_reference.finalizeCount, 1);
+ },
+
+ 'Weak reference',
+ () => {
+ const value = test_reference.createExternalWithFinalize();
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ test_reference.createReference(value, 0);
+ assert.strictEqual(test_reference.referenceValue, value);
+ },
+ () => {
+ // Value should be GC'd because there is only a weak ref
+ assert.strictEqual(test_reference.referenceValue, undefined);
+ assert.strictEqual(test_reference.finalizeCount, 1);
+ test_reference.deleteReference();
+ },
+
+ 'Strong reference',
+ () => {
+ const value = test_reference.createExternalWithFinalize();
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ test_reference.createReference(value, 1);
+ assert.strictEqual(test_reference.referenceValue, value);
+ },
+ () => {
+ // Value should NOT be GC'd because there is a strong ref
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ test_reference.deleteReference();
+ },
+ () => {
+ // Value should be GC'd because the strong ref was deleted
+ assert.strictEqual(test_reference.finalizeCount, 1);
+ },
+
+ 'Strong reference, increment then decrement to weak reference',
+ () => {
+ const value = test_reference.createExternalWithFinalize();
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ test_reference.createReference(value, 1);
+ },
+ () => {
+ // Value should NOT be GC'd because there is a strong ref
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ assert.strictEqual(test_reference.incrementRefcount(), 2);
+ },
+ () => {
+ // Value should NOT be GC'd because there is a strong ref
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ assert.strictEqual(test_reference.decrementRefcount(), 1);
+ },
+ () => {
+ // Value should NOT be GC'd because there is a strong ref
+ assert.strictEqual(test_reference.finalizeCount, 0);
+ assert.strictEqual(test_reference.decrementRefcount(), 0);
+ },
+ () => {
+ // Value should be GC'd because the ref is now weak!
+ assert.strictEqual(test_reference.finalizeCount, 1);
+ test_reference.deleteReference();
+ },
+ () => {
+ // Value was already GC'd
+ assert.strictEqual(test_reference.finalizeCount, 1);
+ },
+]);
+
+// This test creates a napi_ref on an object that has
+// been wrapped by napi_wrap and for which the finalizer
+// for the wrap calls napi_delete_ref on that napi_ref.
+//
+// Since both the wrap and the reference use the same
+// object the finalizer for the wrap and reference
+// may run in the same gc and in any order.
+//
+// It does that to validate that napi_delete_ref can be
+// called before the finalizer has been run for the
+// reference (there is a finalizer behind the scenes even
+// though it cannot be passed to napi_create_reference).
+//
+// Since the order is not guarranteed, run the
+// test a number of times maximize the chance that we
+// get a run with the desired order for the test.
+//
+// 1000 reliably recreated the problem without the fix
+// required to ensure delete could be called before
+// the finalizer in manual testing.
+for (let i = 0; i < 1000; i++) {
+ const wrapObject = new Object();
+ test_reference.validateDeleteBeforeFinalize(wrapObject);
+ global.gc();
+}