]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6258 Persist symbols into file sources
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 14 Apr 2015 14:31:46 +0000 (16:31 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 14 Apr 2015 14:32:34 +0000 (16:32 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/source/HighlightingLineReader.java
server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeHelper.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSymbolsStep.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/source/RangeHelperTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/source/SymbolsLineReaderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSymbolsStepTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/index/SourceDataFactoryTest.java

index 3deab174ed033fdb1ca1f922b6c71bf4f6a7ccac..19c8eaf4a4ed5aa10e1e44ffbf79f24cb3aad216 100644 (file)
@@ -35,9 +35,6 @@ import static com.google.common.collect.Lists.newArrayList;
 
 public class HighlightingLineReader implements LineReader {
 
-  private static final String OFFSET_SEPARATOR = ",";
-  private static final String ITEM_SEPARATOR = ";";
-
   private static final Map<Constants.HighlightingType, String> cssClassByType = ImmutableMap.<Constants.HighlightingType, String>builder()
     .put(Constants.HighlightingType.ANNOTATION, "a")
     .put(Constants.HighlightingType.CONSTANT, "c")
@@ -70,10 +67,8 @@ public class HighlightingLineReader implements LineReader {
       BatchReport.SyntaxHighlighting syntaxHighlighting = syntaxHighlightingIterator.next();
       BatchReport.Range range = syntaxHighlighting.getRange();
       if (range.getStartLine() <= line) {
-        if (highlighting.length() > 0) {
-          highlighting.append(ITEM_SEPARATOR);
-        }
-        highlighting.append(convertHighlightingToString(syntaxHighlighting, line, lineBuilder.getSource()));
+        RangeHelper.appendRange(highlighting, syntaxHighlighting.getRange(), line, lineBuilder.getSource().length());
+        highlighting.append(getCssClass(syntaxHighlighting.getType()));
         if (range.getEndLine() == line) {
           syntaxHighlightingIterator.remove();
         }
@@ -84,29 +79,6 @@ public class HighlightingLineReader implements LineReader {
     }
   }
 
-  private String convertHighlightingToString(BatchReport.SyntaxHighlighting syntaxHighlighting, int line, String sourceLine){
-    BatchReport.Range range = syntaxHighlighting.getRange();
-    validateStartAndEndOffset(range, line);
-
-    StringBuilder symbolLine = new StringBuilder();
-    if (range.getStartLine() == line) {
-      validateStartOffsetNotGreaterThanLineLength(range, sourceLine, line);
-      symbolLine.append(range.getStartOffset()).append(OFFSET_SEPARATOR);
-    } else if (range.getStartLine() < line) {
-      symbolLine.append(0).append(OFFSET_SEPARATOR);
-    }
-
-    if (range.getEndLine() == line) {
-      validateEndOffsetNotGreaterThanLineLength(range, sourceLine, line);
-      symbolLine.append(range.getEndOffset()).append(OFFSET_SEPARATOR);
-    } else if (range.getEndLine() > line) {
-      symbolLine.append(sourceLine.length() - 1).append(OFFSET_SEPARATOR);
-    }
-
-    symbolLine.append(getCssClass(syntaxHighlighting.getType()));
-    return symbolLine.toString();
-  }
-
   private static String getCssClass(Constants.HighlightingType type) {
     String cssClass = cssClassByType.get(type);
     if (cssClass != null) {
@@ -138,22 +110,4 @@ public class HighlightingLineReader implements LineReader {
     return null;
   }
 
-  private static void validateStartAndEndOffset(BatchReport.Range range, int line){
-    if (range.getStartLine() == range.getEndLine() && range.getStartOffset() > range.getEndOffset()) {
-      throw new IllegalArgumentException(String.format("End offset %s cannot be defined before start offset %s on line %s", range.getEndOffset(), range.getStartOffset(), line));
-    }
-  }
-
-  private static void validateStartOffsetNotGreaterThanLineLength(BatchReport.Range range, String sourceLine, int line){
-    if (range.getStartOffset() > sourceLine.length()) {
-      throw new IllegalArgumentException(String.format("Start offset %s is defined outside the length (%s) of the line %s", range.getStartOffset(), sourceLine.length(), line));
-    }
-  }
-
-  private static void validateEndOffsetNotGreaterThanLineLength(BatchReport.Range range, String sourceLine, int line){
-    if (range.getEndOffset() > sourceLine.length()) {
-      throw new IllegalArgumentException(String.format("End offset %s is defined outside the length (%s) of the line %s", range.getEndOffset(), sourceLine.length(), line));
-    }
-  }
-
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeHelper.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/RangeHelper.java
new file mode 100644 (file)
index 0000000..3c460e0
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+package org.sonar.server.computation.source;
+
+import org.sonar.batch.protocol.output.BatchReport;
+
+public class RangeHelper {
+
+  private static final String OFFSET_SEPARATOR = ",";
+  private static final String SYMBOLS_SEPARATOR = ";";
+
+  private RangeHelper() {
+    // Only static methods
+  }
+
+  public static void appendRange(StringBuilder element, BatchReport.Range range, int lineIndex, int lineLength) {
+    validateOffsetOrder(range, lineIndex);
+
+    if (element.length() > 0) {
+      element.append(SYMBOLS_SEPARATOR);
+    }
+
+    if (range.getStartLine() == lineIndex) {
+      validateStartOffsetNotGreaterThanLineLength(range, lineLength, lineIndex);
+      element.append(range.getStartOffset()).append(OFFSET_SEPARATOR);
+    } else if (range.getStartLine() < lineIndex) {
+      element.append(0).append(OFFSET_SEPARATOR);
+    }
+
+    if (range.getEndLine() == lineIndex) {
+      validateEndOffsetNotGreaterThanLineLength(range, lineLength, lineIndex);
+      element.append(range.getEndOffset()).append(OFFSET_SEPARATOR);
+    } else if (range.getEndLine() > lineIndex) {
+      element.append(lineLength - 1).append(OFFSET_SEPARATOR);
+    }
+  }
+
+  private static void validateOffsetOrder(BatchReport.Range range, int line) {
+    if (range.getStartLine() == range.getEndLine() && range.getStartOffset() > range.getEndOffset()) {
+      throw new IllegalArgumentException(String.format("End offset %s cannot be defined before start offset %s on line %s", range.getEndOffset(), range.getStartOffset(), line));
+    }
+  }
+
+  private static void validateStartOffsetNotGreaterThanLineLength(BatchReport.Range range, int lineLength, int line) {
+    if (range.getStartOffset() > lineLength) {
+      throw new IllegalArgumentException(String.format("Start offset %s is defined outside the length (%s) of the line %s", range.getStartOffset(), lineLength, line));
+    }
+  }
+
+  private static void validateEndOffsetNotGreaterThanLineLength(BatchReport.Range range, int lineLength, int line) {
+    if (range.getEndOffset() > lineLength) {
+      throw new IllegalArgumentException(String.format("End offset %s is defined outside the length (%s) of the line %s", range.getEndOffset(), lineLength, line));
+    }
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java
new file mode 100644 (file)
index 0000000..fecebb5
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+package org.sonar.server.computation.source;
+
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.source.db.FileSourceDb;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+
+public class SymbolsLineReader implements LineReader {
+
+  private final List<BatchReport.Symbols.Symbol> symbols;
+  private final Map<BatchReport.Symbols.Symbol, Integer> idsBySymbol;
+
+  public SymbolsLineReader(List<BatchReport.Symbols.Symbol> symbols) {
+    this.symbols = symbols;
+    // Sort symbols to have deterministic results and avoid false variation that would lead to an unnecessary update of the source files
+    // data
+    Collections.sort(this.symbols, new SymbolsDuplication());
+
+    this.idsBySymbol = createIdsBySymbolMap(symbols);
+  }
+
+  @Override
+  public void read(FileSourceDb.Line.Builder lineBuilder) {
+    int line = lineBuilder.getLine();
+    List<BatchReport.Symbols.Symbol> lineSymbols = findSymbolsMatchingLine(line);
+    for (BatchReport.Symbols.Symbol lineSymbol : lineSymbols) {
+      int symbolId = idsBySymbol.get(lineSymbol);
+      StringBuilder symbolString = new StringBuilder(lineBuilder.getSymbols());
+
+      appendSymbol(symbolString, lineSymbol.getDeclaration(), line, symbolId, lineBuilder.getSource());
+      for (BatchReport.Range range : lineSymbol.getReferenceList()) {
+        appendSymbol(symbolString, range, line, symbolId, lineBuilder.getSource());
+      }
+
+      if (symbolString.length() > 0) {
+        lineBuilder.setSymbols(symbolString.toString());
+      }
+    }
+  }
+
+  private void appendSymbol(StringBuilder lineSymbol, BatchReport.Range range, int line, int symbolId, String sourceLine) {
+    if (matchLine(range, line)) {
+      RangeHelper.appendRange(lineSymbol, range, line, sourceLine.length());
+      lineSymbol.append(symbolId);
+    }
+  }
+
+  private List<BatchReport.Symbols.Symbol> findSymbolsMatchingLine(int line) {
+    List<BatchReport.Symbols.Symbol> lineSymbols = newArrayList();
+    for (BatchReport.Symbols.Symbol symbol : symbols) {
+      if (matchLine(symbol.getDeclaration(), line)) {
+        lineSymbols.add(symbol);
+      } else {
+        for (BatchReport.Range range : symbol.getReferenceList()) {
+          if (matchLine(range, line)) {
+            lineSymbols.add(symbol);
+          }
+        }
+      }
+    }
+    return lineSymbols;
+  }
+
+  private static boolean matchLine(BatchReport.Range range, int line) {
+    return range.getStartLine() <= line && range.getEndLine() >= line;
+  }
+
+  private Map<BatchReport.Symbols.Symbol, Integer> createIdsBySymbolMap(List<BatchReport.Symbols.Symbol> symbols) {
+    Map<BatchReport.Symbols.Symbol, Integer> map = newHashMap();
+    int symbolId = 1;
+    for (BatchReport.Symbols.Symbol symbol : symbols) {
+      map.put(symbol, symbolId);
+      symbolId++;
+    }
+    return map;
+  }
+
+  private static class SymbolsDuplication implements Comparator<BatchReport.Symbols.Symbol> {
+    @Override
+    public int compare(BatchReport.Symbols.Symbol o1, BatchReport.Symbols.Symbol o2) {
+      if (o1.getDeclaration().getStartLine() == o2.getDeclaration().getStartLine()) {
+        return Integer.compare(o1.getDeclaration().getStartOffset(), o2.getDeclaration().getStartOffset());
+      } else {
+        return Integer.compare(o1.getDeclaration().getStartLine(), o2.getDeclaration().getStartLine());
+      }
+    }
+  }
+}
index 26e71e31af9fae4d939f3fe991f94545a6f20b75..d6732477793ecf110a69b07c81b58c180242316e 100644 (file)
@@ -176,6 +176,7 @@ public class PersistFileSourcesStep implements ComputationStep {
       File coverageFile = reportReader.readComponentCoverage(componentRef);
       BatchReport.Scm scmReport = reportReader.readComponentScm(componentRef);
       File highlightingFile = reportReader.readComponentSyntaxHighlighting(componentRef);
+      List<BatchReport.Symbols.Symbol> symbols = reportReader.readComponentSymbols(componentRef);
 
       if (coverageFile != null) {
         ReportIterator<BatchReport.Coverage> coverageReportIterator = new ReportIterator<>(coverageFile, BatchReport.Coverage.PARSER);
@@ -190,13 +191,16 @@ public class PersistFileSourcesStep implements ComputationStep {
         reportIterators.add(syntaxHighlightingReportIterator);
         lineReaders.add(new HighlightingLineReader(syntaxHighlightingReportIterator));
       }
+      if (!symbols.isEmpty()) {
+        lineReaders.add(new SymbolsLineReader(newArrayList(symbols)));
+      }
     }
 
-    List<LineReader> readers(){
+    List<LineReader> readers() {
       return lineReaders;
     }
 
-    void close(){
+    void close() {
       for (ReportIterator reportIterator : reportIterators) {
         reportIterator.close();
       }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSymbolsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistSymbolsStep.java
deleted file mode 100644 (file)
index d082495..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.
- */
-
-package org.sonar.server.computation.step;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReportReader;
-import org.sonar.server.computation.ComputationContext;
-
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.collect.Maps.newHashMap;
-
-/**
- * Nothing is persist for the moment. Only Symbols are read and not persist for the moment
- */
-public class PersistSymbolsStep implements ComputationStep {
-
-  private static final String OFFSET_SEPARATOR = ",";
-  private static final String SYMBOLS_SEPARATOR = ";";
-
-  // Temporary variable in order to be able to test that symbols are well computed. Will only contains data from last processed file
-  private Map<Integer, StringBuilder> symbolsByLineForLastProcessedFile;
-
-  @Override
-  public String[] supportedProjectQualifiers() {
-    return new String[]{Qualifiers.PROJECT};
-  }
-
-  @Override
-  public void execute(ComputationContext context) {
-    int rootComponentRef = context.getReportMetadata().getRootComponentRef();
-    recursivelyProcessComponent(context, rootComponentRef);
-  }
-
-  private void recursivelyProcessComponent(ComputationContext context, int componentRef) {
-    BatchReportReader reportReader = context.getReportReader();
-    BatchReport.Component component = reportReader.readComponent(componentRef);
-    List<BatchReport.Symbols.Symbol> symbols = reportReader.readComponentSymbols(componentRef);
-    processSymbols(component, symbols);
-
-    for (Integer childRef : component.getChildRefList()) {
-      recursivelyProcessComponent(context, childRef);
-    }
-  }
-
-  private void processSymbols(BatchReport.Component component, List<BatchReport.Symbols.Symbol> symbols) {
-    symbolsByLineForLastProcessedFile = newHashMap();
-    if (!symbols.isEmpty()) {
-      int symbolId = 1;
-      for (BatchReport.Symbols.Symbol symbol : symbols) {
-        processSymbolRange(symbol.getDeclaration(), symbolId);
-        for (BatchReport.Range reference : symbol.getReferenceList()) {
-          processSymbolRange(reference, symbolId);
-        }
-        symbolId++;
-      }
-    }
-  }
-
-  private void processSymbolRange(BatchReport.Range range, int symboleId){
-    int startLine = range.getStartLine();
-    if (startLine != range.getEndLine()) {
-      // TODO support symbols on multiple lines when source will be in compute, in order to be able to know the end line in this case
-      throw new IllegalStateException("To be implemented : Symbols on multiple lines are not supported for the moment");
-    }
-    StringBuilder symbolLine = symbolsByLineForLastProcessedFile.get(startLine);
-    if (symbolLine == null) {
-      symbolLine = new StringBuilder();
-      symbolsByLineForLastProcessedFile.put(startLine, symbolLine);
-    } else {
-      symbolLine.append(SYMBOLS_SEPARATOR);
-    }
-    symbolLine.append(range.getStartOffset()).append(OFFSET_SEPARATOR);
-    symbolLine.append(range.getEndOffset()).append(OFFSET_SEPARATOR);
-    symbolLine.append(symboleId);
-  }
-
-  @VisibleForTesting
-  Map<Integer, StringBuilder> getSymbolsByLine(){
-    return symbolsByLineForLastProcessedFile;
-  }
-
-  @Override
-  public String getDescription() {
-    return "Read Symbols";
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/source/RangeHelperTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/source/RangeHelperTest.java
new file mode 100644 (file)
index 0000000..0b326c6
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+package org.sonar.server.computation.source;
+
+import org.junit.Test;
+import org.sonar.batch.protocol.output.BatchReport;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;
+
+public class RangeHelperTest {
+
+  @Test
+  public void append_range() throws Exception {
+    StringBuilder element = new StringBuilder();
+    RangeHelper.appendRange(element, BatchReport.Range.newBuilder()
+      .setStartLine(1).setEndLine(1)
+      .setStartOffset(2).setEndOffset(3)
+      .build(),
+      1, 5);
+    assertThat(element.toString()).isEqualTo("2,3,");
+  }
+
+  @Test
+  public void append_range_om_existing_element() throws Exception {
+    StringBuilder element = new StringBuilder("1,2,a");
+    RangeHelper.appendRange(element, BatchReport.Range.newBuilder()
+      .setStartLine(1).setEndLine(1)
+      .setStartOffset(3).setEndOffset(4)
+      .build(),
+      1, 5);
+    assertThat(element.toString()).isEqualTo("1,2,a;3,4,");
+  }
+
+  @Test
+  public void append_range_not_finishing_in_current_line() throws Exception {
+    StringBuilder element = new StringBuilder();
+    RangeHelper.appendRange(element, BatchReport.Range.newBuilder()
+      .setStartLine(1).setEndLine(3)
+      .setStartOffset(2).setEndOffset(3)
+      .build(),
+      1, 5);
+    assertThat(element.toString()).isEqualTo("2,4,");
+  }
+
+  @Test
+  public void append_range_that_began_in_previous_line_and_finish_in_current_line() throws Exception {
+    StringBuilder element = new StringBuilder();
+    RangeHelper.appendRange(element, BatchReport.Range.newBuilder()
+      .setStartLine(1).setEndLine(3)
+      .setStartOffset(2).setEndOffset(3)
+      .build(),
+      3, 5);
+    assertThat(element.toString()).isEqualTo("0,3,");
+  }
+
+  @Test
+  public void append_range_that_began_in_previous_line_and_not_finishing_in_current_line() throws Exception {
+    StringBuilder element = new StringBuilder();
+    RangeHelper.appendRange(element, BatchReport.Range.newBuilder()
+      .setStartLine(1).setEndLine(3)
+      .setStartOffset(2).setEndOffset(3)
+      .build(),
+      2, 5);
+    assertThat(element.toString()).isEqualTo("0,4,");
+  }
+
+  @Test
+  public void fail_when_end_offset_is_before_start_offset() {
+    try {
+      RangeHelper.appendRange(new StringBuilder(), BatchReport.Range.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(4).setEndOffset(2)
+        .build(),
+        1, 5);
+      failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("End offset 2 cannot be defined before start offset 4 on line 1");
+    }
+  }
+
+  @Test
+  public void fail_when_end_offset_is_higher_than_line_length() {
+    try {
+      RangeHelper.appendRange(new StringBuilder(), BatchReport.Range.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(4).setEndOffset(10)
+        .build(),
+        1, 5);
+      failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("End offset 10 is defined outside the length (5) of the line 1");
+    }
+  }
+
+  @Test
+  public void fail_when_start_offset_is_higher_than_line_length() {
+    try {
+      RangeHelper.appendRange(new StringBuilder(), BatchReport.Range.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(10).setEndOffset(11)
+        .build(),
+        1, 5);
+      failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("Start offset 10 is defined outside the length (5) of the line 1");
+    }
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/source/SymbolsLineReaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/source/SymbolsLineReaderTest.java
new file mode 100644 (file)
index 0000000..b5e3c37
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+package org.sonar.server.computation.source;
+
+import org.junit.Test;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.source.db.FileSourceDb;
+
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SymbolsLineReaderTest {
+
+  FileSourceDb.Data.Builder sourceData = FileSourceDb.Data.newBuilder();
+  FileSourceDb.Line.Builder line1 = sourceData.addLinesBuilder().setSource("line1").setLine(1);
+  FileSourceDb.Line.Builder line2 = sourceData.addLinesBuilder().setSource("line2").setLine(2);
+  FileSourceDb.Line.Builder line3 = sourceData.addLinesBuilder().setSource("line3").setLine(3);
+  FileSourceDb.Line.Builder line4 = sourceData.addLinesBuilder().setSource("line4").setLine(4);
+
+  @Test
+  public void read_nothing() throws Exception {
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(Collections.<BatchReport.Symbols.Symbol>emptyList());
+
+    symbolsLineReader.read(line1);
+
+    assertThat(line1.getSymbols()).isEmpty();
+  }
+
+  @Test
+  public void read_symbols() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
+          .build())
+        .build()
+      );
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+    symbolsLineReader.read(line3);
+
+    assertThat(line1.getSymbols()).isEqualTo("2,4,1");
+    assertThat(line2.getSymbols()).isEmpty();
+    assertThat(line3.getSymbols()).isEqualTo("1,3,1");
+  }
+
+  @Test
+  public void read_symbols_with_reference_on_same_line() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
+          .build())
+        .build()
+      );
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+
+    assertThat(line1.getSymbols()).isEqualTo("0,1,1;2,3,1");
+  }
+
+  @Test
+  public void read_symbols_with_two_references() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(2).setEndLine(2).setStartOffset(0).setEndOffset(2)
+          .build())
+        .build()
+      );
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+    symbolsLineReader.read(line3);
+
+    assertThat(line1.getSymbols()).isEqualTo("2,4,1");
+    assertThat(line2.getSymbols()).isEqualTo("0,2,1");
+    assertThat(line3.getSymbols()).isEqualTo("1,3,1");
+  }
+
+  @Test
+  public void read_symbols_when_reference_line_is_before_declaration_line() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(2).setEndLine(2).setStartOffset(3).setEndOffset(4)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(1).setEndOffset(2)
+          .build())
+        .build()
+      );
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+
+    assertThat(line1.getSymbols()).isEqualTo("1,2,1");
+    assertThat(line2.getSymbols()).isEqualTo("3,4,1");
+  }
+
+  @Test
+  public void read_many_symbols_on_lines() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(1).setEndOffset(2)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
+          .build())
+        .build(),
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(3).setEndOffset(4)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(0).setEndOffset(1)
+          .build())
+        .build()
+      );
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+    symbolsLineReader.read(line3);
+
+    assertThat(line1.getSymbols()).isEqualTo("1,2,1;3,4,2");
+    assertThat(line2.getSymbols()).isEmpty();
+    assertThat(line3.getSymbols()).isEqualTo("2,3,1;0,1,2");
+  }
+
+  @Test
+  public void symbol_declaration_should_be_sorted_by_offset() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          // This symbol begins after the second symbol, it should appear in second place
+          .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
+          .build())
+        .build(),
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(0).setEndOffset(1)
+          .build())
+        .build());
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+    symbolsLineReader.read(line3);
+
+    assertThat(line1.getSymbols()).isEqualTo("0,1,1;2,3,2");
+    assertThat(line2.getSymbols()).isEmpty();
+    assertThat(line3.getSymbols()).isEqualTo("0,1,1;2,3,2");
+  }
+
+  @Test
+  public void symbol_declaration_should_be_sorted_by_line() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          // This symbol begins after the second symbol, it should appear in second place
+          .setStartLine(2).setEndLine(2).setStartOffset(0).setEndOffset(1)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
+          .build())
+        .build(),
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(0).setEndOffset(1)
+          .build())
+        .build());
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+    symbolsLineReader.read(line3);
+
+    assertThat(line1.getSymbols()).isEqualTo("0,1,1");
+    assertThat(line2.getSymbols()).isEqualTo("0,1,2");
+    assertThat(line3.getSymbols()).isEqualTo("0,1,1;2,3,2");
+  }
+
+  @Test
+  public void read_symbols_defined_on_many_lines() throws Exception {
+    List<BatchReport.Symbols.Symbol> symbols = newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(2).setStartOffset(1).setEndOffset(3)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(4).setStartOffset(1).setEndOffset(3)
+          .build())
+        .build());
+
+    SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
+    symbolsLineReader.read(line1);
+    symbolsLineReader.read(line2);
+    symbolsLineReader.read(line3);
+    symbolsLineReader.read(line4);
+
+    assertThat(line1.getSymbols()).isEqualTo("1,4,1");
+    assertThat(line2.getSymbols()).isEqualTo("0,3,1");
+    assertThat(line3.getSymbols()).isEqualTo("1,4,1");
+    assertThat(line4.getSymbols()).isEqualTo("0,3,1");
+  }
+
+}
index 79b3b72a9f4838fe1382a89307851f6c9edf1a4c..b75846f1a1e81df5ce689a1ed6bbdd75ed4811dc 100644 (file)
@@ -205,15 +205,14 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
     BatchReportWriter writer = initBasicReport(1);
 
     writer.writeComponentScm(BatchReport.Scm.newBuilder()
-        .setComponentRef(FILE_REF)
-        .addChangeset(BatchReport.Scm.Changeset.newBuilder()
-          .setAuthor("john")
-          .setDate(123456789L)
-          .setRevision("rev-1")
-          .build())
-        .addChangesetIndexByLine(0)
-        .build()
-    );
+      .setComponentRef(FILE_REF)
+      .addChangeset(BatchReport.Scm.Changeset.newBuilder()
+        .setAuthor("john")
+        .setDate(123456789L)
+        .setRevision("rev-1")
+        .build())
+      .addChangesetIndexByLine(0)
+      .build());
 
     sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto(PROJECT_UUID)));
 
