diff --git a/src/main/java/edu/hm/hafner/analysis/parser/violations/SarifAdapter.java b/src/main/java/edu/hm/hafner/analysis/parser/violations/SarifAdapter.java index b8faf2c9d..8d1e6d21f 100644 --- a/src/main/java/edu/hm/hafner/analysis/parser/violations/SarifAdapter.java +++ b/src/main/java/edu/hm/hafner/analysis/parser/violations/SarifAdapter.java @@ -1,5 +1,12 @@ package edu.hm.hafner.analysis.parser.violations; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.regex.Pattern; + +import edu.hm.hafner.analysis.IssueBuilder; + +import se.bjurr.violations.lib.model.Violation; import se.bjurr.violations.lib.parsers.SarifParser; /** @@ -10,8 +17,31 @@ public class SarifAdapter extends AbstractViolationAdapter { private static final long serialVersionUID = -5699747899173867285L; + private static final Pattern WINDOWS_PATH_ON_UNIX = Pattern.compile("^/[a-zA-Z]:.*"); + @Override SarifParser createParser() { return new SarifParser(); } + + @Override + void extractAdditionalProperties(final IssueBuilder builder, final Violation violation) { + try { + var uri = new URI(violation.getFile()); + var path = uri.getPath(); + if (path != null) { + builder.setFileName(removePrefix(path)); + } + } + catch (URISyntaxException exception) { + // ignore + } + } + + private String removePrefix(final String fileName) { + if (WINDOWS_PATH_ON_UNIX.matcher(fileName).matches()) { + return fileName.substring(1); + } + return fileName; + } } diff --git a/src/test/java/edu/hm/hafner/analysis/parser/violations/SarifAdapterTest.java b/src/test/java/edu/hm/hafner/analysis/parser/violations/SarifAdapterTest.java index 4878f7243..937238e3e 100644 --- a/src/test/java/edu/hm/hafner/analysis/parser/violations/SarifAdapterTest.java +++ b/src/test/java/edu/hm/hafner/analysis/parser/violations/SarifAdapterTest.java @@ -1,6 +1,8 @@ package edu.hm.hafner.analysis.parser.violations; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import edu.hm.hafner.analysis.Report; import edu.hm.hafner.analysis.Severity; @@ -46,6 +48,37 @@ void shouldReportDifferentSeverities() { assertThat(report.getSizeOf(Severity.WARNING_LOW)).isEqualTo(3); } + @Test + void handleFilePathsInFileURIschemeFormat() { + Report report = parse("filePathInFileUriScheme.sarif"); + try (SoftAssertions softly = new SoftAssertions()) { + softly.assertThat(report).hasSize(2); + assertThatReportHasSeverities(report, 0, 0, 2, 0); + softly.assertThat(report.get(0)) + .hasSeverity(Severity.WARNING_NORMAL) + .hasLineStart(6) + .hasLineEnd(6) + .hasFileName("C:/my/workspace/project/this/dir/file.cs"); + softly.assertThat(report.get(1)) + .hasSeverity(Severity.WARNING_NORMAL) + .hasLineStart(5) + .hasLineEnd(5) + .hasFileName("C:/my/workspace/project/whatever/€path.cs"); + } + } + + @ParameterizedTest(name = "[{index}] Filename with invalid path: {0}") + @ValueSource(strings = {"brokenfilePath.sarif", "emptyfilePath.sarif"}) + void handleBrokenPathsInFileURIschemeFormat(final String fileName) { + Report report = parse(fileName); + try (SoftAssertions softly = new SoftAssertions()) { + softly.assertThat(report).hasSize(2); + assertThatReportHasSeverities(report, 0, 0, 2, 0); + softly.assertThat(report.get(0).getFileName()).endsWith("this/dir/file.cs"); + softly.assertThat(report.get(1).getFileName()).endsWith("path.cs"); + } + } + @Override protected SarifAdapter createParser() { return new SarifAdapter(); diff --git a/src/test/resources/edu/hm/hafner/analysis/parser/violations/brokenfilePath.sarif b/src/test/resources/edu/hm/hafner/analysis/parser/violations/brokenfilePath.sarif new file mode 100644 index 000000000..0db72f270 --- /dev/null +++ b/src/test/resources/edu/hm/hafner/analysis/parser/violations/brokenfilePath.sarif @@ -0,0 +1,213 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json", + "version": "2.1.0", + "runs": [ + { + "results": [ + { + "ruleId": "FirstRule", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "You should keep an eye on this code" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "whatever/%E2%82%ACpath.cs", + "uriBaseId": "solutionDir", + "index": 0 + }, + "region": { + "startLine": 5, + "startColumn": 1, + "endLine": 5, + "endColumn": 23, + "charOffset": 143, + "charLength": 22 + } + } + } + ], + "partialFingerprints": { + }, + "properties": { + "tags": [ + "C#", + ".NET 8.0" + ] + } + }, + { + "ruleId": "secondRule", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "This is bad code!" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "this/dir/file.cs", + "uriBaseId": "solutionDir", + "index": 1 + }, + "region": { + "startLine": 6, + "startColumn": 1, + "endLine": 6, + "endColumn": 23, + "charOffset": 192, + "charLength": 22 + } + } + } + ], + "partialFingerprints": { + }, + "properties": { + "tags": [ + "C#", + ".NET 8.0" + ] + } + } + ], + "tool": { + "driver": { + "name": "InspectCode", + "organization": "JetBrains, Inc", + "fullName": "JetBrains Inspect Code 2024.2", + "semanticVersion": "242.0.20240814.114127", + "informationUri": "http://www.jetbrains.com/resharper/features/command-line.html", + "rules": [ + { + "id": "RedundantUsingDirective", + "fullDescription": { + "text": "Using directive is not required by the code and can be safely removed" + }, + "help": { + "text": "https://www.jetbrains.com/help/resharper/RedundantUsingDirective.html" + }, + "shortDescription": { + "text": "Redundant using directive" + }, + "defaultConfiguration": { + "level": "warning" + }, + "helpUri": "https://www.jetbrains.com/help/resharper/RedundantUsingDirective.html", + "relationships": [ + { + "target": { + "id": "CSHARP.CodeRedundancy", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + }, + { + "target": { + "id": "ASPX.CodeRedundancy", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + } + ], + "taxa": [ + { + "id": "ASPX", + "name": "Aspx" + }, + { + "id": "ASPX.CodeRedundancy", + "name": "Redundancies in Code", + "relationships": [ + { + "target": { + "id": "ASPX", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + }, + { + "id": "CSHARP", + "name": "C#" + }, + { + "id": "CSHARP.CodeRedundancy", + "name": "Redundancies in Code", + "relationships": [ + { + "target": { + "id": "CSHARP", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "versionControlProvenance": [ + { + "repositoryUri": "https://gitlab.com/ourRepo.git", + "revisionId": "970f02980ede09609791feca6bf8cdcd72bbe217", + "branch": "HEAD", + "mappedTo": { + "uriBaseId": "solutionDir" + } + } + ], + "originalUriBaseIds": { + "solutionDir": { + "uri": "::::::/", + "description": { + "text": "Solution Directory" + } + } + }, + "artifacts": [ + { + "location": { + "uri": "whatever/%E2%82%ACpath.cs", + "uriBaseId": "solutionDir" + } + }, + { + "location": { + "uri": "this/dir/file.cs", + "uriBaseId": "solutionDir" + } + } + ], + "columnKind": "utf16CodeUnits" + } + ] + } diff --git a/src/test/resources/edu/hm/hafner/analysis/parser/violations/emptyfilePath.sarif b/src/test/resources/edu/hm/hafner/analysis/parser/violations/emptyfilePath.sarif new file mode 100644 index 000000000..79efa5729 --- /dev/null +++ b/src/test/resources/edu/hm/hafner/analysis/parser/violations/emptyfilePath.sarif @@ -0,0 +1,213 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json", + "version": "2.1.0", + "runs": [ + { + "results": [ + { + "ruleId": "FirstRule", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "You should keep an eye on this code" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "whatever/%E2%82%ACpath.cs", + "uriBaseId": "solutionDir", + "index": 0 + }, + "region": { + "startLine": 5, + "startColumn": 1, + "endLine": 5, + "endColumn": 23, + "charOffset": 143, + "charLength": 22 + } + } + } + ], + "partialFingerprints": { + }, + "properties": { + "tags": [ + "C#", + ".NET 8.0" + ] + } + }, + { + "ruleId": "secondRule", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "This is bad code!" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "this/dir/file.cs", + "uriBaseId": "solutionDir", + "index": 1 + }, + "region": { + "startLine": 6, + "startColumn": 1, + "endLine": 6, + "endColumn": 23, + "charOffset": 192, + "charLength": 22 + } + } + } + ], + "partialFingerprints": { + }, + "properties": { + "tags": [ + "C#", + ".NET 8.0" + ] + } + } + ], + "tool": { + "driver": { + "name": "InspectCode", + "organization": "JetBrains, Inc", + "fullName": "JetBrains Inspect Code 2024.2", + "semanticVersion": "242.0.20240814.114127", + "informationUri": "http://www.jetbrains.com/resharper/features/command-line.html", + "rules": [ + { + "id": "RedundantUsingDirective", + "fullDescription": { + "text": "Using directive is not required by the code and can be safely removed" + }, + "help": { + "text": "https://www.jetbrains.com/help/resharper/RedundantUsingDirective.html" + }, + "shortDescription": { + "text": "Redundant using directive" + }, + "defaultConfiguration": { + "level": "warning" + }, + "helpUri": "https://www.jetbrains.com/help/resharper/RedundantUsingDirective.html", + "relationships": [ + { + "target": { + "id": "CSHARP.CodeRedundancy", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + }, + { + "target": { + "id": "ASPX.CodeRedundancy", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + } + ], + "taxa": [ + { + "id": "ASPX", + "name": "Aspx" + }, + { + "id": "ASPX.CodeRedundancy", + "name": "Redundancies in Code", + "relationships": [ + { + "target": { + "id": "ASPX", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + }, + { + "id": "CSHARP", + "name": "C#" + }, + { + "id": "CSHARP.CodeRedundancy", + "name": "Redundancies in Code", + "relationships": [ + { + "target": { + "id": "CSHARP", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "versionControlProvenance": [ + { + "repositoryUri": "https://gitlab.com/ourRepo.git", + "revisionId": "970f02980ede09609791feca6bf8cdcd72bbe217", + "branch": "HEAD", + "mappedTo": { + "uriBaseId": "solutionDir" + } + } + ], + "originalUriBaseIds": { + "solutionDir": { + "uri": "empty:", + "description": { + "text": "Solution Directory" + } + } + }, + "artifacts": [ + { + "location": { + "uri": "whatever/%E2%82%ACpath.cs", + "uriBaseId": "solutionDir" + } + }, + { + "location": { + "uri": "this/dir/file.cs", + "uriBaseId": "solutionDir" + } + } + ], + "columnKind": "utf16CodeUnits" + } + ] + } diff --git a/src/test/resources/edu/hm/hafner/analysis/parser/violations/filePathInFileUriScheme.sarif b/src/test/resources/edu/hm/hafner/analysis/parser/violations/filePathInFileUriScheme.sarif new file mode 100644 index 000000000..6ea210e55 --- /dev/null +++ b/src/test/resources/edu/hm/hafner/analysis/parser/violations/filePathInFileUriScheme.sarif @@ -0,0 +1,213 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json", + "version": "2.1.0", + "runs": [ + { + "results": [ + { + "ruleId": "FirstRule", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "You should keep an eye on this code" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "whatever/%E2%82%ACpath.cs", + "uriBaseId": "solutionDir", + "index": 0 + }, + "region": { + "startLine": 5, + "startColumn": 1, + "endLine": 5, + "endColumn": 23, + "charOffset": 143, + "charLength": 22 + } + } + } + ], + "partialFingerprints": { + }, + "properties": { + "tags": [ + "C#", + ".NET 8.0" + ] + } + }, + { + "ruleId": "secondRule", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "This is bad code!" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "this/dir/file.cs", + "uriBaseId": "solutionDir", + "index": 1 + }, + "region": { + "startLine": 6, + "startColumn": 1, + "endLine": 6, + "endColumn": 23, + "charOffset": 192, + "charLength": 22 + } + } + } + ], + "partialFingerprints": { + }, + "properties": { + "tags": [ + "C#", + ".NET 8.0" + ] + } + } + ], + "tool": { + "driver": { + "name": "InspectCode", + "organization": "JetBrains, Inc", + "fullName": "JetBrains Inspect Code 2024.2", + "semanticVersion": "242.0.20240814.114127", + "informationUri": "http://www.jetbrains.com/resharper/features/command-line.html", + "rules": [ + { + "id": "RedundantUsingDirective", + "fullDescription": { + "text": "Using directive is not required by the code and can be safely removed" + }, + "help": { + "text": "https://www.jetbrains.com/help/resharper/RedundantUsingDirective.html" + }, + "shortDescription": { + "text": "Redundant using directive" + }, + "defaultConfiguration": { + "level": "warning" + }, + "helpUri": "https://www.jetbrains.com/help/resharper/RedundantUsingDirective.html", + "relationships": [ + { + "target": { + "id": "CSHARP.CodeRedundancy", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + }, + { + "target": { + "id": "ASPX.CodeRedundancy", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + } + ], + "taxa": [ + { + "id": "ASPX", + "name": "Aspx" + }, + { + "id": "ASPX.CodeRedundancy", + "name": "Redundancies in Code", + "relationships": [ + { + "target": { + "id": "ASPX", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + }, + { + "id": "CSHARP", + "name": "C#" + }, + { + "id": "CSHARP.CodeRedundancy", + "name": "Redundancies in Code", + "relationships": [ + { + "target": { + "id": "CSHARP", + "toolComponent": { + "name": "InspectCode" + } + }, + "kinds": [ + "superset" + ] + } + ] + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "versionControlProvenance": [ + { + "repositoryUri": "https://gitlab.com/ourRepo.git", + "revisionId": "970f02980ede09609791feca6bf8cdcd72bbe217", + "branch": "HEAD", + "mappedTo": { + "uriBaseId": "solutionDir" + } + } + ], + "originalUriBaseIds": { + "solutionDir": { + "uri": "file:///C:/my/workspace/project/", + "description": { + "text": "Solution Directory" + } + } + }, + "artifacts": [ + { + "location": { + "uri": "whatever/%E2%82%ACpath.cs", + "uriBaseId": "solutionDir" + } + }, + { + "location": { + "uri": "this/dir/file.cs", + "uriBaseId": "solutionDir" + } + } + ], + "columnKind": "utf16CodeUnits" + } + ] + } \ No newline at end of file