diff --git a/README.md b/README.md index bea038c3d..02790f8f8 100644 --- a/README.md +++ b/README.md @@ -184,12 +184,12 @@ Examples: ## Remote API -We provide a remote API to retrieve coverage data, using the following URL: `https://[jenkins-url]/job/[job-name]/[build-number]/coverage/api/json?pretty=true`. +We provide a remote API to retrieve a coverage overview, using the following URL: `https://[jenkins-url]/job/[job-name]/[build-number]/coverage/api/json?pretty=true`. Example output: ```json { - "_class" : "io.jenkins.plugins.coverage.metrics.steps.CoverageApi", + "_class" : "io.jenkins.plugins.coverage.metrics.restapi.CoverageApi", "modifiedFilesDelta" : { "branch" : "+1.72%", "class" : "-3.54%", @@ -278,3 +278,34 @@ Example output: "referenceBuild" : "coverage-model-history #10" } ``` + +More concrete, the line coverage for modified code lines is provided per modified file, using the following URL: `https://[jenkins-url]/job/[job-name]/[build-number]/coverage/modified/api/json?pretty=true`. + +Example output: +```json +{ + "_class": "io.jenkins.plugins.coverage.metrics.restapi.ModifiedLinesCoverageApi", + "files": [ + { + "fullyQualifiedFileName": "io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApi.java", + "modifiedLinesBlocks": [ + { + "startLine": 30, + "endLine": 35, + "type": "MISSED" + } + ] + }, + { + "fullyQualifiedFileName": "io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlocks.java", + "modifiedLinesBlocks": [ + { + "startLine": 80, + "endLine": 81, + "type": "COVERED" + } + ] + } + ] +} +``` diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageApi.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi.java similarity index 88% rename from plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageApi.java rename to plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi.java index 19e5a72a9..7b6fd733f 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageApi.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi.java @@ -1,4 +1,4 @@ -package io.jenkins.plugins.coverage.metrics.steps; +package io.jenkins.plugins.coverage.metrics.restapi; import java.util.Collection; import java.util.Locale; @@ -30,7 +30,17 @@ public class CoverageApi { private final QualityGateResult qualityGateResult; private final String referenceBuild; - CoverageApi(final CoverageStatistics statistics, final QualityGateResult qualityGateResult, + /** + * Creates a new instance of {@link CoverageApi}. + * + * @param statistics + * the coverage statistics of the build. + * @param qualityGateResult + * the quality gate result of the build. + * @param referenceBuild + * the build referenced for comparison purposes. + */ + public CoverageApi(final CoverageStatistics statistics, final QualityGateResult qualityGateResult, final String referenceBuild) { this.statistics = statistics; this.qualityGateResult = qualityGateResult; @@ -136,7 +146,10 @@ public Result getOverallResult() { @Exported(inline = true) public Collection getResultItems() { - return qualityGateResult.getResultItems().stream().map(QualityGateItemApi::new).collect(Collectors.toList()); + return qualityGateResult.getResultItems() + .stream() + .map(QualityGateItemApi::new) + .collect(Collectors.toList()); } } diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/FileWithModifiedLines.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/FileWithModifiedLines.java new file mode 100644 index 000000000..5ab4925b1 --- /dev/null +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/FileWithModifiedLines.java @@ -0,0 +1,51 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import java.util.Objects; +import java.util.SortedSet; + +import org.kohsuke.stapler.export.Exported; +import org.kohsuke.stapler.export.ExportedBean; + +/** + * Model class that describes the {@link LineCoverageType coverage} for modified code lines of a file. The file is + * described by its fully qualified name. + */ +@ExportedBean +class FileWithModifiedLines { + private final String fullyQualifiedFileName; + private final SortedSet modifiedLinesBlocks; + + FileWithModifiedLines(final String fullyQualifiedFileName, + final SortedSet modifiedLinesBlocks) { + this.fullyQualifiedFileName = fullyQualifiedFileName; + this.modifiedLinesBlocks = modifiedLinesBlocks; + } + + @Exported(inline = true) + public String getFullyQualifiedFileName() { + return fullyQualifiedFileName; + } + + @Exported(inline = true) + public SortedSet getModifiedLinesBlocks() { + return modifiedLinesBlocks; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FileWithModifiedLines file = (FileWithModifiedLines) o; + return Objects.equals(this.getFullyQualifiedFileName(), file.getFullyQualifiedFileName()) + && Objects.equals(this.getModifiedLinesBlocks(), file.getModifiedLinesBlocks()); + } + + @Override + public int hashCode() { + return Objects.hash(getFullyQualifiedFileName(), getModifiedLinesBlocks()); + } +} diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/LineCoverageType.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/LineCoverageType.java new file mode 100644 index 000000000..233d4e50a --- /dev/null +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/LineCoverageType.java @@ -0,0 +1,10 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +/** + * Defines the type of line coverage. + */ +enum LineCoverageType { + COVERED, + MISSED, + PARTIALLY_COVERED +} diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlock.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlock.java new file mode 100644 index 000000000..0c006e308 --- /dev/null +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlock.java @@ -0,0 +1,63 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import java.util.Objects; + +import org.kohsuke.stapler.export.Exported; +import org.kohsuke.stapler.export.ExportedBean; + +/** + * Model class containing data pertaining to consecutive lines of modified code. Each object possesses a starting and + * ending line number and the type of coverage of the block. Each object is associated with a + * {@link FileWithModifiedLines} object. The class implements {@link Comparable} and is ordered by the start line. Empty + * lines and comments are also included in blocks. + */ +@ExportedBean +class ModifiedLinesBlock implements Comparable { + private final int startLine; + private final int endLine; + private final LineCoverageType type; + + ModifiedLinesBlock(final int startLine, final int endLine, final LineCoverageType type) { + this.startLine = startLine; + this.endLine = endLine; + this.type = type; + } + + @Exported + public int getStartLine() { + return startLine; + } + + @Exported + public int getEndLine() { + return endLine; + } + + @Exported + public LineCoverageType getType() { + return type; + } + + @Override + public int compareTo(final ModifiedLinesBlock other) { + return this.startLine - other.startLine; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ModifiedLinesBlock that = (ModifiedLinesBlock) o; + return getStartLine() == that.getStartLine() && getEndLine() == that.getEndLine() + && getType() == that.getType(); + } + + @Override + public int hashCode() { + return Objects.hash(getStartLine(), getEndLine(), getType()); + } +} diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApi.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApi.java new file mode 100644 index 000000000..836a85f41 --- /dev/null +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApi.java @@ -0,0 +1,147 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import edu.hm.hafner.coverage.FileNode; +import edu.hm.hafner.coverage.Node; + +import org.kohsuke.stapler.export.Exported; +import org.kohsuke.stapler.export.ExportedBean; + +/** + * Remote API to list the details of modified line coverage results. + */ +@ExportedBean +class ModifiedLinesCoverageApi { + private final List filesWithModifiedLines; + + ModifiedLinesCoverageApi(final Node node) { + this.filesWithModifiedLines = createListOfFilesWithModifiedLines(node); + } + + @Exported(inline = true, name = "files") + public List getFilesWithModifiedLines() { + return filesWithModifiedLines; + } + + /** + * Finds all files with modified lines of code in a passed {@link Node} object. + * + * @param node + * containing the file tree. + * + * @return a list of {@link FileWithModifiedLines} objects. + */ + private List createListOfFilesWithModifiedLines(final Node node) { + var result = new ArrayList(); + + for (FileNode fileNode : node.filterByModifiedLines().getAllFileNodes()) { + var modifiedLines = new ArrayList<>(fileNode.getModifiedLines()); + var modifiedLinesWithoutCoverage = modifiedLines.stream() + .filter(line -> !fileNode.getLinesWithCoverage().contains(line)) + .collect(Collectors.toList()); + + var missedLines = filterByModifiedLines(modifiedLines, fileNode.getMissedLines()); + var partiallyCoveredLines = + filterByModifiedLines(modifiedLines, fileNode.getPartiallyCoveredLines().keySet()); + var coveredLines = fileNode.getLinesWithCoverage().stream() + .filter(line -> fileNode.getMissedOfLine(line) == 0) + .filter(modifiedLines::contains) + .collect(Collectors.toList()); + + var modifiedLinesBlocks = new TreeSet(); + + modifiedLinesBlocks.addAll( + calculateModifiedLineBlocks(coveredLines, modifiedLinesWithoutCoverage, LineCoverageType.COVERED)); + modifiedLinesBlocks.addAll( + calculateModifiedLineBlocks(missedLines, modifiedLinesWithoutCoverage, LineCoverageType.MISSED)); + modifiedLinesBlocks.addAll(calculateModifiedLineBlocks(partiallyCoveredLines, modifiedLinesWithoutCoverage, + LineCoverageType.PARTIALLY_COVERED)); + + var changedFile = new FileWithModifiedLines(fileNode.getRelativePath(), modifiedLinesBlocks); + result.add(changedFile); + } + + return result; + } + + /** + * Filters the given lines to only contain the given modified lines. + * + * @param modifiedLines + * the lines that have been modified + * @param lines + * the lines that should be filtered for modified lines only + * + * @return the filtered lines + */ + private List filterByModifiedLines(final Collection modifiedLines, + final Collection lines) { + return lines.stream().filter(modifiedLines::contains).collect(Collectors.toList()); + } + + /** + * This method parses over the modified lines of a file and combines consecutive line numbers with the same coverage + * type into a {@link ModifiedLinesBlock} object. If there are empty lines without coverage information between + * lines with the same type, they will be included in the block. The result is sorted by the starting line number. + * + * @param modifiedLines + * list containing the integer numbers of modified lines. + * @param modifiedLinesWithoutCoverage + * lines that have been modified but have no coverage information + * @param type + * type of coverage pertaining to each line of code ({@link LineCoverageType#COVERED}, + * {@link LineCoverageType#MISSED}, or {@link LineCoverageType#PARTIALLY_COVERED}) + * + * @return the list of {@link ModifiedLinesBlock} + */ + private List calculateModifiedLineBlocks(final List modifiedLines, + final List modifiedLinesWithoutCoverage, final LineCoverageType type) { + var modifiedLinesBlocks = new ArrayList(); + if (modifiedLines.isEmpty()) { + return modifiedLinesBlocks; + } + + int start = modifiedLines.get(0); + int last = start; + if (modifiedLines.size() > 1) { + for (int line : modifiedLines.subList(1, modifiedLines.size())) { + if (line > last + 1 + && hasAnyLinesWithCoverageBetween(last, line, modifiedLinesWithoutCoverage)) { + var modifiedLinesBlock = new ModifiedLinesBlock(start, last, type); + modifiedLinesBlocks.add(modifiedLinesBlock); + start = line; + } + last = line; + } + } + var modifiedLinesBlock = new ModifiedLinesBlock(start, last, type); + modifiedLinesBlocks.add(modifiedLinesBlock); + + return modifiedLinesBlocks; + } + + /** + * Checks whether the range between the first and the second given line contains any lines with coverage + * information. + * + * @param start + * the first line number + * @param end + * the second line number (must be greater than the first) + * @param modifiedLinesWithoutCoverage + * the modified lines without coverage information + * + * @return {@code true} whether there are any lines within the given line range that contains coverage information, + * else {@code false} + */ + private boolean hasAnyLinesWithCoverageBetween(final int start, final int end, + final List modifiedLinesWithoutCoverage) { + return IntStream.range(start + 1, end).anyMatch(line -> !modifiedLinesWithoutCoverage.contains(line)); + } +} diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApiModel.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApiModel.java new file mode 100644 index 000000000..816b0ca9a --- /dev/null +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApiModel.java @@ -0,0 +1,43 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import edu.hm.hafner.coverage.Node; + +import hudson.model.Api; +import hudson.model.ModelObject; + +import io.jenkins.plugins.coverage.metrics.source.Messages; + +/** + * Server side model that provides the data for modified lines coverage results. + */ +public class ModifiedLinesCoverageApiModel implements ModelObject { + private final Node node; + + /** + * Creates a new instance of {@link ModifiedLinesCoverageApiModel}. + * + * @param node + * {@link Node} object + */ + public ModifiedLinesCoverageApiModel(final Node node) { + this.node = node; + } + + /** + * Gets the remote API for details of modified line coverage results. + * + * @return the remote API + */ + public Api getApi() { + return new Api(new ModifiedLinesCoverageApi(getNode())); + } + + public Node getNode() { + return node; + } + + @Override + public String getDisplayName() { + return Messages.Coverage_Title(getNode().getName()); + } +} diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java index 01b2b9698..ca510e9c4 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageViewModel.java @@ -43,6 +43,8 @@ import io.jenkins.plugins.coverage.metrics.color.CoverageColorJenkinsId; import io.jenkins.plugins.coverage.metrics.model.CoverageStatistics; import io.jenkins.plugins.coverage.metrics.model.ElementFormatter; +import io.jenkins.plugins.coverage.metrics.restapi.CoverageApi; +import io.jenkins.plugins.coverage.metrics.restapi.ModifiedLinesCoverageApiModel; import io.jenkins.plugins.coverage.metrics.source.SourceCodeFacade; import io.jenkins.plugins.coverage.metrics.source.SourceViewModel; import io.jenkins.plugins.coverage.metrics.steps.CoverageTableModel.InlineRowRenderer; @@ -71,9 +73,11 @@ public class CoverageViewModel extends DefaultAsyncTableContentProvider implemen static final String INDIRECT_COVERAGE_TABLE_ID = "indirect-coverage-table"; private static final String INLINE_SUFFIX = "-inline"; private static final String INFO_MESSAGES_VIEW_URL = "info"; + private static final String MODIFIED_LINES_API_URL = "modified"; private static final ElementFormatter FORMATTER = new ElementFormatter(); - private static final Set TREE_METRICS = Set.of(Metric.LINE, Metric.INSTRUCTION, Metric.BRANCH, Metric.MUTATION); + private static final Set TREE_METRICS = Set.of(Metric.LINE, Metric.INSTRUCTION, Metric.BRANCH, + Metric.MUTATION); private static final String UNDEFINED = "-"; private final Run owner; private final String optionalName; @@ -448,6 +452,9 @@ public boolean isSourceFileAvailable(final FileNode coverageNode) { @SuppressWarnings("unused") // Called by jelly view @CheckForNull public Object getDynamic(final String link, final StaplerRequest request, final StaplerResponse response) { + if (MODIFIED_LINES_API_URL.equals(link)) { + return new ModifiedLinesCoverageApiModel(node); + } if (INFO_MESSAGES_VIEW_URL.equals(link)) { return new MessagesViewModel(getOwner(), Messages.MessagesViewModel_Title(), log.getInfoMessages(), log.getErrorMessages()); diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi/_api.jelly b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi/_api.jelly new file mode 100644 index 000000000..7cf365965 --- /dev/null +++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi/_api.jelly @@ -0,0 +1,17 @@ + + + +

