| package com.google.protobuf; |
| |
| import com.google.protobuf.DescriptorProtos.DescriptorProto; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.FilterInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import org.junit.Test; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| /** |
| * Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser} |
| * interface are specified to only throw {@link InvalidProtocolBufferException}. But we really want |
| * to distinguish between invalid protos vs. actual I/O errors (like failures reading from a |
| * socket, etc.). So, when we're not using the parser directly, an {@link IOException} should be |
| * thrown where appropriate, instead of always an {@link InvalidProtocolBufferException}. |
| * |
| * @author jh@squareup.com (Joshua Humphries) |
| */ |
| public class ParseExceptionsTest { |
| |
| private interface ParseTester { |
| DescriptorProto parse(InputStream in) throws IOException; |
| } |
| |
| private byte serializedProto[]; |
| |
| private void setup() { |
| serializedProto = DescriptorProto.getDescriptor().toProto().toByteArray(); |
| } |
| |
| private void setupDelimited() { |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
| try { |
| DescriptorProto.getDescriptor().toProto().writeDelimitedTo(bos); |
| } catch (IOException e) { |
| fail("Exception not expected: " + e); |
| } |
| serializedProto = bos.toByteArray(); |
| } |
| |
| @Test public void message_parseFrom_InputStream() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.parseFrom(in); |
| } |
| }); |
| } |
| |
| @Test public void message_parseFrom_InputStreamAndExtensionRegistry() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance()); |
| } |
| }); |
| } |
| |
| @Test public void message_parseFrom_CodedInputStream() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.parseFrom(CodedInputStream.newInstance(in)); |
| } |
| }); |
| } |
| |
| @Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.parseFrom(CodedInputStream.newInstance(in), |
| ExtensionRegistry.newInstance()); |
| } |
| }); |
| } |
| |
| @Test public void message_parseDelimitedFrom_InputStream() { |
| setupDelimited(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.parseDelimitedFrom(in); |
| } |
| }); |
| } |
| |
| @Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() { |
| setupDelimited(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance()); |
| } |
| }); |
| } |
| |
| @Test public void messageBuilder_mergeFrom_InputStream() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.newBuilder().mergeFrom(in).build(); |
| } |
| }); |
| } |
| |
| @Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.newBuilder().mergeFrom(in, ExtensionRegistry.newInstance()).build(); |
| } |
| }); |
| } |
| |
| @Test public void messageBuilder_mergeFrom_CodedInputStream() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build(); |
| } |
| }); |
| } |
| |
| @Test public void messageBuilder_mergeFrom_CodedInputStreamAndExtensionRegistry() { |
| setup(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| return DescriptorProto.newBuilder() |
| .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()).build(); |
| } |
| }); |
| } |
| |
| @Test public void messageBuilder_mergeDelimitedFrom_InputStream() { |
| setupDelimited(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| DescriptorProto.Builder builder = DescriptorProto.newBuilder(); |
| builder.mergeDelimitedFrom(in); |
| return builder.build(); |
| } |
| }); |
| } |
| |
| @Test public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() { |
| setupDelimited(); |
| verifyExceptions(new ParseTester() { |
| public DescriptorProto parse(InputStream in) throws IOException { |
| DescriptorProto.Builder builder = DescriptorProto.newBuilder(); |
| builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance()); |
| return builder.build(); |
| } |
| }); |
| } |
| |
| private void verifyExceptions(ParseTester parseTester) { |
| // No exception |
| try { |
| assertEquals(DescriptorProto.getDescriptor().toProto(), |
| parseTester.parse(new ByteArrayInputStream(serializedProto))); |
| } catch (IOException e) { |
| fail("No exception expected: " + e); |
| } |
| |
| // IOException |
| try { |
| // using a "broken" stream that will throw part-way through reading the message |
| parseTester.parse(broken(new ByteArrayInputStream(serializedProto))); |
| fail("IOException expected but not thrown"); |
| } catch (IOException e) { |
| assertFalse(e instanceof InvalidProtocolBufferException); |
| } |
| |
| // InvalidProtocolBufferException |
| try { |
| // make the serialized proto invalid |
| for (int i = 0; i < 50; i++) { |
| serializedProto[i] = -1; |
| } |
| parseTester.parse(new ByteArrayInputStream(serializedProto)); |
| fail("InvalidProtocolBufferException expected but not thrown"); |
| } catch (IOException e) { |
| assertTrue(e instanceof InvalidProtocolBufferException); |
| } |
| } |
| |
| private InputStream broken(InputStream i) { |
| return new FilterInputStream(i) { |
| int count = 0; |
| |
| @Override public int read() throws IOException { |
| if (count++ >= 50) { |
| throw new IOException("I'm broken!"); |
| } |
| return super.read(); |
| } |
| |
| @Override public int read(byte b[], int off, int len) throws IOException { |
| if ((count += len) >= 50) { |
| throw new IOException("I'm broken!"); |
| } |
| return super.read(b, off, len); |
| } |
| }; |
| } |
| } |