Commit 7a530b5a authored by Jérémy Lal's avatar Jérémy Lal

Imported Upstream version 0.4.13

parents
node_modules/
coverage/
coverage-example/coverage/
# contributors sorted by whether or not they're me
Isaac Z. Schlueter <i@izs.me>
baudehlo <helpme+github@gmail.com>
James Halliday <mail@substack.net>
Jason Smith (air) <jhs@iriscouch.com>
Pedro P. Candel <kusorbox@gmail.com>
Stein Martin Hustad <stein@hustad.com>
Trent Mick <trentm@gmail.com>
Corey Richardson <kb1pkl@aim.com>
Raynos <raynos2@gmail.com>
Siddharth Mahendraker <siddharth_mahen@me.com>
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
All rights reserved.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
This is a mix-and-match set of utilities that you can use to write test
harnesses and frameworks that communicate with one another using the
Test Anything Protocol.
If you don't yet know what TAP is, [you better ask
somebody](http://testanything.org/).
Default Usage:
1. Make a directory. Maybe call it 'test'. That'd be nice and obvious.
2. Put a bunch of test scripts in there. If they're node programs, then
they should be ".js". Anything else is assumed to be some kind of shell
script, which should have a shebang line.
3. `npm install tap`
4. Update package.json scripts.test to include `tap ./test` [example
gist](https://gist.github.com/4469613)
5. `npm test`
The output will be TAP-compliant.
For extra special bonus points, you can do something like this:
var test = require("tap").test
test("make sure the thingie is a thing", function (t) {
t.equal(thingie, "thing", "thingie should be thing")
t.deepEqual(array, ["foo", "bar"], "array has foo and bar elements")
t.deepEqual(object, {foo: 42}, "object has foo property")
t.type(thingie, "string", "type of thingie is string")
t.ok(true, "this is always true")
t.notOk(false, "this is never true")
t.test("a child test", function (t) {
t.equal(this, superEasy, "right!?")
t.similar(7, 2, "ever notice 7 is kinda like 2?", {todo: true})
t.test("so skippable", {skip: true}, function (t) {
t.plan(1) // only one test in this block
t.ok(true, "but when the flag changes, it'll pass")
// no need to end, since we had a plan.
})
t.end()
})
t.ok(99, "can also skip individual assertions", {skip: true})
// end lets it know it's over.
t.end()
})
test("another one", function (t) {
t.plan(1)
t.ok(true, "It's ok to plan, and also end. Watch.")
t.end() // but it must match the plan!
})
Node-tap is actually a collection of several modules, any of which may be
mixed and matched however you please.
If you don't like this test framework, and think you can do much much
better, *I strongly encourage you to do so!* If you use this library,
however, at least to output TAP-compliant results when `process.env.TAP`
is set, then the data coming out of your framework will be much more
consumable by machines.
You can also use this to build programs that *consume* the TAP data, so
this is very useful for CI systems and such.
* tap-assert: A collection of assert functions that return TAP result
objects.
* tap-consumer: A stream interface for consuming TAP data.
* tap-producer: A class that produces a TAP stream by taking in result
objects.
* tap-results: A class for keeping track of TAP result objects as they
pass by, counting up skips, passes, fails, and so on.
* tap-runner: A program that runs through a directory running all the
tests in it. (Tests which may or may not be TAP-outputting tests. But
it's better if they are.)
* tap-test: A class for actually running tests.
* tap-harness: A class that runs tests. (Tests are also Harnesses,
which is how sub-tests run.)
* tap-global-harness: A default harness that provides the top-level
support for running TAP tests.
## Experimental Code Coverage with runforcover & bunker:
```
TAP_COV=1 tap ./test [--cover=./lib,foo.js] [--coverage-dir=./coverage]
```
This feature is experimental, and will most likely change somewhat
before being finalized. Feedback welcome.
#!/usr/bin/env node
// just an example, really
// Run with `node tap-http.js path/to/tests/`
var argv = process.argv.slice(2)
, path = require("path")
, Runner = require("../lib/tap-runner")
, http = require("http")
, server = http.createServer(function (req, res) {
// it'd be nice to return a non-200 if the tests fail, but we don't
// know the status until it's done, so that would mean not being able
// to pipe the output
res.writeHead(200, {'content-type': 'text/plain'})
new Runner(argv, null).pipe(res)
})
server.listen(1337)
#!/usr/bin/env node
// read a tap stream from stdin.
var TapConsumer = require("../lib/tap-consumer")
, TapProducer = require("../lib/tap-producer")
var tc = new TapConsumer
, tp = new TapProducer
//process.stdin.pipe(tc)
process.stdin.on("data", function (c) {
c = c + ""
// console.error(JSON.stringify(c).substr(0, 100))
tc.write(c)
})
process.stdin.on("end", function () { tc.end() })
process.stdin.resume()
//tc.pipe(tp)
tc.on("data", function (c) {
tp.write(c)
})
tc.on("end", function () { tp.end() })
tp.on("data", function (c) {
console.error(["output write", c])
process.stdout.write(c)
})
tp.on("end", function (er, total, ok) {
if (er) throw er
process.exit(total - ok)
})
#!/usr/bin/env node
var argv = process.argv.slice(2)
, path = require("path")
, Runner = require("../lib/tap-runner")
, nopt = require("nopt")
, knownOpts =
{ cover: [path, false]
, "cover-dir": path
, stderr: Boolean
, stdout: Boolean
, diag: Boolean
, version: Boolean
, tap: Boolean
, timeout: Number
, gc: Boolean
, debug: Boolean
, "debug-brk": Boolean
, strict: Boolean
, harmony: Boolean
}
, shorthands =
// debugging 1: show stderr
{ d: ["--stderr"]
// debugging 2: show stderr and tap
, dd: ["--stderr", "--tap"]
// debugging 3: show stderr, tap, AND always show diagnostics.
, ddd: ["--stderr", "--tap", "--diag"]
, "expose-gc": ["--gc"]
, g: ["--gc"]
, e: ["--stderr"]
, t: ["--timeout"]
, o: ["--tap"]
, c: ["--cover"]
, v: ["--version"]
, "?": ["--help"]
, h: ["--help"]
}
, defaults =
{ cover: "./lib"
, "cover-dir": "./coverage"
, stderr: process.env.TAP_STDERR !== '0'
, tap: process.env.TAP
, diag: process.env.TAP_DIAG
, timeout: +process.env.TAP_TIMEOUT || 30
, gc: false
, debug: false
, "debug-brk": false
, strict: false
, harmony: false
, version: false
, help: false }
, options = nopt(knownOpts, shorthands)
if (options.version) {
console.log(require("../package.json").version)
process.exit(0)
}
if (options.help) {
console.log(function(){/*
Usage:
tap <options> <files>
Run the files as tap tests, parse the output, and report the results
Options:
--stderr Print standard error output of tests to standard error.
--tap Print raw tap output.
--diag Print diagnostic output for passed tests, as well as failed.
(Implies --tap)
--gc Expose the garbage collector to tests.
--timeout Maximum time to wait for a subtest, in seconds. Default: 30
--debug Pass the '--debug' flag to node for debugging
--debug-brk Pass the '--debug-brk' flag to node for debugging
--strict Enforce strict mode when running tests.
--harmony Enable harmony features for tests.
--version Print the version of node tap.
--help Print this help.
Please report bugs! https://github.com/isaacs/node-tap/issues
*/}.toString().split(/\n/).slice(1, -1).join("\n"))
process.exit(0)
}
Object.keys(defaults).forEach(function (k) {
if (!options.hasOwnProperty(k)) options[k] = defaults[k]
})
// other tests that might rely on these
if (options.diag) process.env.TAP_DIAG = true
if (options.tap) process.env.TAP = true
if (options.timeout) process.env.TAP_TIMEOUT = options.timeout
var r = new Runner(options)
, TapProducer = require("../lib/tap-producer")
if (options.tap || options.diag) {
r.pipe(process.stdout)
} else {
r.on("file", function (file, results, details) {
var s = (details.ok ? "" : "not ") + "ok "+results.name
, n = details.pass + "/" + details.testsTotal
, dots = new Array(Math.max(1, 60 - s.length - n.length)).join(".")
console.log("%s %s %s", s, dots, n)
if (details.ok) {
if (details.skip) {
console.log(" skipped: %s", details.skipTotal)
}
} else {
// console.error(details)
console.log(" Command: %s", results.command)
console.log(" " + TapProducer.encode(details.list)
.split(/\n/).join("\n "))
}
})
r.on("end", function () {
//console.log(r)
var s = "total"
, n = r.results.pass + "/" + r.results.testsTotal
, dots = new Array(60 - s.length - n.length).join(".")
, ok = r.results.ok ? "ok" : "not ok"
console.log("%s %s %s\n\n%s", s, dots, n, ok)
if (r.doCoverage) {
console.error( "\nCoverage: %s\n"
, path.resolve(r.coverageOutDir, "index.html") )
}
})
}
r.on("end", function () {
process.exit(r.results.tests - r.results.pass)
})
var Bar = module.exports = function(str) {
this.bar = str;
this.str = str;
};
Bar.prototype.foo = function() {
var self = this;
return self.bar;
};
Bar.prototype.baz = function() {
var self = this;
return self.str;
};
var Foo = module.exports = function(str) {
this.foo = str;
this.str = str;
};
Foo.prototype.bar = function() {
var self = this;
return self.foo;
};
Foo.prototype.baz = function() {
var self = this;
return self.str;
};
var test = require('tap').test,
Bar = require('../lib/bar'),
bar;
test('setup', function(t) {
bar = new Bar('baz');
t.ok(bar);
t.end();
});
test('bar', function(t) {
t.equal('baz', bar.foo());
t.end();
});
test('teardown', function(t) {
t.ok(true);
t.end();
});
var test = require('tap').test,
Foo = require('../lib/foo'),
Bar = require('../lib/bar'),
foo, bar;
test('setup', function(t) {
foo = new Foo('baz');
t.ok(foo);
bar = new Bar('baz');
t.ok(bar);
t.end();
});
test('baz from Foo', function(t) {
t.equal('baz', foo.baz());
t.end();
});
test('baz from Bar', function(t) {
t.equal('baz', bar.baz());
t.end();
});
test('teardown', function(t) {
t.ok(true);
t.end();
});
var test = require('tap').test,
Foo = require('../lib/foo'),
foo;
test('setup', function(t) {
foo = new Foo('baz');
t.ok(foo);
t.end();
});
test('bar', function(t) {
t.equal('baz', foo.bar());
t.end();
});
test('teardown', function(t) {
t.ok(true);
t.end();
});
module.exports = Math
var tap = require("tap")
, test = tap.test
, plan = tap.plan
, math
test("load sut", function (t) {
math = require("../lib/math")
t.ok(math, "object loaded")
t.end()
})
test("validate constants", function (t) {
t.equal(math.LN10, 2.302585092994046, "ln 10")
t.equal(math.PI, 3.141592653589793, "pi")
t.equal(math.E, 2.718281828459045, "e")
t.equal(math.LOG10E, 0.4342944819032518, "log 10 e")
t.equal(math.SQRT2, 1.4142135623730951, "sqrt 2")
t.equal(math.SQRT1_2, 0.7071067811865476, "sqrt 1/2")
t.equal(math.LN2, 0.6931471805599453, "ln2")
t.end()
})
test("using this", function (t) {
// this also works.
this.equal(t, this, "call in scope of test obj")
this.end()
})
// test setTimeout, just a trivial example.
test("setTimeout", function (t) {
var start = Date.now()
setTimeout(function () {
t.ok(Date.now() >= start + 50, "timeout fired after delay")
t.end()
}, 50)
})
// another way to do the same, using a plan.
// this is more robust, but annoying when you have a long list
// of tests for something. For async stuff, it's generally better,
// since there's a higher risk of the control flowing off to lala land.
test("setTimeout planned", function (t) {
t.plan(1)
var start = Date.now()
setTimeout(function () {
t.ok(Date.now() >= start + 50, "timeout fired after delay")
}, 50)
})
// plans also are good for cases where things may fire in a non-deterministic
// order, since it won't be as obvious when everything is done.
test("setTimeout parallel", function (t) {
t.plan(2)
var start = Date.now()
setTimeout(function A () {
t.ok(Date.now() >= start + 50, "timeout A fired after delay")
}, 50)
setTimeout(function B () {
t.ok(Date.now() >= start + 50, "timeout B fired after delay")
}, 50)
})
// something slightly less hello worldy
test("async test", function (t) {
t.plan(4)
var fs = require("fs")
t.ok(fs, "fs library should load")
var rs = fs.createReadStream(__filename)
t.ok(rs, "read stream should start fine.")
rs.on("open", function (fd) {
t.type(fd, "number", "file descriptor should be a number")
t.equal(fd, rs.fd, "fd should match stream fd")
})
})
// you can bail out of the entire everything if something is just
// Not Right (db not installed, etc.)
test("tarp", function (parent) {
if (7 === 5) {
parent.bailout("math is broken")
}
// bailout bubbles up a bit like "error" events
// if unhandled, then the parent will bail, as well.
parent.test("child bailouts", function (child) {
child.on("bailout", function (s) {
parent.fail("children shouldn't bail.")
})
child.bailout("try to bail out, but instead just fail a test")
})
parent.test("child bailout 2", function (child) {
child.bailout("this one will bail out")
})
})
// tests marked "todo" can fail without counting against the overall score
// never ever ever write tests to "verify" incorrect behavior!
test("unfinished test", function (t) {
t.equal(math.cos(math.PI), -1, "cos(PI)")
t.equal(math.sin(math.PI), 0, "sin(PI)")
t.equal(math.face, "your face", "math.face should be your face # TODO")
t.end()
})
// tests can have children.
test("http server", function (t) {
// one test plus 4 children.
t.plan(5)
var http = require("http")
, PORT = 12346
t.ok(http, "http module should load")
var server
t.test("set up server", function (t) {
t.plan(2)
server = http.createServer(function (req, res) {
t.comment("Request: "+req.url)
res.writeHead(200, {})
res.end(req.method + " " + req.url)
})
t.ok(server, "createServer should create a server")
server.listen(PORT, t.cb("listen should fire callback"))
})
// set the "parallel" flag on this one.
// That signals the harness to proceed immediately to the next test,
// and run them in parallel.
// Default behavior is to wait for each test to complete before proceeding
// to the next one.
// The first not-parallel test encountered will cause it to wait for that
// test, as well as all the parallel tests before it.
// A, B', C', D', E (where ' means "parallel")
// Runs A, and then B, C, and D in parallel, and then E.
t.test("testing POST", {parallel: true}, function (t) {
t.plan(1)
http.request("POST", { method: "POST"
, host: "localhost"
, path: "/foo"
, port: PORT }).on("response", function (res) {
t.bufferStream(res, function (s) { t.equal(s, "POST /foo") })
}).end()
})
t.test("testing GET", {parallel: true}, function (t) {
t.plan(1)
http.request("POST", { method: "GET"
, host: "localhost"
, path: "/foo"
, port: PORT }).on("response", function (res) {
t.bufferStream(res, function (s) { t.equal(s, "GET /foo") })
}).end()
})
// wrap in a test so that if this throws, it'll log as a failed test.
t.test("teardown", function (t) {
server.close()
t.end()
})
})
// yo dawg!
test("meta-tests", function (t) {
t.plan(5)
// t.fails() wraps a child test and succeeds if it fails.
t.fails(t.test("this should fail", function (t) {
t.ok(false, "assert false")
t.end()
}))
// t.timesOut() wraps a child test and succeeds if it times out.
// if t.end() is called, or if a plan is completed, then it fails.
// set the timeout really low so that it will not take forever.
t.timesOut(t.test("this should timeout", { timeout: 1 }, function (t) {
t.ok(true, "assert true")
// t.end() never called.
}))
// t.incomplete() wraps a child test and succeeds if it ends before
// the plan is finished.
t.incomplete(t.test("this should be incomplete", function (t) {
t.plan(100)
t.ok(true, "assert true")
// calling end prematurely.
t.end()
}))
// t.bailsOut() wraps a child test and succeeds if it calls bailout()
t.bailsOut(t.test("this should bailout", function (t) {
t.bailout("oh noes, bailing out!")
}))
// low-level analysis of subtests
t.test("verifying test success/failure expectations", function (t) {
t.once("end", function () {
var res = t.results
, is = t.equal
// hijack!
t.clear()
is(res.ok, false, "ok")
is(res.bailedOut, false, "bailed out")
is(res.skip, 2, "skips")
is(res.skipPass, 1, "skip that passed")
is(res.skipFail, 1, "skip that failed")
is(res.todo, 2, "todos")
is(res.todoPass, 1, "todo that passed")
is(res.todoFail, 1, "todo that failed")
is(res.failTotal, 3, "failures total")
is(res.fail, 1, "relevant failure")
is(res.passTotal, 3, "passes total")
is(res.pass, 1, "relevant pass")
is(res.testsTotal, 6, "total tests")
is(res.tests, 2, "should be 2 relevant tests")
t.end()
})
// run the metatest.
// *this* is the actual SUT in this case.
t.ok(false, "failing todo #todo")
// can also set #todo or #skip explicitly
t.ok(true, "succeeding todo", {todo: true})
t.ok(false, "failing skip #skip", {skip: true})
t.ok(true, "suceeding skip #skip")
t.ok(false, "failing test")
t.ok(true, "succeeding test")
t.end()
})
})
var GlobalHarness = require("./tap-global-harness")
// this lets you do stuff like:
// var test = require("tap").test
// test(...)
// to run stuff in the global harness.
exports = module.exports = new GlobalHarness()
exports.createProducer = exports.Producer = require("./tap-producer")
exports.createConsumer = exports.Consumer = require("./tap-consumer")
exports.yamlish = require("yamlish")
exports.createTest = exports.Test = require("./tap-test")
exports.createHarness = exports.Harness = require("./tap-harness")
exports.createRunner = exports.Runner = require("./tap-runner")
exports.assert = require("./tap-assert")
This diff is collapsed.
// this is just a harness that pipes to stdout.
// It's the default one.
module.exports = BrowserHarness
var BrowserHarness = global.TAP_Browser_Harness
, inherits = require("inherits")
, Results = require("./tap-results")
, Harness = require("./tap-harness")
, Test = require("./tap-test")
inherits(BrowserHarness, Harness)
function BrowserHarness (outPipe) {
//console.error("calling BrowserHarness")
if (browserHarness) return browserHarness
if (!(this instanceof BrowserHarness)) {
return browserHarness = new BrowserHarness