${%title}

+ +

${%description}

+ +
+
+ ${%modified.title} +
+
+ ${%modified.description} +
+
+ +
\ No newline at end of file diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi/_api.properties b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi/_api.properties new file mode 100644 index 000000000..c59acc381 --- /dev/null +++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/restapi/CoverageApi/_api.properties @@ -0,0 +1,7 @@ +title=Other useful URLs +description=If you are not only interested in the summary of the coverage result \ + you can obtain additional information by calling one of the following APIs. + +modified.title=Modified Lines Coverage +modified.description=The numbers of all modified code lines and their respective \ + line coverage sorted in consecutive line blocks per file. diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractModifiedFilesCoverageTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractModifiedFilesCoverageTest.java new file mode 100644 index 000000000..57e25c3c1 --- /dev/null +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractModifiedFilesCoverageTest.java @@ -0,0 +1,128 @@ +package io.jenkins.plugins.coverage.metrics; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeAll; + +import edu.hm.hafner.coverage.FileNode; +import edu.hm.hafner.coverage.Node; + +import io.jenkins.plugins.coverage.metrics.steps.FileChangesProcessor; +import io.jenkins.plugins.forensics.delta.Change; +import io.jenkins.plugins.forensics.delta.ChangeEditType; +import io.jenkins.plugins.forensics.delta.FileChanges; +import io.jenkins.plugins.forensics.delta.FileEditType; + +/** + * Provides a coverage tree that consists of {@link FileNode}s with modified code lines and corresponding coverage + * information. The test is based on the coverage reports 'file-changes-test-before.xml' and + * 'file-changes-test-after.xml'. + * + * @author Florian Orendi + */ +public abstract class AbstractModifiedFilesCoverageTest extends AbstractCoverageTest { + + private static final String TEST_FILE_MODIFIED = "Test1.java"; + private static final String TEST_FILE_NOT_MODIFIED = "Main.java"; + private static final String TEST_FILE_MODIFIED_PATH = "test/example/" + TEST_FILE_MODIFIED; + private static final String TEST_FILE_MODIFIED_PATH_OLD = "test/example/old/" + TEST_FILE_MODIFIED; + + /** + * A JaCoCo report which contains the code coverage of a test project before the {@link #CODE_CHANGES} has + * been inserted. + */ + private static final String TEST_REPORT_BEFORE = "file-changes-test-before.xml"; + /** + * A JaCoCo report which contains the code coverage of a test project after the {@link #CODE_CHANGES} has + * been inserted. + */ + private static final String TEST_REPORT_AFTER = "file-changes-test-after.xml"; + + /** + * The code changes that took place between the generation of {@link #TEST_REPORT_BEFORE} and + * {@link #TEST_REPORT_AFTER}. + */ + private static final Map CODE_CHANGES = new HashMap<>(); + + /** + * The mapping of the used paths between the generation of {@link #TEST_REPORT_BEFORE} and + * {@link #TEST_REPORT_AFTER}. + */ + private static final Map OLD_PATH_MAPPING = new HashMap<>(); + + /** + * Initializes a map with the inserted {@link #CODE_CHANGES}. + */ + @BeforeAll + static void initFileChanges() { + var insert1 = new Change(ChangeEditType.INSERT, 4, 4, 5, 9); + var insert2 = new Change(ChangeEditType.INSERT, 8, 8, 14, 18); + var insert3 = new Change(ChangeEditType.INSERT, 25, 25, 33, 36); + var replace = new Change(ChangeEditType.REPLACE, 10, 11, 20, 22); + var delete = new Change(ChangeEditType.DELETE, 16, 19, 26, 26); + var fileChanges = new FileChanges(TEST_FILE_MODIFIED_PATH, TEST_FILE_MODIFIED_PATH_OLD, + "test", FileEditType.RENAME, new HashMap<>()); + fileChanges.addChange(insert1); + fileChanges.addChange(insert2); + fileChanges.addChange(insert3); + fileChanges.addChange(replace); + fileChanges.addChange(delete); + CODE_CHANGES.put(TEST_FILE_MODIFIED_PATH, fileChanges); + CODE_CHANGES.put(TEST_FILE_NOT_MODIFIED, + new FileChanges("empty", "empty", "", FileEditType.MODIFY, new HashMap<>())); + OLD_PATH_MAPPING.put(TEST_FILE_MODIFIED_PATH, TEST_FILE_MODIFIED_PATH_OLD); + } + + /** + * Creates a coverage tree that consists of {@link FileNode}s with and without modified lines together with the + * corresponding coverage information. + * + * @return a Node tree with modified and unmodified mock data. + */ + protected Node createCoverageTree() { + var fileChangesProcessor = createFileChangesProcessor(); + var reference = readJacocoResult(TEST_REPORT_BEFORE); + var tree = readJacocoResult(TEST_REPORT_AFTER); + fileChangesProcessor.attachChangedCodeLines(tree, CODE_CHANGES); + fileChangesProcessor.attachFileCoverageDeltas(tree, reference, OLD_PATH_MAPPING); + fileChangesProcessor.attachIndirectCoveragesChanges(tree, reference, CODE_CHANGES, OLD_PATH_MAPPING); + return tree; + } + + /** + * Gets the name of the test file with modified lines. + * + * @return the name of a file with modified code lines. + */ + protected String getNameOfFileWithModifiedLines() { + return TEST_FILE_MODIFIED; + } + + /** + * Gets the path of the test file with modified lines. + * + * @return the relative path of a modified test file. + */ + protected String getPathOfFileWithModifiedLines() { + return TEST_FILE_MODIFIED_PATH; + } + + /** + * Gets the name of the test file without modified lines. + * + * @return the name of a file with no modified code lines. + */ + protected String getNameOfFileWithoutModifiedLines() { + return TEST_FILE_NOT_MODIFIED; + } + + /** + * Creates an instance of {@link FileChangesProcessor}. + * + * @return the created instance + */ + private FileChangesProcessor createFileChangesProcessor() { + return new FileChangesProcessor(); + } +} diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageApiITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/CoverageApiITest.java similarity index 89% rename from plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageApiITest.java rename to plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/CoverageApiITest.java index 9de7d7fca..faa1a068a 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageApiITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/CoverageApiITest.java @@ -1,4 +1,4 @@ -package io.jenkins.plugins.coverage.metrics.steps; +package io.jenkins.plugins.coverage.metrics.restapi; import java.util.List; @@ -14,6 +14,8 @@ import io.jenkins.plugins.coverage.metrics.AbstractCoverageITest; import io.jenkins.plugins.coverage.metrics.model.Baseline; +import io.jenkins.plugins.coverage.metrics.steps.CoverageQualityGate; +import io.jenkins.plugins.coverage.metrics.steps.CoverageRecorder; import io.jenkins.plugins.coverage.metrics.steps.CoverageTool.Parser; import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; @@ -54,8 +56,12 @@ void shouldProvideRemoteApi() { @Test void shouldShowQualityGatesInRemoteApi() { - var qualityGates = List.of(new CoverageQualityGate(100, Metric.LINE, Baseline.PROJECT, QualityGateCriticality.UNSTABLE)); - FreeStyleProject project = createFreestyleJob(Parser.JACOCO, r -> r.setQualityGates(qualityGates), JACOCO_ANALYSIS_MODEL_FILE); + var qualityGate = new CoverageQualityGate(100, Metric.LINE); + qualityGate.setBaseline(Baseline.PROJECT); + qualityGate.setCriticality(QualityGateCriticality.UNSTABLE); + var qualityGates = List.of(qualityGate); + FreeStyleProject project = createFreestyleJob(Parser.JACOCO, r -> r.setQualityGates(qualityGates), + JACOCO_ANALYSIS_MODEL_FILE); Run build = buildWithResult(project, Result.UNSTABLE); diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/FileWithModifiedLinesTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/FileWithModifiedLinesTest.java new file mode 100644 index 000000000..f19d04eb1 --- /dev/null +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/FileWithModifiedLinesTest.java @@ -0,0 +1,15 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +/** + * Tests {@link FileWithModifiedLines}. + */ +class FileWithModifiedLinesTest { + @Test + void shouldObeyEqualsContract() { + EqualsVerifier.forClass(FileWithModifiedLines.class).usingGetClass().verify(); + } +} diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlockTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlockTest.java new file mode 100644 index 000000000..4cbcb3f41 --- /dev/null +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesBlockTest.java @@ -0,0 +1,36 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +import static org.assertj.core.api.Assertions.*; + +/** + * Tests {@link ModifiedLinesBlock}. + */ +class ModifiedLinesBlockTest { + @Test + void testGetters() { + var linesBlockOne = new ModifiedLinesBlock(0, 0, LineCoverageType.COVERED); + var linesBlockTwo = new ModifiedLinesBlock(0, 0, LineCoverageType.MISSED); + var linesBlockThree = new ModifiedLinesBlock(0, 0, LineCoverageType.PARTIALLY_COVERED); + + var startOne = linesBlockOne.getStartLine(); + var endOne = linesBlockOne.getEndLine(); + var typeOne = linesBlockOne.getType(); + var typeTwo = linesBlockTwo.getType(); + var typeThree = linesBlockThree.getType(); + + assertThat(startOne).isEqualTo(0); + assertThat(endOne).isEqualTo(0); + assertThat(typeOne).isEqualTo(LineCoverageType.COVERED); + assertThat(typeTwo).isEqualTo(LineCoverageType.MISSED); + assertThat(typeThree).isEqualTo(LineCoverageType.PARTIALLY_COVERED); + } + + @Test + void shouldObeyEqualsContract() { + EqualsVerifier.forClass(ModifiedLinesBlock.class).usingGetClass().verify(); + } +} diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApiTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApiTest.java new file mode 100644 index 000000000..9dd18b29f --- /dev/null +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/restapi/ModifiedLinesCoverageApiTest.java @@ -0,0 +1,94 @@ +package io.jenkins.plugins.coverage.metrics.restapi; + +import java.util.SortedSet; +import java.util.TreeSet; + +import org.junit.jupiter.api.Test; + +import edu.hm.hafner.coverage.FileNode; +import edu.hm.hafner.coverage.PackageNode; +import edu.hm.hafner.util.LineRange; + +import io.jenkins.plugins.coverage.metrics.AbstractModifiedFilesCoverageTest; + +import static org.assertj.core.api.Assertions.*; + +/** + * Tests {@link ModifiedLinesCoverageApi}. + */ + +class ModifiedLinesCoverageApiTest extends AbstractModifiedFilesCoverageTest { + + /** + * Test to assert that all modified lines and their respective coverage types are correctly extracted from the + * coverage tree created by the {@link #createCoverageTree()} method. + */ + @Test + void shouldCalculateCoverageForAllModifiedLines() { + var node = createCoverageTree(); + var modifiedLineCoverageApi = new ModifiedLinesCoverageApi(node); + var filesWithChangedLines = modifiedLineCoverageApi.getFilesWithModifiedLines(); + + var expectedLineBlocks = createListOfModifiedLines(LineCoverageType.COVERED, + new LineRange(15, 16), new LineRange(21, 22)); + expectedLineBlocks.addAll(createListOfModifiedLines(LineCoverageType.MISSED, new LineRange(35, 36))); + expectedLineBlocks.addAll(createListOfModifiedLines(LineCoverageType.PARTIALLY_COVERED, new LineRange(20, 20))); + var expectedFileWithChangedLines = new FileWithModifiedLines("test/example/Test1.java", expectedLineBlocks); + + assertThat(filesWithChangedLines).containsExactly(expectedFileWithChangedLines); + + } + + @Test + void shouldIncludeLinesWithoutCoverage() { + var fileNode = new FileNode("Test.java", "path"); + fileNode.addModifiedLines(1, 2, 3, 4); + fileNode.addCounters(1, 1, 0); + fileNode.addCounters(4, 1, 0); + var parentNode = new PackageNode("package"); + parentNode.addChild(fileNode); + var expectedBlocks = createListOfModifiedLines(LineCoverageType.COVERED, new LineRange(1, 4)); + + var filesWithModifiedLines = new ModifiedLinesCoverageApi(parentNode).getFilesWithModifiedLines(); + + assertThat(filesWithModifiedLines.get(0).getModifiedLinesBlocks()).containsOnlyOnceElementsOf(expectedBlocks); + } + + @Test + void shouldIgnoreNotModifiedLines() { + var fileNode = new FileNode("Test.java", "path"); + fileNode.addModifiedLines(1); + fileNode.addCounters(1, 1, 0); + fileNode.addCounters(2, 1, 0); + var parentNode = new PackageNode("package"); + parentNode.addChild(fileNode); + var expectedBlocks = createListOfModifiedLines(LineCoverageType.COVERED, new LineRange(1)); + + var filesWithModifiedLines = new ModifiedLinesCoverageApi(parentNode).getFilesWithModifiedLines(); + + assertThat(filesWithModifiedLines.get(0).getModifiedLinesBlocks()).containsOnlyOnceElementsOf(expectedBlocks); + } + + /** + * Creates a list of {@link ModifiedLinesBlock} objects for testing purposes. + * + * @param type + * of line coverage: {@link LineCoverageType#COVERED}, {@link LineCoverageType#MISSED}, or + * {@link LineCoverageType#PARTIALLY_COVERED} + * @param ranges + * the {@link LineRange lines ranges} to be transformed to {@link ModifiedLinesBlock} elements with the + * given coverage type + * + * @return the list {@link ModifiedLinesBlock} objects, sharing a {@link LineCoverageType}. + */ + private SortedSet createListOfModifiedLines(final LineCoverageType type, + final LineRange... ranges) { + var modifiedLinesBlocks = new TreeSet(); + for (LineRange range : ranges) { + var block = new ModifiedLinesBlock(range.getStart(), range.getEnd(), type); + modifiedLinesBlocks.add(block); + } + return modifiedLinesBlocks; + } + +} diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java index 7e22face9..ce21ae9d0 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java @@ -65,14 +65,17 @@ void shouldSelectResultByIdInReferenceBuild() { // Create a build with two different actions setPipelineScript(job, - "recordCoverage tools: [[parser: '" + Parser.PIT.name() + "', pattern: '**/mutations*.xml']], id: 'pit'\n" - + "recordCoverage tools: [[parser: '" + Parser.JACOCO.name() + "', pattern: '**/jacoco*xml']]\n"); + "recordCoverage tools: [[parser: '" + Parser.PIT.name() + + "', pattern: '**/mutations*.xml']], id: 'pit'\n" + + "recordCoverage tools: [[parser: '" + Parser.JACOCO.name() + + "', pattern: '**/jacoco*xml']]\n"); Run firstBuild = buildSuccessfully(job); setPipelineScript(job, - "recordCoverage tools: [[parser: '" + Parser.PIT.name() + "', pattern: '**/mutations.xml']], id: 'pit'\n" - + "recordCoverage tools: [[parser: 'JACOCO', pattern: '" + JACOCO_CODING_STYLE_FILE + "']]"); + "recordCoverage tools: [[parser: '" + Parser.PIT.name() + + "', pattern: '**/mutations.xml']], id: 'pit'\n" + + "recordCoverage tools: [[parser: 'JACOCO', pattern: '" + JACOCO_CODING_STYLE_FILE + "']]"); Run secondBuild = buildSuccessfully(job); var actions = secondBuild.getActions(CoverageBuildAction.class); diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java index ebdc5352e..6c9e280fb 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/FileChangesProcessorTest.java @@ -1,22 +1,14 @@ package io.jenkins.plugins.coverage.metrics.steps; import java.util.AbstractMap.SimpleEntry; -import java.util.HashMap; -import java.util.Map; import org.apache.commons.lang3.math.Fraction; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import edu.hm.hafner.coverage.FileNode; import edu.hm.hafner.coverage.Metric; -import edu.hm.hafner.coverage.Node; -import io.jenkins.plugins.coverage.metrics.AbstractCoverageTest; -import io.jenkins.plugins.forensics.delta.Change; -import io.jenkins.plugins.forensics.delta.ChangeEditType; -import io.jenkins.plugins.forensics.delta.FileChanges; -import io.jenkins.plugins.forensics.delta.FileEditType; +import io.jenkins.plugins.coverage.metrics.AbstractModifiedFilesCoverageTest; import static org.assertj.core.api.Assertions.*; @@ -25,85 +17,30 @@ * * @author Florian Orendi */ -class FileChangesProcessorTest extends AbstractCoverageTest { - private static final String TEST_FILE_1 = "Test1.java"; - private static final String TEST_FILE_2 = "Main.java"; - private static final String TEST_FILE_1_PATH = "test/example/" + TEST_FILE_1; - private static final String TEST_FILE_1_PATH_OLD = "test/example/old/" + TEST_FILE_1; - - /** - * A JaCoCo report which contains the code coverage of a test project before the {@link #CODE_CHANGES} has - * been inserted. - */ - private static final String TEST_REPORT_BEFORE = "file-changes-test-before.xml"; - /** - * A JaCoCo report which contains the code coverage of a test project after the {@link #CODE_CHANGES} has - * been inserted. - */ - private static final String TEST_REPORT_AFTER = "file-changes-test-after.xml"; - - /** - * The code changes that took place between the generation of {@link #TEST_REPORT_BEFORE} and {@link - * #TEST_REPORT_AFTER}. - */ - private static final Map CODE_CHANGES = new HashMap<>(); - - /** - * The mapping of the used paths between the generation of {@link #TEST_REPORT_BEFORE} and {@link - * #TEST_REPORT_AFTER}. - */ - private static final Map OLD_PATH_MAPPING = new HashMap<>(); - - /** - * Initializes a map with the inserted {@link #CODE_CHANGES}. - */ - @BeforeAll - static void initFileChanges() { - Change insert1 = new Change(ChangeEditType.INSERT, 4, 4, 5, 9); - Change insert2 = new Change(ChangeEditType.INSERT, 8, 8, 14, 18); - Change insert3 = new Change(ChangeEditType.INSERT, 25, 25, 33, 36); - Change replace = new Change(ChangeEditType.REPLACE, 10, 11, 20, 22); - Change delete = new Change(ChangeEditType.DELETE, 16, 19, 26, 26); - FileChanges fileChanges = new FileChanges(TEST_FILE_1_PATH, TEST_FILE_1_PATH_OLD, - "test", FileEditType.RENAME, new HashMap<>()); - fileChanges.addChange(insert1); - fileChanges.addChange(insert2); - fileChanges.addChange(insert3); - fileChanges.addChange(replace); - fileChanges.addChange(delete); - CODE_CHANGES.put(TEST_FILE_1_PATH, fileChanges); - CODE_CHANGES.put(TEST_FILE_2, - new FileChanges("empty", "empty", "", FileEditType.MODIFY, new HashMap<>())); - OLD_PATH_MAPPING.put(TEST_FILE_1_PATH, TEST_FILE_1_PATH_OLD); - } +class FileChangesProcessorTest extends AbstractModifiedFilesCoverageTest { @Test void shouldAttachChangesCodeLines() { - FileChangesProcessor fileChangesProcessor = createFileChangesProcessor(); - Node tree = readJacocoResult(TEST_REPORT_AFTER); - fileChangesProcessor.attachChangedCodeLines(tree, CODE_CHANGES); + var tree = createCoverageTree(); - assertThat(tree.findByHashCode(Metric.FILE, TEST_FILE_1_PATH.hashCode())) + assertThat(tree.findByHashCode(Metric.FILE, getPathOfFileWithModifiedLines().hashCode())) .isNotEmpty() .satisfies(node -> assertThat(node.get()) .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getModifiedLines()) - .containsExactly( - 5, 6, 7, 8, 9, 14, 15, 16, 17, 18, 20, 21, 22, 33, 34, 35, 36))); - assertThat(tree.findByHashCode(Metric.FILE, TEST_FILE_2.hashCode())) + .containsExactly( + 5, 6, 7, 8, 9, 14, 15, 16, 17, 18, 20, 21, 22, 33, 34, 35, 36))); + assertThat(tree.findByHashCode(Metric.FILE, getNameOfFileWithoutModifiedLines().hashCode())) .isNotEmpty() .satisfies(node -> assertThat(node.get()) - .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getModifiedLines()) - .isEmpty())); + .isInstanceOfSatisfying(FileNode.class, f -> assertThat(f.getModifiedLines()) + .isEmpty())); } @Test void shouldAttachFileCoverageDelta() { - FileChangesProcessor fileChangesProcessor = createFileChangesProcessor(); - Node reference = readJacocoResult(TEST_REPORT_BEFORE); - Node tree = readJacocoResult(TEST_REPORT_AFTER); - fileChangesProcessor.attachFileCoverageDeltas(tree, reference, OLD_PATH_MAPPING); + var tree = createCoverageTree(); - assertThat(tree.findByHashCode(Metric.FILE, TEST_FILE_1_PATH.hashCode())) + assertThat(tree.findByHashCode(Metric.FILE, getPathOfFileWithModifiedLines().hashCode())) .isNotEmpty() .satisfies(node -> { assertThat(node.get()).isInstanceOf(FileNode.class); @@ -111,30 +48,11 @@ void shouldAttachFileCoverageDelta() { }); } - /** - * Verifies the file coverage delta of {@link #TEST_FILE_1}. - * - * @param file - * The referencing coverage tree {@link FileNode node} - */ - private void verifyFileCoverageDeltaOfTestFile1(final FileNode file) { - assertThat(file.getName()).isEqualTo(TEST_FILE_1); - assertThat(file.getDelta(Metric.LINE)).isEqualTo(Fraction.getFraction(3, 117)); - assertThat(file.getDelta(Metric.BRANCH)).isEqualTo(Fraction.getFraction(3, 24)); - assertThat(file.getDelta(Metric.INSTRUCTION)).isEqualTo(Fraction.getFraction(90, 999)); - assertThat(file.getDelta(Metric.METHOD)).isEqualTo(Fraction.getFraction(-4, 30)); - assertThat(file.getDelta(Metric.CLASS)).isEqualTo(Fraction.ZERO); - assertThat(file.getDelta(Metric.FILE)).isEqualTo(Fraction.ZERO); - } - @Test void shouldAttachIndirectCoverageChanges() { - FileChangesProcessor fileChangesProcessor = createFileChangesProcessor(); - Node reference = readJacocoResult(TEST_REPORT_BEFORE); - Node tree = readJacocoResult(TEST_REPORT_AFTER); - fileChangesProcessor.attachIndirectCoveragesChanges(tree, reference, CODE_CHANGES, OLD_PATH_MAPPING); + var tree = createCoverageTree(); - assertThat(tree.findByHashCode(Metric.FILE, TEST_FILE_1_PATH.hashCode())) + assertThat(tree.findByHashCode(Metric.FILE, getPathOfFileWithModifiedLines().hashCode())) .isNotEmpty() .satisfies(node -> { assertThat(node.get()).isInstanceOf(FileNode.class); @@ -148,11 +66,18 @@ void shouldAttachIndirectCoverageChanges() { } /** - * Creates an instance of {@link FileChangesProcessor}. + * Verifies the file coverage delta of {@link #getPathOfFileWithModifiedLines() the modified file}. * - * @return the created instance + * @param file + * The referencing coverage tree {@link FileNode node} */ - private FileChangesProcessor createFileChangesProcessor() { - return new FileChangesProcessor(); + private void verifyFileCoverageDeltaOfTestFile1(final FileNode file) { + assertThat(file.getName()).isEqualTo(getNameOfFileWithModifiedLines()); + assertThat(file.getDelta(Metric.LINE)).isEqualTo(Fraction.getFraction(3, 117)); + assertThat(file.getDelta(Metric.BRANCH)).isEqualTo(Fraction.getFraction(3, 24)); + assertThat(file.getDelta(Metric.INSTRUCTION)).isEqualTo(Fraction.getFraction(90, 999)); + assertThat(file.getDelta(Metric.METHOD)).isEqualTo(Fraction.getFraction(-4, 30)); + assertThat(file.getDelta(Metric.CLASS)).isEqualTo(Fraction.ZERO); + assertThat(file.getDelta(Metric.FILE)).isEqualTo(Fraction.ZERO); } } diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java index de09947c4..876b6cf09 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java @@ -28,10 +28,12 @@ import io.jenkins.plugins.coverage.metrics.AbstractCoverageITest; import io.jenkins.plugins.coverage.metrics.model.Baseline; +import io.jenkins.plugins.coverage.metrics.restapi.ModifiedLinesCoverageApiModel; import io.jenkins.plugins.coverage.metrics.steps.CoverageTool.Parser; import io.jenkins.plugins.prism.SourceCodeRetention; import static edu.hm.hafner.coverage.Metric.*; +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.*; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assumptions.*; @@ -84,6 +86,8 @@ void shouldComputeDeltaInPipelineOnDockerAgent(final SourceCodeRetention sourceC assertThat(getConsoleLog(build)).contains( "[Coverage] -> 18 files contain changes", "[Coverage] Painting " + expectedNumberOfFilesToBeStored + " source files on agent"); + + verifyModifiedLinesCoverageApi(build); } @Test @@ -108,6 +112,8 @@ void shouldComputeDeltaInFreestyleJobOnDockerAgent() throws IOException { Run build = buildSuccessfully(project); verifyGitIntegration(build, referenceBuild); + + verifyModifiedLinesCoverageApi(build); } /** @@ -216,6 +222,35 @@ private void verifyCodeDelta(final CoverageBuildAction action) { .containsExactlyInAnyOrder(15, 17, 63, 68, 80, 90, 130); } + /** + * Verifies that the {@link ModifiedLinesCoverageApiModel#getApi() modified lines coverage api} provides the + * expected coverage data for the modified files and code lines. + * + * @param build + * The build for that the coverage API should be called + */ + private void verifyModifiedLinesCoverageApi(final Run build) { + var json = callJsonRemoteApi(build.getUrl() + "coverage/modified/api/json").getJSONObject(); + assertThatJson(json).node("files").isEqualTo("[" + + "{" + + "\"fullyQualifiedFileName\":\"io/jenkins/plugins/forensics/util/CommitDecoratorFactory.java\"," + + "\"modifiedLinesBlocks\":[" + + "{" + + "\"endLine\":68," + + "\"startLine\":68," + + "\"type\":\"MISSED\"}" + + "]}," + + "{" + + "\"fullyQualifiedFileName\":\"io/jenkins/plugins/forensics/miner/MinerFactory.java\"," + + "\"modifiedLinesBlocks\":[" + + "{" + + "\"endLine\":80," + + "\"startLine\":80," + + "\"type\":\"COVERED\"" + + "}]" + + "}]"); + } + /** * Creates a {@link FlowDefinition} for a Jenkins pipeline which processes a JaCoCo coverage report. * diff --git a/plugin/src/test/resources/design.puml b/plugin/src/test/resources/design.puml index 82ce678a6..742ca4a32 100644 --- a/plugin/src/test/resources/design.puml +++ b/plugin/src/test/resources/design.puml @@ -11,11 +11,16 @@ skinparam component { [Source] <<..metrics.source>> [Charts] <<..metrics.charts>> [Model] <<..metrics.model>> +[Restapi] <<..metrics.restapi>> + +[Restapi] --> [Model] +[Restapi] --> [Source] [Steps] --> [Model] [Steps] --> [Color] [Steps] --> [Source] [Steps] --> [Charts] +[Steps] --> [Restapi] [Charts] --> [Color] [Charts] --> [Model] diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/file-changes-test-after.xml b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/file-changes-test-after.xml new file mode 100644 index 000000000..1c1b89ba5 --- /dev/null +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/file-changes-test-after.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/file-changes-test-before.xml b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/file-changes-test-before.xml new file mode 100644 index 000000000..63a0fcdb1 --- /dev/null +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/file-changes-test-before.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/jacoco-analysis-model.xml b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/jacoco-analysis-model.xml new file mode 100644 index 000000000..52c1b39a6 --- /dev/null +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/jacoco-analysis-model.xml @@ -0,0 +1,21645 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/jacoco-codingstyle.xml b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/jacoco-codingstyle.xml new file mode 100644 index 000000000..49915a685 --- /dev/null +++ b/plugin/src/test/resources/io/jenkins/plugins/coverage/metrics/restapi/jacoco-codingstyle.xml @@ -0,0 +1,1179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +