Skip to content

Commit

Permalink
test: add first set of symbol tests
Browse files Browse the repository at this point in the history
PR-URL: nodejs/node-addon-api#972
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Nicola Del Gobbo <nicoladelgobbo@gmail.com>
  • Loading branch information
wroy7860 committed Jul 9, 2021
1 parent aebedd2 commit 022af08
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 2 deletions.
17 changes: 15 additions & 2 deletions doc/symbol.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ If an error occurs, a `Napi::Error` will get thrown. If C++ exceptions are not
being used, callers should check the result of `Napi::Env::IsExceptionPending` before
attempting to use the returned value.
### Utf8Value
### WellKnown
```cpp
static Napi::Symbol Napi::Symbol::WellKnown(napi_env env, const std::string& name);
```
Expand All @@ -45,4 +45,17 @@ static Napi::Symbol Napi::Symbol::WellKnown(napi_env env, const std::string& nam
Returns a `Napi::Symbol` representing a well-known `Symbol` from the
`Symbol` registry.

[`Napi::Name`]: ./name.md
### For
```cpp
static Napi::Symbol Napi::Symbol::For(napi_env env, const std::string& description);
static Napi::Symbol Napi::Symbol::For(napi_env env, const char* description);
static Napi::Symbol Napi::Symbol::For(napi_env env, String description);
static Napi::Symbol Napi::Symbol::For(napi_env env, napi_value description);
```
- `[in] env`: The `napi_env` environment in which to construct the `Napi::Symbol` object.
- `[in] description`: The C++ string representing the `Napi::Symbol` in the global registry to retrieve.
Searches in the global registry for existing symbol with the given name. If the symbol already exist it will be returned, otherwise a new symbol will be created in the registry. It's equivalent to Symbol.for() called from JavaScript.
[`Napi::Name`]: ./name.md
21 changes: 21 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,27 @@ inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) {
return Napi::Env(env).Global().Get("Symbol").As<Object>().Get(name).As<Symbol>();
}

inline Symbol Symbol::For(napi_env env, const std::string& description) {
napi_value descriptionValue = String::New(env, description);
return Symbol::For(env, descriptionValue);
}

inline Symbol Symbol::For(napi_env env, const char* description) {
napi_value descriptionValue = String::New(env, description);
return Symbol::For(env, descriptionValue);
}

inline Symbol Symbol::For(napi_env env, String description) {
return Symbol::For(env, static_cast<napi_value>(description));
}

inline Symbol Symbol::For(napi_env env, napi_value description) {
Object symbObject = Napi::Env(env).Global().Get("Symbol").As<Object>();
auto forSymb =
symbObject.Get("for").As<Function>().Call(symbObject, {description});
return forSymb.As<Symbol>();
}

inline Symbol::Symbol() : Name() {
}

