coveraje
Version:
a simple javascript code coverage tool with browser frontend
452 lines (380 loc) • 16.5 kB
JavaScript
/*
coveraje - a simple javascript code coverage tool.
runtime
---------------
methods invoked from the generated file
Copyright (c) 2011-2012 Wolfgang Kluge (klugesoftware.de, gehirnwindung.de)
*/
(function () {
"use strict";
function CoverajeRuntime(instance) {
var option = instance.options;
var data = {};
var startState = {};
var isOwn = require("./utils").isOwn;
function register_key(key) {
if (!(key in data)) {
return data[key] = {
visits: {},
branches: {}
};
}
return data[key];
}
function visit_log(key, pos, endpos) {
var idx = pos + "." + endpos;
data[key].visits[idx].counter++;
}
function visit_register(key, pos, endpos) {
var o = register_key(key).visits;
var idx = pos + "." + endpos;
if (!(idx in o)) {
o[idx] = {pos: pos, endpos: endpos, counter: 0};
return true;
}
return false;
}
function visitsArray(key, counted) {
function sort(a, b) {
if (a.s === b.s) {
if (a.e === b.e) {
return 0;
}
return a.e < b.e ? 1 : -1;
}
return a.s < b.s ? -1 : 1;
}
var ret = {};
var idx;
for (var k in data) {
if (isOwn(data, k) && (key == null || key === k)) {
ret[k] = [];
var o = data[k].visits;
for (idx in o) {
if (isOwn(o, idx)) {
var v = o[idx];
ret[k].push({s: v.pos, e: v.endpos, c: v.counter, i: counted.indexOf(v.counter)});
}
}
ret[k].sort(sort);
}
}
return ret;
}
function branchesArray(key) {
var ret = {};
var idx, iidx;
var br, bs, hasUncovered;
for (var k in data) {
if (isOwn(data, k) && (key == null || key === k)) {
var o = data[k].branches;
ret[k] = [];
for (idx in o) {
if (isOwn(o, idx)) {
br = o[idx];
bs = [];
hasUncovered = false;
for (iidx in br) {
if (iidx !== "pos" && iidx !== "endpos" && isOwn(br, iidx)) {
var b = br[iidx];
if (!hasUncovered && b.counter === 0) hasUncovered = true;
bs.push({s: b.pos, e: b.endpos, c: b.counter});
}
}
ret[k].push({s: br.pos, e: br.endpos, u: hasUncovered, b: bs});
}
}
}
}
return ret;
}
function copy(o) {
var ret, i, il, oks;
if (o == null) {
ret = null;
} else if (Array.isArray(o)) {
ret = [];
for (i = 0, il = o.length; i < il; i++) {
ret.push(copy(o[i]));
}
} else if (typeof o === "object") {
ret = {};
oks = Object.keys(o);
for (i = 0, il = oks.length; i < il; i++) {
var k = oks[i];
ret[k] = copy(o[k]);
}
} else {
ret = o;
}
return ret;
}
return {
init: function (key) {
if (key == null) {
data = {};
startState = {};
} else {
delete data[key];
}
},
setStartState: function (key) {
if (data != null && key != null) {
if (startState[key] == null && data[key] != null) {
startState[key] = copy(data[key]);
}
}
},
reset: function (key) {
var idx, iidx;
for (var k in data) {
if (isOwn(data, k) && (key == null || key === k)) {
var start = startState[k] || {};
var visits = data[k].visits;
var visits_start = start.visits || {};
for (idx in visits) {
if (isOwn(visits, idx)) {
visits[idx].counter = visits_start[idx] == null ? 0 : visits_start[idx].counter;
}
}
var branches = data[k].branches;
var branches_start = start.branches || {};
for (idx in branches) {
if (isOwn(branches, idx)) {
var bd = branches[idx];
var bd_start = branches_start[idx] || {};
for (iidx in bd) {
if (isOwn(bd, iidx) && bd[iidx].counter != null) {
bd[iidx].counter = bd_start[iidx] == null ? 0 : bd_start[iidx].counter;
}
}
}
}
}
}
},
visits: {
register: visit_register,
call: visit_log,
callWithRet: function (key, expr, pos, endpos) {
visit_log(key, pos, endpos);
return expr;
},
callWithRetIfTrue : function (key, expr, pos, endpos) {
if (expr) visit_log(key, pos, endpos);
return expr;
},
funcargs: function (key, args, positions) {
var m = Math.min(args.length, positions.length);
for (var i = 0; i < m; i++) {
visit_log(key, positions[i].pos, positions[i].endpos);
}
},
isCovered: function (el) {
return el.c > 0;
}
},
branches: {
register: function (key, kpos, kend, pos, endpos, isElse) {
if (pos !== 0 && endpos !== 0) {
visit_register(key, pos, endpos);
}
var idx = kpos + "." + kend;
var branches = data[key].branches;
if (!(idx in branches)) {
branches[idx] = { pos: kpos, endpos: kend };
}
var iidx = pos + "." + endpos;
if (!(iidx in branches[idx])) {
branches[idx][iidx] = {pos: pos, endpos: endpos, isElse: isElse, counter: 0};
}
},
call: function (key, kpos, kend, pos, endpos) {
if (pos !== 0 && endpos !== 0) {
visit_log(key, pos, endpos);
}
var idx = kpos + "." + kend;
var branches = data[key].branches;
if (idx in branches) {
var iidx = pos + "." + endpos;
if (iidx in branches[idx]) {
branches[idx][iidx].counter++;
}
}
},
callWithRet: function (key, expr, kpos, kend, pos, endpos) {
this.call(key, kpos, kend, pos, endpos);
return expr;
},
isCovered: function (el) {
return !el.u;
}
},
helper: (function () {
if (typeof require === "undefined") return;
var requirePostfix = "$$_cj_inspected";
var requires = option.resolveRequires,
keys = [],
path = require("path"),
Module = require("module");
function requireCode(code, pathToCode, context, runtimeKey) {
function compile(content, mod, filename, dirname) {
var Script = process.binding('evals').NodeScript;
var runInThisContext = Script.runInThisContext;
// create wrapper function
//
var wrapper = Module.wrap(
"var " + option.prefix + "runtime = exports['" + option.prefix + "runtime'];\n" +
content + "\n" +
option.prefix + "runtime.setStartState(" + runtimeKey + ");"
);
mod.exports = context;
var compiledWrapper = runInThisContext(wrapper, filename, true);
var args = [mod.exports, module.require, mod, filename, dirname];
return compiledWrapper.apply(mod.exports, args);
}
var filepath = path.resolve(process.cwd(), pathToCode);
var dirname = path.dirname(filepath);
var cacheKey = filepath + requirePostfix;
var cachedModule = Module._cache[cacheKey];
if (cachedModule) {
return cachedModule.exports;
}
keys.push(cacheKey);
var mod = new Module(cacheKey, module);
Module._cache[cacheKey] = mod;
mod.filename = filepath;
mod.paths = Module._nodeModulePaths(dirname);
if (context != null) {
compile(code, mod, filepath, dirname);
} else {
mod._compile(code, filepath);
}
mod.loaded = true;
return mod.exports;
}
function requireFrom(filepath) {
var content = require("fs").readFileSync(filepath, 'utf-8');
var code = instance.addCode(filepath, content);
var ctx = {};
ctx[option.prefix + "runtime"] = instance.runtime;
return requireCode(code.codeToRun, filepath, ctx, code.index);
}
function requireTest(m, self) {
var ret = {
useDefault: true,
filename: m
};
if (m.charAt(0) === "." || m.indexOf(":") !== -1) {
var rp = path.resolve(path.dirname(self.filename), m);
var filename = Module._resolveFilename(rp, self);
if (Array.isArray(filename)) filename = filename[1];
ret.filename = filename;
if (requires && (requires.indexOf(filename) !== -1 || requires.indexOf("*") !== -1)) {
ret.useDefault = false;
}
}
return ret;
}
return {
requireReset: function () {
for (var i = 0, il = keys.length; i < il; i++) {
delete Module._cache[keys[i]];
}
keys.length = 0;
},
require: function (m, self) {
var tst = requireTest(m, self);
if (tst.useDefault) {
return self.require(tst.filename);
}
return requireFrom(tst.filename);
},
requireTest: requireTest
};
}()),
reportData: function (key) {
var counted = [];
var idx, v;
for (var k in data) {
if (isOwn(data, k) && (key == null || key === k)) {
var visits = data[k].visits;
for (idx in visits) {
if (isOwn(visits, idx)) {
v = visits[idx];
if (counted.indexOf(v.counter) === -1) {
counted.push(v.counter);
}
}
}
}
}
counted = counted.sort(function (a, b) {
if (a === b) return 0;
if (a < b) return -1;
return 1;
});
if (counted[0] !== 0) counted.splice(0, 0, 0);
return {
counted: counted,
visits: visitsArray(key, counted),
branches: branchesArray(key)
};
},
getResults: function (key) {
var data = this.reportData(key);
var totalCount = 0, totalCovered = 0, totalAreas = 0;
var results = {};
function setTotal(obj) { /*jshint bitwise: false*/
if (obj.items !== 0) {
obj.coverage = (obj.covered / obj.items * 10000 | 0) / 100;
} else {
obj.coverage = 0;
}
}
function calc(name, filter) {
var result, vl, vlt;
var o = data[name];
if (o != null) {
for (var k in o) {
if (isOwn(o, k)) {
var els = o[k];
vl = els.length;
totalCount += vl;
if (vl > 0) {
if (result == null) {
result = {
items: 0,
covered: 0
};
}
vlt = els.filter(filter).length;
totalCovered += vlt;
result.items += vl;
result.covered += vlt;
}
}
}
if (result != null) {
totalAreas++;
setTotal(result);
results[name] = result;
}
}
}
calc("visits", this.visits.isCovered);
calc("branches", this.branches.isCovered);
results.total = {
areas: totalAreas,
items: totalCount,
covered: totalCovered
};
setTotal(results.total);
return results;
}
};
}
if (typeof module !== "undefined") {
module.exports = CoverajeRuntime;
}
}());