Browse Source

SONAR-17560 Move existing sarif object to sonar-core

tags/9.8.0.63668
Antoine Vinot 1 year ago
parent
commit
7b6049377b
24 changed files with 999 additions and 0 deletions
  1. 1
    0
      sonar-core/build.gradle
  2. 34
    0
      sonar-core/src/main/java/org/sonar/core/sarif/ArtifactLocation.java
  3. 26
    0
      sonar-core/src/main/java/org/sonar/core/sarif/CodeFlow.java
  4. 50
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Driver.java
  5. 26
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Location.java
  6. 25
    0
      sonar-core/src/main/java/org/sonar/core/sarif/LocationWrapper.java
  7. 21
    0
      sonar-core/src/main/java/org/sonar/core/sarif/PartialFingerprints.java
  8. 32
    0
      sonar-core/src/main/java/org/sonar/core/sarif/PhysicalLocation.java
  9. 34
    0
      sonar-core/src/main/java/org/sonar/core/sarif/PropertiesBag.java
  10. 77
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Region.java
  11. 97
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Result.java
  12. 76
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Rule.java
  13. 54
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Run.java
  14. 47
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java
  15. 49
    0
      sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializer.java
  16. 26
    0
      sonar-core/src/main/java/org/sonar/core/sarif/ThreadFlow.java
  17. 21
    0
      sonar-core/src/main/java/org/sonar/core/sarif/Tool.java
  18. 43
    0
      sonar-core/src/main/java/org/sonar/core/sarif/WrappedText.java
  19. 23
    0
      sonar-core/src/main/java/org/sonar/core/sarif/package-info.java
  20. 52
    0
      sonar-core/src/test/java/org/sonar/core/sarif/RuleTest.java
  21. 34
    0
      sonar-core/src/test/java/org/sonar/core/sarif/Sarif210SerializationDeserializationTest.java
  22. 43
    0
      sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java
  23. 1
    0
      sonar-core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
  24. 107
    0
      sonar-core/src/test/resources/org/sonar/core/sarif/valid-sarif210.json

+ 1
- 0
sonar-core/build.gradle View File

