Skip to content

Commit e02e8a4

Browse files
JckXiamhdawson
authored andcommitted
test: add first set of symbol tests
PR-URL: #972 Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Nicola Del Gobbo <nicoladelgobbo@gmail.com>
1 parent da50b51 commit e02e8a4

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
@@ -1003,6 +1003,27 @@ inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) {
10031003
return Napi::Env(env).Global().Get("Symbol").As<Object>().Get(name).As<Symbol>();
10041004
}
10051005

1006+
inline Symbol Symbol::For(napi_env env, const std::string& 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, const char* description) {
1012+
napi_value descriptionValue = String::New(env, description);
1013+
return Symbol::For(env, descriptionValue);
1014+
}
1015+
1016+
inline Symbol Symbol::For(napi_env env, String description) {
1017+
return Symbol::For(env, static_cast<napi_value>(description));
1018+
}
1019+
1020+
inline Symbol Symbol::For(napi_env env, napi_value description) {
1021+
Object symbObject = Napi::Env(env).Global().Get("Symbol").As<Object>();
1022+
auto forSymb =
1023+
symbObject.Get("for").As<Function>().Call(symbObject, {description});
1024+
return forSymb.As<Symbol>();
1025+
}
1026+
10061027
inline Symbol::Symbol() : Name() {
10071028
}
10081029

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)