diff --git a/bin/asynct b/bin/asynct new file mode 100755 index 0000000..f3ece1e --- /dev/null +++ b/bin/asynct @@ -0,0 +1,25 @@ +#! /usr/bin/env node + +try { + // always check for a local copy of async_testing first + var testing = require('async_testing'); +} +catch(err) { + if( err.message == "Cannot find module './async_testing'" ) { + // look in the path for async_testing + var testing = require('async_testing'); + } + else { + throw err; + } +} + +exports.test = function (test){ + test.ok(false,"this should not be called!") +} +process.ARGV.shift() //node +process.ARGV.shift() // this file... if i leave this in it tried to run this file as a test, which goes into infinite loop and doesn't exit. +process.ARGV.unshift('node') + +testing.run(process.ARGV); + diff --git a/bin/node-async-test.js b/bin/node-async-test.js new file mode 100755 index 0000000..92ce4c1 --- /dev/null +++ b/bin/node-async-test.js @@ -0,0 +1,32 @@ +#! /usr/bin/env node + +try { + // always check for a local copy of async_testing first + var testing = require('async_testing'); +} +catch(err) { + if( err.message == "Cannot find module './async_testing'" ) { + // look in the path for async_testing + var testing = require('async_testing'); + } + else { + throw err; + } +} + +testing.run(null, process.ARGV, done); + +function done(allResults) { + // we want to have our exit status be the number of problems + + var problems = 0; + + for(var i = 0; i < allResults.length; i++) { + if (allResults[i].tests.length > 0) { + problems += allResults[i].numErrors; + problems += allResults[i].numFailures; + } + } + + process.exit(problems); +} diff --git a/docs/api.html b/docs/api.html new file mode 100644 index 0000000..642e88c --- /dev/null +++ b/docs/api.html @@ -0,0 +1,94 @@ +

module: async_testing

+ +

method: runSuite (testSuite,opts)

+ +