@@ -233,13 +232,13 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
     BatchReportWriter writer = initBasicReport(1);
 
     writer.writeComponentSyntaxHighlighting(FILE_REF, newArrayList(BatchReport.SyntaxHighlighting.newBuilder()
-        .setRange(BatchReport.Range.newBuilder()
-          .setStartLine(1).setEndLine(1)
-          .setStartOffset(2).setEndOffset(4)
-          .build())
-        .setType(Constants.HighlightingType.ANNOTATION)
+      .setRange(BatchReport.Range.newBuilder()
+        .setStartLine(1).setEndLine(1)
+        .setStartOffset(2).setEndOffset(4)
         .build())
-    );
+      .setType(Constants.HighlightingType.ANNOTATION)
+      .build()
+      ));
 
     sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto(PROJECT_UUID)));
 
@@ -252,6 +251,34 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
     assertThat(data.getLines(0).getHighlighting()).isEqualTo("2,4,a");
   }
 
+  @Test
+  public void persist_symbols() throws Exception {
+    BatchReportWriter writer = initBasicReport(3);
+
+    writer.writeComponentSymbols(FILE_REF, newArrayList(
+      BatchReport.Symbols.Symbol.newBuilder()
+        .setDeclaration(BatchReport.Range.newBuilder()
+          .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
+          .build())
+        .addReference(BatchReport.Range.newBuilder()
+          .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
+          .build()
+        ).build()
+      ));
+
+    sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto(PROJECT_UUID)));
+
+    assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
+    FileSourceDto fileSourceDto = dbClient.fileSourceDao().select(FILE_UUID);
+    FileSourceDb.Data data = FileSourceDto.decodeData(fileSourceDto.getBinaryData());
+
+    assertThat(data.getLinesList()).hasSize(3);
+
+    assertThat(data.getLines(0).getSymbols()).isEqualTo("2,4,1");
+    assertThat(data.getLines(1).getSymbols()).isEmpty();
+    assertThat(data.getLines(2).getSymbols()).isEqualTo("1,3,1");
+  }
+
   @Test
   public void not_update_sources_when_nothing_has_changed() throws Exception {
     // Existing sources
@@ -379,7 +406,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
       .build());
 
     List<String> lines = newArrayList();
