mirror of
https://github.com/cfal/shoes.git
synced 2026-11-06 08:14:11 +00:00
Add advisory selector/reload performance reports, optional Linux unit/process coverage with changed-line summaries, and bounded rule-parser property tests to make regressions and verification gaps easier to spot. Reports reject invalid measurements and account for timing noise without introducing hard performance gates; existing tests and production behavior remain unchanged.
91 lines
4.0 KiB
JavaScript
91 lines
4.0 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { changedCoverage, changedLines, coverageLines } from './coverage-lines.mjs';
|
|
|
|
const diff = 'diff --git a/src/a.rs b/src/a.rs\n+++ b/src/a.rs\n@@ -1 +1,3 @@\n+a\n+b\n+c\n';
|
|
const lcov = 'SF:src/a.rs\nDA:1,3\nDA:2,0\nend_of_record\n';
|
|
|
|
test('changed lines distinguish covered, uncovered and unknown/non-executable', () => {
|
|
const report = changedCoverage(diff, lcov);
|
|
assert.equal(report.percent, 50);
|
|
assert.deepEqual(report.files[0].covered, [1]);
|
|
assert.deepEqual(report.files[0].uncovered, [2]);
|
|
assert.deepEqual(report.files[0].not_in_report, [3]);
|
|
});
|
|
test('empty diff and deletion-only hunks are N/A, not 100 percent', () => {
|
|
assert.equal(changedCoverage('', lcov).percent, null);
|
|
assert.deepEqual([...changedLines(diff.replace('+1,3', '+1,0')).get('src/a.rs')], []);
|
|
});
|
|
test('deleted files contribute no candidate lines, including rename-as-delete/add diffs', () => {
|
|
const deletion = 'diff --git a/src/old.rs b/src/old.rs\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-a\n-b\n';
|
|
assert.equal(changedCoverage(deletion, lcov).percent, null);
|
|
assert.equal(changedCoverage(deletion + diff, lcov).percent, 50);
|
|
});
|
|
test('added source text resembling a file header cannot change the current file', () => {
|
|
const report = changedCoverage(diff + '+++ b/wrong.rs\n@@ -9 +9 @@\n+text\n', lcov);
|
|
assert.equal(report.files.length, 1);
|
|
assert.equal(report.files[0].file, 'src/a.rs');
|
|
assert.deepEqual(report.files[0].not_in_report, [3, 9]);
|
|
});
|
|
test('missing file coverage remains unknown', () => {
|
|
const report = changedCoverage(diff.replaceAll('a.rs', 'b.rs'), lcov);
|
|
assert.equal(report.percent, null);
|
|
assert.equal(report.files[0].instrumented, false);
|
|
assert.deepEqual(report.files[0].not_in_report, [1, 2, 3]);
|
|
});
|
|
test('LCOV merges duplicate file instantiations without double counting lines', () => {
|
|
const report = changedCoverage(diff, lcov + lcov.replace('DA:2,0', 'DA:2,4'));
|
|
assert.equal(report.percent, 100);
|
|
assert.equal(report.changed_executable_lines, 2);
|
|
});
|
|
test('zero-line, malformed, missing and incomplete coverage fails closed', () => {
|
|
for (const input of ['', 'SF:src/a.rs\nend_of_record', lcov.replace('DA:1,3', 'DA:1,-1'),
|
|
'DA:1,2\n', lcov.replace('end_of_record', ''), lcov.replace('DA:1,3', 'DA:0,2')]) {
|
|
assert.throws(() => coverageLines(input));
|
|
}
|
|
});
|
|
test('quoted paths and malformed hunk context fail explicitly', () => {
|
|
assert.throws(() => changedLines('+++ "b/weird path"\n@@ -1 +1 @@'));
|
|
assert.throws(() => changedLines('@@ -1 +1 @@'));
|
|
});
|
|
|
|
test('classification preserves hunk order, deduplicates lines and retains empty file records', () => {
|
|
const changes = [
|
|
'diff --git a/src/a.rs b/src/a.rs',
|
|
'+++ b/src/a.rs',
|
|
'@@ -9 +9,2 @@',
|
|
'+late',
|
|
'+unknown',
|
|
'@@ -1 +1,2 @@',
|
|
'+covered',
|
|
'+uncovered',
|
|
'@@ -9 +9 @@',
|
|
'+duplicate',
|
|
'diff --git a/src/b.rs b/src/b.rs',
|
|
'+++ b/src/b.rs',
|
|
'@@ -1 +1 @@',
|
|
'+uninstrumented',
|
|
].join('\n');
|
|
const counts = 'SF:src/a.rs\nDA:1,3\nDA:2,0\nDA:9,1\nend_of_record\nSF:src/b.rs\nend_of_record\n';
|
|
const report = changedCoverage(changes, counts);
|
|
assert.deepEqual(report.files, [
|
|
{ file: 'src/a.rs', changed_lines: 4, instrumented: true, covered: [9, 1], uncovered: [2], not_in_report: [10] },
|
|
{ file: 'src/b.rs', changed_lines: 1, instrumented: true, covered: [], uncovered: [], not_in_report: [1] },
|
|
]);
|
|
assert.equal(report.changed_executable_lines, 3);
|
|
assert.equal(report.percent, 200 / 3);
|
|
});
|
|
|
|
test('malformed LCOV retains specific validation diagnostics', () => {
|
|
const cases = [
|
|
['SF:src/a.rs\nSF:src/b.rs\n', 'unterminated LCOV record'],
|
|
['DA:1,1\n', 'invalid LCOV line count'],
|
|
['SF:src/a.rs\nDA:1,9007199254740992\n', 'invalid LCOV line count'],
|
|
['end_of_record\n', 'LCOV terminator without file'],
|
|
['SF:src/a.rs\nend_of_record\n', 'empty or incomplete coverage'],
|
|
];
|
|
for (const [input, message] of cases) {
|
|
assert.throws(() => coverageLines(input), { message });
|
|
}
|
|
});
|