Skip to content

Commit

Permalink
enable unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Deepak Rajamohan committed Oct 15, 2021
1 parent 71494a4 commit 2fc9d73
Show file tree
Hide file tree
Showing 15 changed files with 491 additions and 12 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,10 @@
"predev:incremental": "node-gyp configure build -C test --debug",
"dev:incremental": "node test",
"doc": "doxygen doc/Doxyfile",
"lint": "node tools/clang-format.js",
"lint:fix": "git-clang-format '*.h', '*.cc'"
"lint": "eslint $(git diff --name-only refs/remotes/origin/main '**/*.js' | xargs) && node tools/clang-format",
"lint:fix": "node tools/clang-format --fix && eslint --fix $(git diff --cached --name-only '**/*.js' | xargs && git diff --name-only '**/*.js' | xargs)",
"preunit": "filter=\"$npm_config_filter\" node-gyp rebuild -C unit-test",
"unit": "filter=\"$npm_config_filter\" node unit-test/test"
},
"pre-commit": "lint",
"version": "3.1.0",
Expand Down
36 changes: 36 additions & 0 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,39 @@ exports.mustNotCall = function(msg) {
assert.fail(msg || 'function should not have been called');
};
};

exports.runTest = async function(test, buildType, buildPathRoot = process.env.BUILD_PATH || '') {
buildType = buildType || process.config.target_defaults.default_configuration || 'Release';

const bindings = [
path.join(buildPathRoot, `../build/${buildType}/binding.node`),
path.join(buildPathRoot, `../build/${buildType}/binding_noexcept.node`),
path.join(buildPathRoot, `../build/${buildType}/binding_noexcept_maybe.node`),
].map(it => require.resolve(it));

for (const item of bindings) {
await Promise.resolve(test(require(item)))
.finally(exports.mustCall());
}
}

exports.runTestWithBindingPath = async function(test, buildType, buildPathRoot = process.env.BUILD_PATH || '') {
buildType = buildType || process.config.target_defaults.default_configuration || 'Release';

const bindings = [
path.join(buildPathRoot, `../build/${buildType}/binding.node`),
path.join(buildPathRoot, `../build/${buildType}/binding_noexcept.node`),
path.join(buildPathRoot, `../build/${buildType}/binding_noexcept_maybe.node`),
].map(it => require.resolve(it));

for (const item of bindings) {
await test(item);
}
}