Expand Down
12 changes: 12 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,18 @@ namespace Napi {
/// Get a public Symbol (e.g. Symbol.iterator).
static Symbol WellKnown(napi_env, const std::string& name);

// Create a symbol in the global registry, UTF-8 Encoded cpp string
static Symbol For(napi_env env, const std::string& description);

// Create a symbol in the global registry, C style string (null terminated)
static Symbol For(napi_env env, const char* description);

// Create a symbol in the global registry, String value describing the symbol
static Symbol For(napi_env env, String description);

// Create a symbol in the global registry, napi_value describing the symbol
static Symbol For(napi_env env, napi_value description);

Symbol(); ///< Creates a new _empty_ Symbol instance.
Symbol(napi_env env,
napi_value value); ///< Wraps a Node-API value primitive.
Expand Down
2 changes: 2 additions & 0 deletions test/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Object InitTypedThreadSafeFunctionSum(Env env);
Object InitTypedThreadSafeFunctionUnref(Env env);
Object InitTypedThreadSafeFunction(Env env);
#endif
Object InitSymbol(Env env);
Object InitTypedArray(Env env);
Object InitGlobalObject(Env env);
Object InitObjectWrap(Env env);
Expand Down Expand Up @@ -117,6 +118,7 @@ Object Init(Env env, Object exports) {
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
exports.Set("promise", InitPromise(env));
exports.Set("run_script", InitRunScript(env));
exports.Set("symbol", InitSymbol(env));
#if (NAPI_VERSION > 3)
exports.Set("threadsafe_function_ctx", InitThreadSafeFunctionCtx(env));
exports.Set("threadsafe_function_existing_tsfn", InitThreadSafeFunctionExistingTsfn(env));
Expand Down
1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
'object/subscript_operator.cc',
'promise.cc',
'run_script.cc',
"symbol.cc",
'threadsafe_function/threadsafe_function_ctx.cc',
'threadsafe_function/threadsafe_function_existing_tsfn.cc',
'threadsafe_function/threadsafe_function_ptr.cc',
Expand Down
77 changes: 77 additions & 0 deletions test/symbol.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <napi.h>
using namespace Napi;

Symbol CreateNewSymbolWithNoArgs(const Napi::CallbackInfo&) {
return Napi::Symbol();
}

Symbol CreateNewSymbolWithCppStrDesc(const Napi::CallbackInfo& info) {
String cppStrKey = info[0].As<String>();
return Napi::Symbol::New(info.Env(), cppStrKey.Utf8Value());
}

Symbol CreateNewSymbolWithCStrDesc(const Napi::CallbackInfo& info) {
String cStrKey = info[0].As<String>();
return Napi::Symbol::New(info.Env(), cStrKey.Utf8Value().c_str());
}

Symbol CreateNewSymbolWithNapiString(const Napi::CallbackInfo& info) {
String strKey = info[0].As<String>();
return Napi::Symbol::New(info.Env(), strKey);
}

Symbol GetWellknownSymbol(const Napi::CallbackInfo& info) {
String registrySymbol = info[0].As<String>();
return Napi::Symbol::WellKnown(info.Env(),
registrySymbol.Utf8Value().c_str());
}

Symbol FetchSymbolFromGlobalRegistry(const Napi::CallbackInfo& info) {
String registrySymbol = info[0].As<String>();
return Napi::Symbol::For(info.Env(), registrySymbol);
}

Symbol FetchSymbolFromGlobalRegistryWithCppKey(const Napi::CallbackInfo& info) {
String cppStringKey = info[0].As<String>();
return Napi::Symbol::For(info.Env(), cppStringKey.Utf8Value());
}

Symbol FetchSymbolFromGlobalRegistryWithCKey(const Napi::CallbackInfo& info) {
String cppStringKey = info[0].As<String>();
return Napi::Symbol::For(info.Env(), cppStringKey.Utf8Value().c_str());
}

Symbol TestUndefinedSymbolsCanBeCreated(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
return Napi::Symbol::For(env, env.Undefined());
}

Symbol TestNullSymbolsCanBeCreated(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
return Napi::Symbol::For(env, env.Null());
}

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

exports["createNewSymbolWithNoArgs"] =
Function::New(env, CreateNewSymbolWithNoArgs);
exports["createNewSymbolWithCppStr"] =
Function::New(env, CreateNewSymbolWithCppStrDesc);
exports["createNewSymbolWithCStr"] =
Function::New(env, CreateNewSymbolWithCStrDesc);
exports["createNewSymbolWithNapi"] =
Function::New(env, CreateNewSymbolWithNapiString);
exports["getWellKnownSymbol"] = Function::New(env, GetWellknownSymbol);
exports["getSymbolFromGlobalRegistry"] =
Function::New(env, FetchSymbolFromGlobalRegistry);
exports["getSymbolFromGlobalRegistryWithCKey"] =
Function::New(env, FetchSymbolFromGlobalRegistryWithCKey);
exports["getSymbolFromGlobalRegistryWithCppKey"] =
Function::New(env, FetchSymbolFromGlobalRegistryWithCppKey);
exports["testUndefinedSymbolCanBeCreated"] =
Function::New(env, TestUndefinedSymbolsCanBeCreated);
exports["testNullSymbolCanBeCreated"] =
Function::New(env, TestNullSymbolsCanBeCreated);
return exports;
}
70 changes: 70 additions & 0 deletions test/symbol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict';

const buildType = process.config.target_defaults.default_configuration;
const assert = require('assert');

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


async function test(binding)
{

const wellKnownSymbolFunctions = ['asyncIterator','hasInstance','isConcatSpreadable', 'iterator','match','matchAll','replace','search','split','species','toPrimitive','toStringTag','unscopables'];

function assertCanCreateSymbol(symbol)
{
assert(binding.symbol.createNewSymbolWithCppStr(symbol) !== null);
assert(binding.symbol.createNewSymbolWithCStr(symbol) !== null);
assert(binding.symbol.createNewSymbolWithNapi(symbol) !== null);
}

function assertSymbolAreUnique(symbol)
{
const symbolOne = binding.symbol.createNewSymbolWithCppStr(symbol);
const symbolTwo = binding.symbol.createNewSymbolWithCppStr(symbol);

assert(symbolOne !== symbolTwo);
}

function assertSymbolIsWellknown(symbol)
{
const symbOne = binding.symbol.getWellKnownSymbol(symbol);
const symbTwo = binding.symbol.getWellKnownSymbol(symbol);
assert(symbOne && symbTwo);
assert(symbOne === symbTwo);
}

function assertSymbolIsNotWellknown(symbol)
{
const symbolTest = binding.symbol.getWellKnownSymbol(symbol);
assert(symbolTest === undefined);
}

function assertCanCreateOrFetchGlobalSymbols(symbol, fetchFunction)
{
const symbOne = fetchFunction(symbol);
const symbTwo = fetchFunction(symbol);
assert(symbOne && symbTwo);
assert(symbOne === symbTwo);
}

assertCanCreateSymbol("testing");
assertSymbolAreUnique("symbol");
assertSymbolIsNotWellknown("testing");

for(const wellknownProperty of wellKnownSymbolFunctions)
{
assertSymbolIsWellknown(wellknownProperty);
}

assertCanCreateOrFetchGlobalSymbols("data", binding.symbol.getSymbolFromGlobalRegistry);
assertCanCreateOrFetchGlobalSymbols("CppKey", binding.symbol.getSymbolFromGlobalRegistryWithCppKey);
assertCanCreateOrFetchGlobalSymbols("CKey", binding.symbol.getSymbolFromGlobalRegistryWithCKey);

assert(binding.symbol.createNewSymbolWithNoArgs() === undefined);

assert(binding.symbol.testNullSymbolCanBeCreated() === binding.symbol.testNullSymbolCanBeCreated());
assert(binding.symbol.testUndefinedSymbolCanBeCreated() === binding.symbol.testUndefinedSymbolCanBeCreated());
assert(binding.symbol.testUndefinedSymbolCanBeCreated() !== binding.symbol.testNullSymbolCanBeCreated());
}

0 comments on commit 022af08

Please sign in to comment.