Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report Logic Truthiness: Port over coverage lib changes. #639

Merged
merged 11 commits into from
Oct 17, 2021
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha --timeout 30000 packages/*/test{,/*}.js",
"posttest": "eslint .",
"fix": "eslint .",
"fix": "eslint . --fix",
"postinstall": "bash scripts/install.sh"
},
"repository": {
Expand Down
24 changes: 17 additions & 7 deletions packages/istanbul-lib-coverage/lib/coverage-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ function blankSummary() {
lines: empty(),
statements: empty(),
functions: empty(),
branches: empty()
branches: empty(),
branchesTrue: empty()
};
}

Expand Down Expand Up @@ -63,12 +64,20 @@ class CoverageSummary {
* @param {CoverageSummary} obj - another coverage summary object
*/
merge(obj) {
const keys = ['lines', 'statements', 'branches', 'functions'];
const keys = [
'lines',
'statements',
'branches',
'functions',
'branchesTrue'
];
keys.forEach(key => {
this[key].total += obj[key].total;
this[key].covered += obj[key].covered;
this[key].skipped += obj[key].skipped;
this[key].pct = percent(this[key].covered, this[key].total);
if (obj[key]) {
this[key].total += obj[key].total;
this[key].covered += obj[key].covered;
this[key].skipped += obj[key].skipped;
this[key].pct = percent(this[key].covered, this[key].total);
}
});

return this;
Expand All @@ -94,7 +103,8 @@ dataProperties(CoverageSummary, [
'lines',
'statements',
'functions',
'branches'
'branches',
'branchesTrue'
]);

module.exports = {
Expand Down
33 changes: 30 additions & 3 deletions packages/istanbul-lib-coverage/lib/file-coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,19 @@ class FileCoverage {
);
this.data.b = hits;
this.data.branchMap = map;

// Tracking additional information about branch truthiness
// can be optionally enabled:
if (this.bT && other.bT) {
[hits, map] = mergeProp(
this.bT,
this.branchMap,
other.bT,
other.branchMap,
keyFromLocationsProp
);
this.data.bT = hits;
}
}

computeSimpleTotals(property) {
Expand All @@ -254,8 +267,8 @@ class FileCoverage {
return ret;
}

computeBranchTotals() {
const stats = this.b;
computeBranchTotals(property) {
const stats = this[property];
const ret = { total: 0, covered: 0, skipped: 0 };

Object.values(stats).forEach(branches => {
Expand All @@ -274,6 +287,7 @@ class FileCoverage {
const statements = this.s;
const functions = this.f;
const branches = this.b;
const branchesTrue = this.bT;
Object.keys(statements).forEach(s => {
statements[s] = 0;
});
Expand All @@ -283,6 +297,13 @@ class FileCoverage {
Object.keys(branches).forEach(b => {
branches[b].fill(0);
});
// Tracking additional information about branch truthiness
// can be optionally enabled:
if (branchesTrue) {
Object.keys(branchesTrue).forEach(bT => {
branchesTrue[bT].fill(0);
});
}
}

/**
Expand All @@ -294,7 +315,12 @@ class FileCoverage {
ret.lines = this.computeSimpleTotals('getLineCoverage');
ret.functions = this.computeSimpleTotals('f', 'fnMap');
ret.statements = this.computeSimpleTotals('s', 'statementMap');
ret.branches = this.computeBranchTotals();
ret.branches = this.computeBranchTotals('b');
// Tracking additional information about branch truthiness
// can be optionally enabled:
if (this['bt']) {
ret.branchesTrue = this.computeBranchTotals('bT');
}
return new CoverageSummary(ret);
}
}
Expand All @@ -308,6 +334,7 @@ dataProperties(FileCoverage, [
's',
'f',
'b',
'bT',
'all'
]);

Expand Down
138 changes: 135 additions & 3 deletions packages/istanbul-lib-coverage/test/file.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('coverage summary', () => {
assert.ok(cs.lines);
assert.ok(cs.functions);
assert.ok(cs.branches);
assert.ok(cs.branchesTrue);
});

it('allows another summary in constructor', () => {
Expand Down Expand Up @@ -70,13 +71,15 @@ describe('coverage summary', () => {
statements: basic(),
functions: basic(),
lines: basic(),
branches: empty()
branches: empty(),
branchesTrue: empty()
});
const cs2 = new CoverageSummary({
statements: basic(),
functions: basic(),
lines: basic(),
branches: empty()
branches: empty(),
branchesTrue: empty()
});
cs2.statements.covered = 5;
cs1.merge(cs2);
Expand All @@ -87,6 +90,7 @@ describe('coverage summary', () => {
pct: 90
});
assert.equal(cs1.branches.pct, 100);
assert.equal(cs1.branchesTrue.pct, 100);
const data = JSON.parse(JSON.stringify(cs1));
assert.deepEqual(data.statements, {
total: 10,
Expand All @@ -95,6 +99,7 @@ describe('coverage summary', () => {
pct: 90
});
assert.equal(data.branches.pct, 100);
assert.equal(data.branchesTrue.pct, 100);
});

it('isEmpty() by default', () => {
Expand Down Expand Up @@ -475,12 +480,135 @@ describe('base coverage', () => {
let cov = createCoverage(true);
cov.merge(createCoverage());
assert.deepEqual(cov.data, expected);

cov = createCoverage();
cov.merge(createCoverage(true));
assert.deepEqual(cov.data, expected);
});

it('merges another file coverage that tracks logical truthiness', () => {
const loc = function(sl, sc, el, ec) {
return {
start: { line: sl, column: sc },
end: { line: el, column: ec }
};
};
const template = new FileCoverage({
path: '/path/to/file',
statementMap: {
0: loc(1, 1, 1, 100),
1: loc(2, 1, 2, 50),
2: loc(2, 51, 2, 100),
3: loc(2, 101, 3, 100)
},
fnMap: {
0: {
name: 'foobar',
line: 1,
loc: loc(1, 1, 1, 50)
}
},
branchMap: {
0: {
type: 'if',
line: 2,
locations: [loc(2, 1, 2, 20), loc(2, 50, 2, 100)]
}
},
s: {
0: 0,
1: 0,
2: 0,
3: 0
},
f: {
0: 0
},
b: {
0: [0, 0]
},
bT: {
0: [0, 0]
}
});
const clone = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
const c1 = new FileCoverage(clone(template));
const c2 = new FileCoverage(clone(template));
let summary;

c1.s[0] = 1;
c1.f[0] = 1;
c1.b[0][0] = 1;
c1.bT[0][0] = 1;

c2.s[1] = 1;
c2.f[0] = 1;
c2.b[0][1] = 2;
c2.bT[0][1] = 2;
summary = c1.toSummary();
assert.ok(summary instanceof CoverageSummary);
assert.deepEqual(summary.statements, {
total: 4,
covered: 1,
skipped: 0,
pct: 25
});
assert.deepEqual(summary.lines, {
total: 2,
covered: 1,
skipped: 0,
pct: 50
});
assert.deepEqual(summary.functions, {
total: 1,
covered: 1,
skipped: 0,
pct: 100
});
assert.deepEqual(summary.branches, {
total: 2,
covered: 1,
skipped: 0,
pct: 50
});

c1.merge(c2);
summary = c1.toSummary();
assert.deepEqual(summary.statements, {
total: 4,
covered: 2,
skipped: 0,
pct: 50
});
assert.deepEqual(summary.lines, {
total: 2,
covered: 2,
skipped: 0,
pct: 100
});
assert.deepEqual(summary.functions, {
total: 1,
covered: 1,
skipped: 0,
pct: 100
});
assert.deepEqual(summary.branches, {
total: 2,
covered: 2,
skipped: 0,
pct: 100
});

assert.equal(c1.s[0], 1);
assert.equal(c1.s[1], 1);
assert.equal(c1.f[0], 2);
assert.equal(c1.b[0][0], 1);
assert.equal(c1.b[0][1], 2);
assert.equal(c1.bT[0][0], 1);
assert.equal(c1.bT[0][1], 2);
});

it('resets hits when requested', () => {
const loc = function(sl, sc, el, ec) {
return {
Expand Down Expand Up @@ -521,12 +649,16 @@ describe('base coverage', () => {
},
b: {
1: [1, 50]
},
bT: {
1: [1, 50]
}
});
fc.resetHits();
assert.deepEqual({ 1: 0, 2: 0, 3: 0, 4: 0 }, fc.s);
assert.deepEqual({ 1: 0 }, fc.f);
assert.deepEqual({ 1: [0, 0] }, fc.b);
assert.deepEqual({ 1: [0, 0] }, fc.bT);
});

it('returns uncovered lines', () => {
Expand Down