Skip to content

Commit

Permalink
Working on problems with async execution
Browse files Browse the repository at this point in the history
  • Loading branch information
lukebayes committed Feb 21, 2011
1 parent 5a4762c commit 66abdd7
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 55 deletions.
23 changes: 23 additions & 0 deletions bin/nodeshould.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

/**
* Run this file with:
*
* nodeshould -s sources \
* -s lib/foo \
* -s lib/bar \
* -t '/test-*.js/' \
* -n '/should make happy/'
*
* @param s Directories that contain code that can be required. If a directory
* is found at ./src or ./test, those directories will be automatically added
* to the load path.
* @param t Regular Expression that matches the test file or files that you
* want to load.
* @param n Regular Expression that matches the test label(s) that you want
* to execute.
*/

var Runner = require('node_should').Runner;
var runner = new Runner();
runner.runFromTerminal(process.argv);

4 changes: 2 additions & 2 deletions example/test/unit/some_class_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ context('SomeClass', function() {

// This is an asynchronous test method:
// Node how we send our custom handler to
// this.async, and send it's response to
// async, and send it's response to
// whatever would normally trigger our custom
// handler.
should('do some long task', function() {
var self = this;
this.instance.doSomeLongAsyncTask(10, this.async(function() {
this.instance.doSomeLongAsyncTask(10, async(function() {
assert.ok(self.instance.isDone, 'long async task completed');
}));
});
Expand Down
14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name" : "nodeshould",
"version" : "0.0.1",
"description" : "A small implementation of Shoulda for testing JavaScript applications with Node",
"keywords" : ["shoulda", "test", "unit", "integration"],
"homepage" : "http://github.com/lukebayes/node-should",
"author" : {
"name" : "Luke Bayes",
"email" : "lbayes@patternpark.com",
"url" : "http://lukebayes.com",
},
"main" : "node_should.js",
"test" : "runner.js",
}
1 change: 1 addition & 0 deletions src/node_should.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

exports.TestHandler = require('node_should/test_handler').TestHandler;
exports.Context = require('node_should/context').Context;
exports.Printer = require('node_should/printer').Printer;
exports.Runner = require('node_should/runner').Runner;
Expand Down
76 changes: 50 additions & 26 deletions src/node_should/context.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

var ArrayIterator = require('node_should/array_iterator').ArrayIterator;
var Composite = require('node_should/composite').Composite;

var AssertionError = require('assert').AssertionError;
var TestHandler = require('node_should/test_handler').TestHandler;
var util = require('util');

var Context = function(label) {
Expand All @@ -15,6 +14,8 @@ var Context = function(label) {

util.inherits(Context, Composite);

Context.DEFAULT_ASYNC_TIMEOUT = 50;

Context.prototype.addExecutionHandler = function(label, handler) {
this._cleanHandlerArguments(arguments);
this._label = label;
Expand All @@ -23,12 +24,12 @@ Context.prototype.addExecutionHandler = function(label, handler) {

Context.prototype.addSetupHandler = function(handler) {
if (handler == null) throw 'The handler provided to Context.addSetupHandler must not be null';
this._setupHandlers.push({ handler: handler });
this._setupHandlers.push(TestHandler.create(this, this.getLabel(), handler));
}

Context.prototype.addTeardownHandler = function(handler) {
if (handler == null) throw 'The handler provided to Context.addTeardownHandler must not be null';
this._teardownHandlers.push({ handler: handler });
this._teardownHandlers.push(TestHandler.create(this, this.getLabel(), handler));
}

/**
Expand All @@ -40,11 +41,48 @@ Context.prototype.addTestHandler = function(label, handler) {
if (this.getLabel() != '') {
label = [this.getLabel(), 'should', label].join(' ');
}
this._testHandlers.push({ handler: handler, label: label });
//this._testHandlers.push({ handler: handler, label: label });
this._testHandlers.push(TestHandler.create(this, label, handler));
// TODO(lukebayes) Probably shouldn't set label here, it's doing work that
// isn't necessary, and will only be used in cases of failure?
}

/**
* Called during test execution and should prevent the call of the next test
* setup, test or teardown until the async handler either times out, or
* completes.
*/
Context.prototype.addAsyncHandler = function(callback, timeout) {
timeout = (timeout == null) ? Context.DEFAULT_ASYNC_TIMEOUT : timeout;
var timeoutError = new Error('Async timeout (' + timeout + 'ms) exceeded.');
var self = this;
var options = this.currentOptions;
var timeoutId = null;
var timeoutExecuted = false;

options.asyncHandlers++;

timeoutId = setTimeout(function() {
console.log("async timeout exceeded with!: " + timeoutError.stack);
timeoutExecuted = true;
options.asyncHandlers--;

self._onError({
error : timeoutError
});

self._executeNextSetupOrTestOrTeardown(options);
}, timeout);

return function() {
if (!timeoutExecuted) {
clearTimeout(timeoutId);
options.asyncHandlers--;
self._callHandler(callback, options);
}
}
}

/**
* Will modify the provided arguments hash that may have a single handler argument,
* or a label, followed by a handler function. Regardless of how the args come in,
Expand Down Expand Up @@ -128,7 +166,7 @@ Context.prototype._createTestHandlerIterator = function(completeHandler) {
// that wraps test methods:
setTimeout(function() {
completeHandler();
}, 0);
});
}
});

Expand All @@ -139,23 +177,9 @@ Context.prototype._getTestExecutionOptions = function(iterator) {
var self = this;
var options = {};

var asyncHandler = function(callback) {
options.asyncHandlers++;
return function() {
options.asyncHandlers--;
self._callHandler(callback, options);
if (options.asyncHandlers == 0) {
self._executeNextSetupOrTestOrTeardown(options);
}
}
}

options.asyncHandlers = 0;
options.iterator = iterator;
options.scope = {
async : asyncHandler
}

options.scope = {};
return options;
}

Expand Down Expand Up @@ -189,6 +213,7 @@ Context.prototype._onFailure = function(testHandlerData) {
}

Context.prototype._onError = function(testHandlerData) {
//console.log(testHandlerData.error.stack);
if (this.listeners('error').length == 0) {
throw testHandlerData.error;
}
Expand All @@ -206,6 +231,7 @@ Context.prototype._callHandler = function(handlerData, options) {
}

try {
this.currentOptions = options;
handler.call(options.scope);
} catch (e) {
//console.log("-----------------");
Expand All @@ -232,16 +258,14 @@ Context.prototype._callHandler = function(handlerData, options) {
throw 'Caught handler exception with no exception? (' + e +')';
}
}

this._executeNextSetupOrTestOrTeardown(options);
}

Context.prototype._executeNextSetupOrTestOrTeardown = function(options) {
var itr = options.iterator;

if (itr.hasNext()) {
if (options.asyncHandlers == 0 && itr.hasNext()) {
this._callHandler(itr.next(), options);
if(options.asyncHandlers == 0) {
this._executeNextSetupOrTestOrTeardown(options);
}
}
}

Expand Down
19 changes: 17 additions & 2 deletions src/node_should/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ var DEFAULT_PRINTERS = [new Printer()];
var Runner = function() {
}

Runner.prototype.runFromTerminal = function(argv, printers, completeHandler) {
console.log("Running from term with: " + argv);
argv.forEach(function(val, index, array) {
console.log("val: " + val + " index: " + index);
if (val == '-s' || val == '--source-path') {
console.log("source path with: " + array[index+1]);
} else if (val == '-t' || val == '--test-expression') {
console.log("testl expression with: " + array[index+1]);
} else if (val == '-n' || val == '--name') {
console.log("test name with: " + array[index+1]);
}
});
}

Runner.prototype.run = function(expr, path, printers, completeHandler) {
printers = (printers) ? printers : DEFAULT_PRINTERS;
// start provided printers:
Expand Down Expand Up @@ -73,15 +87,16 @@ Runner.prototype._createScope = function(file, printers, completeHandler) {
scope[k] = global[k];
}

//scope.exports = this.exports;
//scope.module = this;
scope.global = scope;
scope.root = root;

scope.assert = assert;
scope.require = require;
scope.console = console;

scope.async = function() {
return context.addAsyncHandler.apply(context, arguments);
};
scope.context = function() {
createContext.apply(this, arguments);
};
Expand Down
38 changes: 38 additions & 0 deletions src/node_should/test_handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
var EventEmitter = require('events').EventEmitter;
var util = require('util');

var TestHandler = function() {
EventEmitter.call(this);
this.asyncHandlers = [];
this.context = null;
this.error = null;
this.failure = null;
this.handler = null;
this.label = '';
}

util.inherits(TestHandler, EventEmitter);

TestHandler.create = function(context, label, handler) {
var instance = new TestHandler();
instance.context = context;
instance.handler = handler;
instance.label = label;
return instance;
}

TestHandler.prototype.execute = function() {
}

TestHandler.prototype.onComplete = function() {
this.emit('complete', this);
}

TestHandler.prototype.addAsyncHandler = function(callback, timeout) {
}

TestHandler.prototype.asyncHandlerCount = function() {
return this.asyncHandlers.length;
}

exports.TestHandler = TestHandler;
2 changes: 0 additions & 2 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ IN THE SOFTWARE.

var path = require('path');
var assert = require('node_should/assert');
//require('assert_match');
//require('assert_same');

exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, 'fixtures');
Expand Down
36 changes: 21 additions & 15 deletions test/unit/context_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ context('A new Context', function() {
var executed = [];
var c = new Context();
c.addSetupHandler(function() {
var asyncHandler = this.async(function() {
var asyncHandler = async(function() {
executed.push('asyncsetup');
});
setTimeout(asyncHandler, 0);
Expand All @@ -218,12 +218,12 @@ context('A new Context', function() {
var executed = [];
var c = new Context();
c.addSetupHandler(function() {
setTimeout(this.async(function() {
setTimeout(async(function() {
executed.push('asyncsetup');
}), 0);
});
c.addTestHandler(function() {
setTimeout(this.async(function() {
setTimeout(async(function() {
executed.push('asynctest1');
}), 0);
// TODO(lukebayes) Problem with async tests:
Expand All @@ -232,12 +232,12 @@ context('A new Context', function() {
// This fails!!!!!
});
c.addTestHandler(function() {
setTimeout(this.async(function() {
setTimeout(async(function() {
executed.push('asynctest2');
}), 0);
});
c.addTeardownHandler(function() {
setTimeout(this.async(function() {
setTimeout(async(function() {
executed.push('asyncteardown');
}), 0);
});
Expand Down Expand Up @@ -283,7 +283,7 @@ context('A new Context', function() {
failure = f;
});
c.addTestHandler(function() {
setTimeout(this.async(function() {
setTimeout(c.addAsyncHandler(function() {
assert.ok(false, 'should be false');
}), 0);
});
Expand All @@ -310,15 +310,21 @@ context('A new Context', function() {
var executed = [];
var c = new Context();
c.addTestHandler(function() {
setTimeout(this.async(function() {
executed.push('one');
}), 0);
setTimeout(this.async(function() {
executed.push('two');
}), 0);
setTimeout(this.async(function() {
executed.push('three');
}), 0);
setTimeout(async(function() {
c.addAsyncHandler(function() {
executed.push('one');
});
}));
setTimeout(async(function() {
c.addAsyncHandler(function() {
executed.push('two');
});
}));
setTimeout(async(function() {
c.addAsyncHandler(function() {
executed.push('three');
});
}));
});

c.execute(function() {
Expand Down
Loading

0 comments on commit 66abdd7

Please sign in to comment.