Skip to content

Commit bdefbb0

Browse files
committed
Finished first set of symbol tests
Add new static method to symbol and updated tests Updated Symbol.md 's docs, added function overload for Symbol class and new tests Remove extra space and comments Remove un-necssary string initialization Update PR based on comments received Add test checking if it's possible to pass nullptr to Symbol::For method Update Symbol::For implementations and added new tests Remove default parameter Update documentation for Symbol Fixing merge conflicts
1 parent 37a9b8e commit bdefbb0

File tree

7 files changed

+198
-2
lines changed

7 files changed

+198
-2
lines changed

doc/symbol.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ If an error occurs, a `Napi::Error` will get thrown. If C++ exceptions are not
3434
being used, callers should check the result of `Napi::Env::IsExceptionPending` before
3535
attempting to use the returned value.
3636
37-
### Utf8Value
37+
### WellKnown
3838
```cpp
3939
static Napi::Symbol Napi::Symbol::WellKnown(napi_env env, const std::string& name);
4040
```
@@ -45,4 +45,17 @@ static Napi::Symbol Napi::Symbol::WellKnown(napi_env env, const std::string& nam
4545
Returns a `Napi::Symbol` representing a well-known `Symbol` from the
4646
`Symbol` registry.
4747

48-
[`Napi::Name`]: ./name.md
48+
### For
49+
```cpp
50+
static Napi::Symbol Napi::Symbol::For(napi_env env, const std::string& description);
51+
static Napi::Symbol Napi::Symbol::For(napi_env env, const char* description);
52+
static Napi::Symbol Napi::Symbol::For(napi_env env, String description);
53+
static Napi::Symbol Napi::Symbol::For(napi_env env, napi_value description);
54+
```
55+
56+
- `[in] env`: The `napi_env` environment in which to construct the `Napi::Symbol` object.
57+
- `[in] description`: The C++ string representing the `Napi::Symbol` in the global registry to retrieve.
58+
59+
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.
60+
61+
[`Napi::Name`]: ./name.md

napi-inl.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,27 @@ inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) {
998998
return Napi::Env(env).Global().Get("Symbol").As<Object>().Get(name).As<Symbol>();
999999
}
10001000

1001+
inline Symbol Symbol::For(napi_env env, const std::string& description) {
1002+
napi_value descriptionValue = String::New(env, description);
1003+
return Symbol::For(env, descriptionValue);
1004+
}
1005+
1006+
inline Symbol Symbol::For(napi_env env, const char* description) {
1007+
napi_value descriptionValue = String::New(env, description);
1008+
return Symbol::For(env, descriptionValue);
1009+
}
1010+
1011+
inline Symbol Symbol::For(napi_env env, String description) {
1012+
return Symbol::For(env, static_cast<napi_value>(description));
1013+
}
1014+
1015+
inline Symbol Symbol::For(napi_env env, napi_value description) {
1016+
Object symbObject = Napi::Env(env).Global().Get("Symbol").As<Object>();
1017+
auto forSymb =
1018+
symbObject.Get("for").As<Function>().Call(symbObject, {description});
1019+
return forSymb.As<Symbol>();
1020+
}
1021+
10011022
inline Symbol::Symbol() : Name() {
10021023
}
10031024

