Skip to content

Commit

Permalink
Logging, callbacks and testing basic tools.
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre committed Mar 22, 2010
1 parent 8e2b6de commit a9d340d
Show file tree
Hide file tree
Showing 8 changed files with 915 additions and 0 deletions.
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions README
@@ -0,0 +1,32 @@

## Setup
How to use these libraries / tools :

In your .bashrc (or whatever rc) file, set the bin dir in your PATH env variable:
export PATH=$PATH:/path/to/nodetk/bin

and the src dir in your NODE_PATH env variable:
export NODE_PATH=$NODE_PATH:/path/to/nodetk/src

You should then be able to use the nodetk modules with something like:
var callbacks = require("nodetk/orchestration/callbacks");

You now have the following available commands:
nodetests [-v]


## License

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see [http://www.fsf.org/licensing/licenses/agpl-3.0.html](http://www.fsf.org/licensing/licenses/agpl-3.0.html)

5 changes: 5 additions & 0 deletions bin/nodetests
@@ -0,0 +1,5 @@
#!/bin/bash

BASEDIR=`dirname $0`
node $BASEDIR/../src/nodetk/testing/nodetests.js $*

13 changes: 13 additions & 0 deletions src/nodetk/logging.js
@@ -0,0 +1,13 @@
/* Provides debug function, wrapper around sys.puts, [de]activable on demand.
*/

var sys = require("sys");

var debug_active = false;
exports.debug = function(/* stuff to print*/) {
if(debug_active) sys.puts.apply(this, arguments);
};

exports.debug.on = function() {debug_active=true};
exports.debug.off = function() {debug_active=false};

60 changes: 60 additions & 0 deletions src/nodetk/orchestration/callbacks.js
@@ -0,0 +1,60 @@
// Some function to handle lists (or files) of callbacks


exports.get_waiter = function(calls_needed, callback){
/* Returns a function which will call the given
* callback once she has been called calls_needed times.
* If calls_needed is 0, then the callback is immediatly called.
*/
!calls_needed && callback();
return function(){
!--calls_needed && callback();
}
};


exports.empty_awaiting_callbacks = function(awaiting_callbacks, key, data){
/* Takes the list of functions present in awaiting_callbacks[key],
* calls them with data, and delete awaiting_callbacks[key] */
var to_call = awaiting_callbacks[key] || [];
// Important! The delete must be done BEFORE the call
// of the following callbacks (callback at the end!)
delete awaiting_callbacks[key];
to_call.forEach(function(callback){
callback && callback(data);
});
};


exports.add_awaiting_callbacks = function(awaiting_callbacks, keys, callback){
/* Add (push) the given callback to every awaiting_callbacks[key] for key in keys.
* If awaiting_callbacks[key] does not exist, define it as the list [callback].
*/
keys.forEach(function(key){
if(awaiting_callbacks[key] == undefined) awaiting_callbacks[key] = [callback];
else awaiting_callbacks[key].push(callback);
});
};


var sync_calls = function(fct, args, callback, i/*optional*/) {
/* Runs the fct synchronously for each given set of args in args.
* The last arguments of the fct is a callback, called when fct finishes.
* Callback is called when the last call finished.
*
* Arguments:
* - args: array of single values (one argument for each call) or
* array of arrays (the inside arrays being the arguments).
*/
if(i === undefined) i = 0;
if(i < args.length) {
var args_fct = args[i];
if (args_fct.forEach === undefined) args_fct = [args_fct];
fct.apply(this, args_fct.concat([function(){
sync_calls(fct, args, callback, i+1);
}]));
}
else callback && callback();
};
exports.sync_calls = sync_calls;

26 changes: 26 additions & 0 deletions src/nodetk/testing/custom_assert.js
@@ -0,0 +1,26 @@
/* Wraps assert functions to call a callback, and display a dot (.) when success */

var assert = require('assert');
var sys = require('sys');

// will be called after each assert
var callback = function(){};


for(var attr in assert)
if(typeof assert[attr] == 'function' && attr != 'AssertionError') {
(function(func) {
exports[func] = function() {
assert[func].apply(this, arguments);
sys.print('.');
callback();
};
})(attr);
}

exports._set_assert_callback = function(clbck){
/* Set a callback to call after each assert.
*/
callback = clbck;
};

51 changes: 51 additions & 0 deletions src/nodetk/testing/nodetests.js
@@ -0,0 +1,51 @@
/* Run all tests present in files 'test_*.js' present in given directory or sub dirs.
* Search recursivly for test files.
*/

var fs = require('fs');
var sys = require('sys');

var tests_runner = require('nodetk/testing/tests_runner');

var run_tests = function() {
var args = {};
var tests_dir = '.';

process.argv.shift(); // remove 'node'
process.argv.shift(); // remove 'nodetests.js'

process.argv.forEach(function(e){
if(e[0] == '-') args[e]=true;
else tests_dir = e;
});

if(tests_dir[0] != '/') tests_dir = process.cwd() + '/' + tests_dir;
sys.puts("Run tests in " + tests_dir);

to_test = get_test_files(tests_dir);
tests_runner.run(to_test);
};


var get_test_files = function(tests_dir) {
if(!tests_dir.match(/\/$/)) tests_dir += '/';
var to_search_in = [];
var to_test = fs.readdirSync(tests_dir).map(function(fname){
return tests_dir + fname;
}).filter(function(fpath) {
if (fs.statSync(fpath).isDirectory()) {
to_search_in.push(fpath);
return false;
}
return fpath.match(/\/test_[^\/]+\.js$/);
}).map(function(fpath) {
return fpath.replace(/\.js$/, '');
});
to_search_in.forEach(function(dirpath) {
to_test = to_test.concat(get_test_files(dirpath));
});
return to_test;
};

run_tests();

67 changes: 67 additions & 0 deletions src/nodetk/testing/tests_runner.js
@@ -0,0 +1,67 @@
/* Runs all the tests in a file.
* Tests are ran one by one, synchronously.
*
* Tests must be in module.tests.
* You can specify a setup function (using exports.setup),
* which will run before every test.
*/

var sys = require("sys");

var custom_assert = require("nodetk/testing/custom_assert");
var CLB = require('nodetk/orchestration/callbacks');

var verbose;
var start_time;

exports.run = function(tests_files) {
var args = {};
process.argv.forEach(function(e){args[e]=true;});
verbose = args['-v'];

start_time = new Date().getTime();
CLB.sync_calls(run_test_file, tests_files, function() {
display_process_infos();
// TODO: maybe we should wait a bit here, if there is more callbacks than expected,
// then there is a problem...
process.exit(0);
});
};

var dummy = function(callback) {callback()};
var setup;

var run_test = function(name, expected_asserts, test, callback) {
/* Run given test fct, having given name.
* The test function must use expected_asserts number of asserts.
* callback is ran when the expected number of asserts has been called.
*/
setup(function() {
var test_waiter = CLB.get_waiter(expected_asserts, function(){
verbose && sys.puts(name + ': ' + expected_asserts + " asserts done.");
callback && callback();
});
custom_assert._set_assert_callback(test_waiter);
test();
});
}

var run_test_file = function(test_file, callback) {
var module = require(test_file);
setup = module.setup || dummy;
CLB.sync_calls(run_test, module.tests || [], function() {
verbose && sys.puts('-----------------');
verbose && sys.puts(test_file + '.js: ' + module.tests.length + " test(s) succeed\n");
callback();
});
};

var display_process_infos = function() {
var end_time = new Date().getTime();
var mem_use = process.memoryUsage();
sys.puts("\n================");
sys.puts("Ellapsed time: " + (end_time - start_time) + "ms.");
sys.puts("Memory use: " + JSON.stringify(mem_use));
};


0 comments on commit a9d340d

Please sign in to comment.