testSuite is a test module for example runSuite (require('./test/simpleTest'),opts) +each property in the object should be a test. A test is just a method which takes one argument (test) +and then make assertions by calling test.ok(true) etc. and eventually test.finish() +making an assertion after test.finish() or calling test.finish() twice results in a +testAlreadyFinished error. not calling test.finish() at all is a an error as well. (see onSuiteDone({'0','exit',...)

+ +

Available configuration options: + * ++ parallel: boolean, for whether or not the tests should be run in parallel or serially. Obviously, parallel is faster, but it doesn't give as accurate error reporting ++testName: string or array of strings, the name of a test to be ran ++name: string, the name of the suite being ran ++ onTestStart ++ onTestDone ++ onSuiteDone

+ +

example:

+ +
+      { name: 'string'
+      , testName: [array of test names to run]
+      , onTestStart: function (test) {}
+      , onTestDone: function (status,test) {}
+      , onSuiteDone: function (status,report) {}
+      }
+
+ +

callback arguments: onSuiteDone (status,report)

+ +

status may be:

+ + + +

currently the report differs for each status

+ + + +
+    {tests: //list of tests
+      [
+        { name: [name of test]
+        , numAssertions: [number of Assertions in test]
+        , failure: [error which caused failure] // only if this test failed, or errored.
+        , failureType: ['assertion' or 'error']
+        }
+      ]
+    }
+
+ + + +
+    { err: errorObject
+    , tests: [list of names of tests which where running when err error occured]
+    }
+    //usually an error is caught by the test and it's registered as a failure.
+    //sometimes a test throws an error asyncronously, and async_testing doesn't 
+    //know which test it came from.
+
+ +

callback arguments: onTestStart (test)

+ + + +

callback arguments: onTestDone (status,test)

+ + + +
+    { name: [name of test]
+    , numAssertions: [number of Assertions in test]
+    , failure: [error which caused failure] // only if this test failed, or errored.
+    , failureType: ['assertion' or 'error']
+    }
+
diff --git a/docs/api.markdown b/docs/api.markdown new file mode 100644 index 0000000..991e481 --- /dev/null +++ b/docs/api.markdown @@ -0,0 +1,94 @@ +module: async_testing +===================== + + +## method: runSuite (testSuite,opts) + +`testSuite` is a test module for example `runSuite (require('./test/simpleTest'),opts)` +each property in the object should be a test. A test is just a method which takes one argument `(test)` +and then make assertions by calling `test.ok(true)` etc. and eventually `test.finish()` +making an assertion after `test.finish()` or calling `test.finish()` twice results in a +testAlreadyFinished error. not calling `test.finish()` at all is a an error as well. (see onSuiteDone({'0','exit',...) + + Available configuration options: + * ++ parallel: boolean, for whether or not the tests should be run in parallel or serially. Obviously, parallel is faster, but it doesn't give as accurate error reporting ++testName: string or array of strings, the name of a test to be ran ++name: string, the name of the suite being ran ++ onTestStart ++ onTestDone ++ onSuiteDone + +example: + +
+      { name: 'string'
+      , testName: [array of test names to run]
+      , onTestStart: function (test) {}
+      , onTestDone: function (status,test) {}
+      , onSuiteDone: function (status,report) {}
+      }
+
+ +###callback arguments: onSuiteDone (status,report) + +status may be: + ++ _complete_ : valid result, success or failure ++ _exit_ : some tests did not call `test.finish()` ++ _loadError_ : an error occured while loading the test, i.e. a syntax error ++ _error_ : the test threw an error. + +currently the report differs for each status + ++ complete + +
+    {tests: //list of tests
+      [
+        { name: [name of test]
+        , numAssertions: [number of Assertions in test]
+        , failure: [error which caused failure] // only if this test failed, or errored.
+        , failureType: ['assertion' or 'error']
+        }
+      ]
+    }
+
+ ++ exit [list of tests which did not finish] ++ loadError [error message (string)] ++ error + +
+    { err: errorObject
+    , tests: [list of names of tests which where running when err error occured]
+    }
+    //usually an error is caught by the test and it's registered as a failure.
+    //sometimes a test throws an error asyncronously, and async_testing doesn't 
+    //know which test it came from.
+
+ +###callback arguments: onTestStart (test) + ++ test: name of the test which has started. + +###callback arguments: onTestDone (status,test) ++ status : 'success', or 'failure' ++ report: + +
+    { name: [name of test]
+    , numAssertions: [number of Assertions in test]
+    , failure: [error which caused failure] // only if this test failed, or errored.
+    , failureType: ['assertion' or 'error']
+    }
+
+ + +## method: runFile (modulepath,opts) +module is the path to the test suite to run. run a test in a child process, opts and callbacks are same as for runSuite. + + + + + diff --git a/lib/asynct_adapter.js b/lib/asynct_adapter.js new file mode 100644 index 0000000..969da68 --- /dev/null +++ b/lib/asynct_adapter.js @@ -0,0 +1,5 @@ + +exports.runTest = function (file,callbacks){ + test = require(file) + require('async_testing').runSuite(test,callbacks) +} diff --git a/lib/child2.js b/lib/child2.js new file mode 100644 index 0000000..a4904f0 --- /dev/null +++ b/lib/child2.js @@ -0,0 +1,149 @@ +var messages = require('./messages2') + , assert = require('assert') + , inspect = require('inspect') +// , testing = require('./testing') + +if (module == require.main) { + + process.ARGV.shift()//node + process.ARGV.shift()//__filename + json = process.ARGV.shift() + + var opts = JSON.parse(json) + + assert.ok(opts.start,"expected .start : magic number") + + assert.ok(opts.end,"expected .end : magic number") + + assert.ok(opts.args,"expected .end : magic number") + assert.ok('string' == typeof opts.args[0] ,"expected .end : magic number") + assert.ok('object' == typeof opts.args[1] ,"expected .end : magic number") + + var file = opts.args[0] + , options = opts.args[1] + , messager = messages.useMagicNumbers(opts.start,opts.end) + + callbacks = makeCallbacks(options,send) + + function send(message){ + console.log(messager.messageEncode(message)) + } +/* adapter = require(options.adapter || 'async_testing') + adapter.runSuite(require(file),callbacks) +*/ + adapter = require(options.adapter || 'async_testing/lib/asynct_adapter') + adapter.runTest(file,callbacks) +} + +spawn = require('child_process').spawn + +//master creates slave, and then slave sends messages back. +//call master with callbacks, +//master goes through callbacks and turns gets the name of each one. +//sends a message to slave of function names. +//slave creates functions with these names, and then calls runSuite with them + +exports.runFile = runFile +function runFile (file,options) { + var normalExit = false; + oldOnExit = options.onExit + options.onExit = function (status,report){ + console.log("NORMAL EXIT") + normalExit = true; + oldOnExit && oldOnExit(status,report) + } + + magic = messages.magicNumbers + child = + spawn('node' + , [ __filename + , json = JSON.stringify ( + { start: magic.start + , end: magic.end + , args: [file, makeMessage (options)] } ) ] ) + + var buffer = '' + , messager = messages.useMagicNumbers(magic.start,magic.end) + child.stdout.on('data', function(data) { + data = data.toString(); + + var lines = data.split('\n'); + + lines[0] = buffer + lines[0]; + buffer = lines.pop(); + + console.log(">\t"+data) + + lines = messager.messageDecode(lines); + + lines.forEach(function (message){ + if(message) + parseMessage(message,options) + }) + }) + var errorBuffer = ''; + child.stderr.on('data', function(data) { + errorBuffer += data.toString(); + }); + +/* + always ensure that normal exit has happened? + stall on suite done untill exit registered? + +*/ + + child.stderr.on('close', function() { + if (errorBuffer && options.onSuiteDone && !normalExit) { + options.onSuiteDone('loadError', {stderr: errorBuffer.trim()}); + } + }); + +/* child.on('exit', function (code){ + if(!normalExit) + options.onSuiteDone('loadError', {failure: errorBuffer.trim()}); + })*/ +} + +exports.makeMessage = makeMessage +function makeMessage(callbacks){ + message = {} + for(i in callbacks){ + if('function' === typeof callbacks[i]){ + message[i] = 'typeof function' + } else { + message[i] = callbacks[i] + } + } + return message +} + +exports.makeCallbacks = makeCallbacks + +function makeCallbacks(message,sender){ + var callbacks = {} + for(i in message){ + (function (j){ + if('typeof function' == message[i]){ + callbacks[j] = function (){ + args = [] + for(i in arguments){ + args[i] = arguments[i] + } + + sender.call(null,[j,args]) + } + } else { + callbacks[j] = message[j] + } + })(i) + } + return callbacks +} + +exports.parseMessage = parseMessage +function parseMessage (message,callbacks){ + + callbacks[message[0]].apply(null,message[1]) +} + + diff --git a/lib/console-runner.js b/lib/console-runner.js index 0b9e585..0d2e66f 100644 --- a/lib/console-runner.js +++ b/lib/console-runner.js @@ -161,7 +161,9 @@ exports.run = function(list, options, callback) { } } } - + /* + OUTPUT STARTS + */ var output = { testDone: function(suite, result) { if (!suite.printedName) { @@ -185,7 +187,7 @@ exports.run = function(list, options, callback) { output['suite'+suite.status.substr(0,1).toUpperCase()+suite.status.substr(1)](suite); } , suiteLoadError: function(suite) { - var err = suite.results.stderr; + var err = suite.results.stderr; //... if (!suite.printedName) { console.log(bold(suite.name)); @@ -232,7 +234,8 @@ exports.run = function(list, options, callback) { for(var i = 0; i < tests.length; i++) { var r = tests[i]; if (r.failure) { - var s = r.failure.stack.split("\n"); + + var s = r.failure.stack ? r.failure.stack.split("\n"): ['no stack trace'] console.log(r.failureType == 'assertion' ? ' Failure: '+red(r.name) : ' Error: '+yellow(r.name)); @@ -241,6 +244,7 @@ exports.run = function(list, options, callback) { } if (options.verbosity == 1) { + console.log(s[0].replace(process.cwd(), '.'));//if it's an AssertionError the message is the first line of the stack. if (s.length > 1) { console.log(s[1].replace(process.cwd(), '.')); } @@ -249,7 +253,7 @@ exports.run = function(list, options, callback) { } } else { - for(var k = 1; k < s.length; k++) { + for(var k = 0; k < s.length; k++) {//on an assertion, this was hiding the default message console.log(s[k].replace(process.cwd(), '.')); } } @@ -307,22 +311,26 @@ exports.run = function(list, options, callback) { else { console.log(' Error: ' + yellow(tests[0])); } - - var s = err.stack.split("\n"); + if (err.message) { console.log(' '+err.message); + } else { + console.log('ERROR:' + err); } - if (options.verbosity == 1) { - if (s.length > 1) { - console.log(s[1].replace(process.cwd(), '.')); - } - if (s.length > 2) { - console.log(s[2].replace(process.cwd(), '.')); + if(err.stack){ + var s = err.stack.split("\n") + if (options.verbosity == 1) { + if (s.length > 1) { + console.log(s[1].replace(process.cwd(), '.')); + } + if (s.length > 2) { + console.log(s[2].replace(process.cwd(), '.')); + } } - } - else { - for(var k = 1; k < s.length; k++) { - console.log(s[k]); + else { + for(var k = 0; k < s.length; k++) { + console.log(s[k]); + } } } } @@ -400,4 +408,8 @@ exports.run = function(list, options, callback) { } } } + /* + OUTPUT ENDS + */ + } diff --git a/lib/messages.js b/lib/messages.js new file mode 100644 index 0000000..0f6368d --- /dev/null +++ b/lib/messages.js @@ -0,0 +1,61 @@ + +var messageFrame = "~m~"; +// these encode/decode functions inspired by socket.io's +exports.messageDecode = messageDecode +function messageDecode(lines) { + return lines.map(function(str) { + if (str.substr(0,3) !== messageFrame) { + return str; + } + + var msg = []; + for (var i = 3, number = '', l = str.length; i < l; i++){ + var n = Number(str.substr(i, 1)); + if (str.substr(i, 1) == n){ + number += n; + } else { + number = Number(number); + var m = str.substr(i+messageFrame.length, number); + msg.push(JSON.parse(m)); + i += messageFrame.length*2 + number - 1; + number = ''; + } + } + return msg; + }); +} +exports.messageEncode = function() { + var r = ''; + + for (var i = 0; i < arguments.length; i++) { + var json = JSON.stringify(arguments[i]); + r += messageFrame + json.length + messageFrame + json; + } + + return r; +} + + +//exports.decode = +function decodeLine(string){ + var mm = /~m~(\d+)~m~(.*)/.exec(string) + if(!mm){ + throw new Error("could not decode :" + string + " there was no match for messageFrame ~m~[length]~m~") + } + + var frame = mm[0] + , len = mm[1] + , rest = mm[2] + if(len != rest.length){ + throw new Error("message payload should be :" + len + " long, but was:" + rest.length + "message was:" + rest) + } + return JSON.parse(rest) +} + +//exports.encode = exports.messageEncode +//exports.messageDecode = decode +function decode(lines){ + return lines.map(function(line){ + return decodeLine(line) + }) + } diff --git a/lib/messages2.js b/lib/messages2.js new file mode 100644 index 0000000..2de8077 --- /dev/null +++ b/lib/messages2.js @@ -0,0 +1,29 @@ + +inspect = require('inspect') + +function useMagicNumbers(start,end){ + start = start || Math.round(Math.random()*10000000) + end = end || Math.round(Math.random()*100000000) + return { + messageEncode: messageEncode + , messageDecode: messageDecode + , useMagicNumbers:useMagicNumbers + , magicNumbers: {start: start, end: end} + } + + function messageEncode(x) { + return "" + start + JSON.stringify(x) + end + } + + function messageDecode(lines){ + return lines.map(decodeLine) + } + function decodeLine(string){ + + var m = string.match("" + start + "(.*)" + end) + if(m) + return JSON.parse(m[1]) + } +} +module.exports = useMagicNumbers() + diff --git a/lib/script.js b/lib/script.js new file mode 100644 index 0000000..45e9905 --- /dev/null +++ b/lib/script.js @@ -0,0 +1,41 @@ +//script (runs async test as a script, with nothing clever, incase async_testing is causing errors) + +assert = require('assert') + +if (module == require.main) { + process.ARGV.shift() + process.ARGV.shift() + console.log(process.ARGV) + process.ARGV.forEach(runFile) +} + +exports.runFile = runFile +function runFile(file){ + test = require(/*process.ENV.PWD + '/' +*/ file) + console.log() + console.log() + console.log("running test suite: " + file) + + tests = Object.keys(test) + function next (i){ + + if (i >= tests.length){ + console.log() + console.log("all tests completed!")//since an error should exit. + return + } + + assert.finish = function (){ + next(i + 1) + } + + console.log() + console.log(" running test: " + tests[i]) + + test[tests[i]](assert) + } + + next(0) + +} + diff --git a/lib/subtree.js b/lib/subtree.js new file mode 100644 index 0000000..88dff67 --- /dev/null +++ b/lib/subtree.js @@ -0,0 +1,47 @@ +//subtree +var assert = require('assert') + , inspect = require('util').inspect + +function assert_subtree(little,big,message,chain){ + message = message || ""; + + //check that every property in little is also in big. + chain = chain || []; + + if('object' === typeof little) { + for (var k in little) { + assert.ok(big[k], message + + "results did not have a property:" + + chain.join(".") + "." + k + + " expected " + inspect(little[k])) + + t = assert_subtree(little[k],big[k],message,chain.concat([k])) + } + } else { + assert.notEqual(big,undefined, message + + "\nexpected results to contain " + + chain.join(".") + + " but was undefined"); + assert.strictEqual(little,big, message + + "\nexpected " + + chain.join(".") + " === " + little + + " (" + typeof big + ")" + + " but found: " + big + + " (" + typeof big + ")" + ); + } + } +exports.assert_subtree = assert_subtree + + +exports.subtree = function subtree(little,big){ + try { + assert_subtree(little,big); + return true; + } catch (err){ + console.log('error'); + if (err instanceof assert.AssertionError) { + return false; + } else { throw err }; + } + } diff --git a/lib/tester.js b/lib/tester.js new file mode 100644 index 0000000..47ec7fa --- /dev/null +++ b/lib/tester.js @@ -0,0 +1,67 @@ +var path = require ('path') + , assert = require('assert') + , reports = require('meta-test/test_reports') + + + +function Tester (filename){ + var dirname = path.dirname(filename) + this.run = run + + function run(callbacks){ + + + var report = reports(filename) + report.testNames = [report.name] + + callbacks.onSuiteStart && callbacks.onSuiteStart(report.name,report.suiteStart()) + callbacks.onTestStart && callbacks.onTestStart(report.name,report.testStart(report.name)) + + function onError (error){ + console.log("ON ERROR!") + var r = report.testDone(report.name) + callbacks.onTestDone && callbacks.onTestDone(r.status,r) + } + + process.on("uncaughtException",onError) + + try{ + require(filename) + } catch (error) { //catch sync error + return onError(error) + } +/* callback('success', + { test:name + , status: 'success' } )*/ + + process.on('exit',function (code,status){ + console.log("ON EXIT: SUITE DONE!") + console.log("ON EXIT()!" + !!callbacks.onExit) + try{r = report.suiteDone() + callbacks.onSuiteDone && callbacks.onSuiteDone(r.status,r) + + callbacks.onExit && callbacks.onExit(code,status) + + } catch (error){ + console.log(JSON.stringify(error)) + console.error(error.toString()) + } + }) + + } +} + + +exports = module.exports = Tester +module.exports.errorType = errorType +exports.runTest = function (file,callbacks){ + new Tester(file).run(callbacks) +} + +function errorType(error){ + if('object' == typeof error){ + return error.name || error.constructor.name + } else { + return typeof error + } +} diff --git a/lib/testing.js b/lib/testing.js index bd518b8..00a1055 100644 --- a/lib/testing.js +++ b/lib/testing.js @@ -2,7 +2,11 @@ var assert = require('assert') , path = require('path') , fs = require('fs') , spawn = require('child_process').spawn - ; + , messages = require('./messages') + , inspect = require('inspect') + exports.messageDecode = messages.messageDecode //moved these functions to messages. + exports.messageEncode = messages.messageEncode //exported them again so i didn't change the interface + /* Runs an object with tests. Each property in the object should be a * test. A test is just a method. @@ -22,6 +26,7 @@ var assert = require('assert') * + onTestDone * + onSuiteDone */ + exports.runSuite = function(obj, options) { // make sure options exists options = options || {}; @@ -126,7 +131,11 @@ exports.runSuite = function(obj, options) { } function testAlreadyFinished(test, msg) { - errorHandler(new TestAlreadyFinishedError(test.name + ' already finished!' + (msg ? ' ' + msg : '')), test); + console.log("test") + console.log(inspect(test)) + console.log(msg) + if(!test.failure) // if the test has already errored, don't shadow it! + errorHandler(new TestAlreadyFinishedError(test.name + ' already finished!' + (msg ? ' ' + msg : '')), test); } // this is called after each step in a test (each function in the array). @@ -144,37 +153,43 @@ exports.runSuite = function(obj, options) { if (!test.failure && problem) { test.failure = problem; } - - if (test.func.length == test.history.length) { - testFinished(test); - } - else { - var index = test.history.length; - var match = test.func.length - index - 1; - - if (match >= index) { - // we are still drilling down into the flow, not doing teardowns - if (test.failure) { - // we had a failure, so we don't start any new functions - test.history.push(false); - testProgressed(test); - } - else { - // no failure yet, start next step - runTestFunc(test); - } + if(!test.func){ // I don't know what this is about, but taking this out fixes it. + console.log("NO TEST FUNCTION") + console.log(test) + console.log() + console.log() + } else { + if ( test.func.length == test.history.length) { + testFinished(test); } else { - // we are doing teardowns. We always run a teardown function if its - // matching setup was run - if (test.history[match]) { - // according to the history we ran the match - runTestFunc(test); + var index = test.history.length; + var match = test.func.length - index - 1; + + if (match >= index) { + // we are still drilling down into the flow, not doing teardowns + if (test.failure) { + // we had a failure, so we don't start any new functions + test.history.push(false); + testProgressed(test); + } + else { + // no failure yet, start next step + runTestFunc(test); + } } else { - // didn't run the match so don't run this - test.history.push(false); - testProgressed(test); + // we are doing teardowns. We always run a teardown function if its + // matching setup was run + if (test.history[match]) { + // according to the history we ran the match + runTestFunc(test); + } + else { + // didn't run the match so don't run this + test.history.push(false); + testProgressed(test); + } } } } @@ -283,14 +298,17 @@ exports.runSuite = function(obj, options) { function exitHandler() { if (suite.started.length > 0) { - if (options.onSuiteDone) { - options.onSuiteDone('exit', {tests: suite.started.map(function(t) { return t.name; })}); + if (options.onSuiteDone) { + var tests = suite.started.map(function(t) { return t.name; }) + console.log("SUITE FINISHED -- exitHandler 'exit' :" + tests) + options.onSuiteDone('exit', {tests: tests}); } } } // clean up method which notifies all listeners of what happened function suiteFinished() { + console.log("SUITE FINISHED -- onSuiteDone") if (suite.finished) { return; } suite.finished = true; @@ -309,13 +327,14 @@ exports.runSuite = function(obj, options) { suite.results.forEach(function(r) { result[r.failure ? 'numFailures' : 'numSuccesses']++; }); - options.onSuiteDone('complete', result); } } } exports.runFile = function(modulepath, options) { +console.log("runFile:" + modulepath) + options = options || {}; if (options.testName && !Array.isArray(options.testName)) { options.testName = [options.testName]; @@ -354,6 +373,8 @@ exports.runFile = function(modulepath, options) { }); child.stderr.on('close', function() { + console.log("strerr:" + errorBuffer) + if (errorBuffer && options.onSuiteDone) { options.onSuiteDone('loadError', {stderr: errorBuffer.trim()}); } @@ -504,41 +525,6 @@ exports.getTestsFromObject = function(o, filter, namespace) { return tests; } -var messageFrame = "~m~"; -// these encode/decode functions inspired by socket.io's -exports.messageDecode = function(lines) { - return lines.map(function(str) { - if (str.substr(0,3) !== messageFrame) { - return str; - } - - var msg = []; - for (var i = 3, number = '', l = str.length; i < l; i++){ - var n = Number(str.substr(i, 1)); - if (str.substr(i, 1) == n){ - number += n; - } else { - number = Number(number); - var m = str.substr(i+messageFrame.length, number); - msg.push(JSON.parse(m)); - i += messageFrame.length*2 + number - 1; - number = ''; - } - } - return msg; - }); -} -exports.messageEncode = function() { - var r = ''; - - for (var i = 0; i < arguments.length; i++) { - var json = JSON.stringify(arguments[i]); - r += messageFrame + json.length + messageFrame + json; - } - - return r; -} - var TestAlreadyFinishedError = function(message) { this.name = "TestAlreadyFinishedError"; this.message = message; diff --git a/lib/web-runner.js b/lib/web-runner.js index d53ec62..6e8d63d 100644 --- a/lib/web-runner.js +++ b/lib/web-runner.js @@ -11,9 +11,9 @@ try { } catch(err) { if( err.message == "Cannot find module 'util'" ) { - var util = require('sys'); + var util = require('sys'); + } } - exports.name = 'Web'; exports.runnerFlag = diff --git a/lib/wrap.js b/lib/wrap.js index 835fe11..3e83cb0 100644 --- a/lib/wrap.js +++ b/lib/wrap.js @@ -14,6 +14,9 @@ const PRESETUP = 0 * teardown: a function that should be run after the test */ exports.wrap = function(obj) { + console.log("returring suite!") +// return obj.suite; +// return obj.suite if (!obj.suite) { throw new Error('Cannot wrap suite. No suite provided'); } diff --git a/test/assertions.asynct.js b/test/assertions.asynct.js new file mode 100644 index 0000000..ec5b267 --- /dev/null +++ b/test/assertions.asynct.js @@ -0,0 +1,154 @@ +var inspect = require('util').inspect +, EventEmitter = require('events').EventEmitter +var truthy = [true,1] +, falsey = [0,'',[]] +, ok = [true,1,2,100,-1,"true",{},[],new Error()] +, notOk = [false,0,null,undefined,""] + +exports['ok'] = function(test){ + + ok.forEach(function (t){ + test.ok(t, "expected " + t + " to evaluate to true" ) + }); + + notOk.forEach(function (t){ + test.ok(!t, "expected " + t + " to !evaluate to true" ) + }); + test.finish(); +} + +exports['throws doesNotThrow'] = function (test){ + var throwable = [new Error('throw me'),"thrown",7,null,undefined,[],{}] + + throwable.forEach(function (t) { + test.throws(function(){ + throw t + }); + }); + throwable.forEach(function (t) { + test.doesNotThrow(function(){ + return t + }); + }); + throwable.forEach(function (t) { + test.throws(function(){ + process.emit('error', t) + }); + }); + test.finish() +} + +function comparison(test,method,a,b) { + test[method](a,b,"expected : " + method + "( " + inspect(a) + " , " + inspect(b) + " );") +} +exports['equals deepEquals strictEquals'] = function (test){ + var c1 = [1,2,3] + , c2 = [1,2,3] + + c1.push(c1); + c2.push(c2); + c3 = [1,2,3,c1] + /* + put a bunch of example comparisons in a hash by method name, + then iterate and apply the method + */ + var comparisons = { + equal: [ + [1,1] + , [2,2] + , [2,2.0] + , ['hello',"hello"] + , ['36',36] + , ['36.0',36] + , ['3.6e1',36] + , ['.36e2',36] + , [null,undefined] + , [c1,c1] + , [Array,Array] + , [true,1] // 'truthy' values + , [false,0]//falsey + , [false,''] + , [false,[]] + ] + , notEqual: [ + [1,0] + , ['hello',"Hello"] + , [[],[]] + , [{},{}] + , [c1,c2] + , [c1,c3] + , [function(){},function(){}] + , [function(){},'function(){}'] + , [true,2] + , [true,'true'] + , [false,null] + , [false,undefined] + , [false,'false'] + , [false,true] + , [false,{}] + ] + , strictEqual: [ + [1,1] + , ['hello','hello'] + , [c1,c1] + , [Array,Array] + , [true,true] + , [false,false] + , [test,test] + ] + , notStrictEqual: [ + [1,'1'] + , [null,undefined] + , [true,1] // 'truthy' values + , [false,0] // falsey + , [false,''] + , [false,[]] + , [new EventEmitter(),new EventEmitter()]//not stict equal unless same object + ] + , deepEqual: [ + , [[],[]] + , [{},{}] + , [[1,2,3],[1,2,3]] + , [[1,2,3],['1','2.0','.3e1']] + , [{hello:'hi',goodbye:'bye'},{hello:'hi',goodbye:'bye'}] + , [[1,2,3,{}],[1,2,3,{}]] + , [c1,c1] + //, [c1,c2] // this causes stackoverflow. + , [c1,c3] //but this passes, since c1[3] === c1 and c3[3] === c1 + , [[1,2,3,[],4],[1,2,3,[],4]] + , [[1,2,3,{},4],[1,2,3,{},4]] + , [[1,[2,3],[],4],[1,[2,3],[],4]] + , [new EventEmitter(),new EventEmitter()]//most new objects of same type should be equal + ] + , notDeepEqual: [ + , [new Error(),new Error()]//when a error is created it stack trace gets set, and the message will differ by column number somewhere. + ] + } + + for (method in comparisons) { + comparisons[method].forEach(function(e){ + comparison(test,method,e[0],e[1]) + }); + } + test.finish(); +} +/* + I've noticed that async_testing does not seem to report isError throws + correctly, make a meta test to fix this. + + also, test should have an errorListener method which registers an error but + doesn't throw... & errorListenerThrows, incase thats useful too. +*/ + +exports['ifError'] = function (test){ + //ifError is inverse of ok, but takes no message. + notOk.forEach(function (e){ + test.ifError(e) + }); + ok.forEach(function (e){ + test.throws(function(){ + test.ifError(e) + }); + }); + test.finish(); +} diff --git a/test/async_testing.options.async.js b/test/async_testing.options.async.js new file mode 100644 index 0000000..b17165f --- /dev/null +++ b/test/async_testing.options.async.js @@ -0,0 +1,78 @@ + + +//check that runSuite callbacks are executed in order. + var expected = require('./examples/expected_results') + , subtree = require('async_testing/lib/subtree') + , asynct = require('async_testing') +// , asynct = require('async_testing/lib/child_http') +// , asynct = require('async_testing/lib/child2') + +//var testing = require('async_testing/lib/testing') + , inspect = require('util').inspect + + +function checkCallbacks (test, filename,expected){ + var tests = tests + , started = [] + , finished = [] + + console.log() + console.log("***" + filename) + + var tests = expected.tests.map(function (e){return e.name}) + var reports = {} + expected.tests.forEach(function (e){ + reports[e.name] = e + }) + + asynct.runFile(filename,{onTestStart:testStart,onTestDone:testDone,onSuiteDone:suiteDone}) + + function testStart(testName){ + console.log(" testStarted: " + testName) + + test.ok(testName,'testName must be non null') + test.ok(tests.indexOf(testName) !== -1, 'test \'' + testName + '\' must be in list of tests: ' + inspect (tests)) + test.ok(started.indexOf(testName) === -1, 'test hasn\'t already started') + test.ok(finished.indexOf(testName) === -1, 'test hasn\'t already finished') + + started.push(testName) + } + function testDone(status,report){ + var testName = report.name + + console.log(" ...testDone: " + report.name + " -> " + status) + test.ok(testName,'testName must be non null') + test.ok(tests.indexOf(testName) !== -1, 'test = ' + testName + ' must be in list of tests' + inspect (tests)) + test.ok(started.indexOf(testName) !== -1, 'finished test must have already started') + test.ok(finished.indexOf(testName) === -1, 'test hasn\'t already finished') + + subtree.assert_subtree(reports[testName],report) + + started.splice(started.indexOf(testName),1) + finished.push(testName) + } + function suiteDone(status,report){ + console.log("***" + filename + " DONE") + + test.deepEqual(started,[],"onTestStart called for all tests, started tests where :" + inspect(started)) + test.deepEqual(finished.sort(),tests.sort(),"onTestDone called for all tests") + + subtree.assert_subtree(expected,report) + + + console.log() + + test.finish() + } +} + +//generate tests. + for (i in expected.expected){ + (function (j){ + exports[j] = function (test){ + // var tests = expected.expected[j].tests.map(function (e){return e.name}) + checkCallbacks(test,'async_testing/test/examples/' + j,expected.expected[j]) + } + console.log(j) + })(i) + } diff --git a/test/async_testing.reports.async.js b/test/async_testing.reports.async.js new file mode 100644 index 0000000..b3c582d --- /dev/null +++ b/test/async_testing.reports.async.js @@ -0,0 +1,39 @@ + +if (module == require.main) { + require('async_testing').run(__filename, process.ARGV); +} + + var expected = require('./examples/expected_results') + +//var MetaTest = require('meta_test') +, subtree = require('async_testing/lib/subtree') +, inspect = require('util').inspect +, asynct = require('async_testing') + +function runTest (test,filename,expected){ +// var m = MetaTest() + +// m.run(filename,{onSuiteDone: suiteDone}) + console.log("test started: " + filename) + asynct.runFile(filename,{onSuiteDone: suiteDone}) + + function suiteDone(status,report){ + console.log("...test done: " + filename) + subtree.assert_subtree(expected,report) + test.finish(); + } +} + + + for (i in expected.expected){ + (function (j){ + exports[j] = function (test){ + // var tests = expected.expected[j].tests.map(function (e){return e.name}) + runTest(test,'async_testing/test/examples/' + j,expected.expected[j]) + } + console.log(j) + })(i) + } + + + diff --git a/test/child.asynct.js b/test/child.asynct.js new file mode 100644 index 0000000..c4f305c --- /dev/null +++ b/test/child.asynct.js @@ -0,0 +1,112 @@ +if (module == require.main) { + return require('async_testing').run(process.ARGV); +} + +var child = require('async_testing/lib/child2') + , inspect = require('inspect') + +exports ['can run a simple test'] = function(test){ + + child.runFile('async_testing/test/examples/test-all_passing',{onSuiteDone: suiteDone}) + + function suiteDone(status,report){ + console.log("ERROR:") + console.log(inspect(report)) + test.equal(status,'complete') + + // tset.equal(report.test == 'complete') + test.finish() + } + +} + +exports ['can make callbacks into message and back'] = function(test){ + + var message = 'asdfhasdflsdlf' + var masterCallbacks = { + send: function(m){ + test.equal(m,message) + test.finish() + } + } + + mm = child.makeMessage(masterCallbacks) + + cb = child.makeCallbacks(mm,recieve) + cb.send(message) + function recieve(message){ + child.parseMessage(message,masterCallbacks) + } +} + +/*exports ['ignores noise'] = function(test){ + child.parseMessage(message,test.ifError) +}*/ + +exports ['accepts test adapter'] = function (test){ + var calls = [/*'onSuiteStart',*/'onTestStart','onTestDone','onSuiteDone','onExit'] + var callbacks = { adapter: "async_testing/test/lib/dummy_test_adapter" } + + calls.forEach(each) + + function each(fName){ + callbacks[fName] = function (status,data){ + thisCall = calls.shift() + console.log("dummy test adapter called: " + thisCall + " expected:" + fName) + test.equal(thisCall,fName) + test.equal(status,fName) + test.deepEqual(data , {test: "dummy_test_adapter: " + fName, object: {magicNumber: 123471947194 } } ) + + if (calls.length == 0) { + test.finish() + } + } + } + + child = require('async_testing/lib/child2') + child.runFile("async_testing/test/lib/magic_number" ,callbacks) +} + +exports ['calls onSuiteDone(\'loadError\') if child did not exit properly.' + + ' example: syntax error'] = function (test) { + + var callbacks = + { adapter: "async_testing/test/lib/dummy_test_adapter" + , onSuiteDone: done } + + function done(loadError,data){ + console.log(data) + test.equal(loadError,'loadError') + test.finish() + } + + child = require('async_testing/lib/child2') + child.runFile("async_testing/test/examples/test-error_syntax" ,callbacks) +} + + +exports ['calls onSuiteDone(\'loadError\') does not confuse stderr with real loadError.'] = function (test) { + + var callbacks = + { adapter: "async_testing/test/lib/dummy_test_adapter" + , onSuiteDone: done } + + function done(onSuiteDone,data){ + console.log(data) + test.equal(onSuiteDone,'onSuiteDone') + process.nextTick(test.finish) + } + + child = require('async_testing/lib/child2') + child.runFile("async_testing/test/lib/stderr" ,callbacks) +} + + + + + + + + + + diff --git a/test/examples/async_error.script.js b/test/examples/async_error.script.js new file mode 100644 index 0000000..6103216 --- /dev/null +++ b/test/examples/async_error.script.js @@ -0,0 +1,2 @@ + +process.nextTick(function (){throw new Error("Async Error")}) diff --git a/test/examples/error.script.js b/test/examples/error.script.js new file mode 100644 index 0000000..baae828 --- /dev/null +++ b/test/examples/error.script.js @@ -0,0 +1,6 @@ + +//require('assert').ok(false, "INTENSIONAL FAIL") + +throw new Error ("INTENSIONAL ERROR") + + diff --git a/test/examples/expected_results.js b/test/examples/expected_results.js new file mode 100644 index 0000000..642a1b1 --- /dev/null +++ b/test/examples/expected_results.js @@ -0,0 +1,203 @@ +//expected results + +var tests = 'async_testing/test' +exports.expected = + { 'test-all_passing': + { tests: + [ {name: 'test A' + //, status: 'success' + } + , {name: 'test B' + //, status: 'success' + } + , {name: 'test C' + //, status: 'success' + } + , {name: 'test D' + //, status: 'success' + } + ] + } + , 'test-async_assertions': + { tests: [ + { name: 'test success' + //, status: 'success' + } + , { name: 'test fail' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , { name: 'test success -- numAssertions expected' + //, status: 'success' + } + , { name: 'test fail -- numAssertions expected' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , { name: 'test fail - not enough -- numAssertions expected' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , { name: 'test fail - too many -- numAssertions expected' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + ] + } + , 'test-custom_assertions': + { tests: [ + {name: 'test custom assertion pass' + //, status: 'success' + } + , {name: 'test custom assertion fail' + //, status: 'failure' + , failureType: 'assertion' + } + ] + } + , 'test-errors': + { tests: [ + {name: 'test sync error' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test async error' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + ] + } + , 'test-multiple_errors': + { tests: [ + {name: 'test async error 1' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test sync error' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test async error 2' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test async error 3' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + ] + } + , 'test-sync_assertions': + { tests: [ + {name: 'test success' + //, status: 'success' + } + , {name: 'test fail' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , {name: 'test success -- numAssertions expected' + //, status: 'success' + } + , {name: 'test fail -- numAssertions expected' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , {name: 'test fail - not enough -- numAssertions expected' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , {name: 'test fail - too many -- numAssertions expected' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + ] + } + , 'test-uncaught_exception_handlers': + { tests: [ + {name: 'test catch sync error' + //, status: 'success' + } + , {name: 'test catch async error' + //, status: 'success' + } + , {name: 'test sync error fail' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , {name: 'test async error fail' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , {name: 'test sync error async fail' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } + , {name: 'test async error async fail' + //, status: 'failure' + , failure: {} + , failureType: 'assertion' + } +/* , {name: 'test sync error error again' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test async error error again' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test sync error error again async' + //, status: 'error' + , failure: {} + , failureType: 'error' + } + , {name: 'test async error error again async' + //, status: 'error' + , failure: {} + , failureType: 'error' + }*/ + ] + } + , 'test-wrap_tests': + { tests: [ + {name: 'sync wrap → test' + //, status: 'success' + } + , {name: 'async setup → test' + //, status: 'success' + } + , {name: 'async teardown → test' + //, status: 'error' + } + /* , {name: 'test teardown → test' + //, status: 'success' + } + , {name: 'test teardown async → test' + //, status: 'success' + }*/ + ] + } +} + + + + diff --git a/test/examples/fail.script.js b/test/examples/fail.script.js new file mode 100644 index 0000000..807dc7e --- /dev/null +++ b/test/examples/fail.script.js @@ -0,0 +1,4 @@ + +require('assert').ok(false, "INTENSIONAL FAIL") + + diff --git a/test/examples/invalid/test-example1.js b/test/examples/invalid/test-example1.js new file mode 100644 index 0000000..00de4ce --- /dev/null +++ b/test/examples/invalid/test-example1.js @@ -0,0 +1,15 @@ + +exports['test pass'] = function (test){ + test.ok(true); + test.finish(); +} + +exports['test fail'] = function (test){ + test.ok(false); + test.finish(); +} + +exports['test error'] = function (test){ + throw new Error('INTENSIONAL ERROR') +} + diff --git a/test/examples/invalid/test-finish_then_hang.js b/test/examples/invalid/test-finish_then_hang.js new file mode 100644 index 0000000..bc12256 --- /dev/null +++ b/test/examples/invalid/test-finish_then_hang.js @@ -0,0 +1,7 @@ + +exports['not finished'] = function (test){ + test.finish() + process.nextTick(function (){while(true){}}) +} + + diff --git a/test/examples/invalid/test-hang.js b/test/examples/invalid/test-hang.js new file mode 100644 index 0000000..e510cc9 --- /dev/null +++ b/test/examples/invalid/test-hang.js @@ -0,0 +1,6 @@ + +exports['not finished'] = function (test){ + while(true){} +} + + diff --git a/test/examples/invalid/test-not_finish.js b/test/examples/invalid/test-not_finish.js new file mode 100644 index 0000000..7202f84 --- /dev/null +++ b/test/examples/invalid/test-not_finish.js @@ -0,0 +1,8 @@ + +exports['not finished'] = function (test){ + test.ok(true); + + process.exit(); +} + + diff --git a/test/examples/invalid/test-one_pass.js b/test/examples/invalid/test-one_pass.js new file mode 100644 index 0000000..6244ebf --- /dev/null +++ b/test/examples/invalid/test-one_pass.js @@ -0,0 +1,5 @@ + +exports['pass'] = function (test){ + test.ok(true); + test.finish(); +} diff --git a/test/examples/pass.script.js b/test/examples/pass.script.js new file mode 100644 index 0000000..e5b2056 --- /dev/null +++ b/test/examples/pass.script.js @@ -0,0 +1,7 @@ + +process.on('exit',function(x){ +console.log('passing test') +console.log() + + +}) diff --git a/test/test-all_passing.js b/test/examples/test-all_passing.js similarity index 84% rename from test/test-all_passing.js rename to test/examples/test-all_passing.js index e805a5e..2aa8685 100644 --- a/test/test-all_passing.js +++ b/test/examples/test-all_passing.js @@ -1,5 +1,5 @@ if (module == require.main) { - return require('../lib/async_testing').run(process.ARGV); +// return require('../lib/async_testing').run(process.ARGV); } module.exports = { diff --git a/test/test-async_assertions.js b/test/examples/test-async_assertions.js similarity index 88% rename from test/test-async_assertions.js rename to test/examples/test-async_assertions.js index 40ee2df..bcbe5ad 100644 --- a/test/test-async_assertions.js +++ b/test/examples/test-async_assertions.js @@ -2,6 +2,8 @@ if (module == require.main) { return require('../lib/async_testing').run(process.ARGV); } +var u = require('util') + module.exports = { 'test success': function(test) { setTimeout(function() { @@ -12,8 +14,12 @@ module.exports = { 'test fail': function(test) { setTimeout(function() { +// console.log("~m~12~m~sdfhlasflasdjflasjdkasdhfklasdhfod") + +//u.print('ccccccccccccccccccccccccc') test.ok(false, 'This should be false'); test.finish(); +//u.print('ccccccccccccccccccccccccc') }, 500); }, diff --git a/test/test-custom_assertions.js b/test/examples/test-custom_assertions.js similarity index 88% rename from test/test-custom_assertions.js rename to test/examples/test-custom_assertions.js index 2873650..2ae659b 100644 --- a/test/test-custom_assertions.js +++ b/test/examples/test-custom_assertions.js @@ -1,5 +1,7 @@ -var async_testing = require('../lib/async_testing'); +//require('sys') + +var async_testing = require('async_testing'); if (module == require.main) { return async_testing.run(process.ARGV); } diff --git a/test/examples/test-empty.js b/test/examples/test-empty.js new file mode 100644 index 0000000..e69de29 diff --git a/test/test-error_async.js b/test/examples/test-error_async.js similarity index 100% rename from test/test-error_async.js rename to test/examples/test-error_async.js diff --git a/test/test-error_outside_suite.js b/test/examples/test-error_outside_suite.js similarity index 100% rename from test/test-error_outside_suite.js rename to test/examples/test-error_outside_suite.js diff --git a/test/test-error_sync.js b/test/examples/test-error_sync.js similarity index 100% rename from test/test-error_sync.js rename to test/examples/test-error_sync.js diff --git a/test/test-error_syntax.js b/test/examples/test-error_syntax.js similarity index 100% rename from test/test-error_syntax.js rename to test/examples/test-error_syntax.js diff --git a/test/test-error_test_already_finished.js b/test/examples/test-error_test_already_finished.js similarity index 99% rename from test/test-error_test_already_finished.js rename to test/examples/test-error_test_already_finished.js index 23b0009..081cd07 100644 --- a/test/test-error_test_already_finished.js +++ b/test/examples/test-error_test_already_finished.js @@ -8,3 +8,4 @@ module.exports = { test.finish(); }, } + diff --git a/test/test-error_test_already_finished_async.js b/test/examples/test-error_test_already_finished_async.js similarity index 100% rename from test/test-error_test_already_finished_async.js rename to test/examples/test-error_test_already_finished_async.js diff --git a/test/examples/test-error_test_already_finished_then_assertion.js b/test/examples/test-error_test_already_finished_then_assertion.js new file mode 100644 index 0000000..bf34270 --- /dev/null +++ b/test/examples/test-error_test_already_finished_then_assertion.js @@ -0,0 +1,10 @@ + +if (module == require.main) { + return require('../lib/async_testing').run(process.ARGV); +} +module.exports = { + 'test sync already finished then assertion': function(test) { + test.finish(); + test.ok(true,'this should fail'); + }, +} diff --git a/test/test-error_uncaught_exception_handler.js b/test/examples/test-error_uncaught_exception_handler.js similarity index 100% rename from test/test-error_uncaught_exception_handler.js rename to test/examples/test-error_uncaught_exception_handler.js diff --git a/test/examples/test-errors.js b/test/examples/test-errors.js new file mode 100644 index 0000000..0b18e63 --- /dev/null +++ b/test/examples/test-errors.js @@ -0,0 +1,14 @@ + +exports['test sync error'] = function(test) { + throw new Error(); +}; + +exports['test async error'] = function(test) { + process.nextTick(function() { + throw new Error(); + }); +}; + +if (module == require.main) { + require('../lib/async_testing').run(__filename, process.ARGV); +} diff --git a/test/examples/test-multiple_errors.js b/test/examples/test-multiple_errors.js new file mode 100644 index 0000000..940e57b --- /dev/null +++ b/test/examples/test-multiple_errors.js @@ -0,0 +1,26 @@ + +exports['test async error 1'] = function(test) { + process.nextTick(function() { + throw new Error(); + }); +}; + +exports['test sync error'] = function(test) { + throw new Error('Oooops'); +}; + +exports['test async error 2'] = function(test) { + process.nextTick(function() { + throw new Error(); + }); +}; + +exports['test async error 3'] = function(test) { + process.nextTick(function() { + throw new Error(); + }); +}; + +if (module == require.main) { + require('../lib/async_testing').run(__filename, process.ARGV); +} diff --git a/test/test-overview.js b/test/examples/test-overview.js similarity index 100% rename from test/test-overview.js rename to test/examples/test-overview.js diff --git a/test/examples/test-parse_run_arguments.js b/test/examples/test-parse_run_arguments.js new file mode 100644 index 0000000..bccaba4 --- /dev/null +++ b/test/examples/test-parse_run_arguments.js @@ -0,0 +1,165 @@ +if (module == require.main) { + return require('../lib/async_testing').run(process.ARGV); +} + +var parse = require('../lib/running').parseRunArguments; + +var flags = + { 'group': + [ { longFlag: 'first' + } + , { longFlag: 'flag-with-dashes' + } + , { longFlag: 'single' + , takesValue: 'number' + } + , { longFlag: 'multiple' + , takesValue: 'number' + , multiple: true + } + , { longFlag: 'key' + , key: 'keyed' + } + , { longFlag: 'value' + , value: 42 + } + , { longFlag: 'value0' + , value: 0 + } + , { longFlag: 'value-key' + , key: 'keyedValued' + , value: 10 + } + ] + }; + +module.exports = + { 'test string': function(test) { + var l = []; + var o = {}; + + parse(['name'], l, o, flags); + + test.deepEqual(['name'], l); + test.deepEqual({}, o); + test.finish(); + } + , 'test object': function(test) { + var l = []; + var o = {}; + + parse([{first: true}], l, o, flags); + + test.deepEqual([], l); + test.deepEqual({first: true}, o); + test.finish(); + } + , 'test array': function(test) { + var l = []; + var o = {}; + + parse([['name', '--first']], l, o, flags); + + test.deepEqual({first: true}, o); + test.finish(); + } + , 'test order1': function(test) { + var l = []; + var o = {}; + + parse([{first: false}, ['--first']], l, o, flags); + + test.deepEqual({first: true}, o); + test.finish(); + } + , 'test order2': function(test) { + var l = []; + var o = {}; + + parse([['--first'], {first: false}], l, o, flags); + + test.deepEqual({first: false}, o); + test.finish(); + } + , 'test flag -> key conversion': function(test) { + var l = []; + var o = {}; + + parse([['--flag-with-dashes']], l, o, flags); + + test.deepEqual({'flagWithDashes': true}, o); + test.finish(); + } + , 'test single once': function(test) { + var l = []; + var o = {}; + + parse([['--single', 'one']], l, o, flags); + + test.deepEqual({'single': 'one'}, o); + test.finish(); + } + , 'test single twice': function(test) { + var l = []; + var o = {}; + + parse([['--single', 'one', '--single', 'two']], l, o, flags); + + test.deepEqual({'single': 'two'}, o); + test.finish(); + } + , 'test multiple once': function(test) { + var l = []; + var o = {}; + + parse([['--multiple', 'one']], l, o, flags); + + test.deepEqual({'multiple': ['one']}, o); + test.finish(); + } + , 'test multiple twice': function(test) { + var l = []; + var o = {}; + + parse([['--multiple', 'one', '--multiple', 'two']], l, o, flags); + + test.deepEqual({'multiple': ['one','two']}, o); + test.finish(); + } + , 'test key': function(test) { + var l = []; + var o = {}; + + parse([['--key']], l, o, flags); + + test.deepEqual({'keyed': true}, o); + test.finish(); + } + , 'test value': function(test) { + var l = []; + var o = {}; + + parse([['--value']], l, o, flags); + + test.deepEqual({'value': 42}, o); + test.finish(); + } + , 'test 0 value': function(test) { + var l = []; + var o = {}; + + parse([['--value0']], l, o, flags); + + test.deepEqual({'value0': 0}, o); + test.finish(); + } + , 'test value and key': function(test) { + var l = []; + var o = {}; + + parse([['--value-key']], l, o, flags); + + test.deepEqual({'keyedValued': 10}, o); + test.finish(); + } + }; diff --git a/test/examples/test-stderr.js b/test/examples/test-stderr.js new file mode 100644 index 0000000..fed8a76 --- /dev/null +++ b/test/examples/test-stderr.js @@ -0,0 +1,6 @@ +exports.stderr = function (){ + + require('sys') //generate some stderr + console.error('standard error.... again') + +} diff --git a/test/test-sub_suites.js b/test/examples/test-sub_suites.js similarity index 100% rename from test/test-sub_suites.js rename to test/examples/test-sub_suites.js diff --git a/test/test-sync_assertions.js b/test/examples/test-sync_assertions.js similarity index 74% rename from test/test-sync_assertions.js rename to test/examples/test-sync_assertions.js index e279cae..9e9553d 100644 --- a/test/test-sync_assertions.js +++ b/test/examples/test-sync_assertions.js @@ -13,24 +13,24 @@ module.exports = { test.finish(); }, - 'test success -- numAssertionsExpected': function(test) { + 'test success -- numAssertions expected': function(test) { test.numAssertions = 1; test.ok(true, 'This should be true'); test.finish(); }, - 'test fail -- numAssertionsExpected': function(test) { + 'test fail -- numAssertions expected': function(test) { test.numAssertions = 1; test.ok(false, 'fail -- numAssertions expected shouldn\'t overwrite failures'); test.finish(); }, - 'test fail - not enough -- numAssertionsExpected': function(test) { + 'test fail - not enough -- numAssertions expected': function(test) { test.numAssertions = 1; test.finish(); }, - 'test fail - too many -- numAssertionsExpected': function(test) { + 'test fail - too many -- numAssertions expected': function(test) { test.numAssertions = 1; test.ok(true, 'This should be true'); test.ok(true, 'This should be true'); diff --git a/test/examples/test-throw_null.js b/test/examples/test-throw_null.js new file mode 100644 index 0000000..bced2da --- /dev/null +++ b/test/examples/test-throw_null.js @@ -0,0 +1,25 @@ + +exports ['throw null makes test fail'] = function (test){ + //throw 'string' + throw null +} + +if(require.main === module){ + require('async_testing').run(process.argv) + require('async_testing').runSuite(module.exports,{onSuiteDone: d}) + + function d(status,report){ + console.log(status) + console.log(report) + /* + complete + { tests: + [ { name: 'throw null makes test fail', + numAssertions: 0 } ], + numFailures: 0, + numSuccesses: 1 } + */ + } +} + + diff --git a/test/test-uncaught_exception_handlers.js b/test/examples/test-uncaught_exception_handlers.js similarity index 100% rename from test/test-uncaught_exception_handlers.js rename to test/examples/test-uncaught_exception_handlers.js diff --git a/test/test-wrap_tests.js b/test/examples/test-wrap_tests.js similarity index 97% rename from test/test-wrap_tests.js rename to test/examples/test-wrap_tests.js index 4e57ced..b344f54 100644 --- a/test/test-wrap_tests.js +++ b/test/examples/test-wrap_tests.js @@ -1,4 +1,4 @@ -var async_testing = require('../lib/async_testing') +var async_testing = require('async_testing') , wrap = async_testing.wrap ; diff --git a/test/examples/throw_string.script.js b/test/examples/throw_string.script.js new file mode 100644 index 0000000..a30eaca --- /dev/null +++ b/test/examples/throw_string.script.js @@ -0,0 +1,6 @@ + +//require('assert').ok(false, "INTENSIONAL FAIL") + +throw "INTENSIONAL STRING THROW" + + diff --git a/test/lib/dummy_test_adapter.js b/test/lib/dummy_test_adapter.js new file mode 100644 index 0000000..ca64d40 --- /dev/null +++ b/test/lib/dummy_test_adapter.js @@ -0,0 +1,38 @@ + + +exports.runTest = runTest + +function runTest(file,callbacks){ + var test = require(file) +/* + if(callbacks.onSuiteStart){ + callbacks.onSuiteStart('onSuiteStart', {test: "dummy_test_adapter: onSuiteStart", object: test}) + } + process.nextTick(c) + function c (){*/ + if(callbacks.onTestStart){ + callbacks.onTestStart('onTestStart', {test: "dummy_test_adapter: onTestStart", object: test}) + } + process.nextTick(c) + function c (){ + console.log("DUMMY TEST ADAPTER: call onTestDone") + if(callbacks.onTestDone){ + callbacks.onTestDone('onTestDone', {test: "dummy_test_adapter: onTestDone", object: test}) + } + process.nextTick(c) + function c (){ + console.log("DUMMY TEST ADAPTER: call onSuiteDone") + if(callbacks.onSuiteDone){ + callbacks.onSuiteDone('onSuiteDone', {test: "dummy_test_adapter: onSuiteDone", object: test}) + } + process.nextTick(c) + function c (){ + console.log("DUMMY TEST ADAPTER: call onSuiteDone") + if(callbacks.onExit){ + callbacks.onExit('onExit', {test: "dummy_test_adapter: onExit", object: test})//to mark a normal exit. + } + } + } + } + //} +} diff --git a/test/lib/magic_number.js b/test/lib/magic_number.js new file mode 100644 index 0000000..f2ac87c --- /dev/null +++ b/test/lib/magic_number.js @@ -0,0 +1,3 @@ + + +exports.magicNumber = 123471947194 diff --git a/test/lib/stderr.js b/test/lib/stderr.js new file mode 100644 index 0000000..6776eba --- /dev/null +++ b/test/lib/stderr.js @@ -0,0 +1,3 @@ + +// require('sys') + console.error('standard error.... again') diff --git a/test/messages.asynct.js b/test/messages.asynct.js new file mode 100644 index 0000000..e0ce32e --- /dev/null +++ b/test/messages.asynct.js @@ -0,0 +1,55 @@ + +var messages = require('async_testing/lib/messages2') + , inspect = require('util').inspect + , examples = + [ "hello" + , 37 + , 42 + , null + , '' + , [] + , [24,235,436234] + , {hello: ['a','b','c']} + ] +exports ['(standard interface) messageDecode (messageEncode(X).split(\'\n\')) returns X'] = function(test) { + + function checkEncodeDecode(x){ + console.log("message:" + messages.messageEncode(x)) + test.deepEqual(messages.messageDecode(messages.messageEncode(x).split('\n')),[x]) + } + + examples.forEach(checkEncodeDecode) + checkEncodeDecode(examples) + + test.finish() +} + +exports ['test that messages still works in noise'] = function (test){ + var noises = + [ "dffjasldfjdlsjf" + , '0' + , ' ' + , '___' + , '~' + , '~m~4' ] + + function checkEncodeDecodeWithNoise(x,noise){ + + console.log("message:" + messages.messageEncode(x)) + test.deepEqual(messages.messageDecode((noise + messages.messageEncode(x)).split('\n')),[x]) + test.deepEqual(messages.messageDecode((messages.messageEncode(x) + noise).split('\n')),[x]) + } + + noises.forEach(function (n){ + examples.forEach(function(e){checkEncodeDecodeWithNoise(e,n)}) + }) + checkEncodeDecodeWithNoise(examples,"asflasdfjlsdf") + test.finish() +} + +exports ['useMagicNumbers'] = function (test){ + test.ok(messages.useMagicNumbers) + messager = messages.useMagicNumbers({start: 213,end:32425}) + test.ok(messager.useMagicNumbers) + test.finish() +} diff --git a/test/subtree.asynct.js b/test/subtree.asynct.js new file mode 100644 index 0000000..53b76b2 --- /dev/null +++ b/test/subtree.asynct.js @@ -0,0 +1,58 @@ +var subtree = require("async_testing/lib/subtree") +, sys = require('util'); + + +function sb (test,little,big,bool) { + var bool = bool === undefined ? true : false + , m = bool ? 'doesNotThrow' : 'throws'; + /*sys.puts("bool " + bool); + sys.puts("little " + sys.inspect(little)); + sys.puts("big " + sys.inspect(big));*/ + + test[m](function(){subtree.assert_subtree(little,big)}); + test.ok(bool === subtree.subtree(little,big),"expected: subtree of " + sys.inspect(big) + " but got " + sys.inspect(little)); +// subtree.subtree +} +exports.test_subtree = function (test) { + var little = {a: "a",b:"b"} + , big = {a: "a",b:"b",c:"c"} + , little2 = {a: "a",b:"b",d:'DEE'} + sb(test,little,big); + sb(test,little,little2); +// test.ok(subtree.subtree(little,little2),"expected: subtree of " + sys.inspect(big) + " but got " + sys.inspect(little)); +// test.ok(!subtree.subtree(little2,big),"expected: subtree of " + sys.inspect(big) + " but got " + sys.inspect(little)); + + test.finish(); +} + +exports.test_subtree_errors = function (test) { + var little = {a: "a",b:"b"} + , big = {a: "a",b:"b",c:"c"} + , little2 = {a: "a",b:"b",d:'DEE'} +// sb(test,big,little); + subtree.assert_subtree(little,big); + test.throws(function(){ + subtree.assert_subtree(big,little); + }); + test.finish(); +} + +exports.test_subtree_object = function (test) { + var little = {a: "a",b:"b",d:{}} + , big = {a: "a",b:"b",c:"c",d:{hi: "hello"}} + , big2 = {a: "a",b:"b"} + subtree.assert_subtree(little,big); + test.throws(function(){ + subtree.assert_subtree(little,big2); + }); + test.finish(); +} + + +if (module == require.main) { + require('async_testing').run(__filename, process.ARGV); +} + + + + diff --git a/test/tester.asynct.js b/test/tester.asynct.js new file mode 100644 index 0000000..a4cd2eb --- /dev/null +++ b/test/tester.asynct.js @@ -0,0 +1,158 @@ + +var child = require('async_testing/lib/child2') + , inspect = require('inspect') + , Tester = require('async_testing/lib/tester') + , subtree = require('async_testing/lib/subtree') + +//tester.script.asynct.js + +/* + OKAY! + refactor this to run in a child process... + + i've altered child2 so that you call it with a test adapter. + + NEXT: try loading tester as an adapter for child2. +*/ + + +/* +exports ['can accept a file and return tests for that file'] = function (test){ + + t = new Tester ('./examples/pass.script') + test.deepEqual(t.tests,['pass.script']) + test.finish() +} +*/ + /* + am i gonna have to run all tests as a seperate process? + that may be the most comprehensive solution... + + or design this to run around the test in the seperate process? + - to ensure reporting is correct? + - so child 2 is passed the test, then calls this, which calls the test. + - child2 just handles communicating results. + - this is the adapter to the test framework, & handles making reports + */ +// test.finish() +/* +exports ['can run a test'] = function (test){ + + t = new Tester ('async_testing/test/examples/pass.script') + test.deepEqual(t.tests,['pass.script']) + + t.run('pass.script',done) + + function done (status,data){ + var expected = + { test:'pass.script' + , status: 'success' + } + test.equal(status,'success', "expected success:\n" + inspect(data)) + subtree.assert_subtree(expected,data) + test.finish() + } +} + + +exports ['can run a failing test'] = function (test){ + + var t = new Tester ('async_testing/test/examples/fail.script') + , name = 'fail.script' + test.deepEqual(t.tests,[name]) + + t.run(name,done) + + function done (status,data){ + var expected = + { test:name + , status: 'failure' + , failureType: 'AssertionError' //actual type of error. will be string if a string is thrown. + , failure: {} + } + test.equal(status,'failure', "expected 'failure', got:" + status + "\n" + inspect(data)) + subtree.assert_subtree(expected,data) + test.finish() + } +} + + +exports ['can run an erroring test'] = function (test){ + + var t = new Tester ('async_testing/test/examples/error.script') + , name = 'error.script' + , expectedStatus = 'error' + + test.deepEqual(t.tests,[name]) + + t.run(name,done) + + function done (status,data){ + var expected = + { test:name + , status: expectedStatus + , failureType: 'Error' //actual type of error. will be string if a string is thrown. + , failure: {} } + + test.equal(status,expectedStatus, "expected '" + expectedStatus + "', got:" + status + "\n" + inspect(data)) + subtree.assert_subtree(expected,data) + test.finish() + } +} + +exports ['can run an erroring test, non error thrown'] = function (test){ + + var t = new Tester ('async_testing/test/examples/throw_string.script') + , name = 'throw_string.script' + , expectedStatus = 'error' + + test.deepEqual(t.tests,[name]) + + t.run(name,done) + + function done (status,data){ + var expected = + { test:name + , status: expectedStatus + , failureType: 'string' //actual type of error. will be string if a string is thrown. + , failure: "INTENSIONAL STRING THROW" + } + test.equal(status,expectedStatus, "expected '" + expectedStatus + "', got:" + status + "\n" + inspect(data)) + subtree.assert_subtree(expected,data) + test.finish() + } +} +*/ +exports ['can run an erroring test, async error'] = function (test){ + +/* + to cleanly catch this sort of error, without interfering with THIS test frameworkm + run this test in another process. + + -- or use a script test instead of an asynct test... +*/ + var cb = {adapter: "async_testing/lib/tester", onSuiteDone: done} + + child.runFile('async_testing/test/examples/async_error.script',cb) +// var t = new Tester () + , name = 'async_error.script' + , expectedStatus = 'error' + + function done (status,data){ + var expected = + { test:name + , status: expectedStatus + , failureType: 'string' //actual type of error. will be string if a string is thrown. + , failure: "INTENSIONAL STRING THROW" + } + test.equal(status,expectedStatus, "expected '" + expectedStatus + "', got:" + status + "\n" + inspect(data)) +// subtree.assert_subtree(expected,data) + + //now that I have a good error reporting structure. + //I can use it to define what the test results should be! + + test.finish() + } +} + + diff --git a/todo.txt b/todo.txt index de0fe88..f4239c1 100644 --- a/todo.txt +++ b/todo.txt @@ -55,3 +55,4 @@ Docs ---- + update docs and add list of command line arguments for run and what they do + add note about contributing/contacting +