1 #!/usr/bin/env dub 2 /+ dub.sdl: 3 dependency "liblstparse" version="~>1.1.2" 4 +/ 5 6 /** 7 * Run this script to generate code coverage reports under the coverage/ 8 * directory. 9 */ 10 module gen_coverage; 11 12 import liblstparse.parser; 13 14 import std.process; 15 import std.file; 16 import std.path; 17 import std.stdio; 18 import std.regex; 19 import std.algorithm; 20 21 const double MIN_COVERAGE_PERCENT = 0.95; 22 23 const FILE_IGNORE_PATTERNS = [ 24 `_test_root`, 25 ]; 26 27 const LINE_IGNORE_PATTERNS = [ 28 `cov-ignore$` 29 ]; 30 31 int main() { 32 if (!exists("coverage")) mkdir("coverage"); 33 34 auto result = executeShell("dub test --build=unittest-cov -- --DRT-covopt=\"dstpath:coverage\""); 35 if (result.status != 0) { 36 stderr.writefln!"Code coverage generation failed with code %d"(result.status); 37 stderr.writeln(result.output); 38 return result.status; 39 } 40 41 uint fileCount = 0; 42 ulong lineCount = 0; 43 ulong coveredLineCount = 0; 44 45 foreach (DirEntry entry; dirEntries("coverage", SpanMode.shallow, false)) { 46 bool shouldSkipFile = false; 47 foreach (pattern; FILE_IGNORE_PATTERNS) { 48 auto r = regex(pattern); 49 if (matchFirst(entry.name, r)) { 50 shouldSkipFile = true; 51 break; 52 } 53 } 54 if (shouldSkipFile) continue; 55 56 LSTFile file = LSTFile(entry); 57 fileCount++; 58 59 writeln(file.filename); 60 bool coveredCompletely = true; 61 foreach (idx, line; file.lines) { 62 if (!line.coverage.isNull) { 63 bool shouldSkipLine = false; 64 foreach (pattern; LINE_IGNORE_PATTERNS) { 65 auto r = regex(pattern); 66 if (matchFirst(line.content, r)) { 67 shouldSkipLine = true; 68 break; 69 } 70 } 71 if (shouldSkipLine) continue; 72 uint coverage = line.coverage.get(); 73 if (coverage > 0) { 74 coveredLineCount++; 75 } else { 76 writefln!" ! L%04d -> %s"(idx, line.content); 77 coveredCompletely = false; 78 } 79 lineCount++; 80 } 81 } 82 if (coveredCompletely) { 83 writeln(" 100% Covered!"); 84 } 85 } 86 double coverageAvg = cast(double) coveredLineCount / lineCount; 87 writefln!"Total coverage of %.2f%% (%d/%d) lines in %d files."( 88 coverageAvg * 100, coveredLineCount, lineCount, fileCount 89 ); 90 if (coverageAvg < MIN_COVERAGE_PERCENT) { 91 stderr.writefln!"Coverage is less than the required %.2f%%."(MIN_COVERAGE_PERCENT * 100); 92 return 1; 93 } 94 return 0; 95 }