diff --git a/test/object_reference.cc b/test/object_reference.cc index 34f952088..2d3fc4807 100644 --- a/test/object_reference.cc +++ b/test/object_reference.cc @@ -2,7 +2,7 @@ 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 "assert.h" #include "napi.h" #include "test_helper.h" @@ -16,11 +16,146 @@ 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) { +// Set keys can be one of: +// C style string, std::string& utf8, and const char * + +// Set values can be one of: +// Napi::Value +// napi_value (req static_cast) +// const char* (c style string) +// boolean +// double + +enum VAL_TYPES { JS = 0, C_STR, CPP_STR, BOOL, INT, DOUBLE, JS_CAST }; + +void MoveOperatorsTest(const Napi::CallbackInfo& info) { + Napi::ObjectReference existingRef; + Napi::ObjectReference existingRef2; + Napi::Object testObject = Napi::Object::New(info.Env()); + testObject.Set("testProp", "tProp"); + + // ObjectReference(Reference&& other); + Napi::Reference refObj = + Napi::Reference::New(testObject); + Napi::ObjectReference objRef = std::move(refObj); + std::string prop = MaybeUnwrap(objRef.Get("testProp")).As(); + assert(prop == "tProp"); + + // ObjectReference& operator=(Reference&& other); + Napi::Reference refObj2 = + Napi::Reference::New(testObject); + existingRef = std::move(refObj2); + prop = MaybeUnwrap(existingRef.Get("testProp")).As(); + assert(prop == "tProp"); + + // ObjectReference(ObjectReference&& other); + Napi::ObjectReference objRef3 = std::move(existingRef); + prop = MaybeUnwrap(objRef3.Get("testProp")).As(); + assert(prop == "tProp"); + + // ObjectReference& operator=(ObjectReference&& other); + existingRef2 = std::move(objRef3); + prop = MaybeUnwrap(objRef.Get("testProp")).As(); + assert(prop == "tProp"); +} + +void SetObjectWithCStringKey(Napi::ObjectReference& obj, + Napi::Value key, + Napi::Value val, + int valType) { + std::string c_key = key.As().Utf8Value(); + switch (valType) { + case JS: + obj.Set(c_key.c_str(), val); + break; + + case JS_CAST: + obj.Set(c_key.c_str(), static_cast(val)); + break; + + case C_STR: { + std::string c_val = val.As().Utf8Value(); + obj.Set(c_key.c_str(), c_val.c_str()); + break; + } + + case BOOL: + obj.Set(c_key.c_str(), val.As().Value()); + break; + + case DOUBLE: + obj.Set(c_key.c_str(), val.As().DoubleValue()); + break; + } +} + +void SetObjectWithCppStringKey(Napi::ObjectReference& obj, + Napi::Value key, + Napi::Value val, + int valType) { + std::string c_key = key.As(); + switch (valType) { + case JS: + obj.Set(c_key, val); + break; + + case JS_CAST: + obj.Set(c_key, static_cast(val)); + break; + + case CPP_STR: { + std::string c_val = val.As(); + obj.Set(c_key, c_val); + break; + } + + case BOOL: + obj.Set(c_key, val.As().Value()); + break; + + case DOUBLE: + obj.Set(c_key, val.As().DoubleValue()); + break; + } +} + +void SetObjectWithIntKey(Napi::ObjectReference& obj, + Napi::Value key, + Napi::Value val, + int valType) { + uint32_t c_key = key.As().Uint32Value(); + switch (valType) { + case JS: + obj.Set(c_key, val); + break; + + case JS_CAST: + obj.Set(c_key, static_cast(val)); + break; + + case C_STR: { + std::string c_val = val.As(); + obj.Set(c_key, c_val.c_str()); + break; + } + + case CPP_STR: { + std::string cpp_val = val.As(); + obj.Set(c_key, cpp_val); + break; + } + + case BOOL: + obj.Set(c_key, val.As().Value()); + break; + + case DOUBLE: + obj.Set(c_key, val.As().DoubleValue()); + break; + } +} + +void SetObject(const Napi::CallbackInfo& info) { Env env = info.Env(); HandleScope scope(env); @@ -33,20 +168,35 @@ void SetObjects(const CallbackInfo& info) { reference = Reference::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]); + Napi::Object configObject = info[0].As(); + + int keyType = + MaybeUnwrap(configObject.Get("keyType")).As().Uint32Value(); + int valType = + MaybeUnwrap(configObject.Get("valType")).As().Uint32Value(); + Napi::Value key = MaybeUnwrap(configObject.Get("key")); + Napi::Value val = MaybeUnwrap(configObject.Get("val")); + + switch (keyType) { + case CPP_STR: + SetObjectWithCppStringKey(weak, key, val, valType); + SetObjectWithCppStringKey(persistent, key, val, valType); + SetObjectWithCppStringKey(reference, key, val, valType); + break; + + case C_STR: + SetObjectWithCStringKey(weak, key, val, valType); + SetObjectWithCStringKey(persistent, key, val, valType); + SetObjectWithCStringKey(reference, key, val, valType); + break; + + case INT: + SetObjectWithIntKey(weak, key, val, valType); + SetObjectWithIntKey(persistent, key, val, valType); + SetObjectWithIntKey(reference, key, val, valType); + + default: + break; } } @@ -87,6 +237,53 @@ Value GetFromValue(const CallbackInfo& info) { } } +Value GetHelper(ObjectReference& ref, + Object& configObject, + const Napi::Env& env) { + int keyType = + MaybeUnwrap(configObject.Get("keyType")).As().Uint32Value(); + if (ref.IsEmpty()) { + return String::New(env, "No referenced Value"); + } + + switch (keyType) { + case C_STR: { + std::string c_key = + MaybeUnwrap(configObject.Get("key")).As().Utf8Value(); + return MaybeUnwrap(ref.Get(c_key.c_str())); + break; + } + case CPP_STR: { + std::string cpp_key = + MaybeUnwrap(configObject.Get("key")).As().Utf8Value(); + return MaybeUnwrap(ref.Get(cpp_key)); + break; + } + case INT: { + uint32_t key = + MaybeUnwrap(configObject.Get("key")).As().Uint32Value(); + return MaybeUnwrap(ref.Get(key)); + break; + } + + default: + return String::New(env, "Error: Reached end of getter"); + break; + } +} + +Value GetFromGetters(const CallbackInfo& info) { + std::string object_req = info[0].As(); + Object configObject = info[1].As(); + if (object_req == "weak") { + return GetHelper(weak, configObject, info.Env()); + } else if (object_req == "persistent") { + return GetHelper(persistent, configObject, info.Env()); + } + + return GetHelper(reference, configObject, info.Env()); +} + // 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. @@ -207,13 +404,14 @@ Object InitObjectReference(Env env) { Object exports = Object::New(env); exports["setCastedObjects"] = Function::New(env, SetCastedObjects); - exports["setObjects"] = Function::New(env, SetObjects); + exports["setObject"] = Function::New(env, SetObject); exports["getCastedFromValue"] = Function::New(env, GetCastedFromValue); - exports["getFromGetter"] = Function::New(env, GetFromGetter); + exports["getFromGetters"] = Function::New(env, GetFromGetters); exports["getCastedFromGetter"] = Function::New(env, GetCastedFromGetter); exports["getFromValue"] = Function::New(env, GetFromValue); exports["unrefObjects"] = Function::New(env, UnrefObjects); exports["refObjects"] = Function::New(env, RefObjects); + exports["moveOpTest"] = Function::New(env, MoveOperatorsTest); return exports; } diff --git a/test/object_reference.js b/test/object_reference.js index c1e730813..8039b3741 100644 --- a/test/object_reference.js +++ b/test/object_reference.js @@ -16,7 +16,37 @@ const testUtil = require('./testUtil'); module.exports = require('./common').runTest(test); +const enumType = { + JS: 0, // Napi::Value + C_STR: 1, // const char * + CPP_STR: 2, // std::string + BOOL: 3, // bool + INT: 4, // uint32_t + DOUBLE: 5, // double + JS_CAST: 6 // napi_value +}; + +const configObjects = [ + { keyType: enumType.C_STR, valType: enumType.JS, key: 'hello', val: 'worlds' }, + { keyType: enumType.C_STR, valType: enumType.C_STR, key: 'hello', val: 'worldd' }, + { keyType: enumType.C_STR, valType: enumType.BOOL, key: 'hello', val: false }, + { keyType: enumType.C_STR, valType: enumType.DOUBLE, key: 'hello', val: 3.56 }, + { keyType: enumType.C_STR, valType: enumType.JS_CAST, key: 'hello_cast', val: 'world' }, + { keyType: enumType.CPP_STR, valType: enumType.JS, key: 'hello_cpp', val: 'world_js' }, + { keyType: enumType.CPP_STR, valType: enumType.JS_CAST, key: 'hello_cpp', val: 'world_js_cast' }, + { keyType: enumType.CPP_STR, valType: enumType.CPP_STR, key: 'hello_cpp', val: 'world_cpp_str' }, + { keyType: enumType.CPP_STR, valType: enumType.BOOL, key: 'hello_cpp', val: true }, + { keyType: enumType.CPP_STR, valType: enumType.DOUBLE, key: 'hello_cpp', val: 3.58 }, + { keyType: enumType.INT, valType: enumType.JS, key: 1, val: 'hello world' }, + { keyType: enumType.INT, valType: enumType.JS_CAST, key: 2, val: 'hello world' }, + { keyType: enumType.INT, valType: enumType.C_STR, key: 3, val: 'hello world' }, + { keyType: enumType.INT, valType: enumType.CPP_STR, key: 8, val: 'hello world' }, + { keyType: enumType.INT, valType: enumType.BOOL, key: 3, val: false }, + { keyType: enumType.INT, valType: enumType.DOUBLE, key: 4, val: 3.14159 } +]; + function test (binding) { + binding.objectreference.moveOpTest(); function testCastedEqual (testToCompare) { const compareTest = ['hello', 'world', '!']; if (testToCompare instanceof Array) { @@ -74,45 +104,32 @@ function test (binding) { 'Weak', () => { - binding.objectreference.setObjects('hello', 'world'); - const test = binding.objectreference.getFromValue('weak'); - const test2 = binding.objectreference.getFromGetter('weak', 'hello'); + for (const configObject of configObjects) { + binding.objectreference.setObject(configObject); + const test = binding.objectreference.getFromValue('weak'); + const test2 = binding.objectreference.getFromGetters('weak', configObject); - 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'); + const assertObject = { + [configObject.key]: configObject.val + }; + assert.deepEqual(assertObject, test); + assert.equal(configObject.val, test2); + } + }, () => { + const configObjA = { keyType: enumType.INT, valType: enumType.JS, key: 0, val: 'hello' }; + const configObjB = { keyType: enumType.INT, valType: enumType.JS, key: 1, val: 'world' }; + binding.objectreference.setObject(configObjA); + binding.objectreference.setObject(configObjB); - 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); - + const test2 = binding.objectreference.getFromGetters('weak', configObjA); + const test3 = binding.objectreference.getFromGetters('weak', configObjB); assert.deepEqual({ 1: 'world' }, test); assert.equal(undefined, test2); assert.equal('world', test3); }, () => { - binding.objectreference.setObjects('hello', 'world'); + binding.objectreference.setObject({ keyType: enumType.JS, valType: enumType.JS, key: 'hello', val: 'world' }); assert.doesNotThrow( () => { let rcount = binding.objectreference.refObjects('weak'); @@ -132,16 +149,20 @@ function test (binding) { 'Persistent', () => { - binding.objectreference.setObjects('hello', 'world'); - const test = binding.objectreference.getFromValue('persistent'); - const test2 = binding.objectreference.getFromGetter('persistent', 'hello'); + for (const configObject of configObjects) { + binding.objectreference.setObject(configObject); + const test = binding.objectreference.getFromValue('persistent'); + const test2 = binding.objectreference.getFromGetters('persistent', configObject); + const assertObject = { + [configObject.key]: configObject.val + }; - assert.deepEqual({ hello: 'world' }, test); - assert.equal('world', test2); - assert.equal(test.hello, test2); + assert.deepEqual(assertObject, test); + assert.equal(configObject.val, test2); + } }, () => { - binding.objectreference.setObjects('hello', 'world', 'javascript'); + binding.objectreference.setObject({ keyType: enumType.CPP_STR, valType: enumType.JS, key: 'hello', val: 'world' }); const test = binding.objectreference.getFromValue('persistent'); const test2 = binding.objectreference.getFromValue('persistent', 'hello'); @@ -150,27 +171,21 @@ function test (binding) { assert.deepEqual(test, test2); }, () => { - binding.objectreference.setObjects(1, 'hello world'); - const test = binding.objectreference.getFromValue('persistent'); - const test2 = binding.objectreference.getFromGetter('persistent', 1); + const configObjA = { keyType: enumType.INT, valType: enumType.JS, key: 0, val: 'hello' }; + const configObjB = { keyType: enumType.INT, valType: enumType.JS, key: 1, val: 'world' }; + binding.objectreference.setObject(configObjA); + binding.objectreference.setObject(configObjB); - 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); + const test2 = binding.objectreference.getFromGetters('persistent', configObjA); + const test3 = binding.objectreference.getFromGetters('persistent', configObjB); assert.deepEqual({ 1: 'world' }, test); assert.equal(undefined, test2); assert.equal('world', test3); }, () => { - binding.objectreference.setObjects('hello', 'world'); + binding.objectreference.setObject({ keyType: enumType.CPP_STR, valType: enumType.JS, key: 'hello', val: 'world' }); assert.doesNotThrow( () => { let rcount = binding.objectreference.unrefObjects('persistent'); @@ -196,45 +211,33 @@ function test (binding) { '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); + for (const configObject of configObjects) { + binding.objectreference.setObject(configObject); + const test = binding.objectreference.getFromValue(); + const test2 = binding.objectreference.getFromGetters('reference', configObject); + const assertObject = { + [configObject.key]: configObject.val + }; + assert.deepEqual(assertObject, test); + assert.equal(configObject.val, test2); + } }, () => { - binding.objectreference.setObjects('hello', 'world', 'javascript'); + const configObjA = { keyType: enumType.INT, valType: enumType.JS, key: 0, val: 'hello' }; + const configObjB = { keyType: enumType.INT, valType: enumType.JS, key: 1, val: 'world' }; + binding.objectreference.setObject(configObjA); + binding.objectreference.setObject(configObjB); 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); + const test2 = binding.objectreference.getFromGetters('reference', configObjA); + const test3 = binding.objectreference.getFromGetters('reference', configObjB); assert.deepEqual({ 1: 'world' }, test); assert.equal(undefined, test2); assert.equal('world', test3); }, () => { - binding.objectreference.setObjects('hello', 'world'); + binding.objectreference.setObject({ keyType: enumType.CPP_STR, valType: enumType.JS, key: 'hello', val: 'world' }); assert.doesNotThrow( () => { let rcount = binding.objectreference.unrefObjects('references');