Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test coverage for Symbol class #972

Closed
wants to merge 1 commit into from
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
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);
```

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the documentation for all the overloads of Napi::Symbol Napi::Symbol::WellKnown() methos.

- `[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 @@ -998,6 +998,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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
inline Symbol Symbol::For(napi_env env, const std::string& description) {
inline Symbol Symbol::For(Napi::Env env, const std::string& description) {

... and a similar change for all APIs below.

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;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PLease add one empty new line.

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());
}