Skip to content

Commit

Permalink
src: Add ObjectReference test case
Browse files Browse the repository at this point in the history
PR-URL: #212
Reviewed-By: Michael Dawson <[email protected]>
Anisha Rohra authored and mhdawson committed Jul 30, 2018

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 2885c18 commit 4d92a60
Showing 5 changed files with 483 additions and 1 deletion.
2 changes: 2 additions & 0 deletions test/binding.cc
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ Object InitObject(Env env);
Object InitPromise(Env env);
Object InitTypedArray(Env env);
Object InitObjectWrap(Env env);
Object InitObjectReference(Env env);

Object Init(Env env, Object exports) {
exports.Set("arraybuffer", InitArrayBuffer(env));
@@ -39,6 +40,7 @@ Object Init(Env env, Object exports) {
exports.Set("promise", InitPromise(env));
exports.Set("typedarray", InitTypedArray(env));
exports.Set("objectwrap", InitObjectWrap(env));
exports.Set("objectreference", InitObjectReference(env));
return exports;
}

1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
'promise.cc',
'typedarray.cc',
'objectwrap.cc',
'objectreference.cc',
],
'include_dirs': ["<!@(node -p \"require('../').include\")"],
'dependencies': ["<!(node -p \"require('../').gyp\")"],
3 changes: 2 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
@@ -29,7 +29,8 @@ let testModules = [
'object/set_property',
'promise',
'typedarray',
'objectwrap'
'objectwrap',
'objectreference',
];

if (typeof global.gc === 'function') {
218 changes: 218 additions & 0 deletions test/objectreference.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/* ObjectReference can be used to create references to Values that
are not Objects by creating a blank Object and setting Values to
it. Subclasses of Objects can only be set using an ObjectReference
by first casting it as an Object. */

#include "napi.h"

using namespace Napi;

ObjectReference weak;
ObjectReference persistent;
ObjectReference reference;

ObjectReference casted_weak;
ObjectReference casted_persistent;
ObjectReference casted_reference;

// info[0] is the key, which can be either a string or a number.
// info[1] is the value.
// info[2] is a flag that differentiates whether the key is a
// C string or a JavaScript string.
void SetObjects(const CallbackInfo& info) {
Env env = info.Env();
HandleScope scope(env);

weak = Weak(Object::New(env));
weak.SuppressDestruct();

persistent = Persistent(Object::New(env));
persistent.SuppressDestruct();

reference = Reference<Object>::New(Object::New(env), 2);
reference.SuppressDestruct();

if (info[0].IsString()) {
if (info[2].As<String>() == String::New(env, "javascript")) {
weak.Set(info[0].As<String>(), info[1]);
persistent.Set(info[0].As<String>(), info[1]);
reference.Set(info[0].As<String>(), info[1]);
} else {
weak.Set(info[0].As<String>().Utf8Value(), info[1]);
persistent.Set(info[0].As<String>().Utf8Value(), info[1]);
reference.Set(info[0].As<String>().Utf8Value(), info[1]);
}
} else if (info[0].IsNumber()) {
weak.Set(info[0].As<Number>(), info[1]);
persistent.Set(info[0].As<Number>(), info[1]);
reference.Set(info[0].As<Number>(), info[1]);
}
}

void SetCastedObjects(const CallbackInfo& info) {
Env env = info.Env();
HandleScope scope(env);

Array ex = Array::New(env);
ex.Set((uint32_t)0, String::New(env, "hello"));
ex.Set(1, String::New(env, "world"));
ex.Set(2, String::New(env, "!"));

casted_weak = Weak(ex.As<Object>());
casted_weak.SuppressDestruct();

casted_persistent = Persistent(ex.As<Object>());
casted_persistent.SuppressDestruct();

casted_reference = Reference<Object>::New(ex.As<Object>(), 2);
casted_reference.SuppressDestruct();
}

// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Value GetFromValue(const CallbackInfo& info) {
Env env = info.Env();

if (info[0].As<String>() == String::New(env, "weak")) {
if (weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
return weak.Value();
}
} else if (info[0].As<String>() == String::New(env, "persistent")) {
return persistent.Value();
} else {
return reference.Value();
}
}

// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
// info[1] is the key, and it be either a String or a Number.
Value GetFromGetter(const CallbackInfo& info) {
Env env = info.Env();

if (info[0].As<String>() == String::New(env, "weak")) {
if (weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
if (info[1].IsString()) {
return weak.Get(info[1].As<String>().Utf8Value());
} else if (info[1].IsNumber()) {
return weak.Get(info[1].As<Number>().Uint32Value());
}
}
} else if (info[0].As<String>() == String::New(env, "persistent")) {
if (info[1].IsString()) {
return persistent.Get(info[1].As<String>().Utf8Value());
} else if (info[1].IsNumber()) {
return persistent.Get(info[1].As<Number>().Uint32Value());
}
} else {
if (info[0].IsString()) {
return reference.Get(info[0].As<String>().Utf8Value());
} else if (info[0].IsNumber()) {
return reference.Get(info[0].As<Number>().Uint32Value());
}
}

return String::New(env, "Error: Reached end of getter");
}

// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Value GetCastedFromValue(const CallbackInfo& info) {
Env env = info.Env();

if (info[0].As<String>() == String::New(env, "weak")) {
if (casted_weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
return casted_weak.Value();
}
} else if (info[0].As<String>() == String::New(env, "persistent")) {
return casted_persistent.Value();
} else {
return casted_reference.Value();
}
}

// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
// info[1] is the key and it must be a Number.
Value GetCastedFromGetter(const CallbackInfo& info) {
Env env = info.Env();

if (info[0].As<String>() == String::New(env, "weak")) {
if (casted_weak.IsEmpty()) {
return String::New(env, "No Referenced Value");
} else {
return casted_weak.Get(info[1].As<Number>());
}
} else if (info[0].As<String>() == String::New(env, "persistent")) {
return casted_persistent.Get(info[1].As<Number>());
} else {
return casted_reference.Get(info[1].As<Number>());
}
}

// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Number UnrefObjects(const CallbackInfo& info) {
Env env = info.Env();
uint32_t num;

if (info[0].As<String>() == String::New(env, "weak")) {
num = weak.Unref();
} else if (info[0].As<String>() == String::New(env, "persistent")) {
num = persistent.Unref();
} else if (info[0].As<String>() == String::New(env, "references")) {
num = reference.Unref();
} else if (info[0].As<String>() == String::New(env, "casted weak")) {
num = casted_weak.Unref();
} else if (info[0].As<String>() == String::New(env, "casted persistent")) {
num = casted_persistent.Unref();
} else {
num = casted_reference.Unref();
}

return Number::New(env, num);
}

// info[0] is a flag to determine if the weak, persistent, or
// multiple reference ObjectReference is being requested.
Number RefObjects(const CallbackInfo& info) {
Env env = info.Env();
uint32_t num;

if (info[0].As<String>() == String::New(env, "weak")) {
num = weak.Ref();
} else if (info[0].As<String>() == String::New(env, "persistent")) {
num = persistent.Ref();
} else if (info[0].As<String>() == String::New(env, "references")) {
num = reference.Ref();
} else if (info[0].As<String>() == String::New(env, "casted weak")) {
num = casted_weak.Ref();
} else if (info[0].As<String>() == String::New(env, "casted persistent")) {
num = casted_persistent.Ref();
} else {
num = casted_reference.Ref();
}

return Number::New(env, num);
}

Object InitObjectReference(Env env) {
Object exports = Object::New(env);

exports["setCastedObjects"] = Function::New(env, SetCastedObjects);
exports["setObjects"] = Function::New(env, SetObjects);
exports["getCastedFromValue"] = Function::New(env, GetCastedFromValue);
exports["getFromGetter"] = Function::New(env, GetFromGetter);
exports["getCastedFromGetter"] = Function::New(env, GetCastedFromGetter);
exports["getFromValue"] = Function::New(env, GetFromValue);
exports["unrefObjects"] = Function::New(env, UnrefObjects);
exports["refObjects"] = Function::New(env, RefObjects);

return exports;
}
260 changes: 260 additions & 0 deletions test/objectreference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
/*
* First tests are for setting and getting the ObjectReference on the
* casted Array as Object. Then the tests are for the ObjectReference
* to an empty Object. They test setting the ObjectReference with a C
* string, a JavaScript string, and a JavaScript Number as the keys.
* Then getting the value of those keys through the Reference function
* Value() and through the ObjectReference getters. Finally, they test
* Unref() and Ref() to determine if the reference count is as
* expected and errors are thrown when expected.
*/