napi.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,18 @@ namespace Napi {
538538
/// Get a public Symbol (e.g. Symbol.iterator).
539539
static Symbol WellKnown(napi_env, const std::string& name);
540540

541+
// Create a symbol in the global registry, UTF-8 Encoded cpp string
542+
static Symbol For(napi_env env, const std::string& description);
543+
544+
// Create a symbol in the global registry, C style string (null terminated)
545+
static Symbol For(napi_env env, const char* description);
546+
547+
// Create a symbol in the global registry, String value describing the symbol
548+
static Symbol For(napi_env env, String description);
549+
550+
// Create a symbol in the global registry, napi_value describing the symbol
551+
static Symbol For(napi_env env, napi_value description);
552+
541553
Symbol(); ///< Creates a new _empty_ Symbol instance.
542554
Symbol(napi_env env,
543555
napi_value value); ///< Wraps a Node-API value primitive.

test/binding.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Object InitTypedThreadSafeFunctionSum(Env env);
5858
Object InitTypedThreadSafeFunctionUnref(Env env);
5959
Object InitTypedThreadSafeFunction(Env env);
6060
#endif
61+
Object InitSymbol(Env env);
6162
Object InitTypedArray(Env env);
6263
Object InitGlobalObject(Env env);
6364
Object InitObjectWrap(Env env);
@@ -117,6 +118,7 @@ Object Init(Env env, Object exports) {
117118
#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
118119
exports.Set("promise", InitPromise(env));
119120
exports.Set("run_script", InitRunScript(env));
121+
exports.Set("symbol", InitSymbol(env));
120122
#if (NAPI_VERSION > 3)
121123
exports.Set("threadsafe_function_ctx", InitThreadSafeFunctionCtx(env));
122124
exports.Set("threadsafe_function_existing_tsfn", InitThreadSafeFunctionExistingTsfn(env));

test/binding.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
'object/subscript_operator.cc',
4747
'promise.cc',
4848
'run_script.cc',
49+
"symbol.cc",
4950
'threadsafe_function/threadsafe_function_ctx.cc',
5051
'threadsafe_function/threadsafe_function_existing_tsfn.cc',
5152
'threadsafe_function/threadsafe_function_ptr.cc',

test/symbol.cc

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include <napi.h>
2+
using namespace Napi;
3+
4+
Symbol CreateNewSymbolWithNoArgs(const Napi::CallbackInfo&) {
5+
return Napi::Symbol();
6+
}
7+
8+
Symbol CreateNewSymbolWithCppStrDesc(const Napi::CallbackInfo& info) {
9+
String cppStrKey = info[0].As<String>();
10+
return Napi::Symbol::New(info.Env(), cppStrKey.Utf8Value());
11+
}
12+
13+
Symbol CreateNewSymbolWithCStrDesc(const Napi::CallbackInfo& info) {
14+
String cStrKey = info[0].As<String>();
15+
return Napi::Symbol::New(info.Env(), cStrKey.Utf8Value().c_str());
16+
}
17+
18+
Symbol CreateNewSymbolWithNapiString(const Napi::CallbackInfo& info) {
19+
String strKey = info[0].As<String>();
20+
return Napi::Symbol::New(info.Env(), strKey);
21+
}
22+
23+
Symbol GetWellknownSymbol(const Napi::CallbackInfo& info) {
24+
String registrySymbol = info[0].As<String>();
25+
return Napi::Symbol::WellKnown(info.Env(),
26+
registrySymbol.Utf8Value().c_str());
27+
}
28+
29+
Symbol FetchSymbolFromGlobalRegistry(const Napi::CallbackInfo& info) {
30+
String registrySymbol = info[0].As<String>();
31+
return Napi::Symbol::For(info.Env(), registrySymbol);
32+
}
33+
34+
Symbol FetchSymbolFromGlobalRegistryWithCppKey(const Napi::CallbackInfo& info) {
35+
String cppStringKey = info[0].As<String>();
36+
return Napi::Symbol::For(info.Env(), cppStringKey.Utf8Value());
37+
}
38+
39+
Symbol FetchSymbolFromGlobalRegistryWithCKey(const Napi::CallbackInfo& info) {
40+
String cppStringKey = info[0].As<String>();
41+
return Napi::Symbol::For(info.Env(), cppStringKey.Utf8Value().c_str());
42+
}
43+
44+
Symbol TestUndefinedSymbolsCanBeCreated(const Napi::CallbackInfo& info) {
45+
Napi::Env env = info.Env();
46+
return Napi::Symbol::For(env, env.Undefined());
47+
}
48+
49+
Symbol TestNullSymbolsCanBeCreated(const Napi::CallbackInfo& info) {
50+
Napi::Env env = info.Env();
51+
return Napi::Symbol::For(env, env.Null());
52+
}
53+
54+
Object InitSymbol(Env env) {
55+
Object exports = Object::New(env);
56+
57+
exports["createNewSymbolWithNoArgs"] =
58+
Function::New(env, CreateNewSymbolWithNoArgs);
59+
exports["createNewSymbolWithCppStr"] =
60+
Function::New(env, CreateNewSymbolWithCppStrDesc);
61+
exports["createNewSymbolWithCStr"] =
62+
Function::New(env, CreateNewSymbolWithCStrDesc);
63+
exports["createNewSymbolWithNapi"] =
64+
Function::New(env, CreateNewSymbolWithNapiString);
65+
exports["getWellKnownSymbol"] = Function::New(env, GetWellknownSymbol);
66+
exports["getSymbolFromGlobalRegistry"] =
67+
Function::New(env, FetchSymbolFromGlobalRegistry);
68+
exports["getSymbolFromGlobalRegistryWithCKey"] =
69+
Function::New(env, FetchSymbolFromGlobalRegistryWithCKey);
70+
exports["getSymbolFromGlobalRegistryWithCppKey"] =
71+
Function::New(env, FetchSymbolFromGlobalRegistryWithCppKey);
72+
exports["testUndefinedSymbolCanBeCreated"] =
73+
Function::New(env, TestUndefinedSymbolsCanBeCreated);
74+
exports["testNullSymbolCanBeCreated"] =
75+
Function::New(env, TestNullSymbolsCanBeCreated);
76+
return exports;
77+
}

test/symbol.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
'use strict';
2+
3+
const buildType = process.config.target_defaults.default_configuration;
4+
const assert = require('assert');
5+
6+
test(require(`./build/${buildType}/binding.node`));
7+
test(require(`./build/${buildType}/binding_noexcept.node`));
8+
9+
10+
async function test(binding)
11+
{
12+
13+
const wellKnownSymbolFunctions = ['asyncIterator','hasInstance','isConcatSpreadable', 'iterator','match','matchAll','replace','search','split','species','toPrimitive','toStringTag','unscopables'];
14+
15+
function assertCanCreateSymbol(symbol)
16+
{
17+
assert(binding.symbol.createNewSymbolWithCppStr(symbol) !== null);
18+
assert(binding.symbol.createNewSymbolWithCStr(symbol) !== null);
19+
assert(binding.symbol.createNewSymbolWithNapi(symbol) !== null);
20+
}
21+
22+
function assertSymbolAreUnique(symbol)
23+
{
24+
const symbolOne = binding.symbol.createNewSymbolWithCppStr(symbol);
25+
const symbolTwo = binding.symbol.createNewSymbolWithCppStr(symbol);
26+
27+
assert(symbolOne !== symbolTwo);
28+
}
29+
30+
function assertSymbolIsWellknown(symbol)
31+
{
32+
const symbOne = binding.symbol.getWellKnownSymbol(symbol);
33+
const symbTwo = binding.symbol.getWellKnownSymbol(symbol);
34+
assert(symbOne && symbTwo);
35+
assert(symbOne === symbTwo);
36+
}
37+
38+
function assertSymbolIsNotWellknown(symbol)
39+
{
40+
const symbolTest = binding.symbol.getWellKnownSymbol(symbol);
41+
assert(symbolTest === undefined);
42+
}
43+
44+
function assertCanCreateOrFetchGlobalSymbols(symbol, fetchFunction)
45+
{
46+
const symbOne = fetchFunction(symbol);
47+
const symbTwo = fetchFunction(symbol);
48+
assert(symbOne && symbTwo);
49+
assert(symbOne === symbTwo);
50+
}
51+
52+
assertCanCreateSymbol("testing");
53+
assertSymbolAreUnique("symbol");
54+
assertSymbolIsNotWellknown("testing");
55+
56+
for(const wellknownProperty of wellKnownSymbolFunctions)
57+
{
58+
assertSymbolIsWellknown(wellknownProperty);
59+
}
60+
61+
assertCanCreateOrFetchGlobalSymbols("data", binding.symbol.getSymbolFromGlobalRegistry);
62+
assertCanCreateOrFetchGlobalSymbols("CppKey", binding.symbol.getSymbolFromGlobalRegistryWithCppKey);
63+
assertCanCreateOrFetchGlobalSymbols("CKey", binding.symbol.getSymbolFromGlobalRegistryWithCKey);
64+
65+
assert(binding.symbol.createNewSymbolWithNoArgs() === undefined);
66+
67+
assert(binding.symbol.testNullSymbolCanBeCreated() === binding.symbol.testNullSymbolCanBeCreated());
68+
assert(binding.symbol.testUndefinedSymbolCanBeCreated() === binding.symbol.testUndefinedSymbolCanBeCreated());
69+
assert(binding.symbol.testUndefinedSymbolCanBeCreated() !== binding.symbol.testNullSymbolCanBeCreated());
70+
}

0 commit comments

Comments
 (0)