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

istanbul

Package Overview
Dependencies
Maintainers
1
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

istanbul - npm Package Compare versions

Comparing version 0.1.4 to 0.1.5

551

lib/object-utils.js

@@ -22,288 +22,319 @@ /*

*
* Usage
* -----
* Works on `node` as well as the browser.
*
* Usage on nodejs
* ---------------
*
* var objectUtils = require('istanbul').utils;
*
* @class ObjectUtils
*/
/**
* adds line coverage information to a file coverage object, reverse-engineering
* it from statement coverage. The object passed in is updated in place.
* Usage in a browser
* ------------------
*
* Note that if line coverage information is already present in the object,
* it is not recomputed.
* Load this file using a `script` tag or other means. This will set `window.coverageUtils`
* to this module's exports.
*
* @method addDerivedInfoForFile
* @class ObjectUtils
* @static
* @param {Object} fileCoverage the coverage object for a single file
*/
function addDerivedInfoForFile(fileCoverage) {
var statementMap = fileCoverage.statementMap,
statements = fileCoverage.s,
lineMap;
(function (isNode) {
/**
* adds line coverage information to a file coverage object, reverse-engineering
* it from statement coverage. The object passed in is updated in place.
*
* Note that if line coverage information is already present in the object,
* it is not recomputed.
*
* @method addDerivedInfoForFile
* @static
* @param {Object} fileCoverage the coverage object for a single file
*/
function addDerivedInfoForFile(fileCoverage) {
var statementMap = fileCoverage.statementMap,
statements = fileCoverage.s,
lineMap;
if (!fileCoverage.l) {
fileCoverage.l = lineMap = {};
Object.keys(statements).forEach(function (st) {
var line = statementMap[st].start.line,
count = statements[st],
prevVal = lineMap[line];
if (typeof prevVal === 'undefined' || prevVal < count) {
lineMap[line] = count;
}
if (!fileCoverage.l) {
fileCoverage.l = lineMap = {};
Object.keys(statements).forEach(function (st) {
var line = statementMap[st].start.line,
count = statements[st],
prevVal = lineMap[line];
if (typeof prevVal === 'undefined' || prevVal < count) {
lineMap[line] = count;
}
});
}
}
/**
* adds line coverage information to all file coverage objects.
*
* @method addDerivedInfo
* @static
* @param {Object} coverage the coverage object
*/
function addDerivedInfo(coverage) {
Object.keys(coverage).forEach(function (k) {
addDerivedInfoForFile(coverage[k]);
});
}
}
/**
* adds line coverage information to all file coverage objects.
*
* @method addDerivedInfo
* @static
* @param {Object} coverage the coverage object
*/
function addDerivedInfo(coverage) {
Object.keys(coverage).forEach(function (k) {
addDerivedInfoForFile(coverage[k]);
});
}
/**
* removes line coverage information from all file coverage objects
* @method removeDerivedInfo
* @static
* @param {Object} coverage the coverage object
*/
function removeDerivedInfo(coverage) {
Object.keys(coverage).forEach(function (k) {
delete coverage[k].l;
});
}
function percent(covered, total) {
var tmp;
if (total > 0) {
tmp = 1000 * 100 * covered / total + 5;
return Math.floor(tmp / 10) / 100;
} else {
return 100.00;
/**
* removes line coverage information from all file coverage objects
* @method removeDerivedInfo
* @static
* @param {Object} coverage the coverage object
*/
function removeDerivedInfo(coverage) {
Object.keys(coverage).forEach(function (k) {
delete coverage[k].l;
});
}
}
function computeSimpleTotals(fileCoverage, property) {
var stats = fileCoverage[property],
ret = { total: 0, covered: 0 };
Object.keys(stats).forEach(function (key) {
ret.total += 1;
if (stats[key]) {
ret.covered += 1;
function percent(covered, total) {
var tmp;
if (total > 0) {
tmp = 1000 * 100 * covered / total + 5;
return Math.floor(tmp / 10) / 100;
} else {
return 100.00;
}
});
ret.pct = percent(ret.covered, ret.total);
return ret;
}
}
function computeBranchTotals(fileCoverage) {
var stats = fileCoverage.b,
ret = { total: 0, covered: 0 };
function computeSimpleTotals(fileCoverage, property) {
var stats = fileCoverage[property],
ret = { total: 0, covered: 0 };
Object.keys(stats).forEach(function (key) {
var branches = stats[key],
covered = branches.filter(function (num) { return num > 0; });
ret.total += branches.length;
ret.covered += covered.length;
});
ret.pct = percent(ret.covered, ret.total);
return ret;
}
/**
* returns a blank summary metrics object. A metrics object has the following
* format.
*
* {
* lines: lineMetrics,
* statements: statementMetrics,
* functions: functionMetrics,
* branches: branchMetrics
* }
*
* Each individual metric object looks as follows:
*
* {
* total: n,
* covered: m,
* pct: percent
* }
*
* @method blankSummary
* @static
* @return {Object} a blank metrics object
*/
function blankSummary() {
return {
lines: {
total: 0,
covered: 0,
pct: 'Unknown'
},
statements: {
total: 0,
covered: 0,
pct: 'Unknown'
},
functions: {
total: 0,
covered: 0,
pct: 'Unknown'
},
branches: {
total: 0,
covered: 0,
pct: 'Unknown'
}
};
}
/**
* returns the summary metrics given the coverage object for a single file. See `blankSummary()`
* to understand the format of the returned object.
*
* @method summarizeFileCoverage
* @static
* @param {Object} fileCoverage the coverage object for a single file.
* @return {Object} the summary metrics for the file
*/
function summarizeFileCoverage(fileCoverage) {
var ret = blankSummary();
addDerivedInfoForFile(fileCoverage);
ret.lines = computeSimpleTotals(fileCoverage, 'l');
ret.functions = computeSimpleTotals(fileCoverage, 'f');
ret.statements = computeSimpleTotals(fileCoverage, 's');
ret.branches = computeBranchTotals(fileCoverage);
return ret;
}
/**
* merges two instances of file coverage objects *for the same file*
* such that the execution counts are correct.
*
* @method mergeFileCoverage
* @static
* @param {Object} first the first file coverage object for a given file
* @param {Object} second the second file coverage object for the same file
* @return {Object} an object that is a result of merging the two. Note that
* the input objects are not changed in any way.
*/
function mergeFileCoverage(first, second) {
var ret = JSON.parse(JSON.stringify(first)),
i;
Object.keys(stats).forEach(function (key) {
ret.total += 1;
if (stats[key]) {
ret.covered += 1;
}
});
ret.pct = percent(ret.covered, ret.total);
return ret;
}
delete ret.l; //remove derived info
function computeBranchTotals(fileCoverage) {
var stats = fileCoverage.b,
ret = { total: 0, covered: 0 };
Object.keys(second.s).forEach(function (k) {
ret.s[k] += second.s[k];
});
Object.keys(second.f).forEach(function (k) {
ret.f[k] += second.f[k];
});
Object.keys(second.b).forEach(function (k) {
var retArray = ret.b[k],
secondArray = second.b[k];
for (i = 0; i < retArray.length; i += 1) {
retArray[i] += secondArray[i];
}
});
return ret;
}
/**
* merges multiple summary metrics objects by summing up the `totals` and
* `covered` fields and recomputing the percentages. This function is generic
* and can accept any number of arguments.
*
* @method mergeSummaryObjects
* @static
* @param {Object} summary... multiple summary metrics objects
* @return {Object} the merged summary metrics
*/
function mergeSummaryObjects() {
var ret = blankSummary(),
args = Array.prototype.slice.call(arguments),
keys = ['lines', 'statements', 'branches', 'functions'],
increment = function (obj) {
if (obj) {
keys.forEach(function (key) {
ret[key].total += obj[key].total;
ret[key].covered += obj[key].covered;
});
Object.keys(stats).forEach(function (key) {
var branches = stats[key],
covered = branches.filter(function (num) { return num > 0; });
ret.total += branches.length;
ret.covered += covered.length;
});
ret.pct = percent(ret.covered, ret.total);
return ret;
}
/**
* returns a blank summary metrics object. A metrics object has the following
* format.
*
* {
* lines: lineMetrics,
* statements: statementMetrics,
* functions: functionMetrics,
* branches: branchMetrics
* }
*
* Each individual metric object looks as follows:
*
* {
* total: n,
* covered: m,
* pct: percent
* }
*
* @method blankSummary
* @static
* @return {Object} a blank metrics object
*/
function blankSummary() {
return {
lines: {
total: 0,
covered: 0,
pct: 'Unknown'
},
statements: {
total: 0,
covered: 0,
pct: 'Unknown'
},
functions: {
total: 0,
covered: 0,
pct: 'Unknown'
},
branches: {
total: 0,
covered: 0,
pct: 'Unknown'
}
};
args.forEach(function (arg) {
increment(arg);
});
keys.forEach(function (key) {
ret[key].pct = percent(ret[key].covered, ret[key].total);
});
}
/**
* returns the summary metrics given the coverage object for a single file. See `blankSummary()`
* to understand the format of the returned object.
*
* @method summarizeFileCoverage
* @static
* @param {Object} fileCoverage the coverage object for a single file.
* @return {Object} the summary metrics for the file
*/
function summarizeFileCoverage(fileCoverage) {
var ret = blankSummary();
addDerivedInfoForFile(fileCoverage);
ret.lines = computeSimpleTotals(fileCoverage, 'l');
ret.functions = computeSimpleTotals(fileCoverage, 'f');
ret.statements = computeSimpleTotals(fileCoverage, 's');
ret.branches = computeBranchTotals(fileCoverage);
return ret;
}
/**
* merges two instances of file coverage objects *for the same file*
* such that the execution counts are correct.
*
* @method mergeFileCoverage
* @static
* @param {Object} first the first file coverage object for a given file
* @param {Object} second the second file coverage object for the same file
* @return {Object} an object that is a result of merging the two. Note that
* the input objects are not changed in any way.
*/
function mergeFileCoverage(first, second) {
var ret = JSON.parse(JSON.stringify(first)),
i;
return ret;
}
delete ret.l; //remove derived info
/**
* makes the coverage object generated by this library yuitest_coverage compatible.
* Note that this transformation is lossy since the returned object will not have
* statement and branch coverage.
*
* @method toYUICoverage
* @static
* @param {Object} coverage The `istanbul` coverage object
* @return {Object} a coverage object in `yuitest_coverage` format.
*/
function toYUICoverage(coverage) {
var ret = {};
Object.keys(second.s).forEach(function (k) {
ret.s[k] += second.s[k];
});
Object.keys(second.f).forEach(function (k) {
ret.f[k] += second.f[k];
});
Object.keys(second.b).forEach(function (k) {
var retArray = ret.b[k],
secondArray = second.b[k];
for (i = 0; i < retArray.length; i += 1) {
retArray[i] += secondArray[i];
}
});
addDerivedInfo(coverage);
return ret;
}
/**
* merges multiple summary metrics objects by summing up the `totals` and
* `covered` fields and recomputing the percentages. This function is generic
* and can accept any number of arguments.
*
* @method mergeSummaryObjects
* @static
* @param {Object} summary... multiple summary metrics objects
* @return {Object} the merged summary metrics
*/
function mergeSummaryObjects() {
var ret = blankSummary(),
args = Array.prototype.slice.call(arguments),
keys = ['lines', 'statements', 'branches', 'functions'],
increment = function (obj) {
if (obj) {
keys.forEach(function (key) {
ret[key].total += obj[key].total;
ret[key].covered += obj[key].covered;
});
}
};
args.forEach(function (arg) {
increment(arg);
});
keys.forEach(function (key) {
ret[key].pct = percent(ret[key].covered, ret[key].total);
});
Object.keys(coverage).forEach(function (k) {
var fileCoverage = coverage[k],
lines = fileCoverage.l,
functions = fileCoverage.f,
fnMap = fileCoverage.fnMap,
o;
return ret;
}
/**
* returns the coverage summary for a single coverage object. This is
* wrapper over `summarizeFileCoverage` and `mergeSummaryObjects` for
* the common case of a single coverage object
* @param {Object} coverage the coverage object
* @return {Object} summary coverage metrics across all files in the coverage object
*/
function summarizeCoverage(coverage) {
var fileSummary = [];
Object.keys(coverage).forEach(function (key) {
fileSummary.push(summarizeFileCoverage(coverage[key]));
});
return mergeSummaryObjects.apply(null, fileSummary);
}
o = ret[k] = {
lines: {},
calledLines: 0,
coveredLines: 0,
functions: {},
calledFunctions: 0,
coveredFunctions: 0
};
Object.keys(lines).forEach(function (k) {
o.lines[k] = lines[k];
o.coveredLines += 1;
if (lines[k] > 0) {
o.calledLines += 1;
}
/**
* makes the coverage object generated by this library yuitest_coverage compatible.
* Note that this transformation is lossy since the returned object will not have
* statement and branch coverage.
*
* @method toYUICoverage
* @static
* @param {Object} coverage The `istanbul` coverage object
* @return {Object} a coverage object in `yuitest_coverage` format.
*/
function toYUICoverage(coverage) {
var ret = {};
addDerivedInfo(coverage);
Object.keys(coverage).forEach(function (k) {
var fileCoverage = coverage[k],
lines = fileCoverage.l,
functions = fileCoverage.f,
fnMap = fileCoverage.fnMap,
o;
o = ret[k] = {
lines: {},
calledLines: 0,
coveredLines: 0,
functions: {},
calledFunctions: 0,
coveredFunctions: 0
};
Object.keys(lines).forEach(function (k) {
o.lines[k] = lines[k];
o.coveredLines += 1;
if (lines[k] > 0) {
o.calledLines += 1;
}
});
Object.keys(functions).forEach(function (k) {
var name = fnMap[k].name + ':' + fnMap[k].line;
o.functions[name] = functions[k];
o.coveredFunctions += 1;
if (functions[k] > 0) {
o.calledFunctions += 1;
}
});
});
Object.keys(functions).forEach(function (k) {
var name = fnMap[k].name + ':' + fnMap[k].line;
o.functions[name] = functions[k];
o.coveredFunctions += 1;
if (functions[k] > 0) {
o.calledFunctions += 1;
}
});
});
return ret;
}
return ret;
}
module.exports = {
addDerivedInfo: addDerivedInfo,
addDerivedInfoForFile: addDerivedInfoForFile,
removeDerivedInfo: removeDerivedInfo,
blankSummary: blankSummary,
summarizeFileCoverage: summarizeFileCoverage,
mergeFileCoverage: mergeFileCoverage,
mergeSummaryObjects: mergeSummaryObjects,
toYUICoverage: toYUICoverage
};
var exportables = {
addDerivedInfo: addDerivedInfo,
addDerivedInfoForFile: addDerivedInfoForFile,
removeDerivedInfo: removeDerivedInfo,
blankSummary: blankSummary,
summarizeFileCoverage: summarizeFileCoverage,
summarizeCoverage: summarizeCoverage,
mergeFileCoverage: mergeFileCoverage,
mergeSummaryObjects: mergeSummaryObjects,
toYUICoverage: toYUICoverage
};
if (isNode) {
module.exports = exportables;
} else {
window.coverageUtils = exportables;
}
}(typeof module !== 'undefined' && typeof module.exports !== 'undefined' && typeof exports !== 'undefined'));
{
"name": "istanbul",
"version": "0.1.4",
"version": "0.1.5",
"description": "Yet another JS code coverage tool that computes statement, line, function and branch coverage with module loader hooks to transparently add coverage when running tests. Supports all JS coverage use cases including unit tests, server side functional tests and browser tests. Built for scale",

@@ -5,0 +5,0 @@ "keywords": "coverage,code coverage, JS code coverage, JS coverage",

@@ -144,2 +144,11 @@ /*jslint nomen: true */

},
"should merge summary correctly in one call": function (test) {
var coverage = { foo: it.foo, 'bar': it2.foo },
ret = utils.summarizeCoverage(coverage);
test.deepEqual({ total: 8, covered: 6, pct: 75 }, ret.lines);
test.deepEqual({ total: 10, covered: 8, pct: 80 }, ret.statements);
test.deepEqual({ total: 4, covered: 2, pct: 50 }, ret.functions);
test.deepEqual({ total: 10, covered: 4, pct: 40 }, ret.branches);
test.done();
},
"can merge with a blank object in first position": function (test) {

@@ -146,0 +155,0 @@ var s1 = null,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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