Skip to content

Commit 238f5d1

Browse files
authored
Set up unit tests (#24)
- Set up a pattern for organizing .cc and .js test files roughly corresponding to each class to be tested - Add unit tests for the Function and Error classes - Update test binding.gyp file to build on Windows (fix quotes) - Update test binding.gyp and README to enable exceptions with MSVC - Fix type of CallbackInfo::This
1 parent f938de1 commit 238f5d1

File tree

12 files changed

+282
-19
lines changed

12 files changed

+282
-19
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/node_modules
2+
/build

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ backward-compatibility with use with older versions of Node.js that do
66
not have N-API built-in.
77

88
To use N-API in a native module:
9-
1. Add a dependency on this package to `package.json`.
9+
1. Add a dependency on this package to `package.json`.
1010
It is not yet published to npm, so reference it directly from GitHub.
1111
```json
1212
"dependencies": {
@@ -27,6 +27,9 @@ To use N-API in a native module:
2727
'cflags!': [ '-fno-exceptions' ],
2828
'cflags_cc!': [ '-fno-exceptions' ],
2929
'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' },
30+
'msvs_settings': {
31+
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
32+
},
3033
```
3134

3235
4. Include `napi.h` in the native module code.

napi-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1682,7 +1682,7 @@ inline const Value CallbackInfo::operator [](size_t index) const {
16821682
return index < _argc ? Value(_env, _argv[index]) : Env().Undefined();
16831683
}
16841684

1685-
inline Object CallbackInfo::This() const {
1685+
inline Value CallbackInfo::This() const {
16861686
if (_this == nullptr) {
16871687
return Env().Undefined();
16881688
}

napi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ namespace Napi {
617617
Napi::Env Env() const;
618618
size_t Length() const;
619619
const Value operator [](size_t index) const;
620-
Object This() const;
620+
Value This() const;
621621
void* Data() const;
622622
void SetData(void* data);
623623

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {},
66
"description": "Node.js API (N-API)",
77
"devDependencies": {
8+
"node-gyp": "^3.6.0"
89
},
910
"directories": {},
1011
"homepage": "https://github.com/nodejs/node-api",
@@ -18,6 +19,8 @@
1819
"url": "git://github.com/nodejs/node-api.git"
1920
},
2021
"scripts": {
22+
"pretest": "node-gyp rebuild -C test",
23+
"test": "node test"
2124
},
2225
"version": "0.1.0"
2326
}

test/binding.cc

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@
22

33
using namespace Napi;
44

5-
Value Test1(const CallbackInfo& info) {
6-
auto env = info.Env();
7-
Object obj = Object::New(env);
8-
9-
obj["foo"] = String::New(env, "bar");
10-
11-
return obj;
12-
}
5+
Object InitError(Env env);
6+
Object InitFunction(Env env);
137

148
void Init(Env env, Object exports, Object module) {
15-
exports.Set("test1", Function::New(env, Test1));
9+
exports.Set("error", InitError(env));
10+
exports.Set("function", InitFunction(env));
1611
}
1712

1813
NODE_API_MODULE(addon, Init)

test/binding.gyp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22
'targets': [
33
{
44
'target_name': 'binding',
5-
'sources': [ 'binding.cc' ],
6-
'include_dirs': ['<!(node -p \'require("../").include\')'],
7-
'dependencies': ['<!(node -p \'require("../").gyp\')'],
5+
'sources': [
6+
'binding.cc',
7+
'error.cc',
8+
'function.cc',
9+
],
10+
'include_dirs': ["<!(node -p \"require('../').include\")"],
11+
'dependencies': ["<!(node -p \"require('../').gyp\")"],
812
'cflags!': [ '-fno-exceptions' ],
913
'cflags_cc!': [ '-fno-exceptions' ],
10-
'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' }
14+
'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' },
15+
'msvs_settings': {
16+
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
17+
},
1118
}
1219
]
1320
}

test/error.cc

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "napi.h"
2+
3+
using namespace Napi;
4+
5+
void ThrowError(const CallbackInfo& info) {
6+
std::string message = info[0].As<String>().Utf8Value();
7+
throw Error::New(info.Env(), message);
8+
}
9+
10+
void ThrowTypeError(const CallbackInfo& info) {
11+
std::string message = info[0].As<String>().Utf8Value();
12+
throw TypeError::New(info.Env(), message);
13+
}
14+
15+
void ThrowRangeError(const CallbackInfo& info) {
16+
std::string message = info[0].As<String>().Utf8Value();
17+
throw RangeError::New(info.Env(), message);
18+
}
19+
20+
Value CatchError(const CallbackInfo& info) {
21+
Function thrower = info[0].As<Function>();
22+
try {
23+
thrower({});
24+
} catch (const Error& e) {
25+
return e;
26+
}
27+
return info.Env().Null();
28+
}
29+
30+
Value CatchErrorMessage(const CallbackInfo& info) {
31+
Function thrower = info[0].As<Function>();
32+
try {
33+
thrower({});
34+
} catch (const Error& e) {
35+
std::string message = e.Message();
36+
return String::New(info.Env(), message);
37+
}
38+
return info.Env().Null();
39+
}
40+
41+
void DoNotCatch(const CallbackInfo& info) {
42+
Function thrower = info[0].As<Function>();
43+
thrower({});
44+
}
45+
46+
void CatchAndRethrowError(const CallbackInfo& info) {
47+
Function thrower = info[0].As<Function>();
48+
try {
49+
thrower({});
50+
} catch (Error& e) {
51+
e["caught"] = Boolean::New(info.Env(), true);
52+
throw e;
53+
}
54+
}
55+
56+
Object InitError(Env env) {
57+
Object exports = Object::New(env);
58+
exports["throwError"] = Function::New(env, ThrowError);
59+
exports["throwTypeError"] = Function::New(env, ThrowTypeError);
60+
exports["throwRangeError"] = Function::New(env, ThrowRangeError);
61+
exports["catchError"] = Function::New(env, CatchError);
62+
exports["catchErrorMessage"] = Function::New(env, CatchErrorMessage);
63+
exports["doNotCatch"] = Function::New(env, DoNotCatch);
64+
exports["catchAndRethrowError"] = Function::New(env, CatchAndRethrowError);
65+
return exports;
66+
}

test/error.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
const buildType = process.config.target_defaults.default_configuration;
3+
const binding = require(`./build/${buildType}/binding.node`);
4+
const assert = require('assert');
5+
6+
assert.throws(() => binding.error.throwError('test'), err => {
7+
return err instanceof Error && err.message === 'test';
8+
});
9+
10+
assert.throws(() => binding.error.throwTypeError('test'), err => {
11+
return err instanceof TypeError && err.message === 'test';
12+
});
13+
14+
assert.throws(() => binding.error.throwRangeError('test'), err => {
15+
return err instanceof RangeError && err.message === 'test';
16+
});
17+
18+
assert.throws(
19+
() => binding.error.doNotCatch(
20+
() => {
21+
throw new TypeError('test');
22+
}),
23+
err => {
24+
return err instanceof TypeError && err.message === 'test' && !err.caught;
25+
});
26+
27+
assert.throws(
28+
() => binding.error.catchAndRethrowError(
29+
() => {
30+
throw new TypeError('test');
31+
}),
32+
err => {
33+
return err instanceof TypeError && err.message === 'test' && err.caught;
34+
});
35+
36+
const err = binding.error.catchError(
37+
() => { throw new TypeError('test'); });
38+
assert(err instanceof TypeError);
39+
assert.strictEqual(err.message, 'test');
40+
41+
const msg = binding.error.catchErrorMessage(
42+
() => { throw new TypeError('test'); });
43+
assert.strictEqual(msg, 'test');

test/function.cc

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include "napi.h"
2+
3+
using namespace Napi;
4+
5+
void VoidCallback(const CallbackInfo& info) {
6+
auto env = info.Env();
7+
Object obj = info[0].As<Object>();
8+
9+
obj["foo"] = String::New(env, "bar");
10+
}
11+
12+
Value ValueCallback(const CallbackInfo& info) {
13+
auto env = info.Env();
14+
Object obj = Object::New(env);
15+
16+
obj["foo"] = String::New(env, "bar");
17+
18+
return obj;
19+
}
20+
21+
Value CallWithArgs(const CallbackInfo& info) {
22+
Function func = info[0].As<Function>();
23+
return func({ info[1], info[2], info[3] });
24+
}
25+
26+
Value CallWithVector(const CallbackInfo& info) {
27+
Function func = info[0].As<Function>();
28+
std::vector<napi_value> args;
29+
args.reserve(3);
30+
args.push_back(info[1]);
31+
args.push_back(info[2]);
32+
args.push_back(info[3]);
33+
return func.Call(args);
34+
}
35+
36+
Value CallWithReceiverAndArgs(const CallbackInfo& info) {
37+
Function func = info[0].As<Function>();
38+
Value receiver = info[1];
39+
return func.Call(receiver, { info[2], info[3], info[4] });
40+
}
41+
42+
Value CallWithReceiverAndVector(const CallbackInfo& info) {
43+
Function func = info[0].As<Function>();
44+
Value receiver = info[1];
45+
std::vector<napi_value> args;
46+
args.reserve(3);
47+
args.push_back(info[2]);
48+
args.push_back(info[3]);
49+
args.push_back(info[4]);
50+
return func.Call(receiver, args);
51+
}
52+
53+
Value CallConstructorWithArgs(const CallbackInfo& info) {
54+
Function func = info[0].As<Function>();
55+
return func.New({ info[1], info[2], info[3] });
56+
}
57+
58+
Value CallConstructorWithVector(const CallbackInfo& info) {
59+
Function func = info[0].As<Function>();
60+
std::vector<napi_value> args;
61+
args.reserve(3);
62+
args.push_back(info[1]);
63+
args.push_back(info[2]);
64+
args.push_back(info[3]);
65+
return func.New(args);
66+
}
67+
68+
Object InitFunction(Env env) {
69+
Object exports = Object::New(env);
70+
exports["voidCallback"] = Function::New(env, VoidCallback, "voidCallback");
71+
exports["valueCallback"] = Function::New(env, ValueCallback, std::string("valueCallback"));
72+
exports["callWithArgs"] = Function::New(env, CallWithArgs);
73+
exports["callWithVector"] = Function::New(env, CallWithVector);
74+
exports["callWithReceiverAndArgs"] = Function::New(env, CallWithReceiverAndArgs);
75+
exports["callWithReceiverAndVector"] = Function::New(env, CallWithReceiverAndVector);
76+
exports["callConstructorWithArgs"] = Function::New(env, CallConstructorWithArgs);
77+
exports["callConstructorWithVector"] = Function::New(env, CallConstructorWithVector);
78+
return exports;
79+
}

0 commit comments

Comments
 (0)