Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tap

Package Overview
Dependencies
Maintainers
1
Versions
418
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tap - npm Package Compare versions

Comparing version 0.1.0 to 0.1.1

coverage-example/lib/bar.js

8

bin/tap.js

@@ -15,3 +15,3 @@ #!/usr/bin/env node

, n = details.pass + "/" + details.testsTotal
, dots = new Array(Math.max(1, 40 - s.length - n.length)).join(".")
, dots = new Array(Math.max(1, 60 - s.length - n.length)).join(".")
console.log("%s %s %s", s, dots, n)

@@ -33,5 +33,9 @@ if (details.ok) {

, n = r.results.pass + "/" + r.results.testsTotal
, dots = new Array(40 - s.length - n.length).join(".")
, 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") )
}
// process.stdout.flush()

@@ -38,0 +42,0 @@ })

@@ -91,3 +91,7 @@ // a thing that runs tests.

//console.error("Harness process: no more left. ending")
this.end()
if (this._endNice) {
this._endNice()
} else {
this.end()
}
}

@@ -97,2 +101,5 @@ }

Harness.prototype.end = function () {
if (this._children.length) {
return this.process()
}
//console.error("harness end", this.constructor.name)

@@ -147,2 +154,8 @@ if (this._bailedOut) return

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) {

@@ -155,3 +168,3 @@ if (this._bailedOut) return

conf = conf || {}
conf = (conf ? copyObj(conf) : {})
name = name || ""

@@ -158,0 +171,0 @@

@@ -1,3 +0,1 @@

module.exports = Runner
var fs = require("fs")

@@ -7,23 +5,103 @@ , child_process = require("child_process")

, chain = require("slide").chain
, TapProducer = require("./tap-producer")
, TapConsumer = require("./tap-consumer")
, assert = require("./tap-assert")
, 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")
, doCoverage = process.env.TAP_COV
|| process.env.npm_package_config_coverage
|| process.env.npm_config_coverage
inherits(Runner, TapProducer)
function Runner (dir, diag, cb) {
var Runner = module.exports = function (dir, diag, cb) {
Runner.super.call(this, diag)
if (dir) this.run(dir, cb)
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 = "./coverage"
// 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 = "./lib"
, coverageOutDir = "./coverage"
if (doCoverage) {
dir = dir.filter(function(arg) {
if (arg.match(/^--cover=/)) {
filesToCover = arg.split("--cover=")[1]
return false
} else if (arg.match(/^--cover-dir=/)) {
coverageOutDir = arg.split("--cover-dir=")[1]
return false
}
return true
})
coverageOutDir = path.resolve(coverageOutDir)
path.exists(coverageOutDir, function(exists) {
if (!exists) {
fs.mkdir(coverageOutDir, 0755, function(er) {
if (er) {
throw er
}
})
}
})
this.coverageOutDir = coverageOutDir
this.getFilesToCover(filesToCover)
}
this.run(dir, cb)
}
}
Runner.prototype.run = function () {
inherits(Runner, TapProducer)
Runner.prototype.run = function() {
var self = this
, args = Array.prototype.slice.call(arguments)
, cb = args.pop() || function (er) {
if (er) self.emit("error", er)
self.end()
if (er) {
self.emit("error", er)
}
if (doCoverage) {
// 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()
})
})
})
})
} else {
self.end()
}
}
if (Array.isArray(args[0])) args = args[0]
if (Array.isArray(args[0])) {
args = args[0]
}
self.runFiles(args, "", cb)

@@ -36,9 +114,12 @@ }

if (er) {
self.write(assert.fail("failed to readdir "+dir,
{ error: 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.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))

@@ -50,72 +131,288 @@

Runner.prototype.runFiles = function (files, dir, cb) {
var self = this
chain(files.map(function (f) { return function (cb) {
var relDir = dir || path.dirname(f)
, fileName = relDir === "." ? f : f.substr(relDir.length + 1)
chain(files.map(function(f) {
return function (cb) {
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()
}
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 = []
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 (path.extname(f) === ".js") {
cmd = "node"
args = [fileName]
} else if (path.extname(f) === ".coffee") {
cmd = "coffee"
args = [fileName]
}
var env = {}
for (var i in process.env) env[i] = process.env[i]
env.TAP = 1
if (st.isDirectory()) {
return self.runDir(f, cb)
}
var cp = child_process.spawn(cmd, args, { env: env, cwd: relDir })
, out = ""
, err = ""
, tc = new TapConsumer
, childTests = [f]
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
tc.on("data", function (c) {
self.emit("result", c)
self.write(c)
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]
setTimeout(function () {
if (!cp._ended) {
cp.kill()
console.error("killing: " + f + " (timed out)")
}
}, ((process.env.TAP_TIMEOUT || 30) * 1000))
tc.on("data", function(c) {
self.emit("result", c)
self.write(c)
})
cp.stdout.pipe(tc)
cp.stdout.on("data", function(c) { out += c })
cp.stderr.on("data", function(c) { err += c })
cp.on("exit", function(code) {
cp._ended = true
//childTests.forEach(function (c) { self.write(c) })
var res = { name: path.dirname(f).replace(process.cwd() + "/", "")
+ "/" + fileName
, ok: !code }
if (err) {
res.stderr = err
if (tc.results.ok && tc.results.tests === 0) {
// perhaps a compilation error or something else failed...
console.error(err)
}
}
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)
cp.stdout.pipe(tc)
cp.stdout.on("data", function (c) { out += c })
cp.stderr.on("data", function (c) { err += c })
return self
}
cp.on("exit", function (code) {
//childTests.forEach(function (c) { self.write(c) })
var res = { name: fileName
, ok: !code }
// 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) {
res.stderr = err
if (tc.results.ok && tc.results.tests === 0) {
// perhaps a compilation error or something else failed...
console.error(err)
}
cb(err)
}
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")
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))
})
}
})
}}), cb)
})
return self
// 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()
}

@@ -88,2 +88,3 @@ // This is a very simple test framework that leverages the tap framework

this.result(res)
return res
}}

@@ -90,0 +91,0 @@

{ "name" : "tap"
, "version" : "0.1.0"
, "version" : "0.1.1"
, "author" : "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)"

@@ -11,2 +11,3 @@ , "description" : "A Test-Anything-Protocol library"

, "slide": "*"
, "runforcover": "0.0.1"
}

@@ -13,0 +14,0 @@ , "bundledDependencies" :

@@ -47,3 +47,3 @@ This is a mix-and-match set of utilities that you can use to write test

Node-tap is actually a collection of several packages, any of which may be
Node-tap is actually a collection of several modules, any of which may be
mixed and matched however you please.

@@ -57,4 +57,2 @@

That matters. Or rather, it will, very soon.
You can also use this to build programs that *consume* the TAP data, so

@@ -79,3 +77,9 @@ this is very useful for CI systems and such.

More docs coming soon, hopefully.
## Experimental Code Coverage with runforcover & bunker:
```
TAP_COV=1 tap ./tests [--cover=./lib,foo.js] [--cover-dir=./coverage]
```
This feature is experimental, and will most likely change somewhat
before being finalized. Feedback welcome.

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc