feat: add diffing of lcov files
This commit is contained in:
parent
b1c14afd65
commit
c8ce7f37bd
3 changed files with 83 additions and 3 deletions
26
README.md
26
README.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Diff Cov
|
# Diff Cov
|
||||||
|
|
||||||
Simple CLI to print diffs highlighted with test coverage status
|
Simple CLI to print git and lcov diffs highlighted with test coverage status
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -45,6 +45,8 @@ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/0.x
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Git diff
|
||||||
|
|
||||||
Before you run `diff-cov` you must run your test suite with coverage and output
|
Before you run `diff-cov` you must run your test suite with coverage and output
|
||||||
a `lcov` coverage file. You must also have all your changes committed to ensure
|
a `lcov` coverage file. You must also have all your changes committed to ensure
|
||||||
it's included in the output.
|
it's included in the output.
|
||||||
|
|
@ -62,3 +64,25 @@ diff-cov --coverageFile coverage/lcov.info
|
||||||
|
|
||||||
A report is printed at the bottom and colored with a threshold of `90%`
|
A report is printed at the bottom and colored with a threshold of `90%`
|
||||||
anything below this percentage coverage will be colored red.
|
anything below this percentage coverage will be colored red.
|
||||||
|
|
||||||
|
### LCov diff
|
||||||
|
|
||||||
|
You can also print the coverage difference between to lcov.info files. To use
|
||||||
|
this run your tests with coverage for a first time. After its finished you can
|
||||||
|
copy your lcov.info file somewhere for later for example:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cp ./lcov.info /tmp/lcov.info
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can work on your test and run the tests once more with coverage to
|
||||||
|
generate you a new `lcov.info` file. Then you can print the difference in
|
||||||
|
coverage between the two files with:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
diff-cov --compare /tmp/lcov.info
|
||||||
|
```
|
||||||
|
|
||||||
|
This can come in handy when you need to find out what a test is testing. You
|
||||||
|
can create your base coverage file, comment out a test, run the tests again and
|
||||||
|
diff the results.
|
||||||
|
|
|
||||||
20
src/index.ts
20
src/index.ts
|
|
@ -5,6 +5,7 @@ import { hideBin } from "yargs/helpers";
|
||||||
import exec from "./exec";
|
import exec from "./exec";
|
||||||
|
|
||||||
import report from "./report";
|
import report from "./report";
|
||||||
|
import lcovDiff from "./lcov-diff";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const parseDiff = require("./diff-parser");
|
const parseDiff = require("./diff-parser");
|
||||||
|
|
@ -21,11 +22,16 @@ const options: { [key: string]: Options } = {
|
||||||
description: "The path to the lcov report file",
|
description: "The path to the lcov report file",
|
||||||
type: "string",
|
type: "string",
|
||||||
},
|
},
|
||||||
|
compare: {
|
||||||
|
description: "The path to the lcov report you wish to compare to the `coverage-file`",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type Argv = Arguments<
|
type Argv = Arguments<
|
||||||
Partial<{
|
Partial<{
|
||||||
coverageFile: string;
|
coverageFile: string;
|
||||||
|
compare?: string;
|
||||||
}>
|
}>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
@ -36,6 +42,10 @@ export const validate = async (argv: Argv) => {
|
||||||
`Please ensure you have run tests with coverage enabled.`
|
`Please ensure you have run tests with coverage enabled.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argv.compare && !fs.existsSync(argv.compare)) {
|
||||||
|
return new Error(`Lcov compare file must be a valid file '${argv.compare}' provided.`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const run = async (argv = process.argv) => {
|
export const run = async (argv = process.argv) => {
|
||||||
|
|
@ -45,13 +55,19 @@ export const run = async (argv = process.argv) => {
|
||||||
return error(validationError.message);
|
return error(validationError.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const baseCoverage = await parseLcov.default(parsed.coverageFile);
|
||||||
|
|
||||||
|
if (parsed.compare) {
|
||||||
|
const compareCoverage = await parseLcov.default(parsed.compare);
|
||||||
|
return lcovDiff(baseCoverage, compareCoverage);
|
||||||
|
}
|
||||||
|
|
||||||
const diffText = await exec(`git diff origin/HEAD...HEAD`);
|
const diffText = await exec(`git diff origin/HEAD...HEAD`);
|
||||||
if (diffText.code > 0) {
|
if (diffText.code > 0) {
|
||||||
return error("Error loading the diff\n\n" + diffText.stderr);
|
return error("Error loading the diff\n\n" + diffText.stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const diff = parseDiff.default(diffText.stdout);
|
const diff = parseDiff.default(diffText.stdout);
|
||||||
const coverage = await parseLcov.default(parsed.coverageFile);
|
|
||||||
|
|
||||||
report(diff, coverage);
|
report(diff, baseCoverage);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
40
src/lcov-diff.ts
Normal file
40
src/lcov-diff.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
const buildCoverageSet = (report: any) => {
|
||||||
|
const set = new Set<string>();
|
||||||
|
for (const coverage of report) {
|
||||||
|
for (const detail of coverage.lines.details) {
|
||||||
|
if (detail.hit > 0) {
|
||||||
|
set.add(`${coverage.file}:${detail.line}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
};
|
||||||
|
|
||||||
|
function setDiff<T>(a: Set<T>, b: Set<T>) {
|
||||||
|
return new Set([...a].filter((x) => !b.has(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lcovDiff = async (baseCoverage: any, compareCoverage: any) => {
|
||||||
|
const baseSet = buildCoverageSet(baseCoverage);
|
||||||
|
const compareSet = buildCoverageSet(compareCoverage);
|
||||||
|
|
||||||
|
const map = new Map<string, number>();
|
||||||
|
|
||||||
|
const added = setDiff(baseSet, compareSet);
|
||||||
|
for (const key of added) {
|
||||||
|
map.set(key, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const removed = setDiff(compareSet, baseSet);
|
||||||
|
for (const key of removed) {
|
||||||
|
map.set(key, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, value] of [...map.entries()].sort()) {
|
||||||
|
const color = value > 0 ? "\x1b[32m" : "\x1b[31m";
|
||||||
|
console.log(color, key, "\x1b[0m");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default lcovDiff;
|
||||||
Loading…
Reference in a new issue