-    for (int i=1; i<=numberOfLines; i++) {
+    for (int i = 1; i <= numberOfLines; i++) {
       lines.add("line" + i);
     }
     FileUtils.writeLines(writer.getFileStructure().fileFor(FileStructure.Domain.SOURCE, FILE_REF), lines);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSymbolsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistSymbolsStepTest.java
deleted file mode 100644 (file)
index 327fde4..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.
- */
-
-package org.sonar.server.computation.step;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.batch.protocol.Constants;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReportReader;
-import org.sonar.batch.protocol.output.BatchReportWriter;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.server.computation.ComputationContext;
-import org.sonar.test.DbTests;
-
-import java.io.File;
-import java.io.IOException;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-@Category(DbTests.class)
-public class PersistSymbolsStepTest extends BaseStepTest {
-
-  private static final Integer FILE_REF = 3;
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  File reportDir;
-
-  PersistSymbolsStep step;
-
-  @Before
-  public void setup() throws Exception {
-    reportDir = temp.newFolder();
-    step = new PersistSymbolsStep();
-  }
-
-  @Override
-  protected ComputationStep step() throws IOException {
-    return step;
-  }
-
-  @Test
-  public void compute_no_symbol() throws Exception {
-    initReport();
-
-    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
-
-    assertThat(step.getSymbolsByLine()).isEmpty();
-  }
-
-  @Test
-  public void compute_one_symbol() throws Exception {
-    BatchReportWriter writer = initReport();
-
-    writer.writeComponentSymbols(FILE_REF, newArrayList(BatchReport.Symbols.Symbol.newBuilder()
-      .setDeclaration(BatchReport.Range.newBuilder()
-        .setStartLine(1)
-        .setStartOffset(3)
-        .setEndLine(1)
-        .setEndOffset(5)
-        .build())
-      .addReference(BatchReport.Range.newBuilder()
-        .setStartLine(10)
-        .setStartOffset(15)
-        .setEndLine(10)
-        .setEndOffset(17)
-        .build())
-      .addReference(BatchReport.Range.newBuilder()
-        .setStartLine(11)
-        .setStartOffset(7)
-        .setEndLine(11)
-        .setEndOffset(9)
-        .build())
-      .build()));
-
-    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
-
-    assertThat(step.getSymbolsByLine()).hasSize(3);
-    assertThat(step.getSymbolsByLine().get(1).toString()).isEqualTo("3,5,1");
-    assertThat(step.getSymbolsByLine().get(10).toString()).isEqualTo("15,17,1");
-    assertThat(step.getSymbolsByLine().get(11).toString()).isEqualTo("7,9,1");
-  }
-
-  @Test
-  public void compute_two_symbols() throws Exception {
-    BatchReportWriter writer = initReport();
-
-    writer.writeComponentSymbols(FILE_REF, newArrayList(
-        BatchReport.Symbols.Symbol.newBuilder()
-          .setDeclaration(BatchReport.Range.newBuilder()
-            .setStartLine(1)
-            .setEndLine(1)
-            .setStartOffset(3)
-            .setEndOffset(5)
-            .build())
-          .addReference(BatchReport.Range.newBuilder()
-            .setStartLine(10)
-            .setStartOffset(15)
-            .setEndLine(10)
-            .setEndOffset(16)
-            .build())
-          .build(),
-        BatchReport.Symbols.Symbol.newBuilder()
-          .setDeclaration(BatchReport.Range.newBuilder()
-            .setStartLine(1)
-            .setStartOffset(5)
-            .setEndLine(1)
-            .setEndOffset(6)
-            .build())
-          .addReference(BatchReport.Range.newBuilder()
-            .setStartLine(10)
-            .setStartOffset(9)
-            .setEndLine(10)
-            .setEndOffset(10)
-            .build())
-          .build())
-    );
-
-    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
-
-    assertThat(step.getSymbolsByLine()).hasSize(2);
-    assertThat(step.getSymbolsByLine().get(1).toString()).isEqualTo("3,5,1;5,6,2");
-    assertThat(step.getSymbolsByLine().get(10).toString()).isEqualTo("15,16,1;9,10,2");
-  }
-
-  @Test(expected = IllegalStateException.class)
-  public void fail_when_symbol_is_defined_on_different_line() throws Exception {
-    BatchReportWriter writer = initReport();
-
-    writer.writeComponentSymbols(FILE_REF, newArrayList(BatchReport.Symbols.Symbol.newBuilder()
-      .setDeclaration(BatchReport.Range.newBuilder()
-        .setStartLine(1)
-        .setStartOffset(3)
-        .setEndLine(2)
-        .setEndOffset(1)
-        .build())
-      .addReference(BatchReport.Range.newBuilder()
-        .setStartLine(10)
-        .setStartOffset(15)
-        .setEndLine(10)
-        .setEndOffset(17)
-        .build())
-      .build()));
-
-    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
-  }
-
-  private BatchReportWriter initReport() {
-    BatchReportWriter writer = new BatchReportWriter(reportDir);
-    writer.writeMetadata(BatchReport.Metadata.newBuilder()
-      .setRootComponentRef(1)
-      .setProjectKey("PROJECT_KEY")
-      .setAnalysisDate(150000000L)
-      .build());
-
-    writer.writeComponent(BatchReport.Component.newBuilder()
-      .setRef(1)
-      .setType(Constants.ComponentType.PROJECT)
-      .setUuid("PROJECT_A")
-      .addChildRef(2)
-      .build());
-    writer.writeComponent(BatchReport.Component.newBuilder()
-      .setRef(2)
-      .setType(Constants.ComponentType.MODULE)
-      .setUuid("BCDE")
-      .addChildRef(FILE_REF)
-      .build());
-    writer.writeComponent(BatchReport.Component.newBuilder()
-      .setRef(FILE_REF)
-      .setType(Constants.ComponentType.FILE)
-      .setUuid("FILE_A")
-      .build());
-    return writer;
-  }
-
-}
index 3d003ecc8a3a0b6741686a3da68b5d8053452102..b1c45ac1bd841d3b504ff9ce1ad633f8d6981f56 100644 (file)
@@ -363,6 +363,46 @@ public class SourceDataFactoryTest {
     assertThat(data.getLines(2).getSymbols()).isEqualTo("4,5,1;0,2,2");
   }
 
+  @Test
+  public void applySymbolReferences2() throws Exception {
+    batchReportWriter.writeComponentSymbols(1, Arrays.asList(
+      newSymbol(2, 0, 2, 2,
+        1, 1, 1, 2,
+        3, 0, 3, 2),
+      newSymbol(3, 1, 3, 2,
+        1, 0, 1, 1,
+        3, 4, 3, 5)
+      ));
+    inputFile.setOriginalLineOffsets(new int[] {0, 4, 7});
+
+    sut.applySymbolReferences(inputFile, output);
+
+    FileSourceDb.Data data = output.build();
+    assertThat(data.getLines(0).getSymbols()).isEqualTo("1,2,1;0,1,2");
+    assertThat(data.getLines(1).getSymbols()).isEqualTo("0,2,1");
+    assertThat(data.getLines(2).getSymbols()).isEqualTo("0,2,1;1,2,2;4,5,2");
+  }
+
+  @Test
+  public void applySymbolReferences3() throws Exception {
+    batchReportWriter.writeComponentSymbols(1, Arrays.asList(
+      newSymbol(2, 0, 2, 2,
+        1, 0, 1, 1,
+        3, 0, 3, 2),
+      newSymbol(3, 1, 3, 2,
+        1, 1, 1, 2,
+        3, 4, 3, 5)
+      ));
+    inputFile.setOriginalLineOffsets(new int[] {0, 4, 7});
+
+    sut.applySymbolReferences(inputFile, output);
+
+    FileSourceDb.Data data = output.build();
+    assertThat(data.getLines(0).getSymbols()).isEqualTo("0,1,1;1,2,2");
+    assertThat(data.getLines(1).getSymbols()).isEqualTo("0,2,1");
+    assertThat(data.getLines(2).getSymbols()).isEqualTo("0,2,1;1,2,2;4,5,2");
+  }
+
   @Test
   public void applySymbolReferences_declaration_order_is_not_important() throws Exception {
     batchReportWriter.writeComponentSymbols(1, Arrays.asList(