exports.runTestWithBuildType = async function(test, buildType) {
buildType = buildType || process.config.target_defaults.default_configuration || 'Release';

await Promise.resolve(test(buildType))
.finally(exports.mustCall());
}
41 changes: 32 additions & 9 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,23 @@ if (typeof global.gc !== 'function') {

const fs = require('fs');
const path = require('path');
process.env.filter = require('../unit-test/matchModules').matchWildCards(process.env.filter);

let testModules = [];

const filterCondition = process.env.filter || '';
const filterConditionFiles = filterCondition.split(' ').length ? filterCondition.split(' ') : [filterCondition];


function checkFilterCondition(fileName, parsedFilepath) {
let result = false;

if (!filterConditionFiles.length) result = true;
if (filterConditionFiles.includes(parsedFilepath)) result = true;
if (filterConditionFiles.includes(fileName)) result = true;
return result;
}

// TODO(RaisinTen): Update this when the test filenames
// are changed into test_*.js.
function loadTestModules(currentDirectory = __dirname, pre = '') {
Expand All @@ -50,15 +64,19 @@ function loadTestModules(currentDirectory = __dirname, pre = '') {
return;
}
const absoluteFilepath = path.join(currentDirectory, file);
const parsedFilepath = path.parse(file);
const parsedPath = path.parse(currentDirectory);

if (fs.statSync(absoluteFilepath).isDirectory()) {
if (fs.existsSync(absoluteFilepath + '/index.js')) {
testModules.push(pre + file);
if (checkFilterCondition(parsedFilepath.name, parsedPath.base)) {
testModules.push(pre + file);
}
} else {
loadTestModules(absoluteFilepath, pre + file + '/');
}
} else {
const parsedFilepath = path.parse(file);
if (parsedFilepath.ext === '.js') {
if (parsedFilepath.ext === '.js' && checkFilterCondition(parsedFilepath.name, parsedPath.base)) {
testModules.push(pre + parsedFilepath.name);
}
}
Expand All @@ -69,7 +87,7 @@ loadTestModules();

process.config.target_defaults.default_configuration =
fs
.readdirSync(path.join(__dirname, 'build'))
.readdirSync(path.join(__dirname, process.env.REL_BUILD_PATH, 'build'))
.filter((item) => (item === 'Debug' || item === 'Release'))[0];

let napiVersion = Number(process.versions.napi);
Expand All @@ -86,7 +104,7 @@ if (napiVersion < 3) {
testModules.splice(testModules.indexOf('version_management'), 1);
}

if (napiVersion < 4) {
if (napiVersion < 4 && !filterConditionFiles.length) {
testModules.splice(testModules.indexOf('asyncprogressqueueworker'), 1);
testModules.splice(testModules.indexOf('asyncprogressworker'), 1);
testModules.splice(testModules.indexOf('threadsafe_function/threadsafe_function_ctx'), 1);
Expand All @@ -97,25 +115,30 @@ if (napiVersion < 4) {
testModules.splice(testModules.indexOf('threadsafe_function/threadsafe_function'), 1);
}

if (napiVersion < 5) {
if (napiVersion < 5 && !filterConditionFiles.length) {
testModules.splice(testModules.indexOf('date'), 1);
}

if (napiVersion < 6) {
if (napiVersion < 6 && !filterConditionFiles.length) {
testModules.splice(testModules.indexOf('addon'), 1);
testModules.splice(testModules.indexOf('addon_data'), 1);
testModules.splice(testModules.indexOf('bigint'), 1);
testModules.splice(testModules.indexOf('typedarray-bigint'), 1);
}

if (majorNodeVersion < 12) {
if (majorNodeVersion < 12 && !filterConditionFiles.length) {
testModules.splice(testModules.indexOf('objectwrap_worker_thread'), 1);
testModules.splice(testModules.indexOf('error_terminating_environment'), 1);
}

if (napiVersion < 8 && !filterConditionFiles.length) {
testModules.splice(testModules.indexOf('object/object_freeze_seal'), 1);
}

(async function() {
console.log(`Testing with N-API Version '${napiVersion}'.`);

console.log('Starting test suite\n');
console.log('Starting test suite\n', testModules);

// Requiring each module runs tests in the module.
for (const name of testModules) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = test(require(`../build/${buildType}/binding.node`))

async function test(binding) {
const ctx = { };
const tsfn = new binding.threadsafe_function_ctx.TSFNWrap(ctx);
const tsfn = new binding.typed_threadsafe_function_ctx.TSFNWrap(ctx);
assert(tsfn.getContext() === ctx);
await tsfn.release();
}
3 changes: 3 additions & 0 deletions unit-test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules
/build
/generated
27 changes: 27 additions & 0 deletions unit-test/binding-file-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports.generateFileContent = function(configs) {
const content = [];
const inits = [];
const exports = [];

for (let config of configs) {
inits.push(`Object Init${config.objectName}(Env env);`);
exports.push(`exports.Set(\"${config.propertyName}\", Init${config.objectName}(env));`);
}

content.push("#include \"napi.h\"");
content.push("using namespace Napi;");

//content.push("Object InitName(Env env);");
inits.forEach(init => content.push(init));

content.push("Object Init(Env env, Object exports) {");

//content.push("exports.Set(\"name\", InitName(env));");
exports.forEach(exp => content.push(exp));

content.push("return exports;");
content.push("}");
content.push("NODE_API_MODULE(addon, Init);");

return Promise.resolve(content.join('\r\n'));
}
64 changes: 64 additions & 0 deletions unit-test/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
'target_defaults': {
'includes': ['common.gypi'],
'include_dirs': ['../test/common'],
'variables': {
'build_sources': [
"<!@(node -p \"require('./injectTestParams').filesToCompile()\")",
]
},
},
'targets': [
{
"target_name": "generateBindingCC",
"type": "none",
"actions": [ {
"action_name": "generateBindingCC",
"message": "Generating binding cc file",
"outputs": ["generated/binding.cc"],
"conditions": [
[ "'true'=='true'", {
"inputs": [""],
"action": [
"node",
"generate-binding-cc.js",
"<!@(node -p \"require('./injectTestParams').filesForBinding()\" )"
]
} ]
]
} ]
},
{
'target_name': 'binding',
'includes': ['../except.gypi'],
'sources': ['>@(build_sources)'],
'dependencies': [ 'generateBindingCC' ]
},
{
'target_name': 'binding_noexcept',
'includes': ['../noexcept.gypi'],
'sources': ['>@(build_sources)'],
'dependencies': [ 'generateBindingCC' ]
},
{
'target_name': 'binding_noexcept_maybe',
'includes': ['../noexcept.gypi'],
'sources': ['>@(build_sources)'],
'defines': ['NODE_ADDON_API_ENABLE_MAYBE']
},
{
'target_name': 'binding_swallowexcept',
'includes': ['../except.gypi'],
'sources': ['>@(build_sources)'],
'defines': ['NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS'],
'dependencies': [ 'generateBindingCC' ]
},
{
'target_name': 'binding_swallowexcept_noexcept',
'includes': ['../noexcept.gypi'],
'sources': ['>@(build_sources)'],
'defines': ['NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS'],
'dependencies': [ 'generateBindingCC' ]
},
],
}
21 changes: 21 additions & 0 deletions unit-test/common.gypi
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
'variables': {
'NAPI_VERSION%': "<!(node -p \"process.versions.napi\")",
'disable_deprecated': "<!(node -p \"process.env['npm_config_disable_deprecated']\")"
},
'conditions': [
['NAPI_VERSION!=""', { 'defines': ['NAPI_VERSION=<@(NAPI_VERSION)'] } ],
['disable_deprecated=="true"', {
'defines': ['NODE_ADDON_API_DISABLE_DEPRECATED']
}],
['OS=="mac"', {
'cflags+': ['-fvisibility=hidden'],
'xcode_settings': {
'OTHER_CFLAGS': ['-fvisibility=hidden']
}
}]
],
'include_dirs': ["<!(node -p \"require('../').include_dir\")", "./generated"],
'cflags': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ],
'cflags_cc': [ '-Werror', '-Wall', '-Wextra', '-Wpedantic', '-Wunused-parameter' ]
}
20 changes: 20 additions & 0 deletions unit-test/exceptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
'nouns': {
'constructor': 'constructor',
'threadsafe': 'threadSafe',
'objectwrap': 'objectWrap',
},
'exportNames': {
'AsyncWorkerPersistent': 'PersistentAsyncWorker',
},
'propertyNames': {
'async_worker_persistent': 'persistentasyncworker',
'objectwrap_constructor_exception':'objectwrapConstructorException',
},
'skipBinding': [
'global_object_delete_property',
'global_object_get_property',
'global_object_has_own_property',
'global_object_set_property',
]
};
41 changes: 41 additions & 0 deletions unit-test/generate-binding-cc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const fs = require('fs');
const path = require('path');
const listOfTestModules = require('./listOfTestModules');
const exceptions = require('./exceptions');
const generateFileContent = require('./binding-file-template').generateFileContent;

const buildDirs = listOfTestModules.dirs;
const buildFiles = listOfTestModules.files;

function generateBindingConfigurations() {
const configs = [];

const testFilesToBind = process.argv.slice(2);
console.log('test modules to bind: ', testFilesToBind);

testFilesToBind.forEach((file) => {
const configName = file.split('.cc')[0];

if (buildDirs[configName]) {
for (let file of buildDirs[configName]) {
if (exceptions.skipBinding.includes(file)) continue;
configs.push(buildFiles[file]);
}
} else if (buildFiles[configName]) {
configs.push(buildFiles[configName]);
} else {
console.log('not found', file, configName);
}
});

return Promise.resolve(configs);
}

function writeToBindingFile(content) {
const generatedFilePath = path.join(__dirname, 'generated', 'binding.cc' );
fs.writeFileSync(generatedFilePath , "" );
fs.writeFileSync(generatedFilePath, content, { flag: "a" } );
console.log('generated binding file ', generatedFilePath, new Date());
}

generateBindingConfigurations().then(generateFileContent).then(writeToBindingFile);
Loading

0 comments on commit 2fc9d73

Please sign in to comment.