Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed a fatal bug in coverage

* Droped runforcover as a dep and just took
most of it's code because it needed to be heavily
modified
* Added bunker as a dep
* Fixed many performance issues with runforcover
  • Loading branch information...
commit 9ca181b9c4e087b32a8bfe292cbcb16684dc1905 1 parent 37a4558
@siddMahen authored
View
16 README.md
@@ -1,7 +1,7 @@
# stest - A Sane Async Testing Framework
Frustrated with other testing frameworks which
-kinda sucked at handling async, I decided to make
+kinda sucked at handling async, so I decided to make
stest.
# Installation:
@@ -55,10 +55,18 @@ See the source for more details and documentation.
Tests can be run en masse using `srunner`:
- srunner -r test/test-.*\.js
+ Usage: srunner [-s] [-c] [modules] -r [regexp]
-To run tests silently, run `srunner` with the `-s`
-option. If you prefer not to use `srunner`, you can
+ Options:
+ -s, --silent supress output [boolean]
+ -c, --cover files to output code coverage for [string]
+ -r, --regexp regexp of files to test [string] [required]
+
+Which looks like this in the command line:
+
+ srunner -c lib/foobar.js -r test/test-.*\.js
+
+If you prefer not to use `srunner`, you can
still run tests like this:
node test.js
View
131 bin/coverage.js
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2011, Chris Dickinson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Chris Dickinson nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Chris Dickinson BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var bunker = require('bunker'),
+ Module = require('module').Module,
+ path = require('path'),
+ fs = require('fs'),
+ vm = require('vm');
+
+function CoverageData (filename, bunker, data) {
+ this.bunker = bunker;
+ this.filename = filename;
+ this.filedata = data;
+ this.nodes = {};
+}
+
+CoverageData.prototype.visit = function(node) {
+ (this.nodes[node.id] = this.nodes[node.id] || {node:node, count:0}).count++;
+};
+
+CoverageData.prototype.missing = function() {
+
+ var nodes = this.nodes;
+ return this.bunker.nodes.filter(function(node) { return !nodes[node.id] });
+};
+
+CoverageData.prototype.stats = function() {
+ var missing = this.missing(),
+ filedata = this.filedata.split('\n');
+
+ var seenLines = [],
+ lines =
+ missing.sort(function(lhs, rhs) {
+ return lhs.node[0].start.line < rhs.node[0].start.line ? -1 :
+ lhs.node[0].start.line > rhs.node[0].start.line ? 1 :
+ 0;
+ }).filter(function(node) {
+
+ var okay = (seenLines.indexOf(node.node[0].start.line) < 0);
+ if(okay)
+ seenLines.push(node.node[0].start.line);
+ return okay;
+
+ }).map(function(node, idx, all) {
+ return {
+ lineno:node.node[0].start.line + 1,
+ source:function() { return filedata[node.node[0].start.line]; }
+ };
+ });
+
+ return {
+ percentage:(filedata.length-seenLines.length)/filedata.length,
+ lines:lines,
+ missing:seenLines.length,
+ seen:(filedata.length-seenLines.length)
+ };
+};
+
+var createEnvironment = function(module, filename) {
+
+ var ctxt = {};
+ for(var k in global)
+ ctxt[k] = global[k];
+
+ ctxt.require = require;
+ ctxt.exports = module.exports;
+ ctxt.__filename = filename;
+ ctxt.__dirname = path.dirname(filename);
+ ctxt.process = process;
+ ctxt.console = console;
+ ctxt.module = module;
+ ctxt.global = ctxt;
+
+ return ctxt;
+};
+
+module.exports = function(fileRegex) {
+ var originalRequire = require.extensions['.js'],
+ coverageData = {},
+ match = fileRegex instanceof RegExp ? fileRegex :
+ new RegExp(fileRegex ? fileRegex.replace(/\//g, '\\/').replace(/\./g, '\\.') : '.*');
+
+ require.extensions['.js'] = function(module, filename) {
+ if(!match.test(filename)) return originalRequire(module, filename);
+
+ var context = createEnvironment(module, filename),
+ data = fs.readFileSync(filename, 'utf8'),
+ bunkerized = bunker(data),
+ coverage = coverageData[filename] = new CoverageData(filename, bunkerized, data);
+
+ bunkerized.on('node', coverage.visit.bind(coverage));
+ bunkerized.assign(context);
+
+ var wrapper = '(function(ctxt) { with(ctxt) { return '+Module.wrap(bunkerized.compile())+'; } })',
+ compiledWrapper = vm.runInNewContext(wrapper, filename, context);
+
+ var args = [context.exports, context.require, module, filename, context.__dirname];
+ return compiledWrapper.apply(module.exports, args);
+ };
+
+ var retval = function(ready) { ready(coverageData) };
+ retval.release = function() { require.extensions['.js'] = originalRequire };
+
+ return retval;
+};
+
+module.exports.cover = module.exports;
View
21 bin/srunner.js
@@ -72,31 +72,34 @@ if(!filtered.length){
filtered.forEach(function(file){
cp.exec("node "+dir+"/"+file, function(err, stdout, stderr){
if(err) throw err;
- if(!coverage) info(stdout);
+ info(stdout);
});
});
-if(coverage){
- var codecover = require("runforcover").cover(/.*/g);
-
+if(coverage.length){
+ var codecover = require("./coverage").cover(/.*/);
+
coverage = coverage.map(function(file){ return path.join(process.cwd(), file); });
coverage.forEach(function(file){ require(file); });
-
+
filtered = filtered.map(function(file){ return dir+"/"+file; });
filtered.forEach(function(file){ require(file); });
-
+
+ var counter = 0;
coverage.forEach(function(obj, i){
+ counter++;
codecover(function(cd){
var stats = cd[obj].stats();
-
+
var col = "magenta";
info("Coverage for: "+path.basename(obj)+"\n", col);
info("Lines seen: "+stats.seen+"\n", col);
info("Lines missing: "+stats.missing+"\n", col);
info("Percentage seen: "+Math.floor(stats.percentage*100)+"%\n", col);
info("\n");
+ counter--;
+
+ if(counter === 0) codecover.release();
});
});
-
- codecover.release();
}
View
16 lib/stest.js
@@ -70,7 +70,7 @@ function stest(){
*
* The test object looks something like this:
*
- * {
+ * {
* setup: function(promise){
* // emit events
* promise.emit("event_1", 42);
@@ -85,7 +85,7 @@ function stest(){
* // be modified if you intend to
* // create errors
* }
- * }
+ * }
*
* The setup key is required, all other keys and
* functions are optional. Errors in the teardown
@@ -139,17 +139,19 @@ stest.prototype.run = function(){
var opts = tcase.opts;
var name = tcase.name;
- var setup = test["setup"];
- var teardown = test["teardown"] ? test["teardown"] : function(){};
+ var setup = test.setup;
+ var teardown = test.teardown || function(){};
+
+ if(!setup) throw new Error("A setup method is required");
// to record elapsed time
var totalTime = 0;
// to record error
var errors = [];
- // d elete the setup and teardown keys
- delete test["setup"];
- if(test["teardown"]) delete test["teardown"];
+ // delete the setup and teardown keys
+ delete test.setup;
+ if(test.teardown) delete test.teardown;
// add listeners for each key
Object.keys(test).forEach(function(event, i, array){
View
2  package.json
@@ -27,7 +27,7 @@
"dependencies": {
"optimist": ">=0.2.8",
"colors": ">=0.6.0",
- "runforcover": ">=0.0.1"
+ "bunker": ">=0.1.1"
},
"devDependencies": {}
}
Please sign in to comment.
Something went wrong with that request. Please try again.