]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22541 Import SARIF stacks as issue flows
authorJulien HENRY <julien.henry@sonarsource.com>
Thu, 25 Jul 2024 14:04:01 +0000 (16:04 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 26 Jul 2024 20:02:48 +0000 (20:02 +0000)
sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/LocationMapper.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/LocationMapperTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/ResultMapperTest.java

index df816a466d7b84527c052d5f29171e2767d8310e..4b668c90d569a644032ba88100a984e7dec35387 100644 (file)
@@ -30,7 +30,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
-import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.jetbrains.annotations.NotNull;
 import org.sonar.api.batch.fs.InputFile;
@@ -41,9 +40,7 @@ import org.sonar.api.scanner.ScannerSide;
 import org.sonar.sarif.pojo.ArtifactLocation;
 import org.sonar.sarif.pojo.Location;
 import org.sonar.sarif.pojo.PhysicalLocation;
-import org.sonar.sarif.pojo.Result;
 
-import static java.util.Objects.requireNonNull;
 import static org.sonar.api.utils.Preconditions.checkArgument;
 
 @ScannerSide
@@ -65,31 +62,23 @@ public class LocationMapper {
     this.regionMapper = regionMapper;
   }
 
-  NewIssueLocation fillIssueInProjectLocation(Result result, NewIssueLocation newIssueLocation) {
-    return newIssueLocation
-      .message(getResultMessageOrThrow(result))
+  void fillIssueInProjectLocation(NewIssueLocation newIssueLocation) {
+    newIssueLocation
       .on(sensorContext.project());
   }
 
-  @CheckForNull
-  NewIssueLocation fillIssueInFileLocation(Result result, NewIssueLocation newIssueLocation, Location location) {
-    newIssueLocation.message(getResultMessageOrThrow(result));
+  boolean fillIssueInFileLocation(NewIssueLocation newIssueLocation, Location location) {
     PhysicalLocation physicalLocation = location.getPhysicalLocation();
 
     String fileUri = getFileUriOrThrow(location);
     Optional<InputFile> file = findFile(fileUri);
     if (file.isEmpty()) {
-      return null;
+      return false;
     }
     InputFile inputFile = file.get();
     newIssueLocation.on(inputFile);
     regionMapper.mapRegion(physicalLocation.getRegion(), inputFile).ifPresent(newIssueLocation::at);
-    return newIssueLocation;
-  }
-
-  private static String getResultMessageOrThrow(Result result) {
-    requireNonNull(result.getMessage(), "No messages found for issue thrown by rule " + result.getRuleId());
-    return requireNonNull(result.getMessage().getText(), "No text found for messages in issue thrown by rule " + result.getRuleId());
+    return true;
   }
 
   private static String getFileUriOrThrow(Location location) {
index 21e855051722de2397817cab78c937bae6dadac0..05f8fa09b6ebafdd3ad2ff956b50d8289784aa86 100644 (file)
 package org.sonar.scanner.externalissue.sarif;
 
 import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.batch.rule.Severity;
 import org.sonar.api.batch.sensor.SensorContext;
@@ -34,7 +37,9 @@ import org.sonar.api.rules.CleanCodeAttribute;
 import org.sonar.api.rules.RuleType;
 import org.sonar.api.scanner.ScannerSide;
 import org.sonar.sarif.pojo.Location;
+import org.sonar.sarif.pojo.Message;
 import org.sonar.sarif.pojo.Result;
+import org.sonar.sarif.pojo.Stack;
 
 import static java.util.Objects.requireNonNull;
 import static org.sonar.api.issue.impact.Severity.HIGH;
@@ -96,29 +101,89 @@ public class ResultMapper {
   }
 
   private void mapLocations(Result result, NewExternalIssue newExternalIssue) {
-    NewIssueLocation newIssueLocation = newExternalIssue.newLocation();
-    List<Location> locations = result.getLocations();
-    if (locations == null || locations.isEmpty()) {
-      newExternalIssue.at(locationMapper.fillIssueInProjectLocation(result, newIssueLocation));
-    } else {
-      Location firstLocation = locations.iterator().next();
-      NewIssueLocation primaryLocation = fillFileOrProjectLocation(result, newIssueLocation, firstLocation);
-      newExternalIssue.at(primaryLocation);
+    createPrimaryLocation(newExternalIssue, result);
+    createSecondaryLocations(result, newExternalIssue);
+    createFlows(result, newExternalIssue);
+  }
+
+  private void createFlows(Result result, NewExternalIssue newExternalIssue) {
+    Set<Stack> stacks = Optional.ofNullable(result.getStacks()).orElse(Set.of());
+    if (!stacks.isEmpty()) {
+      stacks.forEach(stack -> {
+        var frames = Optional.ofNullable(stack.getFrames()).orElse(List.of());
+        if (!frames.isEmpty()) {
+          List<NewIssueLocation> flow = new ArrayList<>();
+          frames.forEach(frame -> {
+            var frameLocation = frame.getLocation();
+            if (frameLocation != null) {
+              var newFrameLocation = createIssueLocation(newExternalIssue, frameLocation);
+              flow.add(newFrameLocation);
+            }
+          });
+          newExternalIssue.addFlow(flow);
+        }
+      });
     }
+  }
 
-    Set<Location> relatedLocations = result.getRelatedLocations();
-    if (relatedLocations != null && !relatedLocations.isEmpty()) {
+  private void createSecondaryLocations(Result result, NewExternalIssue newExternalIssue) {
+    Set<Location> relatedLocations = Optional.ofNullable(result.getRelatedLocations()).orElse(Set.of());
+    if (!relatedLocations.isEmpty()) {
       relatedLocations.forEach(relatedLocation -> {
-        NewIssueLocation newRelatedLocation = newExternalIssue.newLocation();
-        fillFileOrProjectLocation(result, newRelatedLocation, relatedLocation);
+        var newRelatedLocation = createIssueLocation(newExternalIssue, relatedLocation);
         newExternalIssue.addLocation(newRelatedLocation);
       });
     }
   }
 
-  private NewIssueLocation fillFileOrProjectLocation(Result result, NewIssueLocation newIssueLocation, Location firstLocation) {
-    return Optional.ofNullable(locationMapper.fillIssueInFileLocation(result, newIssueLocation, firstLocation))
-      .orElseGet(() -> locationMapper.fillIssueInProjectLocation(result, newIssueLocation));
+  private NewIssueLocation createIssueLocation(NewExternalIssue newExternalIssue, Location sarifLocation) {
+    NewIssueLocation newRelatedLocation = newExternalIssue.newLocation();
+    var locationMessageText = getTextMessageOrNull(sarifLocation.getMessage());
+    if (locationMessageText != null) {
+      newRelatedLocation.message(locationMessageText);
+    }
+    fillFileOrProjectLocation(newRelatedLocation, sarifLocation);
+    return newRelatedLocation;
+  }
+
+  private void createPrimaryLocation(NewExternalIssue newExternalIssue, Result result) {
+    NewIssueLocation sonarLocation = newExternalIssue.newLocation();
+    List<Location> sarifLocations = Optional.ofNullable(result.getLocations()).orElse(List.of());
+    var primaryMessage = computePrimaryMessage(result, sarifLocations);
+    sonarLocation.message(primaryMessage);
+    if (sarifLocations.isEmpty()) {
+      locationMapper.fillIssueInProjectLocation(sonarLocation);
+    } else {
+      Location firstSarifLocation = sarifLocations.get(0);
+      fillFileOrProjectLocation(sonarLocation, firstSarifLocation);
+    }
+    newExternalIssue.at(sonarLocation);
+  }
+
+  private static String computePrimaryMessage(Result result, List<Location> locations) {
+    String resultMessage = Objects.requireNonNull(result.getMessage().getText(), "Message text is required on result");
+    if (!locations.isEmpty()) {
+      Location firstLocation = locations.get(0);
+      var locationMessageText = getTextMessageOrNull(firstLocation.getMessage());
+      if (locationMessageText != null) {
+        return resultMessage + " - " + locationMessageText;
+      }
+    }
+    return resultMessage;
+  }
+
+  @CheckForNull
+  private static String getTextMessageOrNull(@Nullable Message message) {
+    if (message == null) {
+      return null;
+    }
+    return message.getText();
+  }
+
+  private void fillFileOrProjectLocation(NewIssueLocation newIssueLocation, Location firstLocation) {
+    if (!locationMapper.fillIssueInFileLocation(newIssueLocation, firstLocation)) {
+      locationMapper.fillIssueInProjectLocation(newIssueLocation);
+    }
   }
 
 }
index 18ddca2a866b72b765d4e923543ff824ced4c0a3..c05e35429a3f1243444f4e010db4b6bb5f0c990c 100644 (file)
@@ -36,7 +36,6 @@ import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.issue.NewIssueLocation;
 import org.sonar.api.scanner.fs.InputProject;
 import org.sonar.sarif.pojo.Location;
-import org.sonar.sarif.pojo.Result;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -49,7 +48,6 @@ import static org.mockito.Mockito.when;
 @RunWith(MockitoJUnitRunner.class)
 public class LocationMapperTest {
 
-  private static final String TEST_MESSAGE = "test message";
   private static final String URI_TEST = "URI_TEST";
   private static final String EXPECTED_MESSAGE_URI_MISSING = "The field location.physicalLocation.artifactLocation.uri is not set.";
 
@@ -65,8 +63,6 @@ public class LocationMapperTest {
   @Mock
   private NewIssueLocation newIssueLocation;
 
-  @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-  private Result result;
   @Mock(answer = Answers.RETURNS_DEEP_STUBS)
   private Location location;
 
@@ -75,13 +71,10 @@ public class LocationMapperTest {
 
   @Before
   public void setup() {
-    when(newIssueLocation.message(any())).thenReturn(newIssueLocation);
     when(newIssueLocation.on(any())).thenReturn(newIssueLocation);
     when(newIssueLocation.at(any())).thenReturn(newIssueLocation);
     when(sensorContext.project()).thenReturn(mock(InputProject.class));
 
-    when(result.getMessage().getText()).thenReturn(TEST_MESSAGE);
-
     when(location.getPhysicalLocation().getArtifactLocation().getUri()).thenReturn(URI_TEST);
     when(sensorContext.fileSystem().inputFile(any(FilePredicate.class))).thenReturn(inputFile);
   }
@@ -105,12 +98,12 @@ public class LocationMapperTest {
   }
 
   @Test
-  public void fillIssueInFileLocation_whenFileNotFound_returnsNull() {
+  public void fillIssueInFileLocation_whenFileNotFound_returnsFalse() {
     when(sensorContext.fileSystem().inputFile(any())).thenReturn(null);
 
-    NewIssueLocation actualIssueLocation = locationMapper.fillIssueInFileLocation(result, newIssueLocation, location);
+    boolean success = locationMapper.fillIssueInFileLocation(newIssueLocation, location);
 
-    assertThat(actualIssueLocation).isNull();
+    assertThat(success).isFalse();
   }
 
   @Test
@@ -118,10 +111,9 @@ public class LocationMapperTest {
     when(regionMapper.mapRegion(location.getPhysicalLocation().getRegion(), inputFile))
       .thenReturn(Optional.empty());
 
-    NewIssueLocation actualIssueLocation = locationMapper.fillIssueInFileLocation(result, newIssueLocation, location);
+    boolean success = locationMapper.fillIssueInFileLocation(newIssueLocation, location);
 
-    assertThat(actualIssueLocation).isSameAs(newIssueLocation);
-    verify(newIssueLocation).message(TEST_MESSAGE);
+    assertThat(success).isTrue();
     verify(newIssueLocation).on(inputFile);
     verifyNoMoreInteractions(newIssueLocation);
   }
@@ -132,10 +124,9 @@ public class LocationMapperTest {
     when(regionMapper.mapRegion(location.getPhysicalLocation().getRegion(), inputFile))
       .thenReturn(Optional.of(textRange));
 
-    NewIssueLocation actualIssueLocation = locationMapper.fillIssueInFileLocation(result, newIssueLocation, location);
+    boolean success = locationMapper.fillIssueInFileLocation(newIssueLocation, location);
 
-    assertThat(actualIssueLocation).isSameAs(newIssueLocation);
-    verify(newIssueLocation).message(TEST_MESSAGE);
+    assertThat(success).isTrue();
     verify(newIssueLocation).on(inputFile);
     verify(newIssueLocation).at(textRange);
     verifyNoMoreInteractions(newIssueLocation);
@@ -146,7 +137,7 @@ public class LocationMapperTest {
     when(location.getPhysicalLocation().getArtifactLocation().getUri()).thenReturn(null);
 
     assertThatIllegalArgumentException()
-      .isThrownBy(() -> locationMapper.fillIssueInFileLocation(result, newIssueLocation, location))
+      .isThrownBy(() -> locationMapper.fillIssueInFileLocation(newIssueLocation, location))
       .withMessage(EXPECTED_MESSAGE_URI_MISSING);
   }
 
@@ -155,7 +146,7 @@ public class LocationMapperTest {
     when(location.getPhysicalLocation().getArtifactLocation()).thenReturn(null);
 
     assertThatIllegalArgumentException()
-      .isThrownBy(() -> locationMapper.fillIssueInFileLocation(result, newIssueLocation, location))
+      .isThrownBy(() -> locationMapper.fillIssueInFileLocation(newIssueLocation, location))
       .withMessage(EXPECTED_MESSAGE_URI_MISSING);
   }
 
@@ -164,7 +155,7 @@ public class LocationMapperTest {
     when(location.getPhysicalLocation().getArtifactLocation()).thenReturn(null);
 
     assertThatIllegalArgumentException()
-      .isThrownBy(() -> locationMapper.fillIssueInFileLocation(result, newIssueLocation, location))
+      .isThrownBy(() -> locationMapper.fillIssueInFileLocation(newIssueLocation, location))
       .withMessage(EXPECTED_MESSAGE_URI_MISSING);
   }
 
index 80e757932239c93bfa1decd043e212216e2782cd..3efc8c512288024d1441aea3cb171fffdd24b200 100644 (file)
@@ -36,10 +36,14 @@ import org.sonar.api.batch.sensor.issue.NewExternalIssue;
 import org.sonar.api.batch.sensor.issue.NewIssueLocation;
 import org.sonar.api.rules.RuleType;
 import org.sonar.sarif.pojo.Location;
+import org.sonar.sarif.pojo.Message;
 import org.sonar.sarif.pojo.Result;
+import org.sonar.sarif.pojo.Stack;
+import org.sonar.sarif.pojo.StackFrame;
 
 import static org.assertj.core.api.Assertions.assertThatNullPointerException;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -68,7 +72,6 @@ public class ResultMapperTest {
   @Mock
   private NewIssueLocation newExternalIssueLocation;
 
-  @Mock
   private Result result;
 
   @InjectMocks
@@ -77,10 +80,10 @@ public class ResultMapperTest {
   @Before
   public void setUp() {
     MockitoAnnotations.openMocks(this);
-    when(result.getRuleId()).thenReturn(RULE_ID);
+    result = new Result().withMessage(new Message().withText("Result message"));
+    result.withRuleId(RULE_ID);
     when(sensorContext.newExternalIssue()).thenReturn(mockExternalIssue);
-    when(locationMapper.fillIssueInFileLocation(any(), any(), any())).thenReturn(newExternalIssueLocation);
-    when(locationMapper.fillIssueInProjectLocation(any(), any())).thenReturn(newExternalIssueLocation);
+    when(locationMapper.fillIssueInFileLocation(any(), any())).thenReturn(true);
     when(mockExternalIssue.newLocation()).thenReturn(newExternalIssueLocation);
   }
 
@@ -96,7 +99,7 @@ public class ResultMapperTest {
 
   @Test
   public void mapResult_ifRuleIdMissing_fails() {
-    when(result.getRuleId()).thenReturn(null);
+    result.withRuleId(null);
     assertThatNullPointerException()
       .isThrownBy(() -> resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result))
       .withMessage("No ruleId found for issue thrown by driver driverName");
@@ -104,44 +107,113 @@ public class ResultMapperTest {
 
   @Test
   public void mapResult_whenLocationExists_createsFileLocation() {
-    Location location = mock(Location.class);
-    when(result.getLocations()).thenReturn(List.of(location));
+    Location location = new Location();
+    result.withLocations(List.of(location));
 
     NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
 
-    verify(locationMapper).fillIssueInFileLocation(result, newExternalIssueLocation, location);
+    verify(locationMapper).fillIssueInFileLocation(newExternalIssueLocation, location);
     verifyNoMoreInteractions(locationMapper);
     verify(newExternalIssue).at(newExternalIssueLocation);
     verify(newExternalIssue, never()).addLocation(any());
     verify(newExternalIssue, never()).addFlow(any());
   }
 
+  @Test
+  public void mapResult_useResultMessageForIssue() {
+    Location location = new Location();
+    result.withLocations(List.of(location));
+
+    resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
+
+    verify(newExternalIssueLocation).message("Result message");
+  }
+
+  @Test
+  public void mapResult_concatResultMessageAndLocationMessageForIssue() {
+    Location location = new Location().withMessage(new Message().withText("Location message"));
+    result.withLocations(List.of(location));
+
+    resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
+
+    verify(newExternalIssueLocation).message("Result message - Location message");
+  }
+
   @Test
   public void mapResult_whenRelatedLocationExists_createsSecondaryFileLocation() {
-    Location location = mock(Location.class);
-    when(result.getRelatedLocations()).thenReturn(Set.of(location));
+    Location relatedLocation = new Location().withMessage(new Message().withText("Related location message"));
+    result.withRelatedLocations(Set.of(relatedLocation));
     var newIssueLocationCall2 = mock(NewIssueLocation.class);
     when(mockExternalIssue.newLocation()).thenReturn(newExternalIssueLocation, newIssueLocationCall2);
 
     NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
 
-    verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation);
-    verify(locationMapper).fillIssueInFileLocation(result, newIssueLocationCall2, location);
+    verify(locationMapper).fillIssueInProjectLocation(newExternalIssueLocation);
+    verify(locationMapper).fillIssueInFileLocation(newIssueLocationCall2, relatedLocation);
     verifyNoMoreInteractions(locationMapper);
     verify(newExternalIssue).at(newExternalIssueLocation);
     verify(newExternalIssue).addLocation(newIssueLocationCall2);
     verify(newExternalIssue, never()).addFlow(any());
+    verify(newIssueLocationCall2).message("Related location message");
+  }
+
+  @Test
+  public void mapResult_whenRelatedLocationExists_createsSecondaryFileLocation_no_messages() {
+    Location relatedLocationWithoutMessage = new Location();
+    result.withRelatedLocations(Set.of(relatedLocationWithoutMessage));
+    var newIssueLocationCall2 = mock(NewIssueLocation.class);
+    when(mockExternalIssue.newLocation()).thenReturn(newExternalIssueLocation, newIssueLocationCall2);
+
+    NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
+
+    verify(newExternalIssue).addLocation(newIssueLocationCall2);
+    verify(newIssueLocationCall2, never()).message(anyString());
+  }
+
+  @Test
+  public void mapResult_whenStacksLocationExists_createsCodeFlowFileLocation() {
+    Location stackFrameLocation = new Location().withMessage(new Message().withText("Stack frame location message"));
+    var stackWithFrame = new Stack().withFrames(List.of(new StackFrame().withLocation(stackFrameLocation)));
+    var stackWithFrameNoLocation = new Stack().withFrames(List.of(new StackFrame()));
+    var stackWithoutFrame = new Stack().withFrames(List.of());
+    var stackWithoutFrame2 = new Stack();
+    result.withStacks(Set.of(stackWithFrame, stackWithFrameNoLocation, stackWithoutFrame, stackWithoutFrame2));
+    var newIssueLocationCall2 = mock(NewIssueLocation.class);
+    when(mockExternalIssue.newLocation()).thenReturn(newExternalIssueLocation, newIssueLocationCall2);
+
+    NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
+
+    verify(locationMapper).fillIssueInProjectLocation(newExternalIssueLocation);
+    verify(locationMapper).fillIssueInFileLocation(newIssueLocationCall2, stackFrameLocation);
+    verifyNoMoreInteractions(locationMapper);
+    verify(newExternalIssue).at(newExternalIssueLocation);
+    verify(newExternalIssue).addFlow(List.of(newIssueLocationCall2));
+    verify(newExternalIssue, never()).addLocation(any());
+    verify(newIssueLocationCall2).message("Stack frame location message");
+  }
+
+  @Test
+  public void mapResult_whenStacksLocationExists_createsCodeFlowFileLocation_no_text_messages() {
+    Location stackFrameLocationWithoutMessage = new Location().withMessage(new Message().withId("1"));
+    result.withStacks(Set.of(new Stack().withFrames(List.of(new StackFrame().withLocation(stackFrameLocationWithoutMessage)))));
+    var newIssueLocationCall2 = mock(NewIssueLocation.class);
+    when(mockExternalIssue.newLocation()).thenReturn(newExternalIssueLocation, newIssueLocationCall2);
+
+    NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
+
+    verify(newExternalIssue).addFlow(List.of(newIssueLocationCall2));
+    verify(newIssueLocationCall2, never()).message(anyString());
   }
 
   @Test
-  public void mapResult_whenLocationExistsButLocationMapperReturnsNull_createsProjectLocation() {
-    Location location = mock(Location.class);
-    when(result.getLocations()).thenReturn(List.of(location));
-    when(locationMapper.fillIssueInFileLocation(any(), any(), any())).thenReturn(null);
+  public void mapResult_whenLocationExistsButLocationMapperReturnsFalse_createsProjectLocation() {
+    Location location = new Location();
+    result.withLocations(List.of(location));
+    when(locationMapper.fillIssueInFileLocation(any(), any())).thenReturn(false);
 
     NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
 
-    verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation);
+    verify(locationMapper).fillIssueInProjectLocation(newExternalIssueLocation);
     verify(newExternalIssue).at(newExternalIssueLocation);
     verify(newExternalIssue, never()).addLocation(any());
     verify(newExternalIssue, never()).addFlow(any());
@@ -150,8 +222,9 @@ public class ResultMapperTest {
   @Test
   public void mapResult_whenLocationsIsEmpty_createsProjectLocation() {
     NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
+    result.withLocations(List.of());
 
-    verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation);
+    verify(locationMapper).fillIssueInProjectLocation(newExternalIssueLocation);
     verifyNoMoreInteractions(locationMapper);
     verify(newExternalIssue).at(newExternalIssueLocation);
     verify(newExternalIssue, never()).addLocation(any());
@@ -160,10 +233,9 @@ public class ResultMapperTest {
 
   @Test
   public void mapResult_whenLocationsIsNull_createsProjectLocation() {
-    when(result.getLocations()).thenReturn(null);
     NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result);
 
-    verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation);
+    verify(locationMapper).fillIssueInProjectLocation(newExternalIssueLocation);
     verifyNoMoreInteractions(locationMapper);
     verify(newExternalIssue).at(newExternalIssueLocation);
     verify(newExternalIssue, never()).addLocation(any());