Skip to content
This repository has been archived by the owner on Jan 22, 2024. It is now read-only.

Commit

Permalink
Fix for #1 Enable source code browsing
Browse files Browse the repository at this point in the history
Publish source files for methods as Opencover saves file paths for them.
  • Loading branch information
tempora-mutantur committed Dec 25, 2019
1 parent ec9cf09 commit 28aedb1
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 5 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>code-coverage-api</artifactId>
<version>1.0.13</version>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ private Element processModule(Document document, Node module) {
String moduleName = moduleElementOpenCover.getElementsByTagName("ModuleName").item(0).getTextContent();
moduleElement.setAttribute("name", moduleName);

Node filesNode = moduleElementOpenCover.getElementsByTagName("Files").item(0);
NodeList listOfFiles = filesNode.getChildNodes();

HashMap<String, String> filesMap = new HashMap<>();

for (int fileIndex = 0; fileIndex < listOfFiles.getLength(); fileIndex++) {
Node fileNode = listOfFiles.item(fileIndex);
if (fileNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
NamedNodeMap fileAttributes = fileNode.getAttributes();

String fileUid = fileAttributes.getNamedItem("uid").getTextContent();
String fileFullPath = fileAttributes.getNamedItem("fullPath").getTextContent();

filesMap.put(fileUid, fileFullPath);
}

Node classesNode = moduleElementOpenCover.getElementsByTagName("Classes").item(0);
NodeList listOfClasses = classesNode.getChildNodes();

Expand All @@ -101,13 +119,13 @@ private Element processModule(Document document, Node module) {
if (classNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element classElement = processClass(document, classNode);
Element classElement = processClass(document, classNode, filesMap);
moduleElement.appendChild(classElement);
}
return moduleElement;
}

private Element processClass(Document document, Node classNode) {
private Element processClass(Document document, Node classNode, HashMap<String, String> filesMap) {
Element openCoverClassElement = (Element) classNode;
String classFullName = openCoverClassElement.getElementsByTagName("FullName").item(0).getTextContent();

Expand All @@ -122,18 +140,25 @@ private Element processClass(Document document, Node classNode) {
if (methodNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element methodElement = processMethod(document, methodNode);
Element methodElement = processMethod(document, methodNode, filesMap);
classElement.appendChild(methodElement);
}
return classElement;
}

private Element processMethod(Document document, Node methodNode) {
private Element processMethod(Document document, Node methodNode, HashMap<String, String> filesMap) {
Element methodElement = document.createElement("method");
Element openCoverMethodElement = (Element) methodNode;
String methodFullName = openCoverMethodElement.getElementsByTagName("Name").item(0).getTextContent();
methodElement.setAttribute("name", methodFullName);

Node fireRefNode = openCoverMethodElement.getElementsByTagName("FileRef").item(0);

String fileRef = fireRefNode.getAttributes().getNamedItem("uid").getTextContent();
if (filesMap.containsKey(fileRef)) {
methodElement.setAttribute("file", filesMap.get(fileRef));
}

ArrayList<Element> lineElements = processLineElements(document, openCoverMethodElement);

for (Element lineElement: lineElements) {
Expand Down Expand Up @@ -288,6 +313,7 @@ protected CoverageResult processElement(Element current, CoverageResult parentRe
case "method":
result = new CoverageResult(CoverageElement.get("Method"), parentResult,
getAttribute(current, "name", ""));
result.setRelativeSourcePath(getAttribute(current, "file", null));
break;
case "line":
processLine(current, parentResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import hudson.FilePath;
import io.jenkins.plugins.coverage.CoverageAction;
import io.jenkins.plugins.coverage.targets.CoverageElement;
import io.jenkins.plugins.coverage.targets.CoverageResult;
import io.jenkins.plugins.coverage.targets.Ratio;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
Expand All @@ -12,6 +13,10 @@
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;

public class OpenCoverReportAdapterTest {
Expand All @@ -21,6 +26,7 @@ public class OpenCoverReportAdapterTest {

@Test
public void StandardReportTest() throws Exception {
// TODO: rename cobertura report
String coberturaReport = "opencover.xml";
StringBuilder sb = new StringBuilder();
sb.append("node {")
Expand Down Expand Up @@ -50,4 +56,47 @@ public void StandardReportTest() throws Exception {
Ratio branchCoverage = coverageAction.getResult().getCoverage(CoverageElement.CONDITIONAL);
Assert.assertEquals(branchCoverage.toString(),"35/48");
}

@Test
public void SourceFileTest() throws Exception {
String opencoverReport = "reporttotestsourcefiles.xml";

StringBuilder sb = new StringBuilder();
sb.append("node {")
.append("publishCoverage(");

sb.append("adapters:[");

sb.append(String.format("opencoverAdapter(path: '%s')], sourceFileResolver: sourceFiles('STORE_LAST_BUILD')", opencoverReport));
sb.append(")").append("}");

WorkflowJob project = j.createProject(WorkflowJob.class, "coverage-pipeline-test");
FilePath workspace = j.jenkins.getWorkspaceFor(project);

String sourceFile = "testsourcefiles.cs";
Objects.requireNonNull(workspace)
.child(sourceFile)
.copyFrom(getClass().getResourceAsStream(sourceFile));

String opencoverReportContent =
new String(Files.readAllBytes(Paths.get(getClass().getResource(opencoverReport).toURI())));
String sourceFileWorkspacePath = workspace.getRemote().concat("/" + sourceFile);
opencoverReportContent =
opencoverReportContent.replace("[PLACEHOLDER]", sourceFileWorkspacePath);
workspace.child(opencoverReport).copyFrom(new ByteArrayInputStream(opencoverReportContent.getBytes(StandardCharsets.UTF_8)));

project.setDefinition(new CpsFlowDefinition(sb.toString(), true));
WorkflowRun r = Objects.requireNonNull(project.scheduleBuild2(0)).waitForStart();
Assert.assertNotNull(r);
j.assertBuildStatusSuccess(j.waitForCompletion(r));
CoverageAction coverageAction = r.getAction(CoverageAction.class);

CoverageResult coverageResult = coverageAction.getResult();
Ratio lineCoverage = coverageResult.getCoverage(CoverageElement.LINE);
Assert.assertEquals(lineCoverage.toString(),"9/15");

CoverageResult moduleCoverageResult = coverageResult.getChild("OpenCover coverage: reporttotestsourcefiles.xml").getChild("ClassLibrary");
CoverageResult methodCoverageResult = moduleCoverageResult.getChild("ClassLibrary.LibraryClass").getChild("System.Int32 ClassLibrary.LibraryClass::Sum(System.Int32,System.Int32)");
Assert.assertEquals(methodCoverageResult.isSourceFileAvailable(), true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<CoverageSession>
<Summary numSequencePoints="15" visitedSequencePoints="9" numBranchPoints="6" visitedBranchPoints="3" sequenceCoverage="60" branchCoverage="50" maxCyclomaticComplexity="6" minCyclomaticComplexity="6" visitedClasses="1" numClasses="1" visitedMethods="1" numMethods="1" />
<Modules>
<Module hash="31750BAB-054A-4C4B-8763-D76F95F0353A">
<ModulePath>ClassLibrary.dll</ModulePath>
<ModuleTime>2019-12-13T01:36:13</ModuleTime>
<ModuleName>ClassLibrary</ModuleName>
<Files>
<File uid="1" fullPath="[PLACEHOLDER]" />
</Files>
<Classes>
<Class>
<Summary numSequencePoints="15" visitedSequencePoints="9" numBranchPoints="6" visitedBranchPoints="3" sequenceCoverage="60" branchCoverage="50" maxCyclomaticComplexity="6" minCyclomaticComplexity="6" visitedClasses="1" numClasses="1" visitedMethods="1" numMethods="1" />
<FullName>ClassLibrary.LibraryClass</FullName>
<Methods>
<Method cyclomaticComplexity="6" nPathComplexity="0" sequenceCoverage="60" branchCoverage="50" isConstructor="False" isGetter="False" isSetter="False" isStatic="True">
<Summary numSequencePoints="15" visitedSequencePoints="9" numBranchPoints="6" visitedBranchPoints="3" sequenceCoverage="60" branchCoverage="50" maxCyclomaticComplexity="6" minCyclomaticComplexity="6" visitedClasses="0" numClasses="0" visitedMethods="1" numMethods="1" />
<MetadataToken />
<Name>System.Int32 ClassLibrary.LibraryClass::Sum(System.Int32,System.Int32)</Name>
<FileRef uid="1" />
<SequencePoints>
<SequencePoint vc="2" uspid="8" ordinal="0" sl="8" sc="1" el="8" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="2" uspid="9" ordinal="1" sl="9" sc="1" el="9" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="2" uspid="10" ordinal="2" sl="10" sc="1" el="10" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="0" uspid="13" ordinal="3" sl="13" sc="1" el="13" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="0" uspid="14" ordinal="4" sl="14" sc="1" el="14" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="0" uspid="16" ordinal="5" sl="16" sc="1" el="16" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="0" uspid="17" ordinal="6" sl="17" sc="1" el="17" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="0" uspid="19" ordinal="7" sl="19" sc="1" el="19" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="0" uspid="20" ordinal="8" sl="20" sc="1" el="20" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="1" uspid="22" ordinal="9" sl="22" sc="1" el="22" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="1" uspid="23" ordinal="10" sl="23" sc="1" el="23" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="1" uspid="25" ordinal="11" sl="25" sc="1" el="25" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="1" uspid="26" ordinal="12" sl="26" sc="1" el="26" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="2" uspid="28" ordinal="13" sl="28" sc="1" el="28" ec="2" bec="0" bev="0" fileid="1" />
<SequencePoint vc="2" uspid="29" ordinal="14" sl="29" sc="1" el="29" ec="2" bec="0" bev="0" fileid="1" />
</SequencePoints>
<BranchPoints>
<BranchPoint vc="0" uspid="10" ordinal="1" path="1" offset="8" offsetend="35" sl="10" fileid="1" />
<BranchPoint vc="0" uspid="10" ordinal="2" path="2" offset="8" offsetend="44" sl="10" fileid="1" />
<BranchPoint vc="0" uspid="10" ordinal="3" path="3" offset="8" offsetend="53" sl="10" fileid="1" />
<BranchPoint vc="1" uspid="10" ordinal="4" path="4" offset="8" offsetend="62" sl="10" fileid="1" />
<BranchPoint vc="1" uspid="10" ordinal="5" path="5" offset="8" offsetend="71" sl="10" fileid="1" />
<BranchPoint vc="2" uspid="10" ordinal="0" path="0" offset="8" offsetend="80" sl="10" fileid="1" />
</BranchPoints>
<MethodPoint vc="9" uspid="0" p8:type="SequencePoint" ordinal="0" offset="0" sc="0" sl="8" ec="1" el="29" bec="0" bev="0" fileid="1" xmlns:p8="xsi" />
</Method>
</Methods>
</Class>
</Classes>
</Module>
</Modules>
</CoverageSession>
31 changes: 31 additions & 0 deletions src/test/resources/io/jenkins/plugins/opencover/testsourcefiles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

namespace ClassLibrary
{
public static class LibraryClass
{
public static int Sum(int number1, int number2)
{
int sum = number1 + number2;
switch (sum)
{
case 0:
Console.WriteLine(sum);
break;
case 1:
Console.WriteLine(sum);
break;
case 2:
Console.WriteLine(sum);
break;
case 3:
Console.WriteLine(sum);
break;
case 4:
Console.WriteLine(sum);
break;
}
return sum;
}
}
}

0 comments on commit 28aedb1

Please sign in to comment.