mirror of
https://github.com/less/less.js.git
synced 2026-01-09 15:48:08 -05:00
* Migrate Less to use valid CSS * Re-organize test structure * Lots of test refactoring * More test updates * Add restructured tests * WIP Signed-off-by: Matthew Dean <matthew-dean@users.noreply.github.com> * More fixes to tests * More test fixes * All tests passing * WIP fix tests * Finished fixing browser tests * Improve test coverage * Add debug tests * Add back debug tests to show equal test coverage * Fix browser tests * More test coverage * Fix sourcemap absolute path for CI * More source map normalization for Windows * Fix source map normalization * Another attempted fix for Windows --------- Signed-off-by: Matthew Dean <matthew-dean@users.noreply.github.com>
159 lines
5.3 KiB
JavaScript
159 lines
5.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Generates a per-file coverage report table for src/ directories
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const coverageSummaryPath = path.join(__dirname, '..', 'coverage', 'coverage-summary.json');
|
|
|
|
if (!fs.existsSync(coverageSummaryPath)) {
|
|
console.error('Coverage summary not found. Run pnpm test:coverage first.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const coverage = JSON.parse(fs.readFileSync(coverageSummaryPath, 'utf8'));
|
|
|
|
// Filter to only src/ files (less, less-node) and bin/ files
|
|
// Note: src/less-browser/ is excluded because browser tests aren't included in coverage
|
|
// Abstract base classes are excluded as they're meant to be overridden by implementations
|
|
const abstractClasses = [
|
|
'abstract-file-manager',
|
|
'abstract-plugin-loader'
|
|
];
|
|
|
|
const srcFiles = Object.entries(coverage)
|
|
.filter(([filePath]) => {
|
|
const normalized = filePath.replace(/\\/g, '/');
|
|
// Exclude abstract classes
|
|
if (abstractClasses.some(abstract => normalized.includes(abstract))) {
|
|
return false;
|
|
}
|
|
return (normalized.includes('/src/less/') && !normalized.includes('/src/less-browser/')) ||
|
|
normalized.includes('/src/less-node/') ||
|
|
normalized.includes('/bin/');
|
|
})
|
|
.map(([filePath, data]) => {
|
|
// Extract relative path from absolute path
|
|
const normalized = filePath.replace(/\\/g, '/');
|
|
// Match src/ paths or bin/ paths
|
|
const match = normalized.match(/((?:src\/[^/]+\/[^/]+\/|bin\/).+)$/);
|
|
const relativePath = match ? match[1] : path.basename(filePath);
|
|
|
|
return {
|
|
path: relativePath,
|
|
statements: data.statements,
|
|
branches: data.branches,
|
|
functions: data.functions,
|
|
lines: data.lines
|
|
};
|
|
})
|
|
.sort((a, b) => {
|
|
// Sort by directory first, then by coverage percentage
|
|
const pathCompare = a.path.localeCompare(b.path);
|
|
if (pathCompare !== 0) return pathCompare;
|
|
return a.statements.pct - b.statements.pct;
|
|
});
|
|
|
|
if (srcFiles.length === 0) {
|
|
console.log('No src/ files found in coverage report.');
|
|
process.exit(0);
|
|
}
|
|
|
|
// Group by directory
|
|
const grouped = {
|
|
'src/less/': [],
|
|
'src/less-node/': [],
|
|
'bin/': []
|
|
};
|
|
|
|
srcFiles.forEach(file => {
|
|
if (file.path.startsWith('src/less/')) {
|
|
grouped['src/less/'].push(file);
|
|
} else if (file.path.startsWith('src/less-node/')) {
|
|
grouped['src/less-node/'].push(file);
|
|
} else if (file.path.startsWith('bin/')) {
|
|
grouped['bin/'].push(file);
|
|
}
|
|
});
|
|
|
|
// Print table
|
|
console.log('\n' + '='.repeat(100));
|
|
console.log('Per-File Coverage Report (src/less/, src/less-node/, and bin/)');
|
|
console.log('='.repeat(100));
|
|
console.log('For line-by-line coverage details, open coverage/index.html in your browser.');
|
|
console.log('='.repeat(100) + '\n');
|
|
|
|
Object.entries(grouped).forEach(([dir, files]) => {
|
|
if (files.length === 0) return;
|
|
|
|
console.log(`\n${dir.toUpperCase()}`);
|
|
console.log('-'.repeat(100));
|
|
console.log(
|
|
'File'.padEnd(50) +
|
|
'Statements'.padStart(12) +
|
|
'Branches'.padStart(12) +
|
|
'Functions'.padStart(12) +
|
|
'Lines'.padStart(12)
|
|
);
|
|
console.log('-'.repeat(100));
|
|
|
|
files.forEach(file => {
|
|
const filename = file.path.replace(dir, '');
|
|
const truncated = filename.length > 48 ? '...' + filename.slice(-45) : filename;
|
|
|
|
console.log(
|
|
truncated.padEnd(50) +
|
|
`${file.statements.pct.toFixed(1)}%`.padStart(12) +
|
|
`${file.branches.pct.toFixed(1)}%`.padStart(12) +
|
|
`${file.functions.pct.toFixed(1)}%`.padStart(12) +
|
|
`${file.lines.pct.toFixed(1)}%`.padStart(12)
|
|
);
|
|
});
|
|
|
|
// Summary for this directory
|
|
const totals = files.reduce((acc, file) => {
|
|
acc.statements.total += file.statements.total;
|
|
acc.statements.covered += file.statements.covered;
|
|
acc.branches.total += file.branches.total;
|
|
acc.branches.covered += file.branches.covered;
|
|
acc.functions.total += file.functions.total;
|
|
acc.functions.covered += file.functions.covered;
|
|
acc.lines.total += file.lines.total;
|
|
acc.lines.covered += file.lines.covered;
|
|
return acc;
|
|
}, {
|
|
statements: { total: 0, covered: 0 },
|
|
branches: { total: 0, covered: 0 },
|
|
functions: { total: 0, covered: 0 },
|
|
lines: { total: 0, covered: 0 }
|
|
});
|
|
|
|
const stmtPct = totals.statements.total > 0
|
|
? (totals.statements.covered / totals.statements.total * 100).toFixed(1)
|
|
: '0.0';
|
|
const branchPct = totals.branches.total > 0
|
|
? (totals.branches.covered / totals.branches.total * 100).toFixed(1)
|
|
: '0.0';
|
|
const funcPct = totals.functions.total > 0
|
|
? (totals.functions.covered / totals.functions.total * 100).toFixed(1)
|
|
: '0.0';
|
|
const linePct = totals.lines.total > 0
|
|
? (totals.lines.covered / totals.lines.total * 100).toFixed(1)
|
|
: '0.0';
|
|
|
|
console.log('-'.repeat(100));
|
|
console.log(
|
|
'TOTAL'.padEnd(50) +
|
|
`${stmtPct}%`.padStart(12) +
|
|
`${branchPct}%`.padStart(12) +
|
|
`${funcPct}%`.padStart(12) +
|
|
`${linePct}%`.padStart(12)
|
|
);
|
|
});
|
|
|
|
console.log('\n' + '='.repeat(100) + '\n');
|
|
|