aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-07-22 14:17:06 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-07-22 14:17:16 +0200
commitc98aca6054048d0293fdb713910b4fa98beaa524 (patch)
tree2335acba0b9ecab3115dc6a49e67db4431dcd53b
parent5539cfffd327697a49278361901335e2d4d6e075 (diff)
downloadsonarqube-c98aca6054048d0293fdb713910b4fa98beaa524.tar.gz
sonarqube-c98aca6054048d0293fdb713910b4fa98beaa524.zip
Improve utility org.sonar.core.util.Protobuf
-rwxr-xr-xcompile_protobuf.sh14
-rwxr-xr-xsonar-batch-protocol/compile_protobuf.sh6
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java121
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java18
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java26
-rw-r--r--sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java71
-rw-r--r--sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java28
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java12
-rw-r--r--sonar-core/pom.xml23
-rw-r--r--sonar-core/src/main/java/org/sonar/core/util/Protobuf.java162
-rw-r--r--sonar-core/src/test/gen-java/org/sonar/core/test/Test.java603
-rw-r--r--sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java120
-rw-r--r--sonar-core/src/test/protobuf/test.proto28
13 files changed, 992 insertions, 240 deletions
diff --git a/compile_protobuf.sh b/compile_protobuf.sh
new file mode 100755
index 00000000000..8e07c4dc2cd
--- /dev/null
+++ b/compile_protobuf.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# Usage: compile_protobuf <inputDir> <outputDir>
+function compile_protobuf {
+ echo "Compiling [$1] to [$2]..."
+ mkdir -p $2
+ protoc --proto_path=$1 --java_out=$2 $1/*.proto
+}
+
+compile_protobuf "sonar-core/src/test/protobuf" "sonar-core/src/test/gen-java"
+compile_protobuf "sonar-batch-protocol/src/main/protobuf" "sonar-batch-protocol/src/main/gen-java"
+
+
+
diff --git a/sonar-batch-protocol/compile_protobuf.sh b/sonar-batch-protocol/compile_protobuf.sh
deleted file mode 100755
index f2d14c4eebc..00000000000
--- a/sonar-batch-protocol/compile_protobuf.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-OUTPUT_DIR="src/main/gen-java"
-
-mkdir -p ${OUTPUT_DIR}
-protoc --proto_path=src/main/protobuf --java_out=${OUTPUT_DIR} src/main/protobuf/*.proto
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java
deleted file mode 100644
index 43d8af6bfbf..00000000000
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java
+++ /dev/null
@@ -1,121 +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.batch.protocol;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.Message;
-import com.google.protobuf.Parser;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import org.apache.commons.io.IOUtils;
-import org.sonar.core.util.CloseableIterator;
-
-import static java.lang.String.format;
-
-public class ProtobufUtil {
- private ProtobufUtil() {
- // only static stuff
- }
-
- /**
- * Returns the message contained in the given file. Throws an unchecked exception
- * if the file does not exist or is empty.
- */
- public static <MSG extends Message> MSG readFile(File file, Parser<MSG> parser) {
- InputStream input = null;
- try {
- input = new BufferedInputStream(new FileInputStream(file));
- return parser.parseFrom(input);
- } catch (IOException e) {
- throw new IllegalStateException(format("Unable to read file %s", file), e);
- } finally {
- IOUtils.closeQuietly(input);
- }
- }
-
- /**
- * Writes a single message to a file, by replacing existing content. The message is
- * NOT appended.
- */
- public static void writeToFile(Message message, File toFile) {
- OutputStream out = null;
- try {
- out = new BufferedOutputStream(new FileOutputStream(toFile, false));
- message.writeTo(out);
- } catch (IOException e) {
- throw new IllegalStateException(format("Unable to write protobuf message to file %s", toFile), e);
- } finally {
- IOUtils.closeQuietly(out);
- }
- }
-
- public static void writeStreamToFile(Iterable<? extends Message> messages, File toFile, boolean append) {
- OutputStream out = null;
- try {
- out = new BufferedOutputStream(new FileOutputStream(toFile, append));
- for (Message message : messages) {
- message.writeDelimitedTo(out);
- }
- } catch (IOException e) {
- throw new IllegalStateException(format("Unable to write protobuf messages to file %s", toFile), e);
- } finally {
- IOUtils.closeQuietly(out);
- }
- }
-
- public static <MSG extends Message> CloseableIterator<MSG> readStreamFromFile(File file, Parser<MSG> parser) {
- try {
- return new ProtobufIterator<>(parser, new BufferedInputStream(new FileInputStream(file)));
- } catch (FileNotFoundException e) {
- throw new IllegalStateException(format("Unable to read protobuf file %s", file), e);
- }
- }
-
- private static class ProtobufIterator<MSG extends Message> extends CloseableIterator<MSG> {
- private final Parser<MSG> parser;
- private final InputStream input;
-
- private ProtobufIterator(Parser<MSG> parser, InputStream input) {
- this.parser = parser;
- this.input = input;
- }
-
- @Override
- protected MSG doNext() {
- try {
- return parser.parseDelimitedFrom(input);
- } catch (InvalidProtocolBufferException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- protected void doClose() throws Exception {
- IOUtils.closeQuietly(input);
- }
- }
-}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
index 70da7179b9f..9cc90da20c5 100644
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
@@ -21,8 +21,8 @@ package org.sonar.batch.protocol.output;
import java.io.File;
import javax.annotation.CheckForNull;
-import org.sonar.batch.protocol.ProtobufUtil;
import org.sonar.core.util.CloseableIterator;
+import org.sonar.core.util.Protobuf;
public class BatchReportReader {
@@ -37,7 +37,7 @@ public class BatchReportReader {
if (!fileExists(file)) {
throw new IllegalStateException("Metadata file is missing in analysis report: " + file);
}
- return ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
+ return Protobuf.read(file, BatchReport.Metadata.PARSER);
}
public CloseableIterator<BatchReport.ActiveRule> readActiveRules() {
@@ -45,13 +45,13 @@ public class BatchReportReader {
if (!fileExists(file)) {
return CloseableIterator.emptyCloseableIterator();
}
- return ProtobufUtil.readStreamFromFile(file, BatchReport.ActiveRule.PARSER);
+ return Protobuf.readStream(file, BatchReport.ActiveRule.PARSER);
}
public CloseableIterator<BatchReport.Measure> readComponentMeasures(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
if (fileExists(file)) {
- return ProtobufUtil.readStreamFromFile(file, BatchReport.Measure.PARSER);
+ return Protobuf.readStream(file, BatchReport.Measure.PARSER);
}
return CloseableIterator.emptyCloseableIterator();
}
@@ -60,7 +60,7 @@ public class BatchReportReader {
public BatchReport.Changesets readChangesets(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.CHANGESETS, componentRef);
if (fileExists(file)) {
- return ProtobufUtil.readFile(file, BatchReport.Changesets.PARSER);
+ return Protobuf.read(file, BatchReport.Changesets.PARSER);
}
return null;
}
@@ -70,13 +70,13 @@ public class BatchReportReader {
if (!fileExists(file)) {
throw new IllegalStateException("Unable to find report for component #" + componentRef + ". File does not exist: " + file);
}
- return ProtobufUtil.readFile(file, BatchReport.Component.PARSER);
+ return Protobuf.read(file, BatchReport.Component.PARSER);
}
public CloseableIterator<BatchReport.Issue> readComponentIssues(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.ISSUES, componentRef);
if (fileExists(file)) {
- return ProtobufUtil.readStreamFromFile(file, BatchReport.Issue.PARSER);
+ return Protobuf.readStream(file, BatchReport.Issue.PARSER);
}
return CloseableIterator.emptyCloseableIterator();
}
@@ -84,7 +84,7 @@ public class BatchReportReader {
public CloseableIterator<BatchReport.Duplication> readComponentDuplications(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.DUPLICATIONS, componentRef);
if (fileExists(file)) {
- return ProtobufUtil.readStreamFromFile(file, BatchReport.Duplication.PARSER);
+ return Protobuf.readStream(file, BatchReport.Duplication.PARSER);
}
return CloseableIterator.emptyCloseableIterator();
}
@@ -92,7 +92,7 @@ public class BatchReportReader {
public CloseableIterator<BatchReport.Symbol> readComponentSymbols(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.SYMBOLS, componentRef);
if (fileExists(file)) {
- return ProtobufUtil.readStreamFromFile(file, BatchReport.Symbol.PARSER);
+ return Protobuf.readStream(file, BatchReport.Symbol.PARSER);
}
return CloseableIterator.emptyCloseableIterator();
}
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java
index b7ac04ed116..bf0cdfcd736 100644
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java
@@ -20,7 +20,7 @@
package org.sonar.batch.protocol.output;
import java.io.File;
-import org.sonar.batch.protocol.ProtobufUtil;
+import org.sonar.core.util.Protobuf;
public class BatchReportWriter {
@@ -46,72 +46,72 @@ public class BatchReportWriter {
* Metadata is mandatory
*/
public File writeMetadata(BatchReport.Metadata metadata) {
- ProtobufUtil.writeToFile(metadata, fileStructure.metadataFile());
+ Protobuf.write(metadata, fileStructure.metadataFile());
return fileStructure.metadataFile();
}
public File writeActiveRules(Iterable<BatchReport.ActiveRule> activeRules) {
- ProtobufUtil.writeStreamToFile(activeRules, fileStructure.activeRules(), false);
+ Protobuf.writeStream(activeRules, fileStructure.activeRules(), false);
return fileStructure.metadataFile();
}
public File writeComponent(BatchReport.Component component) {
File file = fileStructure.fileFor(FileStructure.Domain.COMPONENT, component.getRef());
- ProtobufUtil.writeToFile(component, file);
+ Protobuf.write(component, file);
return file;
}
public File writeComponentIssues(int componentRef, Iterable<BatchReport.Issue> issues) {
File file = fileStructure.fileFor(FileStructure.Domain.ISSUES, componentRef);
- ProtobufUtil.writeStreamToFile(issues, file, false);
+ Protobuf.writeStream(issues, file, false);
return file;
}
public File writeComponentMeasures(int componentRef, Iterable<BatchReport.Measure> measures) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
- ProtobufUtil.writeStreamToFile(measures, file, false);
+ Protobuf.writeStream(measures, file, false);
return file;
}
public File writeComponentChangesets(BatchReport.Changesets changesets) {
File file = fileStructure.fileFor(FileStructure.Domain.CHANGESETS, changesets.getComponentRef());
- ProtobufUtil.writeToFile(changesets, file);
+ Protobuf.write(changesets, file);
return file;
}
public File writeComponentDuplications(int componentRef, Iterable<BatchReport.Duplication> duplications) {
File file = fileStructure.fileFor(FileStructure.Domain.DUPLICATIONS, componentRef);
- ProtobufUtil.writeStreamToFile(duplications, file, false);
+ Protobuf.writeStream(duplications, file, false);
return file;
}
public File writeComponentSymbols(int componentRef, Iterable<BatchReport.Symbol> symbols) {
File file = fileStructure.fileFor(FileStructure.Domain.SYMBOLS, componentRef);
- ProtobufUtil.writeStreamToFile(symbols, file, false);
+ Protobuf.writeStream(symbols, file, false);
return file;
}
public File writeComponentSyntaxHighlighting(int componentRef, Iterable<BatchReport.SyntaxHighlighting> syntaxHighlightingRules) {
File file = fileStructure.fileFor(FileStructure.Domain.SYNTAX_HIGHLIGHTINGS, componentRef);
- ProtobufUtil.writeStreamToFile(syntaxHighlightingRules, file, false);
+ Protobuf.writeStream(syntaxHighlightingRules, file, false);
return file;
}
public File writeComponentCoverage(int componentRef, Iterable<BatchReport.Coverage> coverageList) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGES, componentRef);
- ProtobufUtil.writeStreamToFile(coverageList, file, false);
+ Protobuf.writeStream(coverageList, file, false);
return file;
}
public File writeTests(int componentRef, Iterable<BatchReport.Test> tests) {
File file = fileStructure.fileFor(FileStructure.Domain.TESTS, componentRef);
- ProtobufUtil.writeStreamToFile(tests, file, false);
+ Protobuf.writeStream(tests, file, false);
return file;
}
public File writeCoverageDetails(int componentRef, Iterable<BatchReport.CoverageDetail> tests) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGE_DETAILS, componentRef);
- ProtobufUtil.writeStreamToFile(tests, file, false);
+ Protobuf.writeStream(tests, file, false);
return file;
}
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java
deleted file mode 100644
index 04ebcf7f989..00000000000
--- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java
+++ /dev/null
@@ -1,71 +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.batch.protocol;
-
-import java.io.File;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.test.TestUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ProtobufUtilTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void only_utils() {
- assertThat(TestUtils.hasOnlyPrivateConstructors(ProtobufUtil.class));
- }
-
- @Test
- public void readFile_fails_if_file_does_not_exist() throws Exception {
- thrown.expect(IllegalStateException.class);
-
- File file = temp.newFile();
- FileUtils.forceDelete(file);
- ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
- }
-
- @Test
- public void readFile_returns_empty_message_if_file_is_empty() throws Exception {
- File file = temp.newFile();
- BatchReport.Metadata msg = ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
- assertThat(msg).isNotNull();
- assertThat(msg.isInitialized()).isTrue();
- }
-
- @Test
- public void readFile_returns_message() throws Exception {
- File file = temp.newFile();
- ProtobufUtil.writeToFile(BatchReport.Metadata.getDefaultInstance(), file);
- BatchReport.Metadata message = ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
- assertThat(message).isNotNull();
- assertThat(message.isInitialized()).isTrue();
- }
-}
diff --git a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
index e19e044d2c5..ae1a6cd143e 100644
--- a/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
+++ b/sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
@@ -28,9 +28,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.batch.protocol.Constants;
-import org.sonar.batch.protocol.ProtobufUtil;
import org.sonar.batch.protocol.output.BatchReport.Range;
import org.sonar.core.util.CloseableIterator;
+import org.sonar.core.util.Protobuf;
import static org.assertj.core.api.Assertions.assertThat;
@@ -63,7 +63,7 @@ public class BatchReportWriterTest {
.setRootComponentRef(1);
underTest.writeMetadata(metadata.build());
- BatchReport.Metadata read = ProtobufUtil.readFile(underTest.getFileStructure().metadataFile(), BatchReport.Metadata.PARSER);
+ BatchReport.Metadata read = Protobuf.read(underTest.getFileStructure().metadataFile(), BatchReport.Metadata.PARSER);
assertThat(read.getAnalysisDate()).isEqualTo(15000000L);
assertThat(read.getProjectKey()).isEqualTo("PROJECT_A");
assertThat(read.getRootComponentRef()).isEqualTo(1);
@@ -88,7 +88,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.COMPONENT, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.COMPONENT, 1);
assertThat(file).exists().isFile();
- BatchReport.Component read = ProtobufUtil.readFile(file, BatchReport.Component.PARSER);
+ BatchReport.Component read = Protobuf.read(file, BatchReport.Component.PARSER);
assertThat(read.getRef()).isEqualTo(1);
assertThat(read.getChildRefList()).containsOnly(5, 42);
assertThat(read.hasName()).isFalse();
@@ -111,7 +111,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.ISSUES, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.ISSUES, 1);
assertThat(file).exists().isFile();
- try (CloseableIterator<BatchReport.Issue> read = ProtobufUtil.readStreamFromFile(file, BatchReport.Issue.PARSER)) {
+ try (CloseableIterator<BatchReport.Issue> read = Protobuf.readStream(file, BatchReport.Issue.PARSER)) {
assertThat(Iterators.size(read)).isEqualTo(1);
}
}
@@ -131,7 +131,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.MEASURES, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.MEASURES, 1);
assertThat(file).exists().isFile();
- try (CloseableIterator<BatchReport.Measure> read = ProtobufUtil.readStreamFromFile(file, BatchReport.Measure.PARSER)) {
+ try (CloseableIterator<BatchReport.Measure> read = Protobuf.readStream(file, BatchReport.Measure.PARSER)) {
assertThat(Iterators.size(read)).isEqualTo(1);
}
}
@@ -154,7 +154,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.CHANGESETS, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.CHANGESETS, 1);
assertThat(file).exists().isFile();
- BatchReport.Changesets read = ProtobufUtil.readFile(file, BatchReport.Changesets.PARSER);
+ BatchReport.Changesets read = Protobuf.read(file, BatchReport.Changesets.PARSER);
assertThat(read.getComponentRef()).isEqualTo(1);
assertThat(read.getChangesetCount()).isEqualTo(1);
assertThat(read.getChangesetList()).hasSize(1);
@@ -184,7 +184,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.DUPLICATIONS, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.DUPLICATIONS, 1);
assertThat(file).exists().isFile();
- try (CloseableIterator<BatchReport.Duplication> duplications = ProtobufUtil.readStreamFromFile(file, BatchReport.Duplication.PARSER)) {
+ try (CloseableIterator<BatchReport.Duplication> duplications = Protobuf.readStream(file, BatchReport.Duplication.PARSER)) {
BatchReport.Duplication dup = duplications.next();
assertThat(dup.getOriginPosition()).isNotNull();
assertThat(dup.getDuplicateList()).hasSize(1);
@@ -218,7 +218,7 @@ public class BatchReportWriterTest {
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.SYMBOLS, 1);
assertThat(file).exists().isFile();
- try (CloseableIterator<BatchReport.Symbol> read = ProtobufUtil.readStreamFromFile(file, BatchReport.Symbol.PARSER)) {
+ try (CloseableIterator<BatchReport.Symbol> read = Protobuf.readStream(file, BatchReport.Symbol.PARSER)) {
assertThat(read).hasSize(1);
}
}
@@ -235,8 +235,7 @@ public class BatchReportWriterTest {
.setEndLine(1)
.build())
.setType(Constants.HighlightingType.ANNOTATION)
- .build()
- ));
+ .build()));
assertThat(underTest.hasComponentData(FileStructure.Domain.SYNTAX_HIGHLIGHTINGS, 1)).isTrue();
}
@@ -255,8 +254,7 @@ public class BatchReportWriterTest {
.setUtCoveredConditions(1)
.setItCoveredConditions(1)
.setOverallCoveredConditions(1)
- .build()
- ));
+ .build()));
assertThat(underTest.hasComponentData(FileStructure.Domain.COVERAGES, 1)).isTrue();
}
@@ -266,8 +264,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.TESTS, 1)).isFalse();
underTest.writeTests(1, Arrays.asList(
- BatchReport.Test.getDefaultInstance()
- ));
+ BatchReport.Test.getDefaultInstance()));
assertThat(underTest.hasComponentData(FileStructure.Domain.TESTS, 1)).isTrue();
@@ -278,8 +275,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.COVERAGE_DETAILS, 1)).isFalse();
underTest.writeCoverageDetails(1, Arrays.asList(
- BatchReport.CoverageDetail.getDefaultInstance()
- ));
+ BatchReport.CoverageDetail.getDefaultInstance()));
assertThat(underTest.hasComponentData(FileStructure.Domain.COVERAGE_DETAILS, 1)).isTrue();
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
index 5ee11f7cdf9..a14389648e6 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
@@ -22,6 +22,7 @@ package org.sonar.batch.report;
import java.io.File;
import java.util.Collections;
import java.util.Date;
+import org.apache.commons.lang.exception.ExceptionUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -42,6 +43,7 @@ import org.sonar.core.util.CloseableIterator;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -106,16 +108,18 @@ public class MeasuresPublisherTest {
@Test
public void fail_with_IAE_when_measure_has_no_value() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Measure on metric 'coverage' and component 'foo:src/Foo.php' has no value, but it's not allowed");
-
Measure measure = new Measure<>(CoreMetrics.COVERAGE);
when(measureCache.byResource(sampleFile)).thenReturn(Collections.singletonList(measure));
File outputDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(outputDir);
- publisher.publish(writer);
+ try {
+ publisher.publish(writer);
+ fail();
+ } catch (RuntimeException e) {
+ assertThat(ExceptionUtils.getFullStackTrace(e)).contains("Measure on metric 'coverage' and component 'foo:src/Foo.php' has no value, but it's not allowed");
+ }
}
}
diff --git a/sonar-core/pom.xml b/sonar-core/pom.xml
index 2f9a09ab9d8..010524b4614 100644
--- a/sonar-core/pom.xml
+++ b/sonar-core/pom.xml
@@ -28,6 +28,10 @@
<artifactId>picocontainer</artifactId>
</dependency>
<dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-classloader</artifactId>
</dependency>
@@ -107,6 +111,25 @@
<build>
<plugins>
<plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-test-source</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/test/gen-java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
diff --git a/sonar-core/src/main/java/org/sonar/core/util/Protobuf.java b/sonar-core/src/main/java/org/sonar/core/util/Protobuf.java
new file mode 100644
index 00000000000..7b8b25c6e73
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/util/Protobuf.java
@@ -0,0 +1,162 @@
+/*
+ * 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.core.util;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Message;
+import com.google.protobuf.Parser;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.commons.io.IOUtils;
+
+/**
+ * Utility to read and write Protocol Buffers messages
+ */
+public class Protobuf {
+ private Protobuf() {
+ // only static stuff
+ }
+
+ /**
+ * Returns the message contained in {@code file}. Throws an unchecked exception
+ * if the file does not exist, is empty or does not contain message with the
+ * expected type.
+ */
+ public static <MSG extends Message> MSG read(File file, Parser<MSG> parser) {
+ InputStream input = null;
+ try {
+ input = new BufferedInputStream(new FileInputStream(file));
+ return parser.parseFrom(input);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to read message", e).addContext("file", file);
+ } finally {
+ IOUtils.closeQuietly(input);
+ }
+ }
+
+ /**
+ * Writes a single message to {@code file}. Existing content is replaced, the message is not
+ * appended.
+ */
+ public static void write(Message message, File toFile) {
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(toFile, false));
+ message.writeTo(out);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write message", e).addContext("file", toFile);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Streams multiple messages to {@code file}. Reading the messages back requires to
+ * call methods {@code readStream(...)}.
+ * <p>
+ * See https://developers.google.com/protocol-buffers/docs/techniques#streaming
+ * </p>
+ */
+ public static <MSG extends Message> void writeStream(Iterable<MSG> messages, File toFile, boolean append) {
+ OutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream(toFile, append));
+ writeStream(messages, out);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write messages", e).addContext("file", toFile);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Streams multiple messages to {@code output}. Reading the messages back requires to
+ * call methods {@code readStream(...)}.
+ * <p>
+ * See https://developers.google.com/protocol-buffers/docs/techniques#streaming
+ * </p>
+ */
+ public static <MSG extends Message> void writeStream(Iterable<MSG> messages, OutputStream output) {
+ try {
+ for (Message message : messages) {
+ message.writeDelimitedTo(output);
+ }
+ } catch (Exception e) {
+ throw ContextException.of("Unable to write messages", e);
+ }
+ }
+
+ /**
+ * Reads a stream of messages. This method returns an empty iterator if there are no messages. An
+ * exception is raised on IO error, if file does not exist or if messages have a
+ * different type than {@code parser}.
+ */
+ public static <MSG extends Message> CloseableIterator<MSG> readStream(File file, Parser<MSG> parser) {
+ try {
+ // the input stream is closed by the CloseableIterator
+ BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
+ return readStream(input, parser);
+ } catch (Exception e) {
+ throw ContextException.of("Unable to read messages", e).addContext("file", file);
+ }
+ }
+
+ /**
+ * Reads a stream of messages. This method returns an empty iterator if there are no messages. An
+ * exception is raised on IO error or if messages have a different type than {@code parser}.
+ * <p>
+ * The stream is not closed by this method. It is closed when {@link CloseableIterator} traverses
+ * all messages or when {@link CloseableIterator#close()} is called.
+ * </p>
+ */
+ public static <MSG extends Message> CloseableIterator<MSG> readStream(InputStream input, Parser<MSG> parser) {
+ // the stream is closed by the CloseableIterator
+ return new StreamIterator<>(parser, input);
+ }
+
+ private static class StreamIterator<MSG extends Message> extends CloseableIterator<MSG> {
+ private final Parser<MSG> parser;
+ private final InputStream input;
+
+ private StreamIterator(Parser<MSG> parser, InputStream input) {
+ this.parser = parser;
+ this.input = input;
+ }
+
+ @Override
+ protected MSG doNext() {
+ try {
+ return parser.parsePartialDelimitedFrom(input);
+ } catch (InvalidProtocolBufferException e) {
+ throw ContextException.of(e);
+ }
+ }
+
+ @Override
+ protected void doClose() {
+ IOUtils.closeQuietly(input);
+ }
+ }
+}
diff --git a/sonar-core/src/test/gen-java/org/sonar/core/test/Test.java b/sonar-core/src/test/gen-java/org/sonar/core/test/Test.java
new file mode 100644
index 00000000000..9797ed15898
--- /dev/null
+++ b/sonar-core/src/test/gen-java/org/sonar/core/test/Test.java
@@ -0,0 +1,603 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test.proto
+
+package org.sonar.core.test;
+
+public final class Test {
+ private Test() {}
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistry registry) {
+ }
+ public interface FakeOrBuilder extends
+ // @@protoc_insertion_point(interface_extends:Fake)
+ com.google.protobuf.MessageOrBuilder {
+
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ boolean hasKey();
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ java.lang.String getKey();
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ com.google.protobuf.ByteString
+ getKeyBytes();
+
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ boolean hasLine();
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ int getLine();
+ }
+ /**
+ * Protobuf type {@code Fake}
+ */
+ public static final class Fake extends
+ com.google.protobuf.GeneratedMessage implements
+ // @@protoc_insertion_point(message_implements:Fake)
+ FakeOrBuilder {
+ // Use Fake.newBuilder() to construct.
+ private Fake(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+ super(builder);
+ this.unknownFields = builder.getUnknownFields();
+ }
+ private Fake(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+ private static final Fake defaultInstance;
+ public static Fake getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public Fake getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ private final com.google.protobuf.UnknownFieldSet unknownFields;
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private Fake(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ initFields();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 10: {
+ com.google.protobuf.ByteString bs = input.readBytes();
+ bitField0_ |= 0x00000001;
+ key_ = bs;
+ break;
+ }
+ case 16: {
+ bitField0_ |= 0x00000002;
+ line_ = input.readInt32();
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e.getMessage()).setUnfinishedMessage(this);
+ } finally {
+ this.unknownFields = unknownFields.build();
+ makeExtensionsImmutable();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.sonar.core.test.Test.internal_static_Fake_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.sonar.core.test.Test.internal_static_Fake_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.sonar.core.test.Test.Fake.class, org.sonar.core.test.Test.Fake.Builder.class);
+ }
+
+ public static com.google.protobuf.Parser<Fake> PARSER =
+ new com.google.protobuf.AbstractParser<Fake>() {
+ public Fake parsePartialFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return new Fake(input, extensionRegistry);
+ }
+ };
+
+ @java.lang.Override
+ public com.google.protobuf.Parser<Fake> getParserForType() {
+ return PARSER;
+ }
+
+ private int bitField0_;
+ public static final int KEY_FIELD_NUMBER = 1;
+ private java.lang.Object key_;
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public boolean hasKey() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public java.lang.String getKey() {
+ java.lang.Object ref = key_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ key_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public com.google.protobuf.ByteString
+ getKeyBytes() {
+ java.lang.Object ref = key_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ key_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ public static final int LINE_FIELD_NUMBER = 2;
+ private int line_;
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public boolean hasLine() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public int getLine() {
+ return line_;
+ }
+
+ private void initFields() {
+ key_ = "";
+ line_ = 0;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized == 1) return true;
+ if (isInitialized == 0) return false;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, getKeyBytes());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeInt32(2, line_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, getKeyBytes());
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(2, line_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input);
+ }
+ public static org.sonar.core.test.Test.Fake parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseDelimitedFrom(input, extensionRegistry);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input);
+ }
+ public static org.sonar.core.test.Test.Fake parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return PARSER.parseFrom(input, extensionRegistry);
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.sonar.core.test.Test.Fake prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code Fake}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+ // @@protoc_insertion_point(builder_implements:Fake)
+ org.sonar.core.test.Test.FakeOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.sonar.core.test.Test.internal_static_Fake_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.sonar.core.test.Test.internal_static_Fake_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.sonar.core.test.Test.Fake.class, org.sonar.core.test.Test.Fake.Builder.class);
+ }
+
+ // Construct using org.sonar.core.test.Test.Fake.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ key_ = "";
+ bitField0_ = (bitField0_ & ~0x00000001);
+ line_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.sonar.core.test.Test.internal_static_Fake_descriptor;
+ }
+
+ public org.sonar.core.test.Test.Fake getDefaultInstanceForType() {
+ return org.sonar.core.test.Test.Fake.getDefaultInstance();
+ }
+
+ public org.sonar.core.test.Test.Fake build() {
+ org.sonar.core.test.Test.Fake result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ public org.sonar.core.test.Test.Fake buildPartial() {
+ org.sonar.core.test.Test.Fake result = new org.sonar.core.test.Test.Fake(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.key_ = key_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.line_ = line_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.sonar.core.test.Test.Fake) {
+ return mergeFrom((org.sonar.core.test.Test.Fake)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.sonar.core.test.Test.Fake other) {
+ if (other == org.sonar.core.test.Test.Fake.getDefaultInstance()) return this;
+ if (other.hasKey()) {
+ bitField0_ |= 0x00000001;
+ key_ = other.key_;
+ onChanged();
+ }
+ if (other.hasLine()) {
+ setLine(other.getLine());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ org.sonar.core.test.Test.Fake parsedMessage = null;
+ try {
+ parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ parsedMessage = (org.sonar.core.test.Test.Fake) e.getUnfinishedMessage();
+ throw e;
+ } finally {
+ if (parsedMessage != null) {
+ mergeFrom(parsedMessage);
+ }
+ }
+ return this;
+ }
+ private int bitField0_;
+
+ private java.lang.Object key_ = "";
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public boolean hasKey() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public java.lang.String getKey() {
+ java.lang.Object ref = key_;
+ if (!(ref instanceof java.lang.String)) {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ key_ = s;
+ }
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public com.google.protobuf.ByteString
+ getKeyBytes() {
+ java.lang.Object ref = key_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ key_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public Builder setKey(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ key_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public Builder clearKey() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ key_ = getDefaultInstance().getKey();
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string key = 1;</code>
+ */
+ public Builder setKeyBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ key_ = value;
+ onChanged();
+ return this;
+ }
+
+ private int line_ ;
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public boolean hasLine() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public int getLine() {
+ return line_;
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public Builder setLine(int value) {
+ bitField0_ |= 0x00000002;
+ line_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional int32 line = 2;</code>
+ */
+ public Builder clearLine() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ line_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:Fake)
+ }
+
+ static {
+ defaultInstance = new Fake(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:Fake)
+ }
+
+ private static final com.google.protobuf.Descriptors.Descriptor
+ internal_static_Fake_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_Fake_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ static {
+ java.lang.String[] descriptorData = {
+ "\n\ntest.proto\"!\n\004Fake\022\013\n\003key\030\001 \001(\t\022\014\n\004lin" +
+ "e\030\002 \001(\005B\027\n\023org.sonar.core.testH\001"
+ };
+ com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+ new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
+ public com.google.protobuf.ExtensionRegistry assignDescriptors(
+ com.google.protobuf.Descriptors.FileDescriptor root) {
+ descriptor = root;
+ return null;
+ }
+ };
+ com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ }, assigner);
+ internal_static_Fake_descriptor =
+ getDescriptor().getMessageTypes().get(0);
+ internal_static_Fake_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_Fake_descriptor,
+ new java.lang.String[] { "Key", "Line", });
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java b/sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java
new file mode 100644
index 00000000000..5b30c2b9a7c
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.core.util;
+
+import java.io.File;
+import java.util.Arrays;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.test.TestUtils;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.test.Test.Fake;
+
+public class ProtobufTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void only_utils() {
+ assertThat(TestUtils.hasOnlyPrivateConstructors(Protobuf.class));
+ }
+
+ @Test
+ public void read_file_fails_if_file_does_not_exist() throws Exception {
+ thrown.expect(ContextException.class);
+ thrown.expectMessage("Unable to read message");
+
+ File file = temp.newFile();
+ FileUtils.forceDelete(file);
+ Protobuf.read(file, Fake.PARSER);
+ }
+
+ @Test
+ public void read_file_returns_empty_message_if_file_is_empty() throws Exception {
+ File file = temp.newFile();
+ Fake msg = Protobuf.read(file, Fake.PARSER);
+ assertThat(msg).isNotNull();
+ assertThat(msg.isInitialized()).isTrue();
+ }
+
+ @Test
+ public void read_file_returns_message() throws Exception {
+ File file = temp.newFile();
+ Protobuf.write(Fake.getDefaultInstance(), file);
+ Fake message = Protobuf.read(file, Fake.PARSER);
+ assertThat(message).isNotNull();
+ assertThat(message.isInitialized()).isTrue();
+ }
+
+ @Test
+ public void fail_to_write_single_message() throws Exception {
+ thrown.expect(ContextException.class);
+ thrown.expectMessage("Unable to write message");
+
+ File dir = temp.newFolder();
+ Protobuf.write(Fake.getDefaultInstance(), dir);
+ }
+
+ @Test
+ public void write_and_read_streams() throws Exception {
+ File file = temp.newFile();
+
+ Fake item1 = Fake.newBuilder().setKey("one").setLine(1).build();
+ Fake item2 = Fake.newBuilder().setKey("two").build();
+ Protobuf.writeStream(asList(item1, item2), file, false);
+
+ CloseableIterator<Fake> it = Protobuf.readStream(file, Fake.PARSER);
+ Fake read = it.next();
+ assertThat(read.getKey()).isEqualTo("one");
+ assertThat(read.getLine()).isEqualTo(1);
+ read = it.next();
+ assertThat(read.getKey()).isEqualTo("two");
+ assertThat(read.hasLine()).isFalse();
+ assertThat(it.hasNext()).isFalse();
+ }
+
+ @Test
+ public void fail_to_read_stream() throws Exception {
+ thrown.expect(ContextException.class);
+ thrown.expectMessage("Unable to read messages");
+
+ File dir = temp.newFolder();
+ Protobuf.readStream(dir, Fake.PARSER);
+ }
+
+ @Test
+ public void read_empty_stream() throws Exception {
+ File file = temp.newFile();
+ CloseableIterator<Fake> it = Protobuf.readStream(file, Fake.PARSER);
+ assertThat(it).isNotNull();
+ assertThat(it.hasNext()).isFalse();
+ }
+
+ // TODO test in-moemry file
+}
diff --git a/sonar-core/src/test/protobuf/test.proto b/sonar-core/src/test/protobuf/test.proto
new file mode 100644
index 00000000000..c449a6a0596
--- /dev/null
+++ b/sonar-core/src/test/protobuf/test.proto
@@ -0,0 +1,28 @@
+/*
+ SonarQube, open source software quality management tool.
+ Copyright (C) 2008-2015 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.
+*/
+
+
+option java_package = "org.sonar.core.test";
+option optimize_for = SPEED;
+
+message Fake {
+ optional string key = 1;
+ optional int32 line = 2;
+}