Browse Source

Improve utility org.sonar.core.util.Protobuf

tags/5.2-RC1
Simon Brandhof 9 years ago
parent
commit
c98aca6054

+ 14
- 0
compile_protobuf.sh View File

@@ -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"




+ 0
- 6
sonar-batch-protocol/compile_protobuf.sh View File

@@ -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

+ 0
- 121
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java View File

@@ -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);
}
}
}

+ 9
- 9
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java View File

@@ -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();
}

+ 13
- 13
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java View File

@@ -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;
}


+ 0
- 71
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java View File

@@ -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();
}
}

+ 12
- 16
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java View File

@@ -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();
}

+ 8
- 4
sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java View File

@@ -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");
}
}

}

+ 23
- 0
sonar-core/pom.xml View File

@@ -27,6 +27,10 @@
<groupId>org.picocontainer</groupId>
<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>
@@ -106,6 +110,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>

+ 162
- 0
sonar-core/src/main/java/org/sonar/core/util/Protobuf.java View File

@@ -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);
}
}
}

+ 603
- 0
sonar-core/src/test/gen-java/org/sonar/core/test/Test.java View File

@@ -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)
}

+ 120
- 0
sonar-core/src/test/java/org/sonar/core/util/ProtobufTest.java View File

@@ -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
}

+ 28
- 0
sonar-core/src/test/protobuf/test.proto View File

@@ -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;
}

Loading…
Cancel
Save