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")
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();
}
}
}
- 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) {
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));
- }
- }
-
}
--- /dev/null
+/*
+ * 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));
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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());
+ }
+ }
+ }
+}
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);
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();
}
+++ /dev/null
-/*
- * 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";
- }
-}
--- /dev/null
+/*
+ * 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");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
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)));
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)));
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
.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);
+++ /dev/null
-/*
- * 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;
- }
-
-}
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(