private void assertSingleIssue(Set<AnalyzerMessage> issues) {
   Preconditions.checkState(
       issues.size() == 1, "A single issue is expected with line " + expectFileIssueOnline);
   AnalyzerMessage issue = Iterables.getFirst(issues, null);
   assertThat(issue.getLine()).isEqualTo(expectFileIssueOnline);
   assertThat(issue.getMessage()).isEqualTo(expectFileIssue);
 }
 private static void validateAnalyzerMessage(
     Map<IssueAttribute, String> attrs, AnalyzerMessage analyzerMessage) {
   Double effortToFix = analyzerMessage.getCost();
   if (effortToFix != null) {
     assertEquals(Integer.toString(effortToFix.intValue()), attrs, IssueAttribute.EFFORT_TO_FIX);
   }
   AnalyzerMessage.TextSpan textSpan = analyzerMessage.primaryLocation();
   assertEquals(normalizeColumn(textSpan.startCharacter), attrs, IssueAttribute.START_COLUMN);
   assertEquals(Integer.toString(textSpan.endLine), attrs, IssueAttribute.END_LINE);
   assertEquals(normalizeColumn(textSpan.endCharacter), attrs, IssueAttribute.END_COLUMN);
   if (attrs.containsKey(IssueAttribute.SECONDARY_LOCATIONS)) {
     List<AnalyzerMessage> secondaryLocations = analyzerMessage.secondaryLocations;
     Multiset<String> actualLines = HashMultiset.create();
     for (AnalyzerMessage secondaryLocation : secondaryLocations) {
       actualLines.add(Integer.toString(secondaryLocation.getLine()));
     }
     List<String> expected =
         Lists.newArrayList(
             Splitter.on(",")
                 .omitEmptyStrings()
                 .trimResults()
                 .split(attrs.get(IssueAttribute.SECONDARY_LOCATIONS)));
     List<String> unexpected = new ArrayList<>();
     for (String actualLine : actualLines) {
       if (expected.contains(actualLine)) {
         expected.remove(actualLine);
       } else {
         unexpected.add(actualLine);
       }
     }
     if (!expected.isEmpty() || !unexpected.isEmpty()) {
       Fail.fail("Secondary locations: expected: " + expected + " unexpected:" + unexpected);
     }
   }
 }
 private static void validateIssue(
     Multimap<Integer, Map<IssueAttribute, String>> expected,
     List<Integer> unexpectedLines,
     AnalyzerMessage issue,
     boolean isLinear) {
   int line = issue.getLine();
   if (expected.containsKey(line)) {
     Map<IssueAttribute, String> attrs = Iterables.getLast(expected.get(line));
     assertEquals(issue.getMessage(), attrs, IssueAttribute.MESSAGE);
     Double cost = issue.getCost();
     if (cost != null) {
       assertEquals(Integer.toString(cost.intValue()), attrs, IssueAttribute.EFFORT_TO_FIX);
     } else if (isLinear) {
       Fail.fail("A cost should be provided for a rule with linear remediation function");
     }
     validateAnalyzerMessage(attrs, issue);
     expected.remove(line, attrs);
   } else {
     unexpectedLines.add(line);
   }
 }
 @Override
 public void reportIssue(
     JavaCheck javaCheck,
     Tree syntaxNode,
     String message,
     List<Location> secondary,
     @Nullable Integer cost) {
   AnalyzerMessage analyzerMessage =
       new AnalyzerMessage(
           javaCheck,
           file,
           AnalyzerMessage.textSpanFor(syntaxNode),
           message,
           cost != null ? cost : 0);
   for (Location location : secondary) {
     AnalyzerMessage secondaryLocation =
         new AnalyzerMessage(
             javaCheck, file, AnalyzerMessage.textSpanFor(location.syntaxNode), location.msg, 0);
     analyzerMessage.secondaryLocations.add(secondaryLocation);
   }
   sonarComponents.reportIssue(analyzerMessage);
 }
 private static boolean isLinear(AnalyzerMessage issue) {
   String ruleKey;
   RspecKey rspecKeyAnnotation =
       AnnotationUtils.getAnnotation(issue.getCheck().getClass(), RspecKey.class);
   if (rspecKeyAnnotation != null) {
     ruleKey = rspecKeyAnnotation.value();
   } else {
     ruleKey = AnnotationUtils.getAnnotation(issue.getCheck().getClass(), Rule.class).key();
   }
   try {
     URL resource =
         CheckVerifier.class.getResource(
             "/org/sonar/l10n/java/rules/squid/" + ruleKey + "_java.json");
     if (resource == null) {
       throw new IOException();
     }
     String json = Resources.toString(resource, Charsets.UTF_8);
     return LINEAR_FUNC_PATTERN.matcher(json).find();
   } catch (IOException e) {
     // Failed to open json file, as this is not part of API yet, we should not fail because of
     // this
   }
   return false;
 }