'use strict';
const buildType = process.config.target_defaults.default_configuration;
const assert = require('assert');
const testUtil = require('./testUtil');

test(require(`./build/${buildType}/binding.node`));
test(require(`./build/${buildType}/binding_noexcept.node`));

function test(binding) {
function testCastedEqual(testToCompare) {
var compare_test = ["hello", "world", "!"];
if (testToCompare instanceof Array) {
assert.deepEqual(compare_test, testToCompare);
} else if (testToCompare instanceof String) {
assert.deepEqual("No Referenced Value", testToCompare);
} else {
assert.fail();
}
}

testUtil.runGCTests([
'Weak Casted Array',
() => {
binding.objectreference.setCastedObjects();
var test = binding.objectreference.getCastedFromValue("weak");
var test2 = new Array();
test2[0] = binding.objectreference.getCastedFromGetter("weak", 0);
test2[1] = binding.objectreference.getCastedFromGetter("weak", 1);
test2[2] = binding.objectreference.getCastedFromGetter("weak", 2);

testCastedEqual(test);
testCastedEqual(test2);
},

'Persistent Casted Array',
() => {
binding.objectreference.setCastedObjects();
const test = binding.objectreference.getCastedFromValue("persistent");
const test2 = new Array();
test2[0] = binding.objectreference.getCastedFromGetter("persistent", 0);
test2[1] = binding.objectreference.getCastedFromGetter("persistent", 1);
test2[2] = binding.objectreference.getCastedFromGetter("persistent", 2);

assert.ok(test instanceof Array);
assert.ok(test2 instanceof Array);
testCastedEqual(test);
testCastedEqual(test2);
},

'References Casted Array',
() => {
binding.objectreference.setCastedObjects();
const test = binding.objectreference.getCastedFromValue();
const test2 = new Array();
test2[0] = binding.objectreference.getCastedFromGetter("reference", 0);
test2[1] = binding.objectreference.getCastedFromGetter("reference", 1);
test2[2] = binding.objectreference.getCastedFromGetter("reference", 2);

assert.ok(test instanceof Array);
assert.ok(test2 instanceof Array);
testCastedEqual(test);
testCastedEqual(test2);
},

'Weak',
() => {
binding.objectreference.setObjects("hello", "world");
const test = binding.objectreference.getFromValue("weak");
const test2 = binding.objectreference.getFromGetter("weak", "hello");

assert.deepEqual({ hello: "world"}, test);
assert.equal("world", test2);
assert.equal(test["hello"], test2);
},
() => {
binding.objectreference.setObjects("hello", "world", "javascript");
const test = binding.objectreference.getFromValue("weak");
const test2 = binding.objectreference.getFromValue("weak", "hello");

assert.deepEqual({ hello: "world" }, test);
assert.deepEqual({ hello: "world" }, test2);
assert.equal(test, test2);
},
() => {
binding.objectreference.setObjects(1, "hello world");
const test = binding.objectreference.getFromValue("weak");
const test2 = binding.objectreference.getFromGetter("weak", 1);

assert.deepEqual({ 1: "hello world" }, test);
assert.equal("hello world", test2);
assert.equal(test[1], test2);
},
() => {
binding.objectreference.setObjects(0, "hello");
binding.objectreference.setObjects(1, "world");
const test = binding.objectreference.getFromValue("weak");
const test2 = binding.objectreference.getFromGetter("weak", 0);
const test3 = binding.objectreference.getFromGetter("weak", 1);

assert.deepEqual({ 1: "world" }, test);
assert.equal(undefined, test2);
assert.equal("world", test3);
},
() => {
binding.objectreference.setObjects("hello", "world");
assert.doesNotThrow(
() => {
var rcount = binding.objectreference.refObjects("weak");
assert.equal(rcount, 1);
rcount = binding.objectreference.unrefObjects("weak");
assert.equal(rcount, 0);
},
Error
);
assert.throws(
() => {
binding.objectreference.unrefObjects("weak");
},
Error
);
},

'Persistent',
() => {
binding.objectreference.setObjects("hello", "world");
const test = binding.objectreference.getFromValue("persistent");
const test2 = binding.objectreference.getFromGetter("persistent", "hello");

assert.deepEqual({ hello: "world" }, test);
assert.equal("world", test2);
assert.equal(test["hello"], test2);
},
() => {
binding.objectreference.setObjects("hello", "world", "javascript");
const test = binding.objectreference.getFromValue("persistent");
const test2 = binding.objectreference.getFromValue("persistent", "hello");

assert.deepEqual({ hello: "world" }, test);
assert.deepEqual({ hello: "world" }, test2);
assert.deepEqual(test, test2);
},
() => {
binding.objectreference.setObjects(1, "hello world");
const test = binding.objectreference.getFromValue("persistent");
const test2 = binding.objectreference.getFromGetter("persistent", 1);

assert.deepEqual({ 1: "hello world"}, test);
assert.equal("hello world", test2);
assert.equal(test[1], test2);
},
() => {
binding.objectreference.setObjects(0, "hello");
binding.objectreference.setObjects(1, "world");
const test = binding.objectreference.getFromValue("persistent");
const test2 = binding.objectreference.getFromGetter("persistent", 0);
const test3 = binding.objectreference.getFromGetter("persistent", 1);

assert.deepEqual({ 1: "world"}, test);
assert.equal(undefined, test2);
assert.equal("world", test3);
},
() => {
binding.objectreference.setObjects("hello", "world");
assert.doesNotThrow(
() => {
var rcount = binding.objectreference.unrefObjects("persistent");
assert.equal(rcount, 0);
rcount = binding.objectreference.refObjects("persistent");
assert.equal(rcount, 1);
rcount = binding.objectreference.unrefObjects("persistent");
assert.equal(rcount, 0);
rcount = binding.objectreference.refObjects("persistent");
assert.equal(rcount, 1);
rcount = binding.objectreference.unrefObjects("persistent");
assert.equal(rcount, 0);
},
Error
);
assert.throws(
() => {
binding.objectreference.unrefObjects("persistent");
},
Error
);
},

'References',
() => {
binding.objectreference.setObjects("hello", "world");
const test = binding.objectreference.getFromValue();
const test2 = binding.objectreference.getFromGetter("hello");

assert.deepEqual({ hello: "world" }, test);
assert.equal("world", test2);
assert.equal(test["hello"], test2);
},
() => {
binding.objectreference.setObjects("hello", "world", "javascript");
const test = binding.objectreference.getFromValue();
const test2 = binding.objectreference.getFromValue("hello");

assert.deepEqual({ hello: "world" }, test);
assert.deepEqual({ hello: "world" }, test2);
assert.deepEqual(test, test2);
},
() => {
binding.objectreference.setObjects(1, "hello world");
const test = binding.objectreference.getFromValue();
const test2 = binding.objectreference.getFromGetter(1);

assert.deepEqual({ 1: "hello world"}, test);
assert.equal("hello world", test2);
assert.equal(test[1], test2);
},
() => {
binding.objectreference.setObjects(0, "hello");
binding.objectreference.setObjects(1, "world");
const test = binding.objectreference.getFromValue();
const test2 = binding.objectreference.getFromGetter(0);
const test3 = binding.objectreference.getFromGetter(1);

assert.deepEqual({ 1: "world"}, test);
assert.equal(undefined, test2);
assert.equal("world", test3);
},
() => {
binding.objectreference.setObjects("hello", "world");
assert.doesNotThrow(
() => {
var rcount = binding.objectreference.unrefObjects("references");
assert.equal(rcount, 1);
rcount = binding.objectreference.refObjects("references");
assert.equal(rcount, 2);
rcount = binding.objectreference.unrefObjects("references");
assert.equal(rcount, 1);
rcount = binding.objectreference.unrefObjects("references");
assert.equal(rcount, 0);
},
Error
);
assert.throws(
() => {
binding.objectreference.unrefObjects("references");
},
Error
);
}
])
};

0 comments on commit 4d92a60

Please sign in to comment.