diff --git a/test/binding.cc b/test/binding.cc index 0032c8e30..3b4bb7b0a 100644 --- a/test/binding.cc +++ b/test/binding.cc @@ -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; } diff --git a/test/binding.gyp b/test/binding.gyp index acbbc0a12..698eb45b7 100644 --- a/test/binding.gyp +++ b/test/binding.gyp @@ -24,6 +24,7 @@ 'promise.cc', 'typedarray.cc', 'objectwrap.cc', + 'objectreference.cc', ], 'include_dirs': ["::New(Object::New(env), 2); + reference.SuppressDestruct(); + + if (info[0].IsString()) { + if (info[2].As() == String::New(env, "javascript")) { + weak.Set(info[0].As(), info[1]); + persistent.Set(info[0].As(), info[1]); + reference.Set(info[0].As(), info[1]); + } else { + weak.Set(info[0].As().Utf8Value(), info[1]); + persistent.Set(info[0].As().Utf8Value(), info[1]); + reference.Set(info[0].As().Utf8Value(), info[1]); + } + } else if (info[0].IsNumber()) { + weak.Set(info[0].As(), info[1]); + persistent.Set(info[0].As(), info[1]); + reference.Set(info[0].As(), 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()); + casted_weak.SuppressDestruct(); + + casted_persistent = Persistent(ex.As()); + casted_persistent.SuppressDestruct(); + + casted_reference = Reference::New(ex.As(), 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::New(env, "weak")) { + if (weak.IsEmpty()) { + return String::New(env, "No Referenced Value"); + } else { + return weak.Value(); + } + } else if (info[0].As() == 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::New(env, "weak")) { + if (weak.IsEmpty()) { + return String::New(env, "No Referenced Value"); + } else { + if (info[1].IsString()) { + return weak.Get(info[1].As().Utf8Value()); + } else if (info[1].IsNumber()) { + return weak.Get(info[1].As().Uint32Value()); + } + } + } else if (info[0].As() == String::New(env, "persistent")) { + if (info[1].IsString()) { + return persistent.Get(info[1].As().Utf8Value()); + } else if (info[1].IsNumber()) { + return persistent.Get(info[1].As().Uint32Value()); + } + } else { + if (info[0].IsString()) { + return reference.Get(info[0].As().Utf8Value()); + } else if (info[0].IsNumber()) { + return reference.Get(info[0].As().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::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::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::New(env, "weak")) { + if (casted_weak.IsEmpty()) { + return String::New(env, "No Referenced Value"); + } else { + return casted_weak.Get(info[1].As()); + } + } else if (info[0].As() == String::New(env, "persistent")) { + return casted_persistent.Get(info[1].As()); + } else { + return casted_reference.Get(info[1].As()); + } +} + +// 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::New(env, "weak")) { + num = weak.Unref(); + } else if (info[0].As() == String::New(env, "persistent")) { + num = persistent.Unref(); + } else if (info[0].As() == String::New(env, "references")) { + num = reference.Unref(); + } else if (info[0].As() == String::New(env, "casted weak")) { + num = casted_weak.Unref(); + } else if (info[0].As() == 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::New(env, "weak")) { + num = weak.Ref(); + } else if (info[0].As() == String::New(env, "persistent")) { + num = persistent.Ref(); + } else if (info[0].As() == String::New(env, "references")) { + num = reference.Ref(); + } else if (info[0].As() == String::New(env, "casted weak")) { + num = casted_weak.Ref(); + } else if (info[0].As() == 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; +} diff --git a/test/objectreference.js b/test/objectreference.js new file mode 100644 index 000000000..07de0bc77 --- /dev/null +++ b/test/objectreference.js @@ -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 + ); + } + ]) +};