Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 220 additions & 22 deletions test/object_reference.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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<Object>&& other);
Napi::Reference<Napi::Object> refObj =
Napi::Reference<Napi::Object>::New(testObject);
Napi::ObjectReference objRef = std::move(refObj);
std::string prop = MaybeUnwrap(objRef.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");

// ObjectReference& operator=(Reference<Object>&& other);
Napi::Reference<Napi::Object> refObj2 =
Napi::Reference<Napi::Object>::New(testObject);
existingRef = std::move(refObj2);
prop = MaybeUnwrap(existingRef.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");

// ObjectReference(ObjectReference&& other);
Napi::ObjectReference objRef3 = std::move(existingRef);
prop = MaybeUnwrap(objRef3.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");

// ObjectReference& operator=(ObjectReference&& other);
existingRef2 = std::move(objRef3);
prop = MaybeUnwrap(objRef.Get("testProp")).As<Napi::String>();
assert(prop == "tProp");
}

void SetObjectWithCStringKey(Napi::ObjectReference& obj,
Napi::Value key,
Napi::Value val,
int valType) {
std::string c_key = key.As<Napi::String>().Utf8Value();
switch (valType) {
case JS:
obj.Set(c_key.c_str(), val);
break;

case JS_CAST:
obj.Set(c_key.c_str(), static_cast<napi_value>(val));
break;

case C_STR: {
std::string c_val = val.As<Napi::String>().Utf8Value();
obj.Set(c_key.c_str(), c_val.c_str());
break;
}

case BOOL:
obj.Set(c_key.c_str(), val.As<Napi::Boolean>().Value());
break;

case DOUBLE:
obj.Set(c_key.c_str(), val.As<Napi::Number>().DoubleValue());
break;
}
}

void SetObjectWithCppStringKey(Napi::ObjectReference& obj,
Napi::Value key,
Napi::Value val,
int valType) {
std::string c_key = key.As<Napi::String>();
switch (valType) {
case JS:
obj.Set(c_key, val);
break;

case JS_CAST:
obj.Set(c_key, static_cast<napi_value>(val));
break;

case CPP_STR: {
std::string c_val = val.As<Napi::String>();
obj.Set(c_key, c_val);
break;
}

case BOOL:
obj.Set(c_key, val.As<Napi::Boolean>().Value());
break;

case DOUBLE:
obj.Set(c_key, val.As<Napi::Number>().DoubleValue());
break;
}
}

void SetObjectWithIntKey(Napi::ObjectReference& obj,
Napi::Value key,
Napi::Value val,
int valType) {
uint32_t c_key = key.As<Napi::Number>().Uint32Value();
switch (valType) {
case JS:
obj.Set(c_key, val);
break;

case JS_CAST:
obj.Set(c_key, static_cast<napi_value>(val));
break;

case C_STR: {
std::string c_val = val.As<Napi::String>();
obj.Set(c_key, c_val.c_str());
break;
}

case CPP_STR: {
std::string cpp_val = val.As<Napi::String>();
obj.Set(c_key, cpp_val);
break;
}

case BOOL:
obj.Set(c_key, val.As<Napi::Boolean>().Value());
break;

case DOUBLE:
obj.Set(c_key, val.As<Napi::Number>().DoubleValue());
break;
}
}

void SetObject(const Napi::CallbackInfo& info) {
Env env = info.Env();
HandleScope scope(env);

Expand All @@ -33,20 +168,35 @@ void SetObjects(const CallbackInfo& info) {
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]);
Napi::Object configObject = info[0].As<Napi::Object>();

int keyType =
MaybeUnwrap(configObject.Get("keyType")).As<Napi::Number>().Uint32Value();
int valType =
MaybeUnwrap(configObject.Get("valType")).As<Napi::Number>().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;
}
}

Expand Down Expand Up @@ -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<Napi::Number>().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<String>().Utf8Value();
return MaybeUnwrap(ref.Get(c_key.c_str()));
break;
}
case CPP_STR: {
std::string cpp_key =
MaybeUnwrap(configObject.Get("key")).As<String>().Utf8Value();
return MaybeUnwrap(ref.Get(cpp_key));
break;
}
case INT: {
uint32_t key =
MaybeUnwrap(configObject.Get("key")).As<Number>().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<String>();
Object configObject = info[1].As<Object>();
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.
Expand Down Expand Up @@ -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;
}
Loading