diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/source/SourceViewModel/index.properties b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/source/SourceViewModel/index.properties
index be06b04d5..6f7147695 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/source/SourceViewModel/index.properties
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/source/SourceViewModel/index.properties
@@ -1,8 +1,8 @@
reason.1=\
- You did not enable storing of source files (see parameter 'sourceFiles').
+ You did not enable storing of source files (see parameter 'sourceCodeRetention').
reason.2=\
- Code Coverage API plugin did not find the source files.
+ Code Coverage plugin did not find the source files.
reason.3=\
You do not have sufficient permissions to view source files.
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-criticality.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-criticality.html
index e2322e414..5eb583672 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-criticality.html
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-criticality.html
@@ -11,7 +11,7 @@
FAILURE
- Fail the build if the quality gate has been missed.
+ Fail the step if the quality gate has been missed.
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-failOnError.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-failOnError.html
index c5deb289f..ee8c20f36 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-failOnError.html
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageRecorder/help-failOnError.html
@@ -1,6 +1,6 @@
- This toggle determines if the coverage plugin should fail the build whenever an error occurred during processing
+ This toggle determines if the coverage plugin should fail the step whenever an error occurred during processing
of the coverage results. Several errors might occur: file pattern matches no files, source files
could not be copied, etc. By default, these errors are logged in a separate view but the build status will
- not be altered. If you would rather like to fail the build on such errors, please tick this checkbox.
+ not be altered. If you would rather like to fail the step on such errors, please tick this checkbox.
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-failOnError.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-failOnError.html
index c5deb289f..ee8c20f36 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-failOnError.html
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageStep/help-failOnError.html
@@ -1,6 +1,6 @@
- This toggle determines if the coverage plugin should fail the build whenever an error occurred during processing
+ This toggle determines if the coverage plugin should fail the step whenever an error occurred during processing
of the coverage results. Several errors might occur: file pattern matches no files, source files
could not be copied, etc. By default, these errors are logged in a separate view but the build status will
- not be altered. If you would rather like to fail the build on such errors, please tick this checkbox.
+ not be altered. If you would rather like to fail the step on such errors, please tick this checkbox.
diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties
index 7ac7b2960..0beb594c7 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties
+++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/Messages.properties
@@ -16,7 +16,7 @@ Change_Coverage_Type=Change Coverage
Change_Coverage_Delta_Type=Change Coverage Delta
Indirect_Coverage_Changes_Type=Indirect Coverage Changes
-QualityGate.Failure=Fail the build if the quality gate has been missed
+QualityGate.Failure=Fail the step if the quality gate has been missed
QualityGate.Unstable=Set the build status to unstable if the quality gate has been missed
Column.File=File
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java
index b757075fe..bb7ffd164 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeFacadeTest.java
@@ -59,7 +59,7 @@ private SourceCodeFacade createSourceCodeFacade() {
}
private FileNode createFileCoverageNode() {
- FileNode file = new FileNode("");
+ FileNode file = new FileNode("", "path");
List lines = Arrays.asList(10, 11, 12, 16, 17, 18, 19);
for (Integer line : lines) {
file.addModifiedLines(line);
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java
index b8b5492e2..0dd78efa6 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java
@@ -2,14 +2,17 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import edu.hm.hafner.coverage.Coverage.CoverageBuilder;
+import edu.hm.hafner.coverage.FileNode;
import edu.hm.hafner.coverage.Metric;
import edu.hm.hafner.coverage.Node;
+import edu.hm.hafner.util.PathUtil;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
@@ -45,6 +48,7 @@ abstract class SourceCodeITest extends AbstractCoverageITest {
static final String PATH_UTIL_PACKAGE_PATH = "edu/hm/hafner/util/";
private static final String PATH_UTIL_SOURCE_FILE_PATH = PATH_UTIL_PACKAGE_PATH + PATH_UTIL_FILE_NAME;
static final String AGENT_LABEL = "coverage-agent";
+ private static final PathUtil UTIL = new PathUtil();
/** Verifies that the plugin reads source code from the workspace root. */
@Test
@@ -76,7 +80,8 @@ void coveragePluginPipelineNotRegisteredSourceCodeDirectory() throws IOException
String sourceDirectory = createExternalFolder();
WorkflowJob job = createPipeline();
- copySourceFileToAgent("ignore/", localAgent, job);
+ var subFolder = "ignore/";
+ copySourceFileToAgent(subFolder, localAgent, job);
copyReports(localAgent, job);
job.setDefinition(createPipelineWithSourceCode(EVERY_BUILD, sourceDirectory));
@@ -84,22 +89,23 @@ void coveragePluginPipelineNotRegisteredSourceCodeDirectory() throws IOException
Run, ?> firstBuild = buildSuccessfully(job);
assertThat(getConsoleLog(firstBuild))
+ .contains("-> finished resolving of absolute paths (found: 0, not found: 1)")
.contains("-> finished painting (0 files have been painted, 1 files failed)")
.contains(String.format(
"[-ERROR-] Removing source directory '%s' - it has not been approved in Jenkins' global configuration.",
sourceDirectory));
- verifySourceCodeInBuild(firstBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
+ verifySourceCodeInBuild("", firstBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
localAgent.setLabelString("");
}
- private Run, ?> runCoverageWithSourceCode(final String sourceDirectory)
+ private Run, ?> runCoverageWithSourceCode(final String sourceDir)
throws IOException {
var localAgent = crateCoverageAgent();
WorkflowJob job = createPipeline();
copyReports(localAgent, job);
- copySourceFileToAgent(sourceDirectory, localAgent, job);
+ copySourceFileToAgent(sourceDir, localAgent, job);
// get the temporary directory - used by unit tests - to verify its content
File temporaryDirectory = new File(System.getProperty("java.io.tmpdir"));
@@ -107,28 +113,29 @@ void coveragePluginPipelineNotRegisteredSourceCodeDirectory() throws IOException
assertThat(temporaryDirectory.isDirectory()).isTrue();
File[] temporaryFiles = temporaryDirectory.listFiles();
- job.setDefinition(createPipelineWithSourceCode(EVERY_BUILD, sourceDirectory));
+ job.setDefinition(createPipelineWithSourceCode(EVERY_BUILD, sourceDir));
Run, ?> firstBuild = buildSuccessfully(job);
assertThat(getConsoleLog(firstBuild))
+ .contains("-> resolved absolute paths for all 1 source files")
.contains("-> finished painting successfully");
- verifySourceCodeInBuild(firstBuild, ACU_COBOL_PARSER, PATH_UTIL);
+ verifySourceCodeInBuild(sourceDir, firstBuild, ACU_COBOL_PARSER, PATH_UTIL);
Run, ?> secondBuild = buildSuccessfully(job);
- verifySourceCodeInBuild(secondBuild, ACU_COBOL_PARSER, PATH_UTIL);
- verifySourceCodeInBuild(firstBuild, ACU_COBOL_PARSER, PATH_UTIL); // should be still available
+ verifySourceCodeInBuild(sourceDir, secondBuild, ACU_COBOL_PARSER, PATH_UTIL);
+ verifySourceCodeInBuild(sourceDir, firstBuild, ACU_COBOL_PARSER, PATH_UTIL); // should be still available
- job.setDefinition(createPipelineWithSourceCode(LAST_BUILD, sourceDirectory));
+ job.setDefinition(createPipelineWithSourceCode(LAST_BUILD, sourceDir));
Run, ?> thirdBuild = buildSuccessfully(job);
- verifySourceCodeInBuild(thirdBuild, ACU_COBOL_PARSER, PATH_UTIL);
- verifySourceCodeInBuild(firstBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
- verifySourceCodeInBuild(secondBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
+ verifySourceCodeInBuild(sourceDir, thirdBuild, ACU_COBOL_PARSER, PATH_UTIL);
+ verifySourceCodeInBuild(sourceDir, firstBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
+ verifySourceCodeInBuild(sourceDir, secondBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
- job.setDefinition(createPipelineWithSourceCode(NEVER, sourceDirectory));
+ job.setDefinition(createPipelineWithSourceCode(NEVER, sourceDir));
Run, ?> lastBuild = buildSuccessfully(job);
- verifySourceCodeInBuild(lastBuild, NO_SOURCE_CODE, NO_SOURCE_CODE);
- verifySourceCodeInBuild(firstBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
- verifySourceCodeInBuild(secondBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
- verifySourceCodeInBuild(thirdBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
+ verifySourceCodeInBuild(sourceDir, lastBuild, NO_SOURCE_CODE, NO_SOURCE_CODE);
+ verifySourceCodeInBuild(sourceDir, firstBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
+ verifySourceCodeInBuild(sourceDir, secondBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
+ verifySourceCodeInBuild(sourceDir, thirdBuild, NO_SOURCE_CODE, NO_SOURCE_CODE); // should be still available
assertThat(temporaryDirectory.listFiles()).isEqualTo(temporaryFiles);
@@ -157,31 +164,37 @@ private CpsFlowDefinition createPipelineWithSourceCode(final SourceCodeRetention
+ "}", true);
}
- private void verifySourceCodeInBuild(final Run, ?> build, final String acuCobolParserSourceCodeSnippet,
+ private void verifySourceCodeInBuild(final String pathPrefix, final Run, ?> build, final String acuCobolParserSourceCodeSnippet,
final String pathUtilSourceCodeSnippet) {
List actions = build.getActions(CoverageBuildAction.class);
var builder = new CoverageBuilder().setMetric(Metric.LINE).setMissed(0);
assertThat(actions).hasSize(2).satisfiesExactly(
action -> {
assertThat(action.getAllValues(Baseline.PROJECT)).contains(builder.setCovered(8).build());
- Optional fileNode = action.getResult().find(Metric.FILE, ACU_COBOL_PARSER_SOURCE_FILE_PATH);
- assertThat(fileNode).isNotEmpty()
- .hasValueSatisfying(node -> assertThat(node.getPath()).isEqualTo(
- ACU_COBOL_PARSER_SOURCE_FILE_PATH));
- assertThat(action.getTarget().getSourceCode(String.valueOf(ACU_COBOL_PARSER_SOURCE_FILE_PATH.hashCode()), "coverage-table"))
+ var relativePath = getRelativePath(pathPrefix, ACU_COBOL_PARSER_SOURCE_FILE_PATH);
+ Optional fileNode = action.getResult().find(Metric.FILE, relativePath);
+ assertThat(fileNode).isNotEmpty().get()
+ .isInstanceOfSatisfying(FileNode.class,
+ node -> assertThat(node.getRelativePath()).isEqualTo(relativePath));
+ assertThat(action.getTarget().getSourceCode(String.valueOf(relativePath.hashCode()), "coverage-table"))
.contains(acuCobolParserSourceCodeSnippet);
},
action -> {
assertThat(action.getAllValues(Baseline.PROJECT)).contains(builder.setCovered(43).build());
- Optional fileNode = action.getResult().find(Metric.FILE, PATH_UTIL_SOURCE_FILE_PATH);
- assertThat(fileNode).isNotEmpty()
- .hasValueSatisfying(node -> assertThat(node.getPath()).isEqualTo(
- PATH_UTIL_SOURCE_FILE_PATH));
- assertThat(action.getTarget().getSourceCode(String.valueOf(PATH_UTIL_SOURCE_FILE_PATH.hashCode()), "coverage-table"))
+ var relativePath = getRelativePath(pathPrefix, PATH_UTIL_SOURCE_FILE_PATH);
+ Optional fileNode = action.getResult().find(Metric.FILE, relativePath);
+ assertThat(fileNode).isNotEmpty().get()
+ .isInstanceOfSatisfying(FileNode.class,
+ node -> assertThat(node.getRelativePath()).isEqualTo(relativePath));
+ assertThat(action.getTarget().getSourceCode(String.valueOf(relativePath.hashCode()), "coverage-table"))
.contains(pathUtilSourceCodeSnippet);
});
}
+ private String getRelativePath(final String path, final String filePath) {
+ return UTIL.getRelativePath(Paths.get(path, filePath));
+ }
+
String createDestinationPath(final String sourceDirectory, final String packagePath, final String fileName) {
if (sourceDirectory.isEmpty()) {
return packagePath + fileName;
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CodeDeltaCalculatorTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CodeDeltaCalculatorTest.java
index 7a92e596a..1c8724ede 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CodeDeltaCalculatorTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CodeDeltaCalculatorTest.java
@@ -118,7 +118,7 @@ void shouldNotMapScmChangesWithAmbiguousPaths() throws IllegalStateException {
Node tree = mock(Node.class);
FileNode file1 = mock(FileNode.class);
- when(file1.getPath()).thenReturn(path);
+ when(file1.getRelativePath()).thenReturn(path);
when(tree.getAllFileNodes()).thenReturn(List.of(file1));
when(tree.getFiles()).thenReturn(Set.of(path));
@@ -150,8 +150,8 @@ void shouldNotCreateOldPathMappingWithMissingReferenceNodes() throws IllegalStat
CodeDeltaCalculator codeDeltaCalculator = createCodeDeltaCalculator();
FilteredLog log = createFilteredLog();
- Node tree = new FileNode(REPORT_PATH_RENAME);
- Node referenceTree = new FileNode(REPORT_PATH_MODIFY);
+ Node tree = new FileNode("Test_Renamed.java", REPORT_PATH_RENAME);
+ Node referenceTree = new FileNode("Test.java", REPORT_PATH_MODIFY);
Map changes = new HashMap<>();
changes.put(REPORT_PATH_RENAME, createFileChanges(SCM_PATH_RENAME, OLD_SCM_PATH_RENAME, FileEditType.RENAME));
@@ -257,16 +257,16 @@ private FileChanges createFileChanges(final String filePath, final String oldFil
*/
private Node createStubbedCoverageTree() {
FileNode addFile1 = mock(FileNode.class);
- when(addFile1.getPath()).thenReturn(REPORT_PATH_ADD_1);
+ when(addFile1.getRelativePath()).thenReturn(REPORT_PATH_ADD_1);
FileNode addFile2 = mock(FileNode.class);
- when(addFile2.getPath()).thenReturn(REPORT_PATH_ADD_2);
+ when(addFile2.getRelativePath()).thenReturn(REPORT_PATH_ADD_2);
FileNode modifyFile = mock(FileNode.class);
- when(modifyFile.getPath()).thenReturn(REPORT_PATH_MODIFY);
+ when(modifyFile.getRelativePath()).thenReturn(REPORT_PATH_MODIFY);
FileNode renameFile = mock(FileNode.class);
- when(renameFile.getPath()).thenReturn(REPORT_PATH_RENAME);
+ when(renameFile.getRelativePath()).thenReturn(REPORT_PATH_RENAME);
Node root = mock(Node.class);
when(root.getAllFileNodes()).thenReturn(Arrays.asList(addFile1, addFile2, modifyFile, renameFile));
- var files = root.getAllFileNodes().stream().map(FileNode::getPath).collect(Collectors.toSet());
+ var files = root.getAllFileNodes().stream().map(FileNode::getRelativePath).collect(Collectors.toSet());
when(root.getFiles()).thenReturn(files);
return root;
@@ -280,12 +280,12 @@ private Node createStubbedCoverageTree() {
*/
private Node createStubbedReferenceCoverageTree() {
FileNode modifyFile = mock(FileNode.class);
- when(modifyFile.getPath()).thenReturn(REPORT_PATH_MODIFY);
+ when(modifyFile.getRelativePath()).thenReturn(REPORT_PATH_MODIFY);
FileNode renameFile = mock(FileNode.class);
- when(renameFile.getPath()).thenReturn(OLD_REPORT_PATH_RENAME);
+ when(renameFile.getRelativePath()).thenReturn(OLD_REPORT_PATH_RENAME);
Node root = mock(Node.class);
when(root.getAllFileNodes()).thenReturn(Arrays.asList(renameFile, modifyFile));
- var files = root.getAllFileNodes().stream().map(FileNode::getPath).collect(Collectors.toSet());
+ var files = root.getAllFileNodes().stream().map(FileNode::getRelativePath).collect(Collectors.toSet());
when(root.getFiles()).thenReturn(files);
return root;
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java
index 1c2d3b276..bf3eb96c3 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java
@@ -151,8 +151,8 @@ private static void verifyJaCoCoAction(final CoverageBuildAction coverageResult)
Metric.BRANCH,
Metric.INSTRUCTION,
Metric.COMPLEXITY,
- Metric.COMPLEXITY_DENSITY,
Metric.COMPLEXITY_MAXIMUM,
+ Metric.COMPLEXITY_DENSITY,
Metric.LOC);
assertThat(coverageResult.getMetricsForSummary())
.containsExactly(Metric.LINE, Metric.BRANCH, Metric.MUTATION, Metric.COMPLEXITY_DENSITY, Metric.LOC);
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java
index 6c9cdfa2f..09713a91e 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModelTest.java
@@ -78,7 +78,7 @@ void shouldProvideIndirectCoverageChanges() {
private Node createIndirectCoverageChangesNode() {
var root = new ModuleNode("root");
for (int file = 0; file < 5; file++) {
- var fileNode = new FileNode("File-" + file);
+ var fileNode = new FileNode("File-" + file, "path");
for (int line = 0; line < 2; line++) {
fileNode.addCounters(10 + line, 1, 1);
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java
index 23d4e14e5..804cdf547 100644
--- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageXmlStreamTest.java
@@ -112,8 +112,8 @@ void shouldStoreActionCompactly() throws IOException {
"BRANCH: 109/116",
"INSTRUCTION: 1260/1350",
"COMPLEXITY: 160",
- "COMPLEXITY_DENSITY: 160/323",
"COMPLEXITY_MAXIMUM: 6",
+ "COMPLEXITY_DENSITY: 160/323",
"LOC: 323");
assertThat(Input.from(saved)).nodesByXPath("//" + ACTION_QUALIFIED_NAME + "/projectValues/coverage")
@@ -130,11 +130,11 @@ void shouldStoreActionCompactly() throws IOException {
var action = file.read();
assertThat(action).isNotNull().isInstanceOfSatisfying(CoverageBuildAction.class, a ->
Assertions.assertThat(serializeValues(a))
- .containsExactly("MODULE: 1/1",
- "PACKAGE: 1/1", "FILE: 7/10", "CLASS: 15/18",
- "METHOD: 97/102", "LINE: 294/323", "BRANCH: 109/116",
- "INSTRUCTION: 1260/1350", "COMPLEXITY: 160",
- "COMPLEXITY_DENSITY: 160/323", "COMPLEXITY_MAXIMUM: 6", "LOC: 323"
+ .containsExactly("MODULE: 1/1", "PACKAGE: 1/1", "FILE: 7/10", "CLASS: 15/18",
+ "METHOD: 97/102",
+ "LINE: 294/323", "BRANCH: 109/116", "INSTRUCTION: 1260/1350",
+ "COMPLEXITY: 160", "COMPLEXITY_MAXIMUM: 6", "COMPLEXITY_DENSITY: 160/323",
+ "LOC: 323"
));
}
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/PathResolverTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/PathResolverTest.java
new file mode 100644
index 000000000..1876e1d88
--- /dev/null
+++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/PathResolverTest.java
@@ -0,0 +1,35 @@
+package io.jenkins.plugins.coverage.metrics.steps;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+import io.jenkins.plugins.coverage.metrics.steps.PathResolver.RemoteResultWrapper;
+
+import static org.assertj.core.api.Assertions.*;
+
+class PathResolverTest {
+ @Nested
+ class RemoteResultWrapperTest {
+ @Test
+ void shouldCreateWrapper() {
+ var result = "result";
+
+ var wrapper = new RemoteResultWrapper<>(result, "title");
+
+ assertThat(wrapper.getResult()).isEqualTo(result);
+
+ wrapper.logInfo("Hello %s", "World");
+ assertThat(wrapper.getInfoMessages()).containsExactly("Hello World");
+ }
+
+ @Test
+ void shouldAdhereToEquals() {
+ EqualsVerifier.simple().forClass(RemoteResultWrapper.class)
+ .suppress(Warning.NULL_FIELDS)
+ .verify();
+ }
+ }
+}
diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result
index 896556689..f89d9824e 100644
--- a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result
+++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/steps/coverage-publisher-summary.checks-expected-result
@@ -1,5 +1,6 @@
-Modified lines summary:
-- 1 line has been modified
+#### Summary for modified lines
+
+- 3 lines have been modified
- 1 line is not covered
- 1 line is covered only partially