dot.dot.dot.exampol
This commit is contained in:
commit
a0bc2d79de
406 changed files with 34577 additions and 0 deletions
16
node_modules/tap/lib/main.js
generated
vendored
Normal file
16
node_modules/tap/lib/main.js
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
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")
|
442
node_modules/tap/lib/tap-assert.js
generated
vendored
Normal file
442
node_modules/tap/lib/tap-assert.js
generated
vendored
Normal file
|
@ -0,0 +1,442 @@
|
|||
// an assert module that returns tappable data for each assertion.
|
||||
var difflet = require('difflet')
|
||||
, deepEqual = require('deep-equal')
|
||||
, bufferEqual = require('buffer-equal')
|
||||
|
||||
module.exports = assert
|
||||
|
||||
var syns = {}
|
||||
, id = 1
|
||||
|
||||
function assert (ok, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
|
||||
//console.error("assert %j", [ok, message, extra])
|
||||
//if (extra && extra.skip) return assert.skip(message, extra)
|
||||
//console.error("assert", [ok, message, extra])
|
||||
ok = !!ok
|
||||
var res = { id : id ++, ok: ok }
|
||||
|
||||
var caller = getCaller(extra && extra.error)
|
||||
if (extra && extra.error) {
|
||||
res.type = extra.error.name
|
||||
res.message = extra.error.message
|
||||
res.code = extra.error.code
|
||||
|| extra.error.type
|
||||
res.errno = extra.error.errno
|
||||
delete extra.error
|
||||
}
|
||||
if (caller.file) {
|
||||
res.file = caller.file
|
||||
res.line = +caller.line
|
||||
res.column = +caller.column
|
||||
}
|
||||
res.stack = caller.stack
|
||||
|
||||
res.name = message || "(unnamed assert)"
|
||||
|
||||
if (extra) Object.keys(extra).forEach(function (k) {
|
||||
if (!res.hasOwnProperty(k)) res[k] = extra[k]
|
||||
})
|
||||
|
||||
// strings and objects are hard to diff by eye
|
||||
if (!ok &&
|
||||
res.hasOwnProperty("found") &&
|
||||
res.hasOwnProperty("wanted") &&
|
||||
res.found !== res.wanted) {
|
||||
if (typeof res.wanted !== typeof res.found ||
|
||||
typeof res.wanted === "object" && (!res.found || !res.wanted)) {
|
||||
res.type = { found: typeof found
|
||||
, wanted: typeof wanted }
|
||||
} else if (typeof res.wanted === "string") {
|
||||
res.diff = diffString(res.found, res.wanted)
|
||||
} else if (typeof res.wanted === "object") {
|
||||
res.diff = diffObject(res.found, res.wanted)
|
||||
}
|
||||
}
|
||||
|
||||
//console.error("assert return", res)
|
||||
|
||||
return res
|
||||
}
|
||||
assert.ok = assert
|
||||
syns.ok = [ "true", "assert" ]
|
||||
|
||||
|
||||
function notOk (ok, message, extra) {
|
||||
return assert(!ok, message, extra)
|
||||
}
|
||||
assert.notOk = notOk
|
||||
syns.notOk = [ "false", "notok" ]
|
||||
|
||||
function error (er, message, extra) {
|
||||
if (!er) {
|
||||
// just like notOk(er)
|
||||
return assert(!er, message, extra)
|
||||
}
|
||||
message = message || er.message
|
||||
extra = extra || {}
|
||||
extra.error = er
|
||||
return assert.fail(message, extra)
|
||||
}
|
||||
assert.error = error
|
||||
syns.error = [ "ifError", "ifErr", "iferror" ]
|
||||
|
||||
|
||||
function pass (message, extra) {
|
||||
return assert(true, message, extra)
|
||||
}
|
||||
assert.pass = pass
|
||||
|
||||
function fail (message, extra) {
|
||||
//console.error("assert.fail", [message, extra])
|
||||
//if (extra && extra.skip) return assert.skip(message, extra)
|
||||
return assert(false, message, extra)
|
||||
}
|
||||
assert.fail = fail
|
||||
|
||||
function skip (message, extra) {
|
||||
//console.error("assert.skip", message, extra)
|
||||
if (!extra) extra = {}
|
||||
return { id: id ++, skip: true, name: message || "" }
|
||||
}
|
||||
assert.skip = skip
|
||||
|
||||
function throws (fn, wanted, message, extra) {
|
||||
if (typeof wanted === "string") {
|
||||
extra = message
|
||||
message = wanted
|
||||
wanted = null
|
||||
}
|
||||
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
|
||||
var found = null
|
||||
try {
|
||||
fn()
|
||||
} catch (e) {
|
||||
found = { name: e.name, message: e.message }
|
||||
}
|
||||
|
||||
extra = extra || {}
|
||||
|
||||
extra.found = found
|
||||
if (wanted) {
|
||||
wanted = { name: wanted.name, message: wanted.message }
|
||||
extra.wanted = wanted
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
message = "Expected to throw"
|
||||
if (wanted) message += ": "+wanted.name + " " + wanted.message
|
||||
}
|
||||
|
||||
return (wanted) ? assert.similar(found, wanted, message, extra)
|
||||
: assert.ok(found, message, extra)
|
||||
}
|
||||
assert.throws = throws
|
||||
|
||||
|
||||
function doesNotThrow (fn, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
var found = null
|
||||
try {
|
||||
fn()
|
||||
} catch (e) {
|
||||
found = {name: e.name, message: e.message}
|
||||
}
|
||||
message = message || "Should not throw"
|
||||
|
||||
return assert.equal(found, null, message, extra)
|
||||
}
|
||||
assert.doesNotThrow = doesNotThrow
|
||||
|
||||
|
||||
function equal (a, b, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
extra = extra || {}
|
||||
message = message || "should be equal"
|
||||
extra.found = a
|
||||
extra.wanted = b
|
||||
return assert(a === b, message, extra)
|
||||
}
|
||||
assert.equal = equal
|
||||
syns.equal = ["equals"
|
||||
,"isEqual"
|
||||
,"is"
|
||||
,"strictEqual"
|
||||
,"strictEquals"]
|
||||
|
||||
|
||||
function equivalent (a, b, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
var extra = extra || {}
|
||||
message = message || "should be equivalent"
|
||||
extra.found = a
|
||||
extra.wanted = b
|
||||
|
||||
if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
|
||||
return assert(bufferEqual(a, b), message, extra)
|
||||
} else {
|
||||
return assert(deepEqual(a, b), message, extra)
|
||||
}
|
||||
}
|
||||
assert.equivalent = equivalent
|
||||
syns.equivalent = ["isEquivalent"
|
||||
,"looseEqual"
|
||||
,"looseEquals"
|
||||
,"isDeeply"
|
||||
,"same"
|
||||
,"deepEqual"
|
||||
,"deepEquals"]
|
||||
|
||||
|
||||
function inequal (a, b, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
extra = extra || {}
|
||||
message = message || "should not be equal"
|
||||
extra.found = a
|
||||
extra.doNotWant = b
|
||||
return assert(a !== b, message, extra)
|
||||
}
|
||||
assert.inequal = inequal
|
||||
syns.inequal = ["notEqual"
|
||||
,"notEquals"
|
||||
,"isNotEqual"
|
||||
,"isNot"
|
||||
,"not"
|
||||
,"doesNotEqual"
|
||||
,"isInequal"]
|
||||
|
||||
|
||||
function inequivalent (a, b, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
extra = extra || {}
|
||||
message = message || "should not be equivalent"
|
||||
extra.found = a
|
||||
extra.doNotWant = b
|
||||
|
||||
if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
|
||||
return assert(!bufferEqual(a, b), message, extra)
|
||||
} else {
|
||||
return assert(!deepEqual(a, b), message, extra)
|
||||
}
|
||||
}
|
||||
assert.inequivalent = inequivalent
|
||||
syns.inequivalent = ["notEquivalent"
|
||||
,"notDeepEqual"
|
||||
,"notDeeply"
|
||||
,"notSame"
|
||||
,"isNotDeepEqual"
|
||||
,"isNotDeeply"
|
||||
,"isNotEquivalent"
|
||||
,"isInequivalent"]
|
||||
|
||||
function similar (a, b, message, extra, flip) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
// test that a has all the fields in b
|
||||
message = message || "should be similar"
|
||||
|
||||
if (typeof a === "string" &&
|
||||
(Object.prototype.toString.call(b) === "[object RegExp]")) {
|
||||
extra = extra || {}
|
||||
extra.pattern = b
|
||||
extra.string = a
|
||||
var ok = a.match(b)
|
||||
extra.match = ok
|
||||
if (flip) ok = !ok
|
||||
return assert.ok(ok, message, extra)
|
||||
}
|
||||
|
||||
var isObj = assert(a && typeof a === "object", message, extra)
|
||||
if (!isObj.ok) {
|
||||
// not an object
|
||||
if (a == b) isObj.ok = true
|
||||
if (flip) isObj.ok = !isObj.ok
|
||||
return isObj
|
||||
}
|
||||
|
||||
var eq = flip ? inequivalent : equivalent
|
||||
return eq(selectFields(a, b), b, message, extra)
|
||||
}
|
||||
assert.similar = similar
|
||||
syns.similar = ["isSimilar"
|
||||
,"has"
|
||||
,"hasFields"
|
||||
,"like"
|
||||
,"isLike"]
|
||||
|
||||
function dissimilar (a, b, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
message = message || "should be dissimilar"
|
||||
return similar(a, b, message, extra, true)
|
||||
}
|
||||
assert.dissimilar = dissimilar
|
||||
syns.dissimilar = ["unsimilar"
|
||||
,"notSimilar"
|
||||
,"unlike"
|
||||
,"isUnlike"
|
||||
,"notLike"
|
||||
,"isNotLike"
|
||||
,"doesNotHave"
|
||||
,"isNotSimilar"
|
||||
,"isDissimilar"]
|
||||
|
||||
function type (thing, t, message, extra) {
|
||||
if (extra && extra.skip) return assert.skip(message, extra)
|
||||
var name = t
|
||||
if (typeof name === "function") name = name.name || "(anonymous ctor)"
|
||||
//console.error("name=%s", name)
|
||||
message = message || "type is "+name
|
||||
var type = typeof thing
|
||||
//console.error("type=%s", type)
|
||||
if (!thing && type === "object") type = "null"
|
||||
if (type === "object" && t !== "object") {
|
||||
if (typeof t === "function") {
|
||||
//console.error("it is a function!")
|
||||
extra = extra || {}
|
||||
extra.found = Object.getPrototypeOf(thing).constructor.name
|
||||
extra.wanted = name
|
||||
//console.error(thing instanceof t, name)
|
||||
return assert.ok(thing instanceof t, message, extra)
|
||||
}
|
||||
|
||||
//console.error("check prototype chain")
|
||||
// check against classnames or objects in prototype chain, as well.
|
||||
// type(new Error("asdf"), "Error")
|
||||
// type(Object.create(foo), foo)
|
||||
var p = thing
|
||||
while (p = Object.getPrototypeOf(p)) {
|
||||
if (p === t || p.constructor && p.constructor.name === t) {
|
||||
type = name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.error(type, name, type === name)
|
||||
return assert.equal(type, name, message, extra)
|
||||
}
|
||||
assert.type = type
|
||||
syns.type = ["isa"]
|
||||
|
||||
// synonyms are helpful.
|
||||
Object.keys(syns).forEach(function (c) {
|
||||
syns[c].forEach(function (s) {
|
||||
Object.defineProperty(assert, s, { value: assert[c], enumerable: false })
|
||||
})
|
||||
})
|
||||
|
||||
// helpers below
|
||||
|
||||
function selectFields (a, b) {
|
||||
// get the values in A of the fields in B
|
||||
var ret = Array.isArray(b) ? [] : {}
|
||||
Object.keys(b).forEach(function (k) {
|
||||
if (!a.hasOwnProperty(k)) return
|
||||
var v = b[k]
|
||||
, av = a[k]
|
||||
if (v && av && typeof v === "object" && typeof av === "object"
|
||||
&& !(v instanceof Date)
|
||||
&& !(v instanceof RegExp)
|
||||
&& !(v instanceof String)
|
||||
&& !(v instanceof Boolean)
|
||||
&& !(v instanceof Number)
|
||||
&& !(Array.isArray(v))) {
|
||||
ret[k] = selectFields(av, v)
|
||||
} else ret[k] = av
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
function sortObject (obj) {
|
||||
if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) {
|
||||
return obj
|
||||
}
|
||||
|
||||
return Object.keys(obj).sort().reduce(function (acc, key) {
|
||||
acc[key] = sortObject(obj[key])
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
function stringify (a) {
|
||||
return JSON.stringify(sortObject(a), (function () {
|
||||
var seen = []
|
||||
, keys = []
|
||||
return function (key, val) {
|
||||
var s = seen.indexOf(val)
|
||||
if (s !== -1) {
|
||||
return "[Circular: "+keys[s]+"]"
|
||||
}
|
||||
if (val && typeof val === "object" || typeof val === "function") {
|
||||
seen.push(val)
|
||||
keys.push(val["!"] || val.name || key || "<root>")
|
||||
if (typeof val === "function") {
|
||||
return val.toString().split(/\n/)[0]
|
||||
} else if (typeof val.toUTCString === "function") {
|
||||
return val.toUTCString()
|
||||
}
|
||||
}
|
||||
return val
|
||||
}})())
|
||||
}
|
||||
|
||||
function diffString (f, w) {
|
||||
if (w === f) return null
|
||||
var p = 0
|
||||
, l = w.length
|
||||
while (p < l && w.charAt(p) === f.charAt(p)) p ++
|
||||
w = stringify(w).substr(1).replace(/"$/, "")
|
||||
f = stringify(f).substr(1).replace(/"$/, "")
|
||||
return diff(f, w, p)
|
||||
}
|
||||
|
||||
function diffObject (f, w) {
|
||||
return difflet({ indent : 2, comment : true }).compare(w, f)
|
||||
}
|
||||
|
||||
function diff (f, w, p) {
|
||||
if (w === f) return null
|
||||
var i = p || 0 // it's going to be at least p. JSON can only be bigger.
|
||||
, l = w.length
|
||||
while (i < l && w.charAt(i) === f.charAt(i)) i ++
|
||||
var pos = Math.max(0, i - 20)
|
||||
w = w.substr(pos, 40)
|
||||
f = f.substr(pos, 40)
|
||||
var pointer = i - pos
|
||||
return "FOUND: "+f+"\n"
|
||||
+ "WANTED: "+w+"\n"
|
||||
+ (new Array(pointer + 9).join(" "))
|
||||
+ "^ (at position = "+p+")"
|
||||
}
|
||||
|
||||
function getCaller (er) {
|
||||
// get the first file/line that isn't this file.
|
||||
if (!er) er = new Error
|
||||
var stack = er.stack || ""
|
||||
stack = stack.split(/\n/)
|
||||
for (var i = 1, l = stack.length; i < l; i ++) {
|
||||
var s = stack[i].match(/\(([^):]+):([0-9]+):([0-9]+)\)$/)
|
||||
if (!s) continue
|
||||
var file = s[1]
|
||||
, line = +s[2]
|
||||
, col = +s[3]
|
||||
if (file.indexOf(__dirname) === 0) continue
|
||||
if (file.match(/tap-test\/test.js$/)) continue
|
||||
else break
|
||||
}
|
||||
var res = {}
|
||||
if (file && file !== __filename && !file.match(/tap-test\/test.js$/)) {
|
||||
res.file = file
|
||||
res.line = line
|
||||
res.column = col
|
||||
}
|
||||
|
||||
res.stack = stack.slice(1).map(function (s) {
|
||||
return s.replace(/^\s*at\s*/, "")
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
63
node_modules/tap/lib/tap-browser-harness.js
generated
vendored
Normal file
63
node_modules/tap/lib/tap-browser-harness.js
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
// 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
|
||||
}
|
||||
browserHarness = global.TAP_Browser_Harness = this
|
||||
BrowserHarness.super.call(this, Test)
|
||||
|
||||
if (outPipe) this.output.pipe(outPipe)
|
||||
|
||||
this.test = this.test.bind(this)
|
||||
|
||||
this.plan = this.plan.bind(this)
|
||||
|
||||
var output = this.output
|
||||
this.on("childEnd", function (child) {
|
||||
//console.error("childEnd in global harness")
|
||||
//console.error(child.results)
|
||||
// write out the stuff for this child.
|
||||
//console.error("child.conf", child.conf)
|
||||
output.write(child.conf.name || "(unnamed test)")
|
||||
// maybe write some other stuff about the number of tests in this
|
||||
// thing, etc. I dunno.
|
||||
//console.error("child results", child.results)
|
||||
this.results.list.forEach(function (res) {
|
||||
//delete res.error
|
||||
//console.error("child resuilt", res)
|
||||
output.write(res)
|
||||
})
|
||||
//console.error("wrote child results")
|
||||
this.results.list.length = 0
|
||||
})
|
||||
|
||||
var streamEnded = false
|
||||
this.on("end", function () {
|
||||
//console.error("global ending the stream")
|
||||
if (!streamEnded) {
|
||||
this.results.list.forEach(function (res) {
|
||||
output.write(res)
|
||||
})
|
||||
this.results.list.length = 0
|
||||
output.end()
|
||||
streamEnded = true
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: handle global errors
|
||||
// process.on("unhandledException", function (e) {
|
||||
// this.bailout("unhandled exception: " + e.message)
|
||||
// })
|
||||
}
|
243
node_modules/tap/lib/tap-consumer.js
generated
vendored
Normal file
243
node_modules/tap/lib/tap-consumer.js
generated
vendored
Normal file
|
@ -0,0 +1,243 @@
|
|||
module.exports = TapConsumer
|
||||
|
||||
// pipe a stream into this that's emitting tap-formatted data,
|
||||
// and it'll emit "data" events with test objects or comment strings
|
||||
// and an "end" event with the final results.
|
||||
|
||||
var yamlish = require("yamlish")
|
||||
, Results = require("./tap-results")
|
||||
, inherits = require("inherits")
|
||||
|
||||
TapConsumer.decode = TapConsumer.parse = function (str) {
|
||||
var tc = new TapConsumer
|
||||
, list = []
|
||||
tc.on("data", function (res) {
|
||||
list.push(res)
|
||||
})
|
||||
tc.end(str)
|
||||
tc.results.list = list
|
||||
return tc.results
|
||||
}
|
||||
|
||||
inherits(TapConsumer, require("stream").Stream)
|
||||
function TapConsumer () {
|
||||
if (!(this instanceof TapConsumer)) {
|
||||
return new TapConsumer
|
||||
}
|
||||
|
||||
TapConsumer.super.call(this)
|
||||
this.results = new Results
|
||||
this.readable = this.writable = true
|
||||
|
||||
this.on("data", function (res) {
|
||||
if (typeof res === "object") this.results.add(res)
|
||||
})
|
||||
|
||||
this._plan = null
|
||||
this._buffer = ""
|
||||
this._indent = []
|
||||
this._current = null
|
||||
this._actualCount = 0
|
||||
this._passed = []
|
||||
this._failed = []
|
||||
//console.error("TapConsumer ctor done")
|
||||
}
|
||||
|
||||
TapConsumer.prototype.bailedOut = false
|
||||
|
||||
TapConsumer.prototype.write = function (chunk) {
|
||||
if (!this.writable) this.emit("error", new Error("not writable"))
|
||||
if (this.bailedOut) return true
|
||||
|
||||
this._buffer = this._buffer + chunk
|
||||
// split it up into lines.
|
||||
var lines = this._buffer.split(/\r?\n/)
|
||||
// ignore the last line, since it might be incomplete.
|
||||
this._buffer = lines.pop()
|
||||
|
||||
for (var i = 0, l = lines.length; i < l; i ++) {
|
||||
//console.error([i, lines[i]])
|
||||
// see if it's indented.
|
||||
var line = lines[i]
|
||||
, spaces = (this._indent.length && !line.trim())
|
||||
|| line.match(/^\s/)
|
||||
// at this level, only interested in fully undented stuff.
|
||||
if (spaces) {
|
||||
var c = i
|
||||
while (c < l && (!lines[c].trim() || lines[c].match(/^\s/))) {
|
||||
this._indent.push(lines[c++])
|
||||
}
|
||||
//console.error(c-i, "indented", this._indent, this._current)
|
||||
i = c - 1
|
||||
continue
|
||||
}
|
||||
// some kind of line. summary, ok, notok, comment, or garbage.
|
||||
// this also finishes parsing any of the indented lines from before
|
||||
this._parseLine(line)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
TapConsumer.prototype.end = function () {
|
||||
// finish up any hanging indented sections or final buffer
|
||||
if (this._buffer.match(/^\s/)) this._indent.push(this.buffer)
|
||||
else this._parseLine(this._buffer)
|
||||
|
||||
if (!this.bailedOut &&
|
||||
this._plan !== null &&
|
||||
this.results.testsTotal !== this._plan) {
|
||||
while (this._actualCount < this._plan) {
|
||||
this.emit("data", {ok: false, name:"MISSING TEST",
|
||||
id:this._actualCount ++ })
|
||||
}
|
||||
}
|
||||
|
||||
this._parseLine("")
|
||||
this._buffer = ""
|
||||
this.writable = false
|
||||
this.emit("end", null, this._actualCount, this._passed)
|
||||
}
|
||||
|
||||
TapConsumer.prototype._parseLine = function (line) {
|
||||
if (this.bailedOut) return
|
||||
//console.error("_parseLine", [line])
|
||||
// if there are any indented lines, and there is a
|
||||
// current object already, then they belong to it.
|
||||
// if there is not a current object, then they're garbage.
|
||||
if (this._current && this._indent.length) {
|
||||
this._parseIndented()
|
||||
}
|
||||
this._indent.length = 0
|
||||
if (this._current) {
|
||||
if (this._current.ok) this._passed.push(this._current.id)
|
||||
else this._failed.push(this._current.id)
|
||||
this.emit("data", this._current)
|
||||
}
|
||||
this._current = null
|
||||
line = line.trim()
|
||||
if (!line) return
|
||||
// try to see what kind of line this is.
|
||||
|
||||
var bo
|
||||
if (bo = line.match(/^bail out!\s*(.*)$/i)) {
|
||||
this.bailedOut = true
|
||||
// this.emit("error", new Error(line))
|
||||
this.emit("bailout", bo[1])
|
||||
return
|
||||
}
|
||||
|
||||
if (line.match(/^#/)) { // just a comment
|
||||
line = line.replace(/^#+/, "").trim()
|
||||
// console.error("outputting comment", [line])
|
||||
if (line) this.emit("data", line)
|
||||
return
|
||||
}
|
||||
|
||||
var plan = line.match(/^([0-9]+)\.\.([0-9]+)(?:\s+#(.*))?$/)
|
||||
if (plan) {
|
||||
var start = +(plan[1])
|
||||
, end = +(plan[2])
|
||||
, comment = plan[3]
|
||||
|
||||
// TODO: maybe do something else with this?
|
||||
// it might be something like: "1..0 #Skip because of reasons"
|
||||
this._plan = end
|
||||
this.emit("plan", end, comment)
|
||||
// plan must come before or after all tests.
|
||||
if (this._actualCount !== 0) {
|
||||
this._sawPlan = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (line.match(/^(not )?ok(?:\s+([0-9]+))?/)) {
|
||||
this._parseResultLine(line)
|
||||
return
|
||||
}
|
||||
|
||||
// garbage. emit as a comment.
|
||||
//console.error("emitting", [line.trim()])
|
||||
if (line.trim()) this.emit("data", line.trim())
|
||||
}
|
||||
|
||||
TapConsumer.prototype._parseDirective = function (line) {
|
||||
line = line.trim()
|
||||
if (line.match(/^TODO\b/i)) {
|
||||
return { todo:true, explanation: line.replace(/^TODO\s*/i, "") }
|
||||
} else if (line.match(/^SKIP\b/i)) {
|
||||
return { skip:true, explanation: line.replace(/^SKIP\s*/i, "") }
|
||||
}
|
||||
}
|
||||
|
||||
TapConsumer.prototype._parseResultLine = function (line) {
|
||||
this._actualCount ++
|
||||
if (this._sawPlan) {
|
||||
this.emit("data", {ok: false, name:"plan in the middle of tests"
|
||||
,id:this._actualCount ++})
|
||||
}
|
||||
var parsed = line.match(/^(not )?ok(?: ([0-9]+))?(?:(?: - )?(.*))?$/)
|
||||
, ok = !parsed[1]
|
||||
, id = +(parsed[2] || this._actualCount)
|
||||
, rest = parsed[3] || ""
|
||||
, name
|
||||
, res = { id:id, ok:ok }
|
||||
|
||||
// split on un-escaped # characters
|
||||
|
||||
//console.log("# "+JSON.stringify([name, rest]))
|
||||
rest = rest.replace(/([^\\])((?:\\\\)*)#/g, "$1\n$2").split("\n")
|
||||
name = rest.shift()
|
||||
rest = rest.filter(function (r) { return r.trim() }).join("#")
|
||||
//console.log("# "+JSON.stringify([name, rest]))
|
||||
|
||||
// now, let's see if there's a directive in there.
|
||||
var dir = this._parseDirective(rest.trim())
|
||||
if (!dir) name += rest ? "#" + rest : ""
|
||||
else {
|
||||
res.ok = true
|
||||
if (dir.skip) res.skip = true
|
||||
else if (dir.todo) res.todo = true
|
||||
if (dir.explanation) res.explanation = dir.explanation
|
||||
}
|
||||
res.name = name
|
||||
|
||||
//console.error(line, [ok, id, name])
|
||||
this._current = res
|
||||
}
|
||||
|
||||
TapConsumer.prototype._parseIndented = function () {
|
||||
// pull yamlish block out
|
||||
var ind = this._indent
|
||||
, ys
|
||||
, ye
|
||||
, yind
|
||||
, diag
|
||||
//console.error(ind, this._indent)
|
||||
for (var i = 0, l = ind.length; i < l; i ++) {
|
||||
var line = ind[i]
|
||||
, lt = line.trim()
|
||||
if (!ys) {
|
||||
ys = line.match(/^(\s*)---(.*)$/)
|
||||
if (ys) {
|
||||
yind = ys[1]
|
||||
diag = [ys[2]]
|
||||
//console.error([line,ys, diag])
|
||||
continue
|
||||
} else if (lt) this.emit("data", lt)
|
||||
} else if (ys && !ye) {
|
||||
if (line === yind + "...") ye = true
|
||||
else {
|
||||
diag.push(line.substr(yind.length))
|
||||
}
|
||||
} else if (ys && ye && lt) this.emit("data", lt)
|
||||
}
|
||||
if (diag) {
|
||||
//console.error('about to parse', diag)
|
||||
diag = yamlish.decode(diag.join("\n"))
|
||||
//console.error('parsed', diag)
|
||||
Object.keys(diag).forEach(function (k) {
|
||||
//console.error(this._current, k)
|
||||
if (!this._current.hasOwnProperty(k)) this._current[k] = diag[k]
|
||||
}, this)
|
||||
}
|
||||
}
|
78
node_modules/tap/lib/tap-cov-html.js
generated
vendored
Normal file
78
node_modules/tap/lib/tap-cov-html.js
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
asyncMap = require("slide").asyncMap,
|
||||
util = require('util');
|
||||
|
||||
var CovHtml = module.exports = function(cov_stats, cov_dir, cb) {
|
||||
var index = [];
|
||||
|
||||
asyncMap(
|
||||
Object.keys(cov_stats),
|
||||
function(f, cb) {
|
||||
var st = cov_stats[f],
|
||||
missing_lines = st.missing.map(function(l) {
|
||||
return l.number;
|
||||
}),
|
||||
out = '<!doctype html>\n<html lang="en">\n<head>\n ' +
|
||||
'<meta charset="utf-8">\n <title>' +
|
||||
|
||||
f + ' (' + st.loc + ')</title>\n' +
|
||||
'<style type="text/css">\n' +
|
||||
'li {\n' +
|
||||
' font-family: monospace;\n' +
|
||||
' white-space: pre;\n' +
|
||||
'}\n' +
|
||||
'</style>\n' +
|
||||
'</head>\n<body>\n' +
|
||||
'<h1>' + f + ' (' + st.loc + ')' + '</h1>' +
|
||||
'<h2>Run: ' + (st.missing.length ? st.loc - st.missing.length : st.loc) + ', Missing: ' +
|
||||
st.missing.length + ', Percentage: ' + st.percentage + '</h2>' +
|
||||
'<h2>Source:</h2>\n' +
|
||||
'<ol>\n' +
|
||||
st.lines.map(function(line) {
|
||||
var number = line.number,
|
||||
color = (missing_lines.indexOf(number) !== -1) ? '#fcc' : '#cfc';
|
||||
return '<li id="L' + line.number + '" style="background-color: ' + color +
|
||||
';">' + line.source.replace(/</g, "<") + '</li>';
|
||||
}).join('\n') +
|
||||
'</ol>\n' +
|
||||
'<h2>Data</h2>\n'+
|
||||
'<pre>' + util.inspect(st, true, Infinity, false).replace(/</g, "<") + '</pre></body>\n</html>';
|
||||
|
||||
fs.writeFile(
|
||||
cov_dir + '/' +
|
||||
f.replace(process.cwd() + '/', '').replace(/\//g, '+') + '.html',
|
||||
out,
|
||||
'utf8',
|
||||
function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
index.push(f);
|
||||
cb();
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
var out = '<!doctype html>\n<html lang="en">\n<head>\n ' +
|
||||
'<meta charset="utf-8">\n <title>Coverage Index</title>\n</head>\n' +
|
||||
'<body>\n<h1>Code Coverage Information</h1>\n<ul>' +
|
||||
index.map(function(fname) {
|
||||
return '<li><a href="' +
|
||||
fname.replace(process.cwd() + '/', '').replace(/\//g, '+') + '.html' +
|
||||
'">' + fname + '</a></li>';
|
||||
}).join('\n') + '</ul>\n</body>\n</html>';
|
||||
|
||||
fs.writeFile(cov_dir + '/index.html', out, 'utf8', function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
68
node_modules/tap/lib/tap-global-harness.js
generated
vendored
Normal file
68
node_modules/tap/lib/tap-global-harness.js
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// this is just a harness that pipes to stdout.
|
||||
// It's the default one.
|
||||
module.exports = GlobalHarness
|
||||
|
||||
var globalHarness = global.TAP_Global_Harness
|
||||
, inherits = require("inherits")
|
||||
, Results = require("./tap-results")
|
||||
, Harness = require("./tap-harness")
|
||||
, Test = require("./tap-test")
|
||||
|
||||
inherits(GlobalHarness, Harness)
|
||||
function GlobalHarness () {
|
||||
//console.error("calling GlobalHarness")
|
||||
if (globalHarness) return globalHarness
|
||||
if (!(this instanceof GlobalHarness)) {
|
||||
return globalHarness = new GlobalHarness
|
||||
}
|
||||
|
||||
globalHarness = global.TAP_Global_Harness = this
|
||||
GlobalHarness.super.call(this, Test)
|
||||
|
||||
this.output.pipe(process.stdout)
|
||||
//this.output.on("data", function () {
|
||||
// process.nextTick(process.stdout.flush.bind(process.stdout))
|
||||
//})
|
||||
|
||||
this.test = this.test.bind(this)
|
||||
|
||||
this.plan = this.plan.bind(this)
|
||||
|
||||
var output = this.output
|
||||
this.on("childEnd", function (child) {
|
||||
//console.error("childEnd in global harness")
|
||||
//console.error(child.results)
|
||||
// write out the stuff for this child.
|
||||
//console.error("child.conf", child.conf)
|
||||
output.write(child.conf.name || "(unnamed test)")
|
||||
// maybe write some other stuff about the number of tests in this
|
||||
// thing, etc. I dunno.
|
||||
//console.error("child results", child.results)
|
||||
this.results.list.forEach(function (res) {
|
||||
//delete res.error
|
||||
//console.error("child resuilt", res)
|
||||
output.write(res)
|
||||
})
|
||||
//console.error("wrote child results")
|
||||
this.results.list.length = 0
|
||||
})
|
||||
|
||||
var streamEnded = false
|
||||
this.on("end", function () {
|
||||
//console.error("global ending the stream")
|
||||
if (!streamEnded) {
|
||||
this.results.list.forEach(function (res) {
|
||||
output.write(res)
|
||||
})
|
||||
this.results.list.length = 0
|
||||
output.end()
|
||||
streamEnded = true
|
||||
}
|
||||
})
|
||||
|
||||
//this.on("end", this.output.end.bind(this.output))
|
||||
|
||||
process.on("unhandledException", function (e) {
|
||||
this.bailout("unhandled exception: " + e.message)
|
||||
})
|
||||
}
|
219
node_modules/tap/lib/tap-harness.js
generated
vendored
Normal file
219
node_modules/tap/lib/tap-harness.js
generated
vendored
Normal file
|
@ -0,0 +1,219 @@
|
|||
// a thing that runs tests.
|
||||
// Every "test" is also a harness. If they do not have a harness,
|
||||
// then they are attached to the defaut "global harness",
|
||||
// which writes its results to stdout.
|
||||
|
||||
|
||||
// TODO:
|
||||
// - Bailout should stop running any tests.
|
||||
// - "skip" in the test config obj should skip it.
|
||||
|
||||
module.exports = Harness
|
||||
require("inherits")(Harness, require("events").EventEmitter)
|
||||
|
||||
var Results = require("./tap-results")
|
||||
, TapProducer = require("./tap-producer")
|
||||
, assert = require("./tap-assert")
|
||||
|
||||
function Harness (Test) {
|
||||
if (!(this instanceof Harness)) return new Harness(Test)
|
||||
|
||||
//console.error("Test in "+this.constructor.name, Test)
|
||||
|
||||
this._Test = Test
|
||||
this._plan = null
|
||||
this._children = []
|
||||
this._started = false
|
||||
|
||||
this._testCount = 0
|
||||
this._planSum = 0
|
||||
|
||||
this.results = new Results()
|
||||
// emit result events on the harness.
|
||||
//this.results.on("result", function (res) {
|
||||
// console.error("proxying result ev from res to harness")
|
||||
// this.emit("result", res)
|
||||
//}.bind(this))
|
||||
var me = this
|
||||
this.results.on("result", this.emit.bind(this, "result"))
|
||||
|
||||
var p = this.process.bind(this)
|
||||
this.process = function () {
|
||||
this._started = true
|
||||
process.nextTick(p)
|
||||
}
|
||||
|
||||
this.output = new TapProducer()
|
||||
Harness.super.call(this)
|
||||
}
|
||||
|
||||
// this function actually only gets called bound to
|
||||
// the Harness object, and on process.nextTick. Even if
|
||||
// passed as an event handler, everything *else* will
|
||||
// happen before it gets called.
|
||||
Harness.prototype.process = function () {
|
||||
//console.error("harness process")
|
||||
// "end" can emit multiple times, so only actually move on
|
||||
// to the next test if the current one is actually over.
|
||||
// TODO: multiple in-process tests, if all are marked "async"
|
||||
if (this._current) {
|
||||
if (!this._current._ended) return
|
||||
// handle the current one before moving onto the next.
|
||||
this.childEnd(this._current)
|
||||
}
|
||||
var skip = true
|
||||
while (skip) {
|
||||
//console.error("checking for skips")
|
||||
var current = this._current = this._children.shift()
|
||||
if (current) {
|
||||
skip = current.conf.skip
|
||||
if (skip) {
|
||||
//console.error("add a failure for the skipping")
|
||||
this.results.add(assert.fail(current.conf.name
|
||||
,{skip:true, diag:false}))
|
||||
}
|
||||
} else skip = false
|
||||
}
|
||||
|
||||
// keep processing through skipped tests, instead of running them.
|
||||
if (current && this._bailedOut) {
|
||||
return this.process()
|
||||
}
|
||||
|
||||
//console.error("got current?", !!current)
|
||||
if (current) {
|
||||
current.on("end", this.process)
|
||||
current.emit("ready")
|
||||
//console.error("emitted ready")
|
||||
//console.error("_plan", this._plan, this.constructor.name)
|
||||
} else {
|
||||
//console.error("Harness process: no more left. ending")
|
||||
if (this._endNice) {
|
||||
this._endNice()
|
||||
} else {
|
||||
this.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Harness.prototype.end = function () {
|
||||
if (this._children.length) {
|
||||
return this.process()
|
||||
}
|
||||
//console.error("harness end", this.constructor.name)
|
||||
if (this._bailedOut) return
|
||||
|
||||
// can't call .end() more than once.
|
||||
if (this._ended) {
|
||||
//console.error("adding failure for end calling")
|
||||
this.results.add(assert.fail("end called more than once"))
|
||||
}
|
||||
|
||||
// see if the plan is completed properly, if there was one.
|
||||
if (this._plan !== null) {
|
||||
var total = this._testCount
|
||||
if (total !== this._plan) {
|
||||
this.results.add(assert.equal(total, this._plan, "test count != plan"))
|
||||
}
|
||||
this._plan = total
|
||||
}
|
||||
|
||||
//console.error("setting ended true", this.constructor.name)
|
||||
this._ended = true
|
||||
this.emit("end")
|
||||
}
|
||||
|
||||
Harness.prototype.plan = function (p) {
|
||||
//console.error("setting plan", new Error().stack)
|
||||
if (this._plan !== null) {
|
||||
//console.error("about to add failure for calling plan")
|
||||
return this.results.add(assert.fail("plan set multiple times"))
|
||||
}
|
||||
this._plan = p
|
||||
if (p === 0 || this.results.testsTotal) {
|
||||
this.end()
|
||||
}
|
||||
}
|
||||
|
||||
Harness.prototype.childEnd = function (child) {
|
||||
//console.error("childEnd")
|
||||
this._testCount ++
|
||||
this._planSum += child._plan
|
||||
//console.error("adding set of child.results")
|
||||
this.results.addSet(child.results)
|
||||
this.emit("childEnd", child)
|
||||
// was this planned?
|
||||
if (this._plan === this._testCount) {
|
||||
//console.error("plan", [this._plan, this._testCount])
|
||||
return this.end()
|
||||
}
|
||||
}
|
||||
|
||||
function copyObj(o) {
|
||||
var copied = {}
|
||||
Object.keys(o).forEach(function (k) { copied[k] = o[k] })
|
||||
return copied
|
||||
}
|
||||
|
||||
Harness.prototype.test = function test (name, conf, cb) {
|
||||
if (this._bailedOut) return
|
||||
|
||||
if (typeof conf === "function") cb = conf, conf = null
|
||||
if (typeof name === "object") conf = name, name = null
|
||||
if (typeof name === "function") cb = name, name = null
|
||||
|
||||
conf = (conf ? copyObj(conf) : {})
|
||||
name = name || ""
|
||||
|
||||
//console.error("making test", [name, conf, cb])
|
||||
|
||||
// timeout: value in milliseconds. Defaults to 30s
|
||||
// Set to Infinity to have no timeout.
|
||||
if (isNaN(conf.timeout)) conf.timeout = 30000
|
||||
var t = new this._Test(this, name, conf)
|
||||
var self = this
|
||||
if (cb) {
|
||||
//console.error("attaching cb to ready event")
|
||||
t.on("ready", function () {
|
||||
if (!isNaN(conf.timeout) && isFinite(conf.timeout)) {
|
||||
var timer = setTimeout(this.timeout.bind(this), conf.timeout)
|
||||
var clear = clearTimeout.bind(null, timer)
|
||||
t.on("end", clear)
|
||||
t.on("bailout", function (message) {
|
||||
self.bailout(message)
|
||||
clear()
|
||||
})
|
||||
}
|
||||
})
|
||||
t.on("ready", cb.bind(t, t))
|
||||
// proxy the child results to this object.
|
||||
//t.on("result", function (res) {
|
||||
// console.error("in harness, proxying result up")
|
||||
// t.results.add(res)
|
||||
//})
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
Harness.prototype.bailout = function (message) {
|
||||
// console.error("Harness bailout", this.constructor.name)
|
||||
message = message || ""
|
||||
//console.error("adding bailout message result")
|
||||
this.results.add({bailout: message})
|
||||
// console.error(">>> results after bailout" , this.results)
|
||||
this._bailedOut = true
|
||||
this.emit("bailout", message)
|
||||
this.output.end({bailout: message})
|
||||
}
|
||||
|
||||
Harness.prototype.add = function (child) {
|
||||
//console.error("adding child")
|
||||
this._children.push(child)
|
||||
if (!this._started) this.process()
|
||||
}
|
||||
|
||||
// the tearDown function is *always* guaranteed to happen.
|
||||
// Even if there's a bailout.
|
||||
Harness.prototype.tearDown = function (fn) {
|
||||
this.on("end", fn)
|
||||
}
|
130
node_modules/tap/lib/tap-producer.js
generated
vendored
Normal file
130
node_modules/tap/lib/tap-producer.js
generated
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
module.exports = TapProducer
|
||||
|
||||
var Results = require("./tap-results")
|
||||
, inherits = require("inherits")
|
||||
, yamlish = require("yamlish")
|
||||
|
||||
TapProducer.encode = function (result, diag) {
|
||||
var tp = new TapProducer(diag)
|
||||
, out = ""
|
||||
tp.on("data", function (c) { out += c })
|
||||
if (Array.isArray(result)) {
|
||||
result.forEach(tp.write, tp)
|
||||
} else tp.write(result)
|
||||
tp.end()
|
||||
return out
|
||||
}
|
||||
|
||||
inherits(TapProducer, require("stream").Stream)
|
||||
function TapProducer (diag) {
|
||||
TapProducer.super.call(this)
|
||||
this.diag = diag
|
||||
this.count = 0
|
||||
this.readable = this.writable = true
|
||||
this.results = new Results
|
||||
}
|
||||
|
||||
TapProducer.prototype.trailer = true
|
||||
|
||||
TapProducer.prototype.write = function (res) {
|
||||
// console.error("TapProducer.write", res)
|
||||
if (typeof res === "function") throw new Error("wtf?")
|
||||
if (!this.writable) this.emit("error", new Error("not writable"))
|
||||
|
||||
if (!this._didHead) {
|
||||
this.emit("data", "TAP version 13\n")
|
||||
this._didHead = true
|
||||
}
|
||||
|
||||
var diag = res.diag
|
||||
if (diag === undefined) diag = this.diag
|
||||
|
||||
this.emit("data", encodeResult(res, this.count + 1, diag))
|
||||
|
||||
if (typeof res === "string") return true
|
||||
|
||||
if (res.bailout) {
|
||||
var bo = "bail out!"
|
||||
if (typeof res.bailout === "string") bo += " " + res.bailout
|
||||
this.emit("data", bo)
|
||||
return
|
||||
}
|
||||
this.results.add(res, false)
|
||||
|
||||
this.count ++
|
||||
}
|
||||
|
||||
TapProducer.prototype.end = function (res) {
|
||||
if (res) this.write(res)
|
||||
// console.error("TapProducer end", res, this.results)
|
||||
this.emit("data", "\n1.."+this.results.testsTotal+"\n")
|
||||
if (this.trailer && typeof this.trailer !== "string") {
|
||||
// summary trailer.
|
||||
var trailer = "tests "+this.results.testsTotal + "\n"
|
||||
if (this.results.pass) {
|
||||
trailer += "pass " + this.results.pass + "\n"
|
||||
}
|
||||
if (this.results.fail) {
|
||||
trailer += "fail " + this.results.fail + "\n"
|
||||
}
|
||||
if (this.results.skip) {
|
||||
trailer += "skip "+this.results.skip + "\n"
|
||||
}
|
||||
if (this.results.todo) {
|
||||
trailer += "todo "+this.results.todo + "\n"
|
||||
}
|
||||
if (this.results.bailedOut) {
|
||||
trailer += "bailed out" + "\n"
|
||||
}
|
||||
|
||||
if (this.results.testsTotal === this.results.pass) {
|
||||
trailer += "\nok\n"
|
||||
}
|
||||
this.trailer = trailer
|
||||
}
|
||||
if (this.trailer) this.write(this.trailer)
|
||||
this.writable = false
|
||||
this.emit("end", null, this.count, this.ok)
|
||||
}
|
||||
|
||||
function encodeResult (res, count, diag) {
|
||||
// console.error(res, count, diag)
|
||||
if (typeof res === "string") {
|
||||
res = res.split(/\r?\n/).map(function (l) {
|
||||
if (!l.trim()) return l.trim()
|
||||
return "# " + l
|
||||
}).join("\n")
|
||||
if (res.substr(-1) !== "\n") res += "\n"
|
||||
return res
|
||||
}
|
||||
|
||||
if (res.bailout) return ""
|
||||
|
||||
|
||||
if (!!process.env.TAP_NODIAG) diag = false
|
||||
else if (!!process.env.TAP_DIAG) diag = true
|
||||
else if (diag === undefined) diag = !res.ok
|
||||
|
||||
var output = ""
|
||||
res.name = res.name && ("" + res.name).trim()
|
||||
output += ( !res.ok ? "not " : "") + "ok " + count
|
||||
+ ( !res.name ? ""
|
||||
: " " + res.name.replace(/[\r\n]/g, " ") )
|
||||
+ ( res.skip ? " # SKIP"
|
||||
: res.todo ? " # TODO"
|
||||
: "" )
|
||||
+ "\n"
|
||||
|
||||
if (!diag) return output
|
||||
var d = {}
|
||||
, dc = 0
|
||||
Object.keys(res).filter(function (k) {
|
||||
return k !== "ok" && k !== "name" && k !== "id"
|
||||
}).forEach(function (k) {
|
||||
dc ++
|
||||
d[k] = res[k]
|
||||
})
|
||||
//console.error(d, "about to encode")
|
||||
if (dc > 0) output += " ---"+yamlish.encode(d)+"\n ...\n"
|
||||
return output
|
||||
}
|
71
node_modules/tap/lib/tap-results.js
generated
vendored
Normal file
71
node_modules/tap/lib/tap-results.js
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
// A class for counting up results in a test harness.
|
||||
|
||||
module.exports = Results
|
||||
|
||||
var inherits = require("inherits")
|
||||
, EventEmitter = require("events").EventEmitter
|
||||
|
||||
inherits(Results, EventEmitter)
|
||||
|
||||
function Results (r) {
|
||||
//console.error("result constructor", r)
|
||||
this.ok = true
|
||||
this.addSet(r)
|
||||
}
|
||||
|
||||
Results.prototype.addSet = function (r) {
|
||||
//console.error("add set of results", r)
|
||||
r = r || {ok: true}
|
||||
; [ "todo"
|
||||
, "todoPass"
|
||||
, "todoFail"
|
||||
, "skip"
|
||||
, "skipPass"
|
||||
, "skipFail"
|
||||
, "pass"
|
||||
, "passTotal"
|
||||
, "fail"
|
||||
, "failTotal"
|
||||
, "tests"
|
||||
, "testsTotal" ].forEach(function (k) {
|
||||
this[k] = (this[k] || 0) + (r[k] || 0)
|
||||
//console.error([k, this[k]])
|
||||
}, this)
|
||||
|
||||
this.ok = this.ok && r.ok && true
|
||||
this.bailedOut = this.bailedOut || r.bailedOut || false
|
||||
this.list = (this.list || []).concat(r.list || [])
|
||||
this.emit("set", this.list)
|
||||
//console.error("after addSet", this)
|
||||
}
|
||||
|
||||
Results.prototype.add = function (r, addToList) {
|
||||
//console.error("add result", r)
|
||||
var pf = r.ok ? "pass" : "fail"
|
||||
, PF = r.ok ? "Pass" : "Fail"
|
||||
|
||||
this.testsTotal ++
|
||||
this[pf + "Total"] ++
|
||||
|
||||
if (r.skip) {
|
||||
this["skip" + PF] ++
|
||||
this.skip ++
|
||||
} else if (r.todo) {
|
||||
this["todo" + PF] ++
|
||||
this.todo ++
|
||||
} else {
|
||||
this.tests ++
|
||||
this[pf] ++
|
||||
}
|
||||
|
||||
if (r.bailout || typeof r.bailout === "string") {
|
||||
// console.error("Bailing out in result")
|
||||
this.bailedOut = true
|
||||
}
|
||||
this.ok = !!(this.ok && r.ok)
|
||||
|
||||
if (addToList === false) return
|
||||
this.list = this.list || []
|
||||
this.list.push(r)
|
||||
this.emit("result", r)
|
||||
}
|
434
node_modules/tap/lib/tap-runner.js
generated
vendored
Normal file
434
node_modules/tap/lib/tap-runner.js
generated
vendored
Normal file
|
@ -0,0 +1,434 @@
|
|||
var fs = require("fs")
|
||||
, child_process = require("child_process")
|
||||
, path = require("path")
|
||||
, chain = require("slide").chain
|
||||
, asyncMap = require("slide").asyncMap
|
||||
, TapProducer = require("./tap-producer.js")
|
||||
, TapConsumer = require("./tap-consumer.js")
|
||||
, assert = require("./tap-assert.js")
|
||||
, inherits = require("inherits")
|
||||
, util = require("util")
|
||||
, CovHtml = require("./tap-cov-html.js")
|
||||
|
||||
// XXX Clean up the coverage options
|
||||
, doCoverage = process.env.TAP_COV
|
||||
|| process.env.npm_package_config_coverage
|
||||
|| process.env.npm_config_coverage
|
||||
|
||||
module.exports = Runner
|
||||
|
||||
inherits(Runner, TapProducer)
|
||||
|
||||
function Runner (options, cb) {
|
||||
this.options = options
|
||||
|
||||
var diag = this.options.diag
|
||||
var dir = this.options.argv.remain
|
||||
Runner.super.call(this, diag)
|
||||
|
||||
this.doCoverage = doCoverage
|
||||
// An array of full paths to files to obtain coverage
|
||||
this.coverageFiles = []
|
||||
// The source of these files
|
||||
this.coverageFilesSource = {}
|
||||
// Where to write coverage information
|
||||
this.coverageOutDir = this.options["coverage-dir"]
|
||||
// Temporary test files bunkerified we'll remove later
|
||||
this.f2delete = []
|
||||
// Raw coverage stats, as read from JSON files
|
||||
this.rawCovStats = []
|
||||
// Processed coverage information, per file to cover:
|
||||
this.covStats = {}
|
||||
|
||||
if (dir) {
|
||||
var filesToCover = this.options.cover
|
||||
|
||||
if (doCoverage) {
|
||||
var mkdirp = require("mkdirp")
|
||||
this.coverageOutDir = path.resolve(this.coverageOutDir)
|
||||
this.getFilesToCover(filesToCover)
|
||||
var self = this
|
||||
return mkdirp(this.coverageOutDir, 0755, function (er) {
|
||||
if (er) return self.emit("error", er)
|
||||
self.run(dir, cb)
|
||||
})
|
||||
}
|
||||
|
||||
this.run(dir, cb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Runner.prototype.run = function() {
|
||||
var self = this
|
||||
, args = Array.prototype.slice.call(arguments)
|
||||
, cb = args.pop() || finish
|
||||
|
||||
function finish (er) {
|
||||
if (er) {
|
||||
self.emit("error", er)
|
||||
}
|
||||
|
||||
if (!doCoverage) return self.end()
|
||||
|
||||
// Cleanup temporary test files with coverage:
|
||||
self.f2delete.forEach(function(f) {
|
||||
fs.unlinkSync(f)
|
||||
})
|
||||
self.getFilesToCoverSource(function(err, data) {
|
||||
if (err) {
|
||||
self.emit("error", err)
|
||||
}
|
||||
self.getPerFileCovInfo(function(err, data) {
|
||||
if (err) {
|
||||
self.emit("error", err)
|
||||
}
|
||||
self.mergeCovStats(function(err, data) {
|
||||
if (err) {
|
||||
self.emit("error", err)
|
||||
}
|
||||
CovHtml(self.covStats, self.coverageOutDir, function() {
|
||||
self.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (Array.isArray(args[0])) {
|
||||
args = args[0]
|
||||
}
|
||||
self.runFiles(args, "", cb)
|
||||
}
|
||||
|
||||
Runner.prototype.runDir = function (dir, cb) {
|
||||
var self = this
|
||||
fs.readdir(dir, function (er, files) {
|
||||
if (er) {
|
||||
self.write(assert.fail("failed to readdir " + dir, { error: er }))
|
||||
self.end()
|
||||
return
|
||||
}
|
||||
files = files.sort(function(a, b) {
|
||||
return a > b ? 1 : -1
|
||||
})
|
||||
files = files.filter(function(f) {
|
||||
return !f.match(/^\./)
|
||||
})
|
||||
files = files.map(path.resolve.bind(path, dir))
|
||||
|
||||
self.runFiles(files, path.resolve(dir), cb)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Runner.prototype.runFiles = function (files, dir, cb) {
|
||||
|
||||
var self = this
|
||||
chain(files.map(function(f) {
|
||||
return function (cb) {
|
||||
if (self._bailedOut) return
|
||||
var relDir = dir || path.dirname(f)
|
||||
, fileName = relDir === "." ? f : f.substr(relDir.length + 1)
|
||||
|
||||
self.write(fileName)
|
||||
fs.lstat(f, function(er, st) {
|
||||
if (er) {
|
||||
self.write(assert.fail("failed to stat " + f, {error: er}))
|
||||
return cb()
|
||||
}
|
||||
|
||||
var cmd = f, args = [], env = {}
|
||||
|
||||
if (path.extname(f) === ".js") {
|
||||
cmd = "node"
|
||||
args = [fileName]
|
||||
} else if (path.extname(f) === ".coffee") {
|
||||
cmd = "coffee"
|
||||
args = [fileName]
|
||||
}
|
||||
|
||||
if (st.isDirectory()) {
|
||||
return self.runDir(f, cb)
|
||||
}
|
||||
|
||||
if (doCoverage && path.extname(f) === ".js") {
|
||||
var foriginal = fs.readFileSync(f, "utf8")
|
||||
, fcontents = self.coverHeader() + foriginal + self.coverFooter()
|
||||
, tmpBaseName = path.basename(f, path.extname(f))
|
||||
+ ".with-coverage." + process.pid + path.extname(f)
|
||||
, tmpFname = path.resolve(path.dirname(f), tmpBaseName)
|
||||
, i
|
||||
|
||||
fs.writeFileSync(tmpFname, fcontents, "utf8")
|
||||
args = [tmpFname]
|
||||
}
|
||||
|
||||
for (i in process.env) {
|
||||
env[i] = process.env[i]
|
||||
}
|
||||
env.TAP = 1
|
||||
|
||||
var cp = child_process.spawn(cmd, args, { env: env, cwd: relDir })
|
||||
, out = ""
|
||||
, err = ""
|
||||
, tc = new TapConsumer()
|
||||
, childTests = [f]
|
||||
|
||||
var timeout = setTimeout(function () {
|
||||
if (!cp._ended) {
|
||||
cp._timedOut = true
|
||||
cp.kill()
|
||||
}
|
||||
}, self.options.timeout * 1000)
|
||||
|
||||
tc.on("data", function(c) {
|
||||
self.emit("result", c)
|
||||
self.write(c)
|
||||
})
|
||||
|
||||
tc.on("bailout", function (message) {
|
||||
clearTimeout(timeout)
|
||||
console.log("# " + f.substr(process.cwd().length + 1))
|
||||
process.stderr.write(err)
|
||||
process.stdout.write(out + "\n")
|
||||
self._bailedOut = true
|
||||
cp._ended = true
|
||||
cp.kill()
|
||||
})
|
||||
|
||||
cp.stdout.pipe(tc)
|
||||
cp.stdout.on("data", function (c) { out += c })
|
||||
cp.stderr.on("data", function (c) {
|
||||
if (self.options.stderr) process.stderr.write(c)
|
||||
err += c
|
||||
})
|
||||
|
||||
cp.on("exit", function (code) {
|
||||
if (cp._ended) return
|
||||
cp._ended = true
|
||||
var ok = !cp._timedOut && !code
|
||||
clearTimeout(timeout)
|
||||
//childTests.forEach(function (c) { self.write(c) })
|
||||
var res = { name: path.dirname(f).replace(process.cwd() + "/", "")
|
||||
+ "/" + fileName
|
||||
, ok: ok
|
||||
, timedOut: cp._timedOut
|
||||
, exit: code }
|
||||
|
||||
if (err) {
|
||||
res.stderr = err
|
||||
if (tc.results.ok &&
|
||||
tc.results.tests === 0 &&
|
||||
!self.options.stderr) {
|
||||
// perhaps a compilation error or something else failed.
|
||||
// no need if stderr is set, since it will have been
|
||||
// output already anyway.
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// tc.results.ok = tc.results.ok && ok
|
||||
tc.results.add(res)
|
||||
res.command = [cmd].concat(args).map(JSON.stringify).join(" ")
|
||||
self.emit("result", res)
|
||||
self.emit("file", f, res, tc.results)
|
||||
self.write(res)
|
||||
self.write("\n")
|
||||
if (doCoverage) {
|
||||
self.f2delete.push(tmpFname)
|
||||
}
|
||||
cb()
|
||||
})
|
||||
})
|
||||
}
|
||||
}), cb)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
|
||||
// Get an array of full paths to files we are interested into obtain
|
||||
// code coverage.
|
||||
Runner.prototype.getFilesToCover = function(filesToCover) {
|
||||
var self = this
|
||||
filesToCover = filesToCover.split(",").map(function(f) {
|
||||
return path.resolve(f)
|
||||
}).filter(function(f) {
|
||||
return path.existsSync(f)
|
||||
})
|
||||
|
||||
function recursive(f) {
|
||||
if (path.extname(f) === "") {
|
||||
// Is a directory:
|
||||
fs.readdirSync(f).forEach(function(p) {
|
||||
recursive(f + "/" + p)
|
||||
})
|
||||
} else {
|
||||
self.coverageFiles.push(f)
|
||||
}
|
||||
}
|
||||
filesToCover.forEach(function(f) {
|
||||
recursive(f)
|
||||
})
|
||||
}
|
||||
|
||||
// Prepend to every test file to run. Note tap.test at the very top due it
|
||||
// "plays" with include paths.
|
||||
Runner.prototype.coverHeader = function() {
|
||||
// semi here since we're injecting it before the first line,
|
||||
// and don't want to mess up line numbers in the test files.
|
||||
return "var ___TAP_COVERAGE = require("
|
||||
+ JSON.stringify(require.resolve("runforcover"))
|
||||
+ ").cover(/.*/g);"
|
||||
}
|
||||
|
||||
// Append at the end of every test file to run. Actually, the stuff which gets
|
||||
// the coverage information.
|
||||
// Maybe it would be better to move into a separate file template so editing
|
||||
// could be easier.
|
||||
Runner.prototype.coverFooter = function() {
|
||||
var self = this
|
||||
// This needs to be a string with proper interpolations:
|
||||
return [ ""
|
||||
, "var ___TAP = require(" + JSON.stringify(require.resolve("./main.js")) + ")"
|
||||
, "if (typeof ___TAP._plan === 'number') ___TAP._plan ++"
|
||||
, "___TAP.test(" + JSON.stringify("___coverage") + ", function(t) {"
|
||||
, " var covFiles = " + JSON.stringify(self.coverageFiles)
|
||||
, " , covDir = " + JSON.stringify(self.coverageOutDir)
|
||||
, " , path = require('path')"
|
||||
, " , fs = require('fs')"
|
||||
, " , testFnBase = path.basename(__filename, '.js') + '.json'"
|
||||
, " , testFn = path.resolve(covDir, testFnBase)"
|
||||
, ""
|
||||
, " function asyncForEach(arr, fn, callback) {"
|
||||
, " if (!arr.length) {"
|
||||
, " return callback()"
|
||||
, " }"
|
||||
, " var completed = 0"
|
||||
, " arr.forEach(function(i) {"
|
||||
, " fn(i, function (err) {"
|
||||
, " if (err) {"
|
||||
, " callback(err)"
|
||||
, " callback = function () {}"
|
||||
, " } else {"
|
||||
, " completed += 1"
|
||||
, " if (completed === arr.length) {"
|
||||
, " callback()"
|
||||
, " }"
|
||||
, " }"
|
||||
, " })"
|
||||
, " })"
|
||||
, " }"
|
||||
, ""
|
||||
, " ___TAP_COVERAGE(function(coverageData) {"
|
||||
, " var outObj = {}"
|
||||
, " asyncForEach(covFiles, function(f, cb) {"
|
||||
, " if (coverageData[f]) {"
|
||||
, " var stats = coverageData[f].stats()"
|
||||
, " , stObj = stats"
|
||||
, " stObj.lines = stats.lines.map(function (l) {"
|
||||
, " return { number: l.lineno, source: l.source() }"
|
||||
, " })"
|
||||
, " outObj[f] = stObj"
|
||||
, " }"
|
||||
, " cb()"
|
||||
, " }, function(err) {"
|
||||
, " ___TAP_COVERAGE.release()"
|
||||
, " fs.writeFileSync(testFn, JSON.stringify(outObj))"
|
||||
, " t.end()"
|
||||
, " })"
|
||||
, " })"
|
||||
, "})" ].join("\n")
|
||||
}
|
||||
|
||||
|
||||
Runner.prototype.getFilesToCoverSource = function(cb) {
|
||||
var self = this
|
||||
asyncMap(self.coverageFiles, function(f, cb) {
|
||||
fs.readFile(f, "utf8", function(err, data) {
|
||||
var lc = 0
|
||||
if (err) {
|
||||
cb(err)
|
||||
}
|
||||
self.coverageFilesSource[f] = data.split("\n").map(function(l) {
|
||||
lc += 1
|
||||
return { number: lc, source: l }
|
||||
})
|
||||
cb()
|
||||
})
|
||||
}, cb)
|
||||
}
|
||||
|
||||
Runner.prototype.getPerFileCovInfo = function(cb) {
|
||||
var self = this
|
||||
, covPath = path.resolve(self.coverageOutDir)
|
||||
|
||||
fs.readdir(covPath, function(err, files) {
|
||||
if (err) {
|
||||
self.emit("error", err)
|
||||
}
|
||||
var covFiles = files.filter(function(f) {
|
||||
return path.extname(f) === ".json"
|
||||
})
|
||||
asyncMap(covFiles, function(f, cb) {
|
||||
fs.readFile(path.resolve(covPath, f), "utf8", function(err, data) {
|
||||
if (err) {
|
||||
cb(err)
|
||||
}
|
||||
self.rawCovStats.push(JSON.parse(data))
|
||||
cb()
|
||||
})
|
||||
}, function(f, cb) {
|
||||
fs.unlink(path.resolve(covPath, f), cb)
|
||||
}, cb)
|
||||
})
|
||||
}
|
||||
|
||||
Runner.prototype.mergeCovStats = function(cb) {
|
||||
var self = this
|
||||
self.rawCovStats.forEach(function(st) {
|
||||
Object.keys(st).forEach(function(i) {
|
||||
// If this is the first time we reach this file, just add the info:
|
||||
if (!self.covStats[i]) {
|
||||
self.covStats[i] = {
|
||||
missing: st[i].lines
|
||||
}
|
||||
} else {
|
||||
// If we already added info for this file before, we need to remove
|
||||
// from self.covStats any line not duplicated again (since it has
|
||||
// run on such case)
|
||||
self.covStats[i].missing = self.covStats[i].missing.filter(
|
||||
function(l) {
|
||||
return (st[i].lines.indexOf(l))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// This is due to a bug into
|
||||
// chrisdickinson/node-bunker/blob/feature/add-coverage-interface
|
||||
// which is using array indexes for line numbers instead of the right number
|
||||
Object.keys(self.covStats).forEach(function(f) {
|
||||
self.covStats[f].missing = self.covStats[f].missing.map(function(line) {
|
||||
return { number: line.number, source: line.source }
|
||||
})
|
||||
})
|
||||
|
||||
Object.keys(self.coverageFilesSource).forEach(function(f) {
|
||||
if (!self.covStats[f]) {
|
||||
self.covStats[f] = { missing: self.coverageFilesSource[f]
|
||||
, percentage: 0
|
||||
}
|
||||
}
|
||||
self.covStats[f].lines = self.coverageFilesSource[f]
|
||||
self.covStats[f].loc = self.coverageFilesSource[f].length
|
||||
|
||||
if (!self.covStats[f].percentage) {
|
||||
self.covStats[f].percentage =
|
||||
1 - (self.covStats[f].missing.length / self.covStats[f].loc)
|
||||
}
|
||||
|
||||
})
|
||||
cb()
|
||||
}
|
109
node_modules/tap/lib/tap-test.js
generated
vendored
Normal file
109
node_modules/tap/lib/tap-test.js
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
// This is a very simple test framework that leverages the tap framework
|
||||
// to run tests and output tap-parseable results.
|
||||
|
||||
module.exports = Test
|
||||
|
||||
var assert = require("./tap-assert")
|
||||
, inherits = require("inherits")
|
||||
, Results = require("./tap-results")
|
||||
|
||||
// tests are also test harnesses
|
||||
inherits(Test, require("./tap-harness"))
|
||||
|
||||
function Test (harness, name, conf) {
|
||||
//console.error("test ctor")
|
||||
if (!(this instanceof Test)) return new Test(harness, name, conf)
|
||||
|
||||
Test.super.call(this, Test)
|
||||
|
||||
conf.name = name || conf.name || "(anonymous)"
|
||||
this.conf = conf
|
||||
|
||||
this.harness = harness
|
||||
this.harness.add(this)
|
||||
}
|
||||
|
||||
// it's taking too long!
|
||||
Test.prototype.timeout = function () {
|
||||
// detect false alarms
|
||||
if (this._ended) return
|
||||
this.fail("Timeout!")
|
||||
this.end()
|
||||
}
|
||||
|
||||
Test.prototype.clear = function () {
|
||||
this._started = false
|
||||
this._ended = false
|
||||
this._plan = null
|
||||
this._bailedOut = false
|
||||
this._testCount = 0
|
||||
this.results = new Results()
|
||||
}
|
||||
|
||||
// this gets called if a test throws ever
|
||||
Test.prototype.threw = function (ex) {
|
||||
//console.error("threw!", ex.stack)
|
||||
this.fail(ex.name + ": " + ex.message, { error: ex, thrown: true })
|
||||
// may emit further failing tests if the plan is not completed
|
||||
//console.error("end, because it threw")
|
||||
this.end()
|
||||
}
|
||||
|
||||
Test.prototype.comment = function (m) {
|
||||
if (typeof m !== "string") {
|
||||
return this.fail("Test.comment argument must be a string")
|
||||
}
|
||||
this.result("\n" + m.trim())
|
||||
}
|
||||
|
||||
Test.prototype.result = function (res) {
|
||||
this.results.add(res)
|
||||
this._testCount ++
|
||||
this.emit("result", res)
|
||||
if (this._plan === this._testCount) {
|
||||
process.nextTick(this._endNice.bind(this))
|
||||
}
|
||||
}
|
||||
|
||||
Test.prototype._endNice = function () {
|
||||
if (!this._ended) this.end()
|
||||
}
|
||||
|
||||
// parasitic
|
||||
// Who says you can't do multiple inheritance in js?
|
||||
Object.getOwnPropertyNames(assert).forEach(function (k) {
|
||||
if (k === "prototype" || k === "name") return
|
||||
var d = Object.getOwnPropertyDescriptor(assert, k)
|
||||
, v = d.value
|
||||
if (!v) return
|
||||
d.value = assertParasite(v)
|
||||
Object.defineProperty(Test.prototype, k, d)
|
||||
})
|
||||
|
||||
function assertParasite (fn) { return function _testAssert () {
|
||||
//console.error("_testAssert", fn.name, arguments)
|
||||
if (this._bailedOut) return
|
||||
var res = fn.apply(assert, arguments)
|
||||
this.result(res)
|
||||
return res
|
||||
}}
|
||||
|
||||
// a few tweaks on the EE emit function, because
|
||||
// we want to catch all thrown errors and bubble up "bailout"
|
||||
Test.prototype.emit = (function (em) { return function (t) {
|
||||
// bailouts bubble until handled
|
||||
if (t === "bailout" &&
|
||||
this.listeners(t).length === 0 &&
|
||||
this.harness) {
|
||||
return this.harness.bailout(arguments[1])
|
||||
}
|
||||
|
||||
if (t === "error") return em.apply(this, arguments)
|
||||
try {
|
||||
em.apply(this, arguments)
|
||||
} catch (ex) {
|
||||
// any exceptions in a test are a failure
|
||||
//console.error("caught!", ex.stack)
|
||||
this.threw(ex)
|
||||
}
|
||||
}})(Test.super.prototype.emit)
|
Loading…
Add table
Add a link
Reference in a new issue