index.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. Copyright 2012-2015, Yahoo Inc.
  3. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
  4. */
  5. const path = require('path');
  6. function CoberturaReport(opts) {
  7. this.cw = null;
  8. this.xml = null;
  9. this.projectRoot = opts.projectRoot || process.cwd();
  10. this.file = opts.file || 'cobertura-coverage.xml';
  11. }
  12. function asJavaPackage(node) {
  13. return node
  14. .getRelativeName()
  15. .replace(/\//g, '.')
  16. .replace(/\\/g, '.')
  17. .replace(/\.$/, '');
  18. }
  19. function asClassName(node) {
  20. return node.getRelativeName().replace(/.*[\\/]/, '');
  21. }
  22. CoberturaReport.prototype.onStart = function(root, context) {
  23. this.cw = context.writer.writeFile(this.file);
  24. this.xml = context.getXMLWriter(this.cw);
  25. this.writeRootStats(root);
  26. };
  27. CoberturaReport.prototype.onEnd = function() {
  28. this.xml.closeAll();
  29. this.cw.close();
  30. };
  31. CoberturaReport.prototype.writeRootStats = function(node) {
  32. const metrics = node.getCoverageSummary();
  33. this.cw.println('<?xml version="1.0" ?>');
  34. this.cw.println(
  35. '<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">'
  36. );
  37. this.xml.openTag('coverage', {
  38. 'lines-valid': metrics.lines.total,
  39. 'lines-covered': metrics.lines.covered,
  40. 'line-rate': metrics.lines.pct / 100.0,
  41. 'branches-valid': metrics.branches.total,
  42. 'branches-covered': metrics.branches.covered,
  43. 'branch-rate': metrics.branches.pct / 100.0,
  44. timestamp: Date.now().toString(),
  45. complexity: '0',
  46. version: '0.1'
  47. });
  48. this.xml.openTag('sources');
  49. this.xml.inlineTag('source', null, this.projectRoot);
  50. this.xml.closeTag('sources');
  51. this.xml.openTag('packages');
  52. };
  53. CoberturaReport.prototype.onSummary = function(node) {
  54. if (node.isRoot()) {
  55. return;
  56. }
  57. const metrics = node.getCoverageSummary(true);
  58. if (!metrics) {
  59. return;
  60. }
  61. this.xml.openTag('package', {
  62. name: asJavaPackage(node),
  63. 'line-rate': metrics.lines.pct / 100.0,
  64. 'branch-rate': metrics.branches.pct / 100.0
  65. });
  66. this.xml.openTag('classes');
  67. };
  68. CoberturaReport.prototype.onSummaryEnd = function(node) {
  69. if (node.isRoot()) {
  70. return;
  71. }
  72. this.xml.closeTag('classes');
  73. this.xml.closeTag('package');
  74. };
  75. CoberturaReport.prototype.onDetail = function(node) {
  76. const fileCoverage = node.getFileCoverage();
  77. const metrics = node.getCoverageSummary();
  78. const branchByLine = fileCoverage.getBranchCoverageByLine();
  79. this.xml.openTag('class', {
  80. name: asClassName(node),
  81. filename: path.relative(this.projectRoot, fileCoverage.path),
  82. 'line-rate': metrics.lines.pct / 100.0,
  83. 'branch-rate': metrics.branches.pct / 100.0
  84. });
  85. this.xml.openTag('methods');
  86. const fnMap = fileCoverage.fnMap;
  87. Object.keys(fnMap).forEach(k => {
  88. const name = fnMap[k].name;
  89. const hits = fileCoverage.f[k];
  90. this.xml.openTag('method', {
  91. name,
  92. hits,
  93. signature: '()V' //fake out a no-args void return
  94. });
  95. this.xml.openTag('lines');
  96. //Add the function definition line and hits so that jenkins cobertura plugin records method hits
  97. this.xml.inlineTag('line', {
  98. number: fnMap[k].decl.start.line,
  99. hits
  100. });
  101. this.xml.closeTag('lines');
  102. this.xml.closeTag('method');
  103. });
  104. this.xml.closeTag('methods');
  105. this.xml.openTag('lines');
  106. const lines = fileCoverage.getLineCoverage();
  107. Object.keys(lines).forEach(k => {
  108. const attrs = {
  109. number: k,
  110. hits: lines[k],
  111. branch: 'false'
  112. };
  113. const branchDetail = branchByLine[k];
  114. if (branchDetail) {
  115. attrs.branch = true;
  116. attrs['condition-coverage'] =
  117. branchDetail.coverage +
  118. '% (' +
  119. branchDetail.covered +
  120. '/' +
  121. branchDetail.total +
  122. ')';
  123. }
  124. this.xml.inlineTag('line', attrs);
  125. });
  126. this.xml.closeTag('lines');
  127. this.xml.closeTag('class');
  128. };
  129. module.exports = CoberturaReport;