@@ -24,6 +24,7 @@ dependencies {
compile project(':sonar-plugin-api-impl')

compileOnly 'com.google.code.findbugs:jsr305'
compileOnly 'com.google.code.gson:gson'

testCompile 'com.tngtech.java:junit-dataprovider'
testCompile 'junit:junit'

+ 34
- 0
sonar-core/src/main/java/org/sonar/core/sarif/ArtifactLocation.java View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class ArtifactLocation {
private static final String URI_BASE_ID = "%SRCROOT";

@SerializedName("uri")
private final String uri;
@SerializedName("uriBaseId")
private final String uriBaseId;

private ArtifactLocation(String uriBaseId, String uri) {
this.uriBaseId = uriBaseId;
this.uri = uri;
}

public static ArtifactLocation of(String uri) {
return new ArtifactLocation(URI_BASE_ID, uri);
}

public String getUri() {
return uri;
}

public String getUriBaseId() {
return uriBaseId;
}
}

+ 26
- 0
sonar-core/src/main/java/org/sonar/core/sarif/CodeFlow.java View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.List;

public class CodeFlow {
@SerializedName("threadFlows")
private final List<ThreadFlow> threadFlows;

private CodeFlow(List<ThreadFlow> threadFlows) {
this.threadFlows = threadFlows;
}

public static CodeFlow of(List<ThreadFlow> threadFlows) {
return new CodeFlow(threadFlows);
}

public List<ThreadFlow> getThreadFlows() {
return threadFlows;
}
}

+ 50
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Driver.java View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.Set;

public class Driver {
private static final String TOOL_NAME = "SonarQube";
private static final String ORGANIZATION_NAME = "SonarSource";

@SerializedName("name")
private final String name;
@SerializedName("organization")
private final String organization;
@SerializedName("semanticVersion")
private final String semanticVersion;
@SerializedName("rules")
private final Set<Rule> rules;

public Driver(String semanticVersion, Set<Rule> rules) {
this(TOOL_NAME, ORGANIZATION_NAME, semanticVersion, rules);
}

private Driver(String name, String organization, String semanticVersion, Set<Rule> rules) {
this.name = name;
this.organization = organization;
this.semanticVersion = semanticVersion;
this.rules = Set.copyOf(rules);
}

public String getName() {
return name;
}

public String getOrganization() {
return organization;
}

public String getSemanticVersion() {
return semanticVersion;
}

public Set<Rule> getRules() {
return rules;
}
}

+ 26
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Location.java View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class Location {
@SerializedName("physicalLocation")
private final PhysicalLocation physicalLocation;

private Location(PhysicalLocation physicalLocation) {
this.physicalLocation = physicalLocation;
}

public static Location of(PhysicalLocation physicalLocation) {
return new Location(physicalLocation);
}

public PhysicalLocation getPhysicalLocation() {
return physicalLocation;
}

}

+ 25
- 0
sonar-core/src/main/java/org/sonar/core/sarif/LocationWrapper.java View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class LocationWrapper {
@SerializedName("location")
private final Location location;

private LocationWrapper(Location location) {
this.location = location;
}

public static LocationWrapper of(Location location) {
return new LocationWrapper(location);
}

public Location getLocation() {
return location;
}
}

+ 21
- 0
sonar-core/src/main/java/org/sonar/core/sarif/PartialFingerprints.java View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class PartialFingerprints {
@SerializedName("primaryLocationLineHash")
private final String primaryLocationLineHash;

public PartialFingerprints(String primaryLocationLineHash) {
this.primaryLocationLineHash = primaryLocationLineHash;
}

public String getPrimaryLocationLineHash() {
return primaryLocationLineHash;
}
}

+ 32
- 0
sonar-core/src/main/java/org/sonar/core/sarif/PhysicalLocation.java View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class PhysicalLocation {
@SerializedName("artifactLocation")
private final ArtifactLocation artifactLocation;
@SerializedName("region")
private final Region region;

private PhysicalLocation(ArtifactLocation artifactLocation, Region region) {
this.artifactLocation = artifactLocation;
this.region = region;
}

public static PhysicalLocation of(ArtifactLocation artifactLocation, Region region) {
return new PhysicalLocation(artifactLocation, region);
}

public ArtifactLocation getArtifactLocation() {
return artifactLocation;
}

public Region getRegion() {
return region;
}
}

+ 34
- 0
sonar-core/src/main/java/org/sonar/core/sarif/PropertiesBag.java View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.Set;

public class PropertiesBag {
@SerializedName("tags")
private final Set<String> tags;
@SerializedName("security-severity")
private final String securitySeverity;

private PropertiesBag(String securitySeverity, Set<String> tags) {
this.tags = Set.copyOf(tags);
this.securitySeverity = securitySeverity;
}

public static PropertiesBag of(String securitySeverity, Set<String> tags) {
return new PropertiesBag(securitySeverity, tags);
}

public Set<String> getTags() {
return tags;
}

public String getSecuritySeverity() {
return securitySeverity;
}
}

+ 77
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Region.java View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class Region {
@SerializedName("startLine")
private final int startLine;
@SerializedName("endLine")
private final int endLine;
@SerializedName("startColumn")
private final int startColumn;
@SerializedName("endColumn")
private final int endColumn;

private Region(int startLine, int endLine, int startColumn, int endColumn) {
this.startLine = startLine;
this.endLine = endLine;
this.startColumn = startColumn;
this.endColumn = endColumn;
}

public static RegionBuilder builder() {
return new RegionBuilder();
}

public int getStartLine() {
return startLine;
}

public int getEndLine() {
return endLine;
}

public int getStartColumn() {
return startColumn;
}

public int getEndColumn() {
return endColumn;
}

public static final class RegionBuilder {
private int startLine;
private int endLine;
private int startColumn;
private int endColumn;

public RegionBuilder startLine(int startLine) {
this.startLine = startLine;
return this;
}

public RegionBuilder endLine(int endLine) {
this.endLine = endLine;
return this;
}

public RegionBuilder startColumn(int startColumn) {
this.startColumn = startColumn;
return this;
}

public RegionBuilder endColumn(int endColumn) {
this.endColumn = endColumn;
return this;
}

public Region build() {
return new Region(startLine, endLine, startColumn, endColumn);
}
}
}

+ 97
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Result.java View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.List;
import java.util.Set;
import org.sonar.api.rule.RuleKey;

public class Result {
@SerializedName("ruleId")
private final String ruleId;
@SerializedName("message")
private final WrappedText message;
@SerializedName("locations")
private final Set<Location> locations;
@SerializedName("partialFingerprints")
private final PartialFingerprints partialFingerprints;
@SerializedName("codeFlows")
private final List<CodeFlow> codeFlows;


private Result(RuleKey ruleKey, String message, Location location, String primaryLocationLineHash, List<CodeFlow> codeFlows) {
this.ruleId = ruleKey.toString();
this.message = WrappedText.of(message);
this.locations = Set.of(location);
this.partialFingerprints = new PartialFingerprints(primaryLocationLineHash);
this.codeFlows = List.copyOf(codeFlows);
}

public String getRuleId() {
return ruleId;
}

public WrappedText getMessage() {
return message;
}

public Set<Location> getLocations() {
return locations;
}

public PartialFingerprints getPartialFingerprints() {
return partialFingerprints;
}

public List<CodeFlow> getCodeFlows() {
return codeFlows;
}

public static ResultBuilder builder() {
return new ResultBuilder();
}

public static final class ResultBuilder {
private RuleKey ruleKey;
private String message;
private Location location;
private String hash;
private List<CodeFlow> codeFlows;

private ResultBuilder() {
}

public ResultBuilder ruleKey(RuleKey ruleKey) {
this.ruleKey = ruleKey;
return this;
}

public ResultBuilder message(String message) {
this.message = message;
return this;
}

public ResultBuilder locations(Location location) {
this.location = location;
return this;
}

public ResultBuilder hash(String hash) {
this.hash = hash;
return this;
}

public ResultBuilder codeFlows(List<CodeFlow> codeFlows) {
this.codeFlows = codeFlows;
return this;
}

public Result build() {
return new Result(ruleKey, message, location, hash, codeFlows);
}
}
}

+ 76
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Rule.java View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.Objects;
import org.sonar.api.rule.RuleKey;

public class Rule {
@SerializedName("id")
private final String id;
@SerializedName("name")
private final String name;
@SerializedName("shortDescription")
private final WrappedText shortDescription;
@SerializedName("fullDescription")
private final WrappedText fullDescription;
@SerializedName("help")
private final WrappedText help;
@SerializedName("properties")
private final PropertiesBag properties;

public Rule(RuleKey ruleKey, String ruleName, String ruleDescription, PropertiesBag properties) {
id = ruleKey.toString();
name = ruleKey.toString();
shortDescription = WrappedText.of(ruleName);
fullDescription = WrappedText.of(ruleName);
help = WrappedText.of(ruleDescription);
this.properties = properties;
}

public String getId() {
return id;
}

public String getName() {
return name;
}

public WrappedText getShortDescription() {
return shortDescription;
}

public WrappedText getFullDescription() {
return fullDescription;
}

public WrappedText getHelp() {
return help;
}

public PropertiesBag getProperties() {
return properties;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Rule rule = (Rule) o;
return Objects.equals(id, rule.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

}

+ 54
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Run.java View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.common.annotations.VisibleForTesting;
import com.google.gson.annotations.SerializedName;
import java.util.Set;

public class Run {

@VisibleForTesting
public static final String LANGUAGE_EN_US = "en-us";
@VisibleForTesting
public static final String COLUMN_KIND = "utf16CodeUnits";

@SerializedName("tool")
private final Tool tool;
@SerializedName("results")
private final Set<Result> results;
@SerializedName("language")
private final String language;
@SerializedName("columnKind")
private final String columnKind;

public Run(Tool tool, Set<Result> results) {
this(tool, results, LANGUAGE_EN_US, COLUMN_KIND);
}

private Run(Tool tool, Set<Result> results, String language, String columnKind) {
this.tool = tool;
this.results = Set.copyOf(results);
this.language = language;
this.columnKind = columnKind;
}

public String getLanguage() {
return language;
}

public String getColumnKind() {
return columnKind;
}

public Tool getTool() {
return tool;
}

public Set<Result> getResults() {
return results;
}
}

+ 47
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Sarif210.java View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.common.annotations.VisibleForTesting;
import com.google.gson.annotations.SerializedName;
import java.util.Set;

public class Sarif210 {

@VisibleForTesting
public static final String SARIF_SCHEMA_URL = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json";
@VisibleForTesting
public static final String SARIF_VERSION = "2.1.0";

@SerializedName("version")
private final String version;
@SerializedName("$schema")
private final String schema;
@SerializedName("runs")
private final Set<Run> runs;

public Sarif210(Run run) {
this(SARIF_SCHEMA_URL, SARIF_VERSION, run);
}

private Sarif210(String schema, String version, Run run) {
this.schema = schema;
this.version = version;
this.runs = Set.of(run);
}

public String getVersion() {
return version;
}

public String getSchema() {
return schema;
}

public Set<Run> getRuns() {
return runs;
}
}

+ 49
- 0
sonar-core/src/main/java/org/sonar/core/sarif/SarifSerializer.java View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.common.annotations.VisibleForTesting;
import com.google.gson.Gson;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Base64;
import java.util.zip.GZIPOutputStream;
import javax.inject.Inject;
import org.sonar.api.ce.ComputeEngineSide;

import static java.nio.charset.StandardCharsets.UTF_8;

@ComputeEngineSide
public class SarifSerializer {
private final Gson gson;

@Inject
public SarifSerializer() {
this(new Gson());
}

@VisibleForTesting
SarifSerializer(Gson gson) {
this.gson = gson;
}

public String serializeAndEncode(Sarif210 sarif210) {
String serializedSarif = gson.toJson(sarif210);
return compressToGzipAndEncodeBase64(serializedSarif);
}

private static String compressToGzipAndEncodeBase64(String input) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream(outputStream)) {
gzipStream.write(input.getBytes(UTF_8));
gzipStream.finish();
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
} catch (IOException e) {
throw new UncheckedIOException(String.format("Failed to compress and encode the input: %s", input), e);
}
}
}

+ 26
- 0
sonar-core/src/main/java/org/sonar/core/sarif/ThreadFlow.java View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.List;

public class ThreadFlow {
@SerializedName("locations")
private final List<LocationWrapper> locations;

private ThreadFlow(List<LocationWrapper> locations) {
this.locations = locations;
}

public static ThreadFlow of(List<LocationWrapper> locations) {
return new ThreadFlow(locations);
}

public List<LocationWrapper> getLocations() {
return locations;
}
}

+ 21
- 0
sonar-core/src/main/java/org/sonar/core/sarif/Tool.java View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;

public class Tool {
@SerializedName("driver")
private final Driver driver;

public Tool(Driver driver) {
this.driver = driver;
}

public Driver getDriver() {
return driver;
}
}

+ 43
- 0
sonar-core/src/main/java/org/sonar/core/sarif/WrappedText.java View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.annotations.SerializedName;
import java.util.Objects;

public class WrappedText {
@SerializedName("text")
private final String text;

private WrappedText(String textToWrap) {
this.text = textToWrap;
}

public static WrappedText of(String textToWrap) {
return new WrappedText(textToWrap);
}

public String getText() {
return text;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
WrappedText that = (WrappedText) o;
return Objects.equals(text, that.text);
}

@Override
public int hashCode() {
return Objects.hash(text);
}
}

+ 23
- 0
sonar-core/src/main/java/org/sonar/core/sarif/package-info.java View File

@@ -0,0 +1,23 @@
/*
* SonarQube
* Copyright (C) 2009-2022 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@ParametersAreNonnullByDefault
package org.sonar.core.sarif;

import javax.annotation.ParametersAreNonnullByDefault;

+ 52
- 0
sonar-core/src/test/java/org/sonar/core/sarif/RuleTest.java View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import java.util.Set;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.sarif.PropertiesBag;
import org.sonar.core.sarif.Rule;

import static org.assertj.core.api.Assertions.assertThat;


public class RuleTest {

@Test
public void equals_matchOnlyOnId() {
Rule rule1 = createRule("rep1", "rule1");
Rule rule1Bis = createRule("rep1", "rule1");
Rule rule2 = withRuleId(rule1, "rep1", "rule2");

assertThat(rule1).isEqualTo(rule1Bis).isNotEqualTo(rule2);
}

@Test
public void equals_notMatchWithNull(){
Rule rule1 = createRule("rep1", "rule2");

assertThat(rule1).isNotEqualTo(null);
}

@Test
public void equals_matchWithSameObject(){
Rule rule1 = createRule("rep5", "rule2");

assertThat(rule1).isEqualTo(rule1);
}

private static Rule withRuleId(Rule rule, String repoName, String ruleName) {
return new Rule(RuleKey.of(repoName, ruleName), rule.getName(), rule.getFullDescription().getText(), rule.getProperties());
}

private static Rule createRule(String repoName, String ruleName) {
return new Rule(RuleKey.of(repoName, ruleName), RandomStringUtils.randomAlphanumeric(5), RandomStringUtils.randomAlphanumeric(5),
PropertiesBag.of(RandomStringUtils.randomAlphanumeric(3), Set.of(RandomStringUtils.randomAlphanumeric(4))));
}

}

+ 34
- 0
sonar-core/src/test/java/org/sonar/core/sarif/Sarif210SerializationDeserializationTest.java View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.sonar.core.sarif.Sarif210;
import org.sonar.test.JsonAssert;

import static java.util.Objects.requireNonNull;

public class Sarif210SerializationDeserializationTest {

private static final String VALID_SARIF_210_FILE_JSON = "valid-sarif210.json";

@Test
public void verify_json_serialization_of_sarif210() throws IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();

String expectedJson = IOUtils.toString(requireNonNull(getClass().getResource(VALID_SARIF_210_FILE_JSON)), StandardCharsets.UTF_8);
Sarif210 deserializedJson = gson.fromJson(expectedJson, Sarif210.class);
String reserializedJson = gson.toJson(deserializedJson);

JsonAssert.assertJson(reserializedJson).isSimilarTo(expectedJson);
}

}

+ 43
- 0
sonar-core/src/test/java/org/sonar/core/sarif/SarifSerializerTest.java View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017-2022 SonarSource SA
* All rights reserved
* mailto:info AT sonarsource DOT com
*/
package org.sonar.core.sarif;

import com.google.gson.Gson;
import org.sonar.core.sarif.Sarif210;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class SarifSerializerTest {

private static final String SARIF_JSON = "{\"message\" : \"A sarif in json format as String.\"}";
private static final String SARIF_JSON_ENCODED = "H4sIAAAAAAAAAKtWyk0tLk5MT1VSsFJQclQoTizKTFPIzFPIKs7PU0jLL8pNLFFILFYILinKzEvXU6oFACgK7/YxAAAA";

@Mock
private Gson gson;

@InjectMocks
private SarifSerializer serializer;

@Test
public void serializeAndEncode_should_compressInGZipAndEncodeBase64() {
when(gson.toJson(any(Sarif210.class))).thenReturn(SARIF_JSON);
Sarif210 sarif210 = mock(Sarif210.class);

String encoded = serializer.serializeAndEncode(sarif210);

assertThat(encoded).isEqualTo(SARIF_JSON_ENCODED);
}

}

+ 1
- 0
sonar-core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker View File

@@ -0,0 +1 @@
mock-maker-inline

+ 107
- 0
sonar-core/src/test/resources/org/sonar/core/sarif/valid-sarif210.json View File

@@ -0,0 +1,107 @@
{
"version": "2.1.0",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"runs": [
{
"tool": {
"driver": {
"name": "SonarQube",
"organization": "SonarSource",
"semanticVersion": "9.6",
"rules": [
{
"id": "java:S5132",
"name": "java:S5132",
"shortDescription": {
"text": "Make this final static field too."
},
"fullDescription": {
"text": "Make this final static field too."
},
"help": {
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu."
},
"properties": {
"tags": [
"tag1",
"tag2"
]
}
}
]
}
},
"results": [
{
"ruleId": "java:S5132",
"message": {
"text": "this is the message"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "www.google.com",
"uriBaseId": "%SRCROOT"
},
"region": {
"startLine": 11,
"endLine": 222,
"startColumn": 54,
"endColumn": 4
}
}
}
],
"partialFingerprints": {
"primaryLocationLineHash": "thisISTHEHAS"
},
"codeFlows": [
{
"threadFlows": [
{
"locations": [
{
"location": {
"physicalLocation": {
"artifactLocation": {
"uri": "www.google.com",
"uriBaseId": "%SRCROOT"
},
"region": {
"startLine": 11,
"endLine": 222,
"startColumn": 54,
"endColumn": 4
}
}
}
},
{
"location": {
"physicalLocation": {
"artifactLocation": {
"uri": "www.google.com",
"uriBaseId": "%SRCROOT"
},
"region": {
"startLine": 22,
"endLine": 4323,
"startColumn": 545,
"endColumn": 4324
}
}
}
}
]
}
]
}
]
}
],
"language": "en-us",
"columnKind": "utf16CodeUnits"
}
]
}

Loading…
Cancel
Save