diff options
author | jieluo@google.com <jieluo@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2014-07-18 00:47:59 +0000 |
---|---|---|
committer | jieluo@google.com <jieluo@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2014-07-18 00:47:59 +0000 |
commit | 4de8f55113007fdc8e34107950e605fc0209d465 (patch) | |
tree | 92b7da8757a7740d9e1f2d3ead233542947d8c8c /java/src/test | |
parent | c5553a3d18f80132b9079c5504bc0aa1f7f950a0 (diff) | |
download | protobuf-4de8f55113007fdc8e34107950e605fc0209d465.tar.gz protobuf-4de8f55113007fdc8e34107950e605fc0209d465.tar.bz2 protobuf-4de8f55113007fdc8e34107950e605fc0209d465.zip |
down integrate to svn
Diffstat (limited to 'java/src/test')
33 files changed, 3078 insertions, 45 deletions
diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java index 3d05cb7d..fcbf019d 100644 --- a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -506,4 +506,22 @@ public class AbstractMessageTest extends TestCase { String.format("%s should have a different hash code from %s", m1, m2), m1.hashCode() == m2.hashCode()); } + + public void testCheckByteStringIsUtf8OnUtf8() { + ByteString byteString = ByteString.copyFromUtf8("some text"); + AbstractMessageLite.checkByteStringIsUtf8(byteString); + // No exception thrown. + } + + public void testCheckByteStringIsUtf8OnNonUtf8() { + ByteString byteString = + ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte. + try { + AbstractMessageLite.checkByteStringIsUtf8(byteString); + fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException"); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + } diff --git a/java/src/test/java/com/google/protobuf/ByteStringTest.java b/java/src/test/java/com/google/protobuf/ByteStringTest.java index 7a1d6823..88d7e779 100644 --- a/java/src/test/java/com/google/protobuf/ByteStringTest.java +++ b/java/src/test/java/com/google/protobuf/ByteStringTest.java @@ -35,6 +35,7 @@ import com.google.protobuf.ByteString.Output; import junit.framework.TestCase; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -676,6 +677,21 @@ public class ByteStringTest extends TestCase { assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY)); } + public void testEndsWith() { + byte[] bytes = getTestBytes(1000, 1234L); + ByteString string = ByteString.copyFrom(bytes); + ByteString prefix = ByteString.copyFrom(bytes, 0, 500); + ByteString suffix = ByteString.copyFrom(bytes, 400, 600); + assertTrue(string.endsWith(ByteString.EMPTY)); + assertTrue(string.endsWith(string)); + assertTrue(string.endsWith(suffix)); + assertFalse(string.endsWith(prefix)); + assertFalse(suffix.endsWith(prefix)); + assertFalse(prefix.endsWith(suffix)); + assertFalse(ByteString.EMPTY.endsWith(suffix)); + assertTrue(ByteString.EMPTY.endsWith(ByteString.EMPTY)); + } + static List<ByteString> makeConcretePieces(byte[] referenceBytes) { List<ByteString> pieces = new ArrayList<ByteString>(); // Starting length should be small enough that we'll do some concatenating by @@ -689,4 +705,55 @@ public class ByteStringTest extends TestCase { } return pieces; } + + private byte[] substringUsingWriteTo( + ByteString data, int offset, int length) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + data.writeTo(output, offset, length); + return output.toByteArray(); + } + + public void testWriteToOutputStream() throws Exception { + // Choose a size large enough so when two ByteStrings are concatenated they + // won't be merged into one byte array due to some optimizations. + final int dataSize = ByteString.CONCATENATE_BY_COPY_SIZE + 1; + byte[] data1 = new byte[dataSize]; + for (int i = 0; i < data1.length; i++) { + data1[i] = (byte) 1; + } + data1[1] = (byte) 11; + // Test LiteralByteString.writeTo(OutputStream,int,int) + LiteralByteString left = new LiteralByteString(data1); + byte[] result = substringUsingWriteTo(left, 1, 1); + assertEquals(1, result.length); + assertEquals((byte) 11, result[0]); + + byte[] data2 = new byte[dataSize]; + for (int i = 0; i < data1.length; i++) { + data2[i] = (byte) 2; + } + LiteralByteString right = new LiteralByteString(data2); + // Concatenate two ByteStrings to create a RopeByteString. + ByteString root = left.concat(right); + // Make sure we are actually testing a RopeByteString with a simple tree + // structure. + assertEquals(1, root.getTreeDepth()); + // Write parts of the left node. + result = substringUsingWriteTo(root, 0, dataSize); + assertEquals(dataSize, result.length); + assertEquals((byte) 1, result[0]); + assertEquals((byte) 1, result[dataSize - 1]); + // Write parts of the right node. + result = substringUsingWriteTo(root, dataSize, dataSize); + assertEquals(dataSize, result.length); + assertEquals((byte) 2, result[0]); + assertEquals((byte) 2, result[dataSize - 1]); + // Write a segment of bytes that runs across both nodes. + result = substringUsingWriteTo(root, dataSize / 2, dataSize); + assertEquals(dataSize, result.length); + assertEquals((byte) 1, result[0]); + assertEquals((byte) 1, result[dataSize - dataSize / 2 - 1]); + assertEquals((byte) 2, result[dataSize - dataSize / 2]); + assertEquals((byte) 2, result[dataSize - 1]); + } } diff --git a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java new file mode 100644 index 00000000..97bf1c7a --- /dev/null +++ b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java @@ -0,0 +1,141 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper; +import proto2_test_check_utf8.TestCheckUtf8.StringWrapper; +import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize; +import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize; +import junit.framework.TestCase; + +/** + * Test that protos generated with file option java_string_check_utf8 do in + * fact perform appropriate UTF-8 checks. + * + * @author jbaum@google.com (Jacob Butcher) + */ +public class CheckUtf8Test extends TestCase { + + private static final String UTF8_BYTE_STRING_TEXT = "some text"; + private static final ByteString UTF8_BYTE_STRING = + ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT); + private static final ByteString NON_UTF8_BYTE_STRING = + ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte. + + public void testBuildRequiredStringWithGoodUtf8() throws Exception { + assertEquals(UTF8_BYTE_STRING_TEXT, + StringWrapper.newBuilder().setReqBytes(UTF8_BYTE_STRING).getReq()); + } + + public void testParseRequiredStringWithGoodUtf8() throws Exception { + ByteString serialized = + BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString(); + assertEquals(UTF8_BYTE_STRING_TEXT, + StringWrapper.PARSER.parseFrom(serialized).getReq()); + } + + public void testBuildRequiredStringWithBadUtf8() throws Exception { + try { + StringWrapper.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING); + fail("Expected IllegalArgumentException for non UTF-8 byte string."); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + + public void testBuildOptionalStringWithBadUtf8() throws Exception { + try { + StringWrapper.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING); + fail("Expected IllegalArgumentException for non UTF-8 byte string."); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + + public void testBuildRepeatedStringWithBadUtf8() throws Exception { + try { + StringWrapper.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING); + fail("Expected IllegalArgumentException for non UTF-8 byte string."); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + + public void testParseRequiredStringWithBadUtf8() throws Exception { + ByteString serialized = + BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString(); + try { + StringWrapper.PARSER.parseFrom(serialized); + fail("Expected InvalidProtocolBufferException for non UTF-8 byte string."); + } catch (InvalidProtocolBufferException exception) { + assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()); + } + } + + public void testBuildRequiredStringWithBadUtf8Size() throws Exception { + try { + StringWrapperSize.newBuilder().setReqBytes(NON_UTF8_BYTE_STRING); + fail("Expected IllegalArgumentException for non UTF-8 byte string."); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + + public void testBuildOptionalStringWithBadUtf8Size() throws Exception { + try { + StringWrapperSize.newBuilder().setOptBytes(NON_UTF8_BYTE_STRING); + fail("Expected IllegalArgumentException for non UTF-8 byte string."); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + + public void testBuildRepeatedStringWithBadUtf8Size() throws Exception { + try { + StringWrapperSize.newBuilder().addRepBytes(NON_UTF8_BYTE_STRING); + fail("Expected IllegalArgumentException for non UTF-8 byte string."); + } catch (IllegalArgumentException exception) { + assertEquals("Byte string is not UTF-8.", exception.getMessage()); + } + } + + public void testParseRequiredStringWithBadUtf8Size() throws Exception { + ByteString serialized = + BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString(); + try { + StringWrapperSize.PARSER.parseFrom(serialized); + fail("Expected InvalidProtocolBufferException for non UTF-8 byte string."); + } catch (InvalidProtocolBufferException exception) { + assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()); + } + } + +} diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java index 83f7f8da..3b50e497 100644 --- a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -30,15 +30,20 @@ package com.google.protobuf; +import protobuf_unittest.UnittestProto.BoolMessage; +import protobuf_unittest.UnittestProto.Int32Message; +import protobuf_unittest.UnittestProto.Int64Message; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestRecursiveMessage; import junit.framework.TestCase; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.FilterInputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; /** * Unit test for {@link CodedInputStream}. @@ -85,28 +90,54 @@ public class CodedInputStreamTest extends TestCase { } } + private void assertDataConsumed(byte[] data, CodedInputStream input) + throws IOException { + assertEquals(data.length, input.getTotalBytesRead()); + assertTrue(input.isAtEnd()); + } + /** * Parses the given bytes using readRawVarint32() and readRawVarint64() and * checks that the result matches the given value. */ private void assertReadVarint(byte[] data, long value) throws Exception { CodedInputStream input = CodedInputStream.newInstance(data); - assertEquals((int)value, input.readRawVarint32()); + assertEquals((int) value, input.readRawVarint32()); + assertDataConsumed(data, input); input = CodedInputStream.newInstance(data); assertEquals(value, input.readRawVarint64()); - assertTrue(input.isAtEnd()); + assertDataConsumed(data, input); + + input = CodedInputStream.newInstance(data); + assertEquals(value, input.readRawVarint64SlowPath()); + assertDataConsumed(data, input); + + input = CodedInputStream.newInstance(data); + assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT)); + assertDataConsumed(data, input); // Try different block sizes. for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { input = CodedInputStream.newInstance( new SmallBlockInputStream(data, blockSize)); - assertEquals((int)value, input.readRawVarint32()); + assertEquals((int) value, input.readRawVarint32()); + assertDataConsumed(data, input); input = CodedInputStream.newInstance( new SmallBlockInputStream(data, blockSize)); assertEquals(value, input.readRawVarint64()); - assertTrue(input.isAtEnd()); + assertDataConsumed(data, input); + + input = CodedInputStream.newInstance( + new SmallBlockInputStream(data, blockSize)); + assertEquals(value, input.readRawVarint64SlowPath()); + assertDataConsumed(data, input); + + input = CodedInputStream.newInstance( + new SmallBlockInputStream(data, blockSize)); + assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT)); + assertDataConsumed(data, input); } // Try reading direct from an InputStream. We want to verify that it @@ -115,7 +146,7 @@ public class CodedInputStreamTest extends TestCase { byte[] longerData = new byte[data.length + 1]; System.arraycopy(data, 0, longerData, 0, data.length); InputStream rawInput = new ByteArrayInputStream(longerData); - assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput)); + assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput)); assertEquals(1, rawInput.available()); } @@ -143,6 +174,14 @@ public class CodedInputStreamTest extends TestCase { assertEquals(expected.getMessage(), e.getMessage()); } + input = CodedInputStream.newInstance(data); + try { + input.readRawVarint64SlowPath(); + fail("Should have thrown an exception."); + } catch (InvalidProtocolBufferException e) { + assertEquals(expected.getMessage(), e.getMessage()); + } + // Make sure we get the same error when reading direct from an InputStream. try { CodedInputStream.readRawVarint32(new ByteArrayInputStream(data)); @@ -311,6 +350,7 @@ public class CodedInputStreamTest extends TestCase { } } + /** * Test that a bug in skipRawBytes() has been fixed: if the skip skips * exactly up to a limit, this should not break things. @@ -350,7 +390,7 @@ public class CodedInputStreamTest extends TestCase { // Allocate and initialize a 1MB blob. byte[] blob = new byte[1 << 20]; for (int i = 0; i < blob.length; i++) { - blob[i] = (byte)i; + blob[i] = (byte) i; } // Make a message containing it. @@ -437,16 +477,23 @@ public class CodedInputStreamTest extends TestCase { } } + private void checkSizeLimitExceeded(InvalidProtocolBufferException e) { + assertEquals( + InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), + e.getMessage()); + } + public void testSizeLimit() throws Exception { CodedInputStream input = CodedInputStream.newInstance( - TestUtil.getAllSet().toByteString().newInput()); + new SmallBlockInputStream( + TestUtil.getAllSet().toByteString().newInput(), 16)); input.setSizeLimit(16); try { TestAllTypes.parseFrom(input); fail("Should have thrown an exception!"); - } catch (InvalidProtocolBufferException e) { - // success. + } catch (InvalidProtocolBufferException expected) { + checkSizeLimitExceeded(expected); } } @@ -460,8 +507,8 @@ public class CodedInputStreamTest extends TestCase { try { input.readRawByte(); fail("Should have thrown an exception!"); - } catch (InvalidProtocolBufferException e) { - // success. + } catch (InvalidProtocolBufferException expected) { + checkSizeLimitExceeded(expected); } input.resetSizeCounter(); @@ -469,28 +516,50 @@ public class CodedInputStreamTest extends TestCase { input.readRawByte(); // No exception thrown. input.resetSizeCounter(); assertEquals(0, input.getTotalBytesRead()); + input.readRawBytes(16); + assertEquals(16, input.getTotalBytesRead()); + input.resetSizeCounter(); try { - input.readRawBytes(16); // Hits limit again. + input.readRawBytes(17); // Hits limit again. fail("Should have thrown an exception!"); - } catch (InvalidProtocolBufferException e) { - // success. + } catch (InvalidProtocolBufferException expected) { + checkSizeLimitExceeded(expected); + } + } + + public void testSizeLimitMultipleMessages() throws Exception { + byte[] bytes = new byte[256]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (byte) i; + } + CodedInputStream input = CodedInputStream.newInstance( + new SmallBlockInputStream(bytes, 7)); + input.setSizeLimit(16); + for (int i = 0; i < 256 / 16; i++) { + byte[] message = input.readRawBytes(16); + for (int j = 0; j < message.length; j++) { + assertEquals(i * 16 + j, message[j] & 0xff); + } + assertEquals(16, input.getTotalBytesRead()); + input.resetSizeCounter(); + assertEquals(0, input.getTotalBytesRead()); } } /** - * Tests that if we read an string that contains invalid UTF-8, no exception + * Tests that if we readString invalid UTF-8 bytes, no exception * is thrown. Instead, the invalid bytes are replaced with the Unicode * "replacement character" U+FFFD. */ - public void testReadInvalidUtf8() throws Exception { + public void testReadStringInvalidUtf8() throws Exception { ByteString.Output rawOutput = ByteString.newOutput(); CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); output.writeRawVarint32(tag); output.writeRawVarint32(1); - output.writeRawBytes(new byte[] { (byte)0x80 }); + output.writeRawBytes(new byte[] { (byte) 0x80 }); output.flush(); CodedInputStream input = rawOutput.toByteString().newCodedInput(); @@ -499,13 +568,37 @@ public class CodedInputStreamTest extends TestCase { assertEquals(0xfffd, text.charAt(0)); } + /** + * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an + * InvalidProtocolBufferException is thrown. + */ + public void testReadStringRequireUtf8InvalidUtf8() throws Exception { + ByteString.Output rawOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); + + int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); + output.writeRawVarint32(tag); + output.writeRawVarint32(1); + output.writeRawBytes(new byte[] { (byte) 0x80 }); + output.flush(); + + CodedInputStream input = rawOutput.toByteString().newCodedInput(); + assertEquals(tag, input.readTag()); + try { + input.readStringRequireUtf8(); + fail("Expected invalid UTF-8 exception."); + } catch (InvalidProtocolBufferException exception) { + assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()); + } + } + public void testReadFromSlice() throws Exception { byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5); assertEquals(0, in.getTotalBytesRead()); for (int i = 3; i < 8; i++) { assertEquals(i, in.readRawByte()); - assertEquals(i-2, in.getTotalBytesRead()); + assertEquals(i - 2, in.getTotalBytesRead()); } // eof assertEquals(0, in.readTag()); @@ -525,4 +618,152 @@ public class CodedInputStreamTest extends TestCase { } } } + + public void testReadByteArray() throws Exception { + ByteString.Output rawOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); + // Zero-sized bytes field. + output.writeRawVarint32(0); + // One one-byte bytes field + output.writeRawVarint32(1); + output.writeRawBytes(new byte[] { (byte) 23 }); + // Another one-byte bytes field + output.writeRawVarint32(1); + output.writeRawBytes(new byte[] { (byte) 45 }); + // A bytes field large enough that won't fit into the 4K buffer. + final int bytesLength = 16 * 1024; + byte[] bytes = new byte[bytesLength]; + bytes[0] = (byte) 67; + bytes[bytesLength - 1] = (byte) 89; + output.writeRawVarint32(bytesLength); + output.writeRawBytes(bytes); + + output.flush(); + CodedInputStream inputStream = rawOutput.toByteString().newCodedInput(); + + byte[] result = inputStream.readByteArray(); + assertEquals(0, result.length); + result = inputStream.readByteArray(); + assertEquals(1, result.length); + assertEquals((byte) 23, result[0]); + result = inputStream.readByteArray(); + assertEquals(1, result.length); + assertEquals((byte) 45, result[0]); + result = inputStream.readByteArray(); + assertEquals(bytesLength, result.length); + assertEquals((byte) 67, result[0]); + assertEquals((byte) 89, result[bytesLength - 1]); + } + + public void testReadByteBuffer() throws Exception { + ByteString.Output rawOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); + // Zero-sized bytes field. + output.writeRawVarint32(0); + // One one-byte bytes field + output.writeRawVarint32(1); + output.writeRawBytes(new byte[]{(byte) 23}); + // Another one-byte bytes field + output.writeRawVarint32(1); + output.writeRawBytes(new byte[]{(byte) 45}); + // A bytes field large enough that won't fit into the 4K buffer. + final int bytesLength = 16 * 1024; + byte[] bytes = new byte[bytesLength]; + bytes[0] = (byte) 67; + bytes[bytesLength - 1] = (byte) 89; + output.writeRawVarint32(bytesLength); + output.writeRawBytes(bytes); + + output.flush(); + CodedInputStream inputStream = rawOutput.toByteString().newCodedInput(); + + ByteBuffer result = inputStream.readByteBuffer(); + assertEquals(0, result.capacity()); + result = inputStream.readByteBuffer(); + assertEquals(1, result.capacity()); + assertEquals((byte) 23, result.get()); + result = inputStream.readByteBuffer(); + assertEquals(1, result.capacity()); + assertEquals((byte) 45, result.get()); + result = inputStream.readByteBuffer(); + assertEquals(bytesLength, result.capacity()); + assertEquals((byte) 67, result.get()); + result.position(bytesLength - 1); + assertEquals((byte) 89, result.get()); + } + + public void testReadByteBufferAliasing() throws Exception { + ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); + CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream); + // Zero-sized bytes field. + output.writeRawVarint32(0); + // One one-byte bytes field + output.writeRawVarint32(1); + output.writeRawBytes(new byte[]{(byte) 23}); + // Another one-byte bytes field + output.writeRawVarint32(1); + output.writeRawBytes(new byte[]{(byte) 45}); + // A bytes field large enough that won't fit into the 4K buffer. + final int bytesLength = 16 * 1024; + byte[] bytes = new byte[bytesLength]; + bytes[0] = (byte) 67; + bytes[bytesLength - 1] = (byte) 89; + output.writeRawVarint32(bytesLength); + output.writeRawBytes(bytes); + output.flush(); + byte[] data = byteArrayStream.toByteArray(); + + // Without aliasing + CodedInputStream inputStream = CodedInputStream.newInstance(data); + ByteBuffer result = inputStream.readByteBuffer(); + assertEquals(0, result.capacity()); + result = inputStream.readByteBuffer(); + assertTrue(result.array() != data); + assertEquals(1, result.capacity()); + assertEquals((byte) 23, result.get()); + result = inputStream.readByteBuffer(); + assertTrue(result.array() != data); + assertEquals(1, result.capacity()); + assertEquals((byte) 45, result.get()); + result = inputStream.readByteBuffer(); + assertTrue(result.array() != data); + assertEquals(bytesLength, result.capacity()); + assertEquals((byte) 67, result.get()); + result.position(bytesLength - 1); + assertEquals((byte) 89, result.get()); + + // Enable aliasing + inputStream = CodedInputStream.newInstance(data); + inputStream.enableAliasing(true); + result = inputStream.readByteBuffer(); + assertEquals(0, result.capacity()); + result = inputStream.readByteBuffer(); + assertTrue(result.array() == data); + assertEquals(1, result.capacity()); + assertEquals((byte) 23, result.get()); + result = inputStream.readByteBuffer(); + assertTrue(result.array() == data); + assertEquals(1, result.capacity()); + assertEquals((byte) 45, result.get()); + result = inputStream.readByteBuffer(); + assertTrue(result.array() == data); + assertEquals(bytesLength, result.capacity()); + assertEquals((byte) 67, result.get()); + result.position(bytesLength - 1); + assertEquals((byte) 89, result.get()); + } + + public void testCompatibleTypes() throws Exception { + long data = 0x100000000L; + Int64Message message = Int64Message.newBuilder().setData(data).build(); + ByteString serialized = message.toByteString(); + + // Test int64(long) is compatible with bool(boolean) + BoolMessage msg2 = BoolMessage.parseFrom(serialized); + assertTrue(msg2.getData()); + + // Test int64(long) is compatible with int32(int) + Int32Message msg3 = Int32Message.parseFrom(serialized); + assertEquals((int) data, msg3.getData()); + } } diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java index 86255029..da70be42 100644 --- a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java @@ -38,6 +38,7 @@ import protobuf_unittest.UnittestProto.TestSparseEnum; import junit.framework.TestCase; import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -314,4 +315,87 @@ public class CodedOutputStreamTest extends TestCase { SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes); assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum()); } + + /** Test getTotalBytesWritten() */ + public void testGetTotalBytesWritten() throws Exception { + final int BUFFER_SIZE = 4 * 1024; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE); + CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream); + byte[] value = "abcde".getBytes("UTF-8"); + for (int i = 0; i < 1024; ++i) { + codedStream.writeRawBytes(value, 0, value.length); + } + // Make sure we have written more bytes than the buffer could hold. This is + // to make the test complete. + assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE); + assertEquals(value.length * 1024, codedStream.getTotalBytesWritten()); + } + + public void testWriteToByteBuffer() throws Exception { + final int bufferSize = 16 * 1024; + ByteBuffer buffer = ByteBuffer.allocate(bufferSize); + CodedOutputStream codedStream = CodedOutputStream.newInstance(buffer); + // Write raw bytes into the ByteBuffer. + final int length1 = 5000; + for (int i = 0; i < length1; i++) { + codedStream.writeRawByte((byte) 1); + } + final int length2 = 8 * 1024; + byte[] data = new byte[length2]; + for (int i = 0; i < length2; i++) { + data[i] = (byte) 2; + } + codedStream.writeRawBytes(data); + final int length3 = bufferSize - length1 - length2; + for (int i = 0; i < length3; i++) { + codedStream.writeRawByte((byte) 3); + } + codedStream.flush(); + + // Check that data is correctly written to the ByteBuffer. + assertEquals(0, buffer.remaining()); + buffer.flip(); + for (int i = 0; i < length1; i++) { + assertEquals((byte) 1, buffer.get()); + } + for (int i = 0; i < length2; i++) { + assertEquals((byte) 2, buffer.get()); + } + for (int i = 0; i < length3; i++) { + assertEquals((byte) 3, buffer.get()); + } + } + + public void testWriteByteBuffer() throws Exception { + byte[] value = "abcde".getBytes("UTF-8"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream); + ByteBuffer byteBuffer = ByteBuffer.wrap(value, 0, 1); + // This will actually write 5 bytes into the CodedOutputStream as the + // ByteBuffer's capacity() is 5. + codedStream.writeRawBytes(byteBuffer); + // The above call shouldn't affect the ByteBuffer's state. + assertEquals(0, byteBuffer.position()); + assertEquals(1, byteBuffer.limit()); + + // The correct way to write part of an array using ByteBuffer. + codedStream.writeRawBytes(ByteBuffer.wrap(value, 2, 1).slice()); + + codedStream.flush(); + byte[] result = outputStream.toByteArray(); + assertEquals(6, result.length); + for (int i = 0; i < 5; i++) { + assertEquals(value[i], result[i]); + } + assertEquals(value[2], result[5]); + } + + public void testWriteByteArrayWithOffsets() throws Exception { + byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88); + byte[] destination = new byte[4]; + CodedOutputStream codedStream = CodedOutputStream.newInstance(destination); + codedStream.writeByteArrayNoTag(fullArray, 2, 2); + assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination); + assertEquals(3, codedStream.getTotalBytesWritten()); + } } diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java index 9c310919..30e01493 100644 --- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -39,6 +39,7 @@ import com.google.protobuf.Descriptors.DescriptorValidationException; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.protobuf.Descriptors.EnumDescriptor; import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; @@ -53,10 +54,13 @@ import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; +import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestService; import protobuf_unittest.UnittestCustomOptions; +import protobuf_unittest.TestCustomOptions; + import junit.framework.TestCase; @@ -308,6 +312,7 @@ public class DescriptorsTest extends TestCase { EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor(); assertEquals(value, enumType.getValues().get(0)); assertEquals("FOREIGN_FOO", value.getName()); + assertEquals("FOREIGN_FOO", value.toString()); assertEquals(4, value.getNumber()); assertEquals(value, enumType.findValueByName("FOREIGN_FOO")); assertEquals(value, enumType.findValueByNumber(4)); @@ -324,7 +329,6 @@ public class DescriptorsTest extends TestCase { assertEquals("protobuf_unittest.TestService", service.getFullName()); assertEquals(UnittestProto.getDescriptor(), service.getFile()); - assertEquals(2, service.getMethods().size()); MethodDescriptor fooMethod = service.getMethods().get(0); assertEquals("Foo", fooMethod.getName()); @@ -351,8 +355,12 @@ public class DescriptorsTest extends TestCase { public void testCustomOptions() throws Exception { + // Get the descriptor indirectly from a dependent proto class. This is to + // ensure that when a proto class is loaded, custom options defined in its + // dependencies are also properly initialized. Descriptor descriptor = - UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor(); + TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor() + .findFieldByName("field").getMessageType(); assertTrue( descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1)); @@ -511,9 +519,35 @@ public class DescriptorsTest extends TestCase { assertTrue(barFound); } + public void testDependencyOrder() throws Exception { + FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() + .setName("foo.proto").build(); + FileDescriptorProto barProto = FileDescriptorProto.newBuilder() + .setName("bar.proto") + .addDependency("foo.proto") + .build(); + FileDescriptorProto bazProto = FileDescriptorProto.newBuilder() + .setName("baz.proto") + .addDependency("foo.proto") + .addDependency("bar.proto") + .addPublicDependency(0) + .addPublicDependency(1) + .build(); + FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, + new FileDescriptor[0]); + FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, + new FileDescriptor[] {fooFile}); + + // Items in the FileDescriptor array can be in any order. + Descriptors.FileDescriptor.buildFrom(bazProto, + new FileDescriptor[] {fooFile, barFile}); + Descriptors.FileDescriptor.buildFrom(bazProto, + new FileDescriptor[] {barFile, fooFile}); + } + public void testInvalidPublicDependency() throws Exception { FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() - .setName("foo.proto") .build(); + .setName("foo.proto").build(); FileDescriptorProto barProto = FileDescriptorProto.newBuilder() .setName("boo.proto") .addDependency("foo.proto") @@ -645,4 +679,30 @@ public class DescriptorsTest extends TestCase { "a.b.c.d.bar.shared")); } } + + public void testOneofDescriptor() throws Exception { + Descriptor messageType = TestAllTypes.getDescriptor(); + FieldDescriptor field = + messageType.findFieldByName("oneof_nested_message"); + OneofDescriptor oneofDescriptor = field.getContainingOneof(); + assertNotNull(oneofDescriptor); + assertSame(oneofDescriptor, messageType.getOneofs().get(0)); + assertEquals("oneof_field", oneofDescriptor.getName()); + + assertEquals(4, oneofDescriptor.getFieldCount()); + assertSame(oneofDescriptor.getField(1), field); + } + + public void testMessageDescriptorExtensions() throws Exception { + assertFalse(TestAllTypes.getDescriptor().isExtendable()); + assertTrue(TestAllExtensions.getDescriptor().isExtendable()); + assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable()); + + assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3)); + assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3)); + assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42)); + assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43)); + assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142)); + assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)); + } } diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java index 990e8ca6..ee3769ce 100644 --- a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -30,6 +30,9 @@ package com.google.protobuf; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.OneofDescriptor; + import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestEmptyMessage; @@ -241,6 +244,19 @@ public class DynamicMessageTest extends TestCase { DynamicMessage copy = DynamicMessage.newBuilder(message).build(); reflectionTester.assertAllFieldsSetViaReflection(copy); + + // Test oneof behavior + FieldDescriptor bytesField = + TestAllTypes.getDescriptor().findFieldByName("oneof_bytes"); + FieldDescriptor uint32Field = + TestAllTypes.getDescriptor().findFieldByName("oneof_uint32"); + assertTrue(copy.hasField(bytesField)); + assertFalse(copy.hasField(uint32Field)); + DynamicMessage copy2 = + DynamicMessage.newBuilder(message).setField(uint32Field, 123).build(); + assertFalse(copy2.hasField(bytesField)); + assertTrue(copy2.hasField(uint32Field)); + assertEquals(123, copy2.getField(uint32Field)); } public void testToBuilder() throws Exception { @@ -261,4 +277,34 @@ public class DynamicMessageTest extends TestCase { assertEquals(Arrays.asList(unknownFieldVal), derived.getUnknownFields().getField(unknownFieldNum).getVarintList()); } + + public void testDynamicOneofMessage() throws Exception { + DynamicMessage.Builder builder = + DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); + OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0); + assertFalse(builder.hasOneof(oneof)); + assertSame(null, builder.getOneofFieldDescriptor(oneof)); + + reflectionTester.setAllFieldsViaReflection(builder); + assertTrue(builder.hasOneof(oneof)); + FieldDescriptor field = oneof.getField(3); + assertSame(field, builder.getOneofFieldDescriptor(oneof)); + + DynamicMessage message = builder.buildPartial(); + assertTrue(message.hasOneof(oneof)); + + DynamicMessage.Builder mergedBuilder = + DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); + FieldDescriptor mergedField = oneof.getField(0); + mergedBuilder.setField(mergedField, 123); + assertTrue(mergedBuilder.hasField(mergedField)); + mergedBuilder.mergeFrom(message); + assertTrue(mergedBuilder.hasField(field)); + assertFalse(mergedBuilder.hasField(mergedField)); + + builder.clearOneof(oneof); + assertSame(null, builder.getOneofFieldDescriptor(oneof)); + message = builder.build(); + assertSame(null, message.getOneofFieldDescriptor(oneof)); + } } diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index bf9db75b..eb9e6322 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -45,6 +45,9 @@ import protobuf_unittest.NonNestedExtension.MyNonNestedExtension; import protobuf_unittest.NonNestedExtensionLite; import protobuf_unittest.NonNestedExtensionLite.MessageLiteToBeExtended; import protobuf_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite; +import protobuf_unittest.OuterClassNameTest2OuterClass; +import protobuf_unittest.OuterClassNameTest3OuterClass; +import protobuf_unittest.OuterClassNameTestOuterClass; import protobuf_unittest.ServiceWithNoOuter; import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize; @@ -58,6 +61,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder; import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; +import protobuf_unittest.UnittestProto.TestOneof2; import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestUnpackedTypes; @@ -69,6 +73,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; /** @@ -399,6 +404,44 @@ public class GeneratedMessageTest extends TestCase { // We expect this exception. } } + + public void testRepeatedAppendIterateOnlyOnce() throws Exception { + // Create a Iterable that can only be iterated once. + Iterable<String> stringIterable = new Iterable<String>() { + private boolean called = false; + @Override + public Iterator<String> iterator() { + if (called) { + throw new IllegalStateException(); + } + called = true; + return Arrays.asList("one", "two", "three").iterator(); + } + }; + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.addAllRepeatedString(stringIterable); + assertEquals(3, builder.getRepeatedStringCount()); + assertEquals("one", builder.getRepeatedString(0)); + assertEquals("two", builder.getRepeatedString(1)); + assertEquals("three", builder.getRepeatedString(2)); + + try { + builder.addAllRepeatedString(stringIterable); + fail("Exception was not thrown"); + } catch (IllegalStateException e) { + // We expect this exception. + } + } + + public void testMergeFromOtherRejectsNull() throws Exception { + try { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.mergeFrom((TestAllTypes) null); + fail("Exception was not thrown"); + } catch (NullPointerException e) { + // We expect this exception. + } + } public void testSettingForeignMessageUsingBuilder() throws Exception { TestAllTypes message = TestAllTypes.newBuilder() @@ -496,6 +539,34 @@ public class GeneratedMessageTest extends TestCase { TestAllTypes.newBuilder().build()); } + public void testReflectionGetOneof() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + reflectionTester.setAllFieldsViaReflection(builder); + Descriptors.OneofDescriptor oneof = + TestAllTypes.getDescriptor().getOneofs().get(0); + Descriptors.FieldDescriptor field = + TestAllTypes.getDescriptor().findFieldByName("oneof_bytes"); + assertSame(field, builder.getOneofFieldDescriptor(oneof)); + + TestAllTypes message = builder.build(); + assertSame(field, message.getOneofFieldDescriptor(oneof)); + } + + public void testReflectionClearOneof() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + reflectionTester.setAllFieldsViaReflection(builder); + Descriptors.OneofDescriptor oneof = + TestAllTypes.getDescriptor().getOneofs().get(0); + Descriptors.FieldDescriptor field = + TestAllTypes.getDescriptor().findFieldByName("oneof_bytes"); + + assertTrue(builder.hasOneof(oneof)); + assertTrue(builder.hasField(field)); + builder.clearOneof(oneof); + assertFalse(builder.hasOneof(oneof)); + assertFalse(builder.hasField(field)); + } + public void testEnumInterface() throws Exception { assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum() instanceof ProtocolMessageEnum); @@ -697,6 +768,15 @@ public class GeneratedMessageTest extends TestCase { // ================================================================= // multiple_files_test + // Test that custom options of an file level enum are properly initialized. + // This test needs to be put before any other access to MultipleFilesTestProto + // or messages defined in multiple_files_test.proto because the class loading + // order affects initialization process of custom options. + public void testEnumValueOptionsInMultipleFilesMode() throws Exception { + assertEquals(12345, EnumWithNoOuter.FOO.getValueDescriptor().getOptions() + .getExtension(MultipleFilesTestProto.enumValueOption).intValue()); + } + public void testMultipleFilesOption() throws Exception { // We mostly just want to check that things compile. MessageWithNoOuter message = @@ -795,7 +875,7 @@ public class GeneratedMessageTest extends TestCase { UnittestProto.TestRecursiveMessage message = UnittestProto.TestRecursiveMessage.getDefaultInstance(); assertTrue(message != null); - assertTrue(message.getA() != null); + assertNotNull(message.getA()); assertTrue(message.getA() == message); } @@ -1143,4 +1223,293 @@ public class GeneratedMessageTest extends TestCase { // We expect this exception. } } + + // Test that when the default outer class name conflicts with another type + // defined in the proto the compiler will append a suffix to avoid the + // conflict. + public void testConflictingOuterClassName() { + // We just need to make sure we can refer to the outer class with the + // expected name. There is nothing else to test. + OuterClassNameTestOuterClass.OuterClassNameTest message = + OuterClassNameTestOuterClass.OuterClassNameTest.newBuilder().build(); + assertTrue(message.getDescriptorForType() == + OuterClassNameTestOuterClass.OuterClassNameTest.getDescriptor()); + + OuterClassNameTest2OuterClass.TestMessage2.NestedMessage.OuterClassNameTest2 + message2 = OuterClassNameTest2OuterClass.TestMessage2.NestedMessage + .OuterClassNameTest2.newBuilder().build(); + assertEquals(0, message2.getSerializedSize()); + + OuterClassNameTest3OuterClass.TestMessage3.NestedMessage.OuterClassNameTest3 + enumValue = OuterClassNameTest3OuterClass.TestMessage3.NestedMessage + .OuterClassNameTest3.DUMMY_VALUE; + assertEquals(1, enumValue.getNumber()); + } + + // ================================================================= + // oneof generated code test + public void testOneofEnumCase() throws Exception { + TestOneof2 message = TestOneof2.newBuilder() + .setFooInt(123).setFooString("foo").setFooCord("bar").build(); + TestUtil.assertAtMostOneFieldSetOneof(message); + } + + public void testClearOneof() throws Exception { + TestOneof2.Builder builder = TestOneof2.newBuilder().setFooInt(123); + assertEquals(TestOneof2.FooCase.FOO_INT, builder.getFooCase()); + builder.clearFoo(); + assertEquals(TestOneof2.FooCase.FOO_NOT_SET, builder.getFooCase()); + } + + public void testSetOneofClearsOthers() throws Exception { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = + builder.setFooInt(123).setFooString("foo").buildPartial(); + assertTrue(message.hasFooString()); + TestUtil.assertAtMostOneFieldSetOneof(message); + + message = builder.setFooCord("bar").buildPartial(); + assertTrue(message.hasFooCord()); + TestUtil.assertAtMostOneFieldSetOneof(message); + + message = builder.setFooStringPiece("baz").buildPartial(); + assertTrue(message.hasFooStringPiece()); + TestUtil.assertAtMostOneFieldSetOneof(message); + + message = builder.setFooBytes(TestUtil.toBytes("qux")).buildPartial(); + assertTrue(message.hasFooBytes()); + TestUtil.assertAtMostOneFieldSetOneof(message); + + message = builder.setFooEnum(TestOneof2.NestedEnum.FOO).buildPartial(); + assertTrue(message.hasFooEnum()); + TestUtil.assertAtMostOneFieldSetOneof(message); + + message = builder.setFooMessage( + TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).buildPartial(); + assertTrue(message.hasFooMessage()); + TestUtil.assertAtMostOneFieldSetOneof(message); + + message = builder.setFooInt(123).buildPartial(); + assertTrue(message.hasFooInt()); + TestUtil.assertAtMostOneFieldSetOneof(message); + } + + public void testOneofTypes() throws Exception { + // Primitive + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + assertEquals(builder.getFooInt(), 0); + assertFalse(builder.hasFooInt()); + assertTrue(builder.setFooInt(123).hasFooInt()); + assertEquals(builder.getFooInt(), 123); + TestOneof2 message = builder.buildPartial(); + assertTrue(message.hasFooInt()); + assertEquals(message.getFooInt(), 123); + + assertFalse(builder.clearFooInt().hasFooInt()); + TestOneof2 message2 = builder.build(); + assertFalse(message2.hasFooInt()); + assertEquals(message2.getFooInt(), 0); + } + + // Enum + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO); + assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum()); + assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR); + TestOneof2 message = builder.buildPartial(); + assertTrue(message.hasFooEnum()); + assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR); + + assertFalse(builder.clearFooEnum().hasFooEnum()); + TestOneof2 message2 = builder.build(); + assertFalse(message2.hasFooEnum()); + assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO); + } + + // String + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + assertEquals(builder.getFooString(), ""); + builder.setFooString("foo"); + assertTrue(builder.hasFooString()); + assertEquals(builder.getFooString(), "foo"); + TestOneof2 message = builder.buildPartial(); + assertTrue(message.hasFooString()); + assertEquals(message.getFooString(), "foo"); + assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo")); + + assertFalse(builder.clearFooString().hasFooString()); + TestOneof2 message2 = builder.buildPartial(); + assertFalse(message2.hasFooString()); + assertEquals(message2.getFooString(), ""); + assertEquals(message2.getFooStringBytes(), TestUtil.toBytes("")); + + // Get method should not change the oneof value. + builder.setFooInt(123); + assertEquals(builder.getFooString(), ""); + assertEquals(builder.getFooStringBytes(), TestUtil.toBytes("")); + assertEquals(123, builder.getFooInt()); + + message = builder.build(); + assertEquals(message.getFooString(), ""); + assertEquals(message.getFooStringBytes(), TestUtil.toBytes("")); + assertEquals(123, message.getFooInt()); + } + + // Cord + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + assertEquals(builder.getFooCord(), ""); + builder.setFooCord("foo"); + assertTrue(builder.hasFooCord()); + assertEquals(builder.getFooCord(), "foo"); + TestOneof2 message = builder.buildPartial(); + assertTrue(message.hasFooCord()); + assertEquals(message.getFooCord(), "foo"); + assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo")); + + assertFalse(builder.clearFooCord().hasFooCord()); + TestOneof2 message2 = builder.build(); + assertFalse(message2.hasFooCord()); + assertEquals(message2.getFooCord(), ""); + assertEquals(message2.getFooCordBytes(), TestUtil.toBytes("")); + } + + // StringPiece + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + assertEquals(builder.getFooStringPiece(), ""); + builder.setFooStringPiece("foo"); + assertTrue(builder.hasFooStringPiece()); + assertEquals(builder.getFooStringPiece(), "foo"); + TestOneof2 message = builder.buildPartial(); + assertTrue(message.hasFooStringPiece()); + assertEquals(message.getFooStringPiece(), "foo"); + assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo")); + + assertFalse(builder.clearFooStringPiece().hasFooStringPiece()); + TestOneof2 message2 = builder.build(); + assertFalse(message2.hasFooStringPiece()); + assertEquals(message2.getFooStringPiece(), ""); + assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes("")); + } + + // Message + { + // set + TestOneof2.Builder builder = TestOneof2.newBuilder(); + assertEquals(builder.getFooMessage().getQuxInt(), 0); + builder.setFooMessage( + TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()); + assertTrue(builder.hasFooMessage()); + assertEquals(builder.getFooMessage().getQuxInt(), 234); + TestOneof2 message = builder.buildPartial(); + assertTrue(message.hasFooMessage()); + assertEquals(message.getFooMessage().getQuxInt(), 234); + + // clear + assertFalse(builder.clearFooMessage().hasFooString()); + message = builder.build(); + assertFalse(message.hasFooMessage()); + assertEquals(message.getFooMessage().getQuxInt(), 0); + + // nested builder + builder = TestOneof2.newBuilder(); + assertSame(builder.getFooMessageOrBuilder(), + TestOneof2.NestedMessage.getDefaultInstance()); + assertFalse(builder.hasFooMessage()); + builder.getFooMessageBuilder().setQuxInt(123); + assertTrue(builder.hasFooMessage()); + assertEquals(builder.getFooMessage().getQuxInt(), 123); + message = builder.build(); + assertTrue(message.hasFooMessage()); + assertEquals(message.getFooMessage().getQuxInt(), 123); + } + + // LazyMessage is tested in LazyMessageLiteTest.java + } + + public void testOneofMerge() throws Exception { + // Primitive Type + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooInt(123).build(); + TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); + assertTrue(message2.hasFooInt()); + assertEquals(message2.getFooInt(), 123); + } + + // String + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooString("foo").build(); + TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); + assertTrue(message2.hasFooString()); + assertEquals(message2.getFooString(), "foo"); + } + + // Enum + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build(); + TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); + assertTrue(message2.hasFooEnum()); + assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR); + } + + // Message + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooMessage( + TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build(); + TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); + assertTrue(message2.hasFooMessage()); + assertEquals(message2.getFooMessage().getQuxInt(), 234); + } + } + + public void testOneofSerialization() throws Exception { + // Primitive Type + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooInt(123).build(); + ByteString serialized = message.toByteString(); + TestOneof2 message2 = TestOneof2.parseFrom(serialized); + assertTrue(message2.hasFooInt()); + assertEquals(message2.getFooInt(), 123); + } + + // String + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooString("foo").build(); + ByteString serialized = message.toByteString(); + TestOneof2 message2 = TestOneof2.parseFrom(serialized); + assertTrue(message2.hasFooString()); + assertEquals(message2.getFooString(), "foo"); + } + + // Enum + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build(); + ByteString serialized = message.toByteString(); + TestOneof2 message2 = TestOneof2.parseFrom(serialized); + assertTrue(message2.hasFooEnum()); + assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR); + } + + // Message + { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestOneof2 message = builder.setFooMessage( + TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build(); + ByteString serialized = message.toByteString(); + TestOneof2 message2 = TestOneof2.parseFrom(serialized); + assertTrue(message2.hasFooMessage()); + assertEquals(message2.getFooMessage().getQuxInt(), 234); + } + } } diff --git a/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java new file mode 100644 index 00000000..33a7297b --- /dev/null +++ b/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java @@ -0,0 +1,134 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; + +import java.io.IOException; +import junit.framework.TestCase; + +/** + * Unit test for {@link LazyFieldLite}. + * + * @author xiangl@google.com (Xiang Li) + */ +public class LazyFieldLiteTest extends TestCase { + + public void testGetValue() { + MessageLite message = TestUtil.getAllSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance())); + changeValue(lazyField); + assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance())); + } + + public void testGetValueEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + assertEquals(message, lazyField.getValue(TestAllExtensions.getDefaultInstance())); + changeValue(lazyField); + assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance())); + } + + public void testSetValue() { + MessageLite message = TestUtil.getAllSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + changeValue(lazyField); + assertNotEqual(message, lazyField.getValue(TestAllTypes.getDefaultInstance())); + message = lazyField.getValue(TestAllTypes.getDefaultInstance()); + changeValue(lazyField); + assertEquals(message, lazyField.getValue(TestAllTypes.getDefaultInstance())); + } + + public void testSetValueEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + changeValue(lazyField); + assertNotEqual(message, lazyField.getValue(TestAllExtensions.getDefaultInstance())); + MessageLite value = lazyField.getValue(TestAllExtensions.getDefaultInstance()); + changeValue(lazyField); + assertEquals(value, lazyField.getValue(TestAllExtensions.getDefaultInstance())); + } + + public void testGetSerializedSize() { + MessageLite message = TestUtil.getAllSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + assertEquals(message.getSerializedSize(), lazyField.getSerializedSize()); + changeValue(lazyField); + assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize()); + } + + public void testGetSerializedSizeEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + assertEquals(message.getSerializedSize(), lazyField.getSerializedSize()); + changeValue(lazyField); + assertNotEqual(message.getSerializedSize(), lazyField.getSerializedSize()); + } + + public void testGetByteString() { + MessageLite message = TestUtil.getAllSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + assertEquals(message.toByteString(), lazyField.toByteString()); + changeValue(lazyField); + assertNotEqual(message.toByteString(), lazyField.toByteString()); + } + + public void testGetByteStringEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyFieldLite lazyField = createLazyFieldLiteFromMessage(message); + assertEquals(message.toByteString(), lazyField.toByteString()); + changeValue(lazyField); + assertNotEqual(message.toByteString(), lazyField.toByteString()); + } + + + // Help methods. + + private LazyFieldLite createLazyFieldLiteFromMessage(MessageLite message) { + ByteString bytes = message.toByteString(); + return new LazyFieldLite(TestUtil.getExtensionRegistry(), bytes); + } + + private void changeValue(LazyFieldLite lazyField) { + TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder(); + builder.addRepeatedBool(true); + MessageLite newMessage = builder.build(); + lazyField.setValue(newMessage); + } + + private void assertNotEqual(Object unexpected, Object actual) { + assertFalse(unexpected == actual + || (unexpected != null && unexpected.equals(actual))); + } + +} diff --git a/java/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/src/test/java/com/google/protobuf/LazyFieldTest.java new file mode 100644 index 00000000..5aedc32a --- /dev/null +++ b/java/src/test/java/com/google/protobuf/LazyFieldTest.java @@ -0,0 +1,121 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; + +import java.io.IOException; +import junit.framework.TestCase; + +/** + * Unit test for {@link LazyField}. + * + * @author xiangl@google.com (Xiang Li) + */ +public class LazyFieldTest extends TestCase { + public void testHashCode() { + MessageLite message = TestUtil.getAllSet(); + LazyField lazyField = + createLazyFieldFromMessage(message); + assertEquals(message.hashCode(), lazyField.hashCode()); + lazyField.getValue(); + assertEquals(message.hashCode(), lazyField.hashCode()); + changeValue(lazyField); + // make sure two messages have different hash code + assertNotEqual(message.hashCode(), lazyField.hashCode()); + } + + public void testHashCodeEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyField lazyField = createLazyFieldFromMessage(message); + assertEquals(message.hashCode(), lazyField.hashCode()); + lazyField.getValue(); + assertEquals(message.hashCode(), lazyField.hashCode()); + changeValue(lazyField); + // make sure two messages have different hash code + assertNotEqual(message.hashCode(), lazyField.hashCode()); + } + + public void testGetValue() { + MessageLite message = TestUtil.getAllSet(); + LazyField lazyField = createLazyFieldFromMessage(message); + assertEquals(message, lazyField.getValue()); + changeValue(lazyField); + assertNotEqual(message, lazyField.getValue()); + } + + public void testGetValueEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyField lazyField = createLazyFieldFromMessage(message); + assertEquals(message, lazyField.getValue()); + changeValue(lazyField); + assertNotEqual(message, lazyField.getValue()); + } + + public void testEqualsObject() { + MessageLite message = TestUtil.getAllSet(); + LazyField lazyField = createLazyFieldFromMessage(message); + assertTrue(lazyField.equals(message)); + changeValue(lazyField); + assertFalse(lazyField.equals(message)); + assertFalse(message.equals(lazyField.getValue())); + } + + public void testEqualsObjectEx() throws Exception { + TestAllExtensions message = TestUtil.getAllExtensionsSet(); + LazyField lazyField = createLazyFieldFromMessage(message); + assertTrue(lazyField.equals(message)); + changeValue(lazyField); + assertFalse(lazyField.equals(message)); + assertFalse(message.equals(lazyField.getValue())); + } + + // Help methods. + + private LazyField createLazyFieldFromMessage(MessageLite message) { + ByteString bytes = message.toByteString(); + return new LazyField(message.getDefaultInstanceForType(), + TestUtil.getExtensionRegistry(), bytes); + } + + private void changeValue(LazyField lazyField) { + TestAllTypes.Builder builder = TestUtil.getAllSet().toBuilder(); + builder.addRepeatedBool(true); + MessageLite newMessage = builder.build(); + lazyField.setValue(newMessage); + } + + private void assertNotEqual(Object unexpected, Object actual) { + assertFalse(unexpected == actual + || (unexpected != null && unexpected.equals(actual))); + } +} diff --git a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java new file mode 100644 index 00000000..63028db9 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java @@ -0,0 +1,319 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import protobuf_unittest.LazyFieldsLite.LazyInnerMessageLite; +import protobuf_unittest.LazyFieldsLite.LazyMessageLite; +import protobuf_unittest.LazyFieldsLite.LazyNestedInnerMessageLite; + +import junit.framework.TestCase; + +import org.easymock.classextension.EasyMock; + +import java.util.ArrayList; + +/** + * Unit test for messages with lazy fields. + * + * @author niwasaki@google.com (Naoki Iwasaki) + */ +public class LazyMessageLiteTest extends TestCase { + + private Parser<LazyInnerMessageLite> originalLazyInnerMessageLiteParser; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + originalLazyInnerMessageLiteParser = LazyInnerMessageLite.PARSER; + } + + @Override + protected void tearDown() throws Exception { + LazyInnerMessageLite.PARSER = originalLazyInnerMessageLiteParser; + + super.tearDown(); + } + + public void testSetValues() { + LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder() + .setNum(3) + .build(); + LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder() + .setNum(2) + .setNested(nested) + .build(); + LazyMessageLite outer = LazyMessageLite.newBuilder() + .setNum(1) + .setInner(inner) + .setOneofNum(123) + .setOneofInner(inner) + .build(); + + assertEquals(1, outer.getNum()); + assertEquals(421, outer.getNumWithDefault()); + + assertEquals(2, outer.getInner().getNum()); + assertEquals(42, outer.getInner().getNumWithDefault()); + + assertEquals(3, outer.getInner().getNested().getNum()); + assertEquals(4, outer.getInner().getNested().getNumWithDefault()); + + assertFalse(outer.hasOneofNum()); + assertTrue(outer.hasOneofInner()); + + assertEquals(2, outer.getOneofInner().getNum()); + assertEquals(42, outer.getOneofInner().getNumWithDefault()); + assertEquals(3, outer.getOneofInner().getNested().getNum()); + assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault()); + } + + public void testSetRepeatedValues() { + LazyMessageLite outer = LazyMessageLite.newBuilder() + .setNum(1) + .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119)) + .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122)) + .build(); + + assertEquals(1, outer.getNum()); + assertEquals(2, outer.getRepeatedInnerCount()); + assertEquals(119, outer.getRepeatedInner(0).getNum()); + assertEquals(122, outer.getRepeatedInner(1).getNum()); + } + + public void testAddAll() { + ArrayList<LazyInnerMessageLite> inners = new ArrayList<LazyInnerMessageLite>(); + int count = 4; + for (int i = 0; i < count; i++) { + LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder() + .setNum(i) + .build(); + inners.add(inner); + } + + LazyMessageLite outer = LazyMessageLite.newBuilder() + .addAllRepeatedInner(inners) + .build(); + assertEquals(count, outer.getRepeatedInnerCount()); + for (int i = 0; i < count; i++) { + assertEquals(i, outer.getRepeatedInner(i).getNum()); + } + } + + public void testGetDefaultValues() { + LazyMessageLite outer = LazyMessageLite.newBuilder() + .build(); + + assertEquals(0, outer.getNum()); + assertEquals(421, outer.getNumWithDefault()); + + assertEquals(0, outer.getInner().getNum()); + assertEquals(42, outer.getInner().getNumWithDefault()); + + assertEquals(0, outer.getInner().getNested().getNum()); + assertEquals(4, outer.getInner().getNested().getNumWithDefault()); + + assertEquals(0, outer.getOneofNum()); + + assertEquals(0, outer.getOneofInner().getNum()); + assertEquals(42, outer.getOneofInner().getNumWithDefault()); + assertEquals(0, outer.getOneofInner().getNested().getNum()); + assertEquals(4, outer.getOneofInner().getNested().getNumWithDefault()); + } + + public void testClearValues() { + LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder() + .setNum(115) + .build(); + + LazyMessageLite.Builder outerBuilder = LazyMessageLite.newBuilder(); + + assertEquals(0, outerBuilder.build().getNum()); + + + // Set/Clear num + outerBuilder.setNum(100); + + assertEquals(100, outerBuilder.build().getNum()); + assertEquals(421, outerBuilder.build().getNumWithDefault()); + assertFalse(outerBuilder.build().hasInner()); + + outerBuilder.clearNum(); + + assertEquals(0, outerBuilder.build().getNum()); + assertEquals(421, outerBuilder.build().getNumWithDefault()); + assertFalse(outerBuilder.build().hasInner()); + + + // Set/Clear all + outerBuilder.setNum(100) + .setInner(inner) + .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(119)) + .addRepeatedInner(LazyInnerMessageLite.newBuilder().setNum(122)) + .setOneofInner(LazyInnerMessageLite.newBuilder().setNum(123)); + + LazyMessageLite outer = outerBuilder.build(); + assertEquals(100, outer.getNum()); + assertEquals(421, outer.getNumWithDefault()); + assertTrue(outer.hasInner()); + assertEquals(115, outer.getInner().getNum()); + assertEquals(2, outer.getRepeatedInnerCount()); + assertEquals(119, outer.getRepeatedInner(0).getNum()); + assertEquals(122, outer.getRepeatedInner(1).getNum()); + assertTrue(outer.hasOneofInner()); + assertEquals(123, outer.getOneofInner().getNum()); + + outerBuilder.clear(); + + outer = outerBuilder.build(); + + assertEquals(0, outer.getNum()); + assertEquals(421, outer.getNumWithDefault()); + assertFalse(outer.hasInner()); + assertEquals(0, outer.getRepeatedInnerCount()); + assertFalse(outer.hasOneofInner()); + assertEquals(0, outer.getOneofInner().getNum()); + } + + public void testMergeValues() { + LazyMessageLite outerBase = LazyMessageLite.newBuilder() + .setNumWithDefault(122) + .build(); + + LazyInnerMessageLite innerMerging = LazyInnerMessageLite.newBuilder() + .setNum(115) + .build(); + LazyMessageLite outerMerging = LazyMessageLite.newBuilder() + .setNum(119) + .setInner(innerMerging) + .setOneofInner(innerMerging) + .build(); + + LazyMessageLite merged = LazyMessageLite + .newBuilder(outerBase) + .mergeFrom(outerMerging) + .build(); + assertEquals(119, merged.getNum()); + assertEquals(122, merged.getNumWithDefault()); + assertEquals(115, merged.getInner().getNum()); + assertEquals(42, merged.getInner().getNumWithDefault()); + assertEquals(115, merged.getOneofInner().getNum()); + assertEquals(42, merged.getOneofInner().getNumWithDefault()); + } + + public void testMergeDefaultValues() { + LazyInnerMessageLite innerBase = LazyInnerMessageLite.newBuilder() + .setNum(115) + .build(); + LazyMessageLite outerBase = LazyMessageLite.newBuilder() + .setNum(119) + .setNumWithDefault(122) + .setInner(innerBase) + .setOneofInner(innerBase) + .build(); + + LazyMessageLite outerMerging = LazyMessageLite.newBuilder() + .build(); + + LazyMessageLite merged = LazyMessageLite + .newBuilder(outerBase) + .mergeFrom(outerMerging) + .build(); + // Merging default-instance shouldn't overwrite values in the base message. + assertEquals(119, merged.getNum()); + assertEquals(122, merged.getNumWithDefault()); + assertEquals(115, merged.getInner().getNum()); + assertEquals(42, merged.getInner().getNumWithDefault()); + assertEquals(115, merged.getOneofInner().getNum()); + assertEquals(42, merged.getOneofInner().getNumWithDefault()); + } + + public void testSerialize() throws InvalidProtocolBufferException { + LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder() + .setNum(3) + .build(); + LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder() + .setNum(2) + .setNested(nested) + .build(); + LazyMessageLite outer = LazyMessageLite.newBuilder() + .setNum(1) + .setInner(inner) + .setOneofInner(inner) + .build(); + + ByteString bytes = outer.toByteString(); + assertEquals(bytes.size(), outer.getSerializedSize()); + + LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes); + + assertEquals(1, deserialized.getNum()); + assertEquals(421, deserialized.getNumWithDefault()); + + assertEquals(2, deserialized.getInner().getNum()); + assertEquals(42, deserialized.getInner().getNumWithDefault()); + + assertEquals(3, deserialized.getInner().getNested().getNum()); + assertEquals(4, deserialized.getInner().getNested().getNumWithDefault()); + + assertEquals(2, deserialized.getOneofInner().getNum()); + assertEquals(42, deserialized.getOneofInner().getNumWithDefault()); + assertEquals(3, deserialized.getOneofInner().getNested().getNum()); + assertEquals(4, deserialized.getOneofInner().getNested().getNumWithDefault()); + + assertEquals(bytes, deserialized.toByteString()); + } + + public void testLaziness() throws InvalidProtocolBufferException { + LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder() + .setNum(2) + .build(); + LazyMessageLite outer = LazyMessageLite.newBuilder() + .setNum(1) + .setInner(inner) + .setOneofInner(inner) + .build(); + ByteString bytes = outer.toByteString(); + + + // The parser for inner / oneofInner message shouldn't be used if + // getInner / getOneofInner is not called. + LazyInnerMessageLite.PARSER = EasyMock.createStrictMock(Parser.class); + + EasyMock.replay(LazyInnerMessageLite.PARSER); + + LazyMessageLite deserialized = LazyMessageLite.parseFrom(bytes); + assertEquals(1, deserialized.getNum()); + assertEquals(421, deserialized.getNumWithDefault()); + + EasyMock.verify(LazyInnerMessageLite.PARSER); + } +} diff --git a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java index d500595f..850658ca 100644 --- a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java +++ b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java @@ -67,6 +67,14 @@ public class LazyStringArrayListTest extends TestCase { list.remove(1); assertSame(STRING_A, list.get(0)); assertSame(STRING_C, list.get(1)); + + List<ByteString> byteStringList = list.asByteStringList(); + assertEquals(BYTE_STRING_A, byteStringList.get(0)); + assertEquals(BYTE_STRING_C, byteStringList.get(1)); + + // Underlying list should be transformed. + assertSame(byteStringList.get(0), list.getByteString(0)); + assertSame(byteStringList.get(1), list.getByteString(1)); } public void testJustByteString() { @@ -83,6 +91,10 @@ public class LazyStringArrayListTest extends TestCase { list.remove(1); assertSame(BYTE_STRING_A, list.getByteString(0)); assertSame(BYTE_STRING_C, list.getByteString(1)); + + List<ByteString> byteStringList = list.asByteStringList(); + assertSame(BYTE_STRING_A, byteStringList.get(0)); + assertSame(BYTE_STRING_C, byteStringList.get(1)); } public void testConversionBackAndForth() { diff --git a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java new file mode 100644 index 00000000..471acbb6 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java @@ -0,0 +1,85 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; + +import junit.framework.TestCase; + +/** + * Test generate equal and hash methods for the lite runtime. + * + * @author pbogle@google.com Phil Bogle + */ +public class LiteEqualsAndHashTest extends TestCase { + + public void testEquals() throws Exception { + // Since the generated equals and hashCode methods for lite messages are a + // mostly complete subset of those for regular messages, we can mostly assume + // that the generated methods are already thoroughly tested by the regular tests. + + // This test mostly just verifies is that a proto with + // optimize_for = LITE_RUNTIME and java_generates_equals_and_hash_compiles + // correctly when linked only against the lite library. + + // We do however do some basic testing to make sure that equals is actually + // overriden to test for value equality rather than simple object equality. + + // Check that two identical objs are equal. + Foo foo1a = Foo.newBuilder() + .setValue(1) + .addBar(Bar.newBuilder().setName("foo1")) + .build(); + Foo foo1b = Foo.newBuilder() + .setValue(1) + .addBar(Bar.newBuilder().setName("foo1")) + .build(); + Foo foo2 = Foo.newBuilder() + .setValue(1) + .addBar(Bar.newBuilder().setName("foo2")) + .build(); + + // Check that equals is doing value rather than object equality. + assertEquals(foo1a, foo1b); + assertEquals(foo1a.hashCode(), foo1b.hashCode()); + + // Check that a diffeent object is not equal. + assertFalse(foo1a.equals(foo2)); + + // Check that two objects which have different types but the same field values are not + // considered to be equal. + Bar bar = Bar.newBuilder().setName("bar").build(); + BarPrime barPrime = BarPrime.newBuilder().setName("bar").build(); + assertFalse(bar.equals(barPrime)); + } +} diff --git a/java/src/test/java/com/google/protobuf/ParserTest.java b/java/src/test/java/com/google/protobuf/ParserTest.java index 396902cf..8cc4693e 100644 --- a/java/src/test/java/com/google/protobuf/ParserTest.java +++ b/java/src/test/java/com/google/protobuf/ParserTest.java @@ -33,15 +33,14 @@ package com.google.protobuf; import com.google.protobuf.UnittestLite.TestAllTypesLite; import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; import com.google.protobuf.UnittestLite.TestParsingMergeLite; -import com.google.protobuf.UnittestLite; import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize; import protobuf_unittest.UnittestOptimizeFor; import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestEmptyMessage; -import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestParsingMerge; +import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto; import junit.framework.TestCase; @@ -84,12 +83,15 @@ public class ParserTest extends TestCase { CodedInputStream.newInstance(data), registry)); } + @SuppressWarnings("unchecked") private void assertRoundTripEquals(MessageLite message) throws Exception { final byte[] data = message.toByteArray(); final int offset = 20; final int length = data.length; final int padding = 30; - Parser<? extends MessageLite> parser = message.getParserForType(); + + Parser<MessageLite> parser = + (Parser<MessageLite>) message.getParserForType(); assertMessageEquals(message, parser.parseFrom(data)); assertMessageEquals(message, parser.parseFrom( generatePaddingArray(data, offset, padding), @@ -101,7 +103,8 @@ public class ParserTest extends TestCase { CodedInputStream.newInstance(data))); } - private void assertMessageEquals(MessageLite expected, MessageLite actual) + private void assertMessageEquals( + MessageLite expected, MessageLite actual) throws Exception { if (expected instanceof Message) { assertEquals(expected, actual); @@ -120,15 +123,17 @@ public class ParserTest extends TestCase { assertRoundTripEquals(TestUtil.getAllSet()); } + public void testParsePartial() throws Exception { - Parser<TestRequired> parser = TestRequired.PARSER; + assertParsePartial(TestRequired.PARSER, + TestRequired.newBuilder().setA(1).buildPartial()); + } + + private <T extends MessageLite> void assertParsePartial( + Parser<T> parser, T partialMessage) throws Exception { final String errorString = "Should throw exceptions when the parsed message isn't initialized."; - // TestRequired.b and TestRequired.c are not set. - TestRequired partialMessage = TestRequired.newBuilder() - .setA(1).buildPartial(); - // parsePartialFrom should pass. byte[] data = partialMessage.toByteArray(); assertEquals(partialMessage, parser.parsePartialFrom(data)); @@ -218,6 +223,7 @@ public class ParserTest extends TestCase { emptyMessage.toByteString()); } + public void testOptimizeForSize() throws Exception { TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder(); builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build()); diff --git a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java index 382acf0f..84f16947 100644 --- a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java +++ b/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java @@ -60,4 +60,37 @@ public class TestBadIdentifiers extends TestCase { .Descriptor.NestedDescriptor.getDefaultInstance() .getDescriptorForType(); } + + public void testConflictingFieldNames() throws Exception { + TestBadIdentifiersProto.TestConflictingFieldNames message = + TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance(); + // Make sure generated accessors are properly named. + assertEquals(0, message.getInt32Field1Count()); + assertEquals(0, message.getEnumField2Count()); + assertEquals(0, message.getStringField3Count()); + assertEquals(0, message.getBytesField4Count()); + assertEquals(0, message.getMessageField5Count()); + + assertEquals(0, message.getInt32FieldCount11()); + assertEquals(1, message.getEnumFieldCount12().getNumber()); + assertEquals("", message.getStringFieldCount13()); + assertEquals(ByteString.EMPTY, message.getBytesFieldCount14()); + assertEquals(0, message.getMessageFieldCount15().getSerializedSize()); + + assertEquals(0, message.getInt32Field21Count()); + assertEquals(0, message.getEnumField22Count()); + assertEquals(0, message.getStringField23Count()); + assertEquals(0, message.getBytesField24Count()); + assertEquals(0, message.getMessageField25Count()); + + assertEquals(0, message.getInt32Field1List().size()); + assertEquals(0, message.getInt32FieldList31()); + + assertEquals(0, message.getInt64FieldCount()); + assertEquals(0L, message.getExtension( + TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue()); + assertEquals(0L, message.getExtension( + TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue()); + + } } diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java index 76f5c602..e3cf8a63 100644 --- a/java/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/src/test/java/com/google/protobuf/TestUtil.java @@ -56,6 +56,11 @@ import static protobuf_unittest.UnittestProto.defaultImportEnumExtension; import static protobuf_unittest.UnittestProto.defaultStringPieceExtension; import static protobuf_unittest.UnittestProto.defaultCordExtension; +import static protobuf_unittest.UnittestProto.oneofUint32Extension; +import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension; +import static protobuf_unittest.UnittestProto.oneofStringExtension; +import static protobuf_unittest.UnittestProto.oneofBytesExtension; + import static protobuf_unittest.UnittestProto.optionalInt32Extension; import static protobuf_unittest.UnittestProto.optionalInt64Extension; import static protobuf_unittest.UnittestProto.optionalUint32Extension; @@ -148,6 +153,11 @@ import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite; import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite; import static com.google.protobuf.UnittestLite.defaultCordExtensionLite; +import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.oneofStringExtensionLite; +import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite; + import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite; import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite; import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite; @@ -223,6 +233,7 @@ import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder; +import protobuf_unittest.UnittestProto.TestOneof2; import protobuf_unittest.UnittestProto.TestPackedExtensions; import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestUnpackedTypes; @@ -469,6 +480,12 @@ public final class TestUtil { message.setDefaultStringPiece("424"); message.setDefaultCord("425"); + + message.setOneofUint32(601); + message.setOneofNestedMessage( + TestAllTypes.NestedMessage.newBuilder().setBb(602).build()); + message.setOneofString("603"); + message.setOneofBytes(toBytes("604")); } // ------------------------------------------------------------------- @@ -718,6 +735,13 @@ public final class TestUtil { Assert.assertEquals("424", message.getDefaultStringPiece()); Assert.assertEquals("425", message.getDefaultCord()); + + Assert.assertFalse(message.hasOneofUint32()); + Assert.assertFalse(message.hasOneofNestedMessage()); + Assert.assertFalse(message.hasOneofString()); + Assert.assertTrue(message.hasOneofBytes()); + + Assert.assertEquals(toBytes("604"), message.getOneofBytes()); } // ------------------------------------------------------------------- @@ -872,6 +896,11 @@ public final class TestUtil { Assert.assertEquals("abc", message.getDefaultStringPiece()); Assert.assertEquals("123", message.getDefaultCord()); + + Assert.assertFalse(message.hasOneofUint32()); + Assert.assertFalse(message.hasOneofNestedMessage()); + Assert.assertFalse(message.hasOneofString()); + Assert.assertFalse(message.hasOneofBytes()); } // ------------------------------------------------------------------- @@ -1358,6 +1387,12 @@ public final class TestUtil { message.setExtension(defaultStringPieceExtension, "424"); message.setExtension(defaultCordExtension, "425"); + + message.setExtension(oneofUint32Extension, 601); + message.setExtension(oneofNestedMessageExtension, + TestAllTypes.NestedMessage.newBuilder().setBb(602).build()); + message.setExtension(oneofStringExtension, "603"); + message.setExtension(oneofBytesExtension, toBytes("604")); } // ------------------------------------------------------------------- @@ -1621,6 +1656,10 @@ public final class TestUtil { assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension)); assertEqualsExactType("425", message.getExtension(defaultCordExtension)); + + Assert.assertTrue(message.hasExtension(oneofBytesExtension)); + + assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtension)); } // ------------------------------------------------------------------- @@ -1807,6 +1846,11 @@ public final class TestUtil { assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension)); assertEqualsExactType("123", message.getExtension(defaultCordExtension)); + + Assert.assertFalse(message.hasExtension(oneofUint32Extension)); + Assert.assertFalse(message.hasExtension(oneofNestedMessageExtension)); + Assert.assertFalse(message.hasExtension(oneofStringExtension)); + Assert.assertFalse(message.hasExtension(oneofBytesExtension)); } // ------------------------------------------------------------------- @@ -2133,6 +2177,12 @@ public final class TestUtil { message.setExtension(defaultStringPieceExtensionLite, "424"); message.setExtension(defaultCordExtensionLite, "425"); + + message.setExtension(oneofUint32ExtensionLite, 601); + message.setExtension(oneofNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build()); + message.setExtension(oneofStringExtensionLite, "603"); + message.setExtension(oneofBytesExtensionLite, toBytes("604")); } // ------------------------------------------------------------------- @@ -2397,6 +2447,10 @@ public final class TestUtil { assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite)); assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite)); + + Assert.assertTrue(message.hasExtension(oneofBytesExtensionLite)); + + assertEqualsExactType(toBytes("604"), message.getExtension(oneofBytesExtensionLite)); } // ------------------------------------------------------------------- @@ -2562,6 +2616,11 @@ public final class TestUtil { assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite)); assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite)); + + Assert.assertFalse(message.hasExtension(oneofUint32ExtensionLite)); + Assert.assertFalse(message.hasExtension(oneofNestedMessageExtensionLite)); + Assert.assertFalse(message.hasExtension(oneofStringExtensionLite)); + Assert.assertFalse(message.hasExtension(oneofBytesExtensionLite)); } // ------------------------------------------------------------------- @@ -2749,6 +2808,82 @@ public final class TestUtil { message.getExtension(packedEnumExtensionLite, 1)); } + // =================================================================== + // oneof + public static void setOneof(TestOneof2.Builder message) { + message.setFooLazyMessage( + TestOneof2.NestedMessage.newBuilder().setQuxInt(100).build()); + message.setBarString("101"); + message.setBazInt(102); + message.setBazString("103"); + } + + public static void assertOneofSet(TestOneof2 message) { + Assert.assertTrue(message.hasFooLazyMessage ()); + Assert.assertTrue(message.getFooLazyMessage().hasQuxInt()); + + Assert.assertTrue(message.hasBarString()); + Assert.assertTrue(message.hasBazInt ()); + Assert.assertTrue(message.hasBazString()); + + Assert.assertEquals(100 , message.getFooLazyMessage().getQuxInt()); + Assert.assertEquals("101", message.getBarString ()); + Assert.assertEquals(102 , message.getBazInt ()); + Assert.assertEquals("103", message.getBazString ()); + } + + public static void assertAtMostOneFieldSetOneof(TestOneof2 message) { + int count = 0; + if (message.hasFooInt()) { ++count; } + if (message.hasFooString()) { ++count; } + if (message.hasFooCord()) { ++count; } + if (message.hasFooStringPiece()) { ++count; } + if (message.hasFooBytes()) { ++count; } + if (message.hasFooEnum()) { ++count; } + if (message.hasFooMessage()) { ++count; } + if (message.hasFooGroup()) { ++count; } + if (message.hasFooLazyMessage()) { ++count; } + Assert.assertTrue(count <= 1); + + count = 0; + if (message.hasBarInt()) { ++count; } + if (message.hasBarString()) { ++count; } + if (message.hasBarCord()) { ++count; } + if (message.hasBarStringPiece()) { ++count; } + if (message.hasBarBytes()) { ++count; } + if (message.hasBarEnum()) { ++count; } + Assert.assertTrue(count <= 1); + + switch (message.getFooCase()) { + case FOO_INT: + Assert.assertTrue(message.hasFooInt()); + break; + case FOO_STRING: + Assert.assertTrue(message.hasFooString()); + break; + case FOO_CORD: + Assert.assertTrue(message.hasFooCord()); + break; + case FOO_BYTES: + Assert.assertTrue(message.hasFooBytes()); + break; + case FOO_ENUM: + Assert.assertTrue(message.hasFooEnum()); + break; + case FOO_MESSAGE: + Assert.assertTrue(message.hasFooMessage()); + break; + case FOOGROUP: + Assert.assertTrue(message.hasFooGroup()); + break; + case FOO_LAZY_MESSAGE: + Assert.assertTrue(message.hasFooLazyMessage()); + break; + case FOO_NOT_SET: + break; + } + } + // ================================================================= /** @@ -2915,8 +3050,8 @@ public final class TestUtil { return parent.newBuilderForField(field); } else { ExtensionRegistry.ExtensionInfo extension = - extensionRegistry.findExtensionByNumber(field.getContainingType(), - field.getNumber()); + extensionRegistry.findImmutableExtensionByNumber( + field.getContainingType(), field.getNumber()); Assert.assertNotNull(extension); Assert.assertNotNull(extension.defaultInstance); return extension.defaultInstance.newBuilderForType(); @@ -3078,6 +3213,13 @@ public final class TestUtil { message.setField(f("default_string_piece" ), "424"); message.setField(f("default_cord" ), "425"); + + message.setField(f("oneof_uint32" ), 601); + message.setField(f("oneof_nested_message"), + newBuilderForField(message, f("oneof_nested_message")) + .setField(nestedB, 602).build()); + message.setField(f("oneof_string" ), "603"); + message.setField(f("oneof_bytes" ), toBytes("604")); } // ------------------------------------------------------------------- @@ -3372,6 +3514,24 @@ public final class TestUtil { Assert.assertEquals("424", message.getField(f("default_string_piece"))); Assert.assertEquals("425", message.getField(f("default_cord"))); + + Assert.assertTrue(message.hasField(f("oneof_bytes"))); + Assert.assertEquals(toBytes("604"), message.getField(f("oneof_bytes"))); + + if (extensionRegistry == null) { + Assert.assertFalse(message.hasField(f("oneof_uint32"))); + Assert.assertFalse(message.hasField(f("oneof_nested_message"))); + Assert.assertFalse(message.hasField(f("oneof_string"))); + } else { + Assert.assertTrue(message.hasField(f("oneof_uint32"))); + Assert.assertTrue(message.hasField(f("oneof_nested_message"))); + Assert.assertTrue(message.hasField(f("oneof_string"))); + Assert.assertEquals(601, message.getField(f("oneof_uint32"))); + Assert.assertEquals(602, + ((MessageOrBuilder) message.getField(f("oneof_nested_message"))) + .getField(nestedB)); + Assert.assertEquals("603", message.getField(f("oneof_string"))); + } } // ------------------------------------------------------------------- @@ -3549,6 +3709,15 @@ public final class TestUtil { Assert.assertEquals("abc", message.getField(f("default_string_piece"))); Assert.assertEquals("123", message.getField(f("default_cord"))); + + Assert.assertFalse(message.hasField(f("oneof_uint32"))); + Assert.assertFalse(message.hasField(f("oneof_nested_message"))); + Assert.assertFalse(message.hasField(f("oneof_string"))); + Assert.assertFalse(message.hasField(f("oneof_bytes"))); + + Assert.assertEquals(0, message.getField(f("oneof_uint32"))); + Assert.assertEquals("", message.getField(f("oneof_string"))); + Assert.assertEquals(toBytes(""), message.getField(f("oneof_bytes"))); } @@ -3910,7 +4079,7 @@ public final class TestUtil { */ public static ByteString getGoldenMessage() { if (goldenMessage == null) { - goldenMessage = readBytesFromFile("golden_message"); + goldenMessage = readBytesFromFile("golden_message_oneof_implemented"); } return goldenMessage; } diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 5323d70e..7cb70021 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -31,6 +31,7 @@ package com.google.protobuf; import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; import protobuf_unittest.UnittestMset.TestMessageSet; import protobuf_unittest.UnittestMset.TestMessageSetExtension1; import protobuf_unittest.UnittestMset.TestMessageSetExtension2; @@ -39,6 +40,7 @@ import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; import protobuf_unittest.UnittestProto.TestEmptyMessage; +import protobuf_unittest.UnittestProto.TestOneof2; import junit.framework.TestCase; @@ -64,7 +66,7 @@ public class TextFormatTest extends TestCase { + "and \\t tabs and \\001 slashes \\\\"; private static String allFieldsSetText = TestUtil.readTextFromFile( - "text_format_unittest_data.txt"); + "text_format_unittest_data_oneof_implemented.txt"); private static String allExtensionsSetText = TestUtil.readTextFromFile( "text_format_unittest_extensions_data.txt"); @@ -109,6 +111,26 @@ public class TextFormatTest extends TestCase { " str: \"foo\"\n" + "}\n"; + private String messageSetTextWithRepeatedExtension = + "[protobuf_unittest.TestMessageSetExtension1] {\n" + + " i: 123\n" + + "}\n" + + "[protobuf_unittest.TestMessageSetExtension1] {\n" + + " i: 456\n" + + "}\n"; + + private final TextFormat.Parser parserAllowingUnknownFields = + TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build(); + + private final TextFormat.Parser parserWithOverwriteForbidden = + TextFormat.Parser.newBuilder() + .setSingularOverwritePolicy( + SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES) + .build(); + + private final TextFormat.Parser defaultParser = + TextFormat.Parser.newBuilder().build(); + /** Print TestAllTypes and compare with golden file. */ public void testPrintMessage() throws Exception { String javaText = TextFormat.printToString(TestUtil.getAllSet()); @@ -250,8 +272,8 @@ public class TextFormatTest extends TestCase { .addRepeatedInt32 (1 << 31) .addRepeatedUint32(1 << 31) - .addRepeatedInt64 (1l << 63) - .addRepeatedUint64(1l << 63) + .addRepeatedInt64 (1L << 63) + .addRepeatedUint64(1L << 63) // Floats of various precisions and exponents. .addRepeatedDouble(123) @@ -371,6 +393,40 @@ public class TextFormatTest extends TestCase { TestMessageSetExtension2.messageSetExtension)); assertEquals("foo", messageSet.getExtension( TestMessageSetExtension2.messageSetExtension).getStr()); + + builder = TestMessageSet.newBuilder(); + TextFormat.merge(messageSetTextWithRepeatedExtension, extensionRegistry, + builder); + messageSet = builder.build(); + assertEquals(456, messageSet.getExtension( + TestMessageSetExtension1.messageSetExtension).getI()); + } + + public void testParseMessageSetWithOverwriteForbidden() throws Exception { + ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); + extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); + extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); + + TestMessageSet.Builder builder = TestMessageSet.newBuilder(); + parserWithOverwriteForbidden.merge( + messageSetText, extensionRegistry, builder); + TestMessageSet messageSet = builder.build(); + assertEquals(123, messageSet.getExtension( + TestMessageSetExtension1.messageSetExtension).getI()); + assertEquals("foo", messageSet.getExtension( + TestMessageSetExtension2.messageSetExtension).getStr()); + + builder = TestMessageSet.newBuilder(); + try { + parserWithOverwriteForbidden.merge( + messageSetTextWithRepeatedExtension, extensionRegistry, builder); + fail("expected parse exception"); + } catch (TextFormat.ParseException e) { + assertEquals("6:1: Non-repeated field " + + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\"" + + " cannot be overwritten.", + e.getMessage()); + } } public void testParseNumericEnum() throws Exception { @@ -407,12 +463,51 @@ public class TextFormatTest extends TestCase { } } + private void assertParseErrorWithUnknownFields(String error, String text) { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + try { + parserAllowingUnknownFields.merge( + text, TestUtil.getExtensionRegistry(), builder); + fail("Expected parse exception."); + } catch (TextFormat.ParseException e) { + assertEquals(error, e.getMessage()); + } + } + + private TestAllTypes assertParseSuccessWithUnknownFields(String text) + throws TextFormat.ParseException { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + parserAllowingUnknownFields.merge( + text, TestUtil.getExtensionRegistry(), builder); + return builder.build(); + } + + private void assertParseErrorWithOverwriteForbidden(String error, + String text) { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + try { + parserWithOverwriteForbidden.merge( + text, TestUtil.getExtensionRegistry(), builder); + fail("Expected parse exception."); + } catch (TextFormat.ParseException e) { + assertEquals(error, e.getMessage()); + } + } + + private TestAllTypes assertParseSuccessWithOverwriteForbidden( + String text) throws TextFormat.ParseException { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + parserWithOverwriteForbidden.merge( + text, TestUtil.getExtensionRegistry(), builder); + return builder.build(); + } + public void testParseErrors() throws Exception { assertParseError( "1:16: Expected \":\".", "optional_int32 123"); assertParseError( - "1:23: Expected identifier.", + "1:23: Expected identifier. Found '?'", "optional_nested_enum: ?"); assertParseError( "1:18: Couldn't parse integer: Number must be positive: -1", @@ -469,10 +564,10 @@ public class TextFormatTest extends TestCase { // Delimiters must match. assertParseError( - "1:22: Expected identifier.", + "1:22: Expected identifier. Found '}'", "OptionalGroup < a: 1 }"); assertParseError( - "1:22: Expected identifier.", + "1:22: Expected identifier. Found '>'", "OptionalGroup { a: 1 >"); } @@ -762,7 +857,7 @@ public class TextFormatTest extends TestCase { TextFormat.shortDebugString(makeUnknownFieldSet())); } - public void testPrintToUnicodeString() { + public void testPrintToUnicodeString() throws Exception { assertEquals( "optional_string: \"abc\u3042efg\"\n" + "optional_bytes: \"\\343\\201\\202\"\n" + @@ -772,6 +867,49 @@ public class TextFormatTest extends TestCase { .setOptionalBytes(bytes(0xe3, 0x81, 0x82)) .addRepeatedString("\u3093XYZ") .build())); + + // Double quotes and backslashes should be escaped + assertEquals( + "optional_string: \"a\\\\bc\\\"ef\\\"g\"\n", + TextFormat.printToUnicodeString(TestAllTypes.newBuilder() + .setOptionalString("a\\bc\"ef\"g") + .build())); + + // Test escaping roundtrip + TestAllTypes message = TestAllTypes.newBuilder() + .setOptionalString("a\\bc\\\"ef\"g") + .build(); + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + TextFormat.merge(TextFormat.printToUnicodeString(message), builder); + assertEquals(message.getOptionalString(), builder.getOptionalString()); + } + + public void testPrintToUnicodeStringWithNewlines() { + // No newlines at start and end + assertEquals("optional_string: \"test newlines\n\nin\nstring\"\n", + TextFormat.printToUnicodeString(TestAllTypes.newBuilder() + .setOptionalString("test newlines\n\nin\nstring") + .build())); + + // Newlines at start and end + assertEquals("optional_string: \"\ntest\nnewlines\n\nin\nstring\n\"\n", + TextFormat.printToUnicodeString(TestAllTypes.newBuilder() + .setOptionalString("\ntest\nnewlines\n\nin\nstring\n") + .build())); + + // Strings with 0, 1 and 2 newlines. + assertEquals("optional_string: \"\"\n", + TextFormat.printToUnicodeString(TestAllTypes.newBuilder() + .setOptionalString("") + .build())); + assertEquals("optional_string: \"\n\"\n", + TextFormat.printToUnicodeString(TestAllTypes.newBuilder() + .setOptionalString("\n") + .build())); + assertEquals("optional_string: \"\n\n\"\n", + TextFormat.printToUnicodeString(TestAllTypes.newBuilder() + .setOptionalString("\n\n") + .build())); } public void testPrintToUnicodeString_unknown() { @@ -783,4 +921,177 @@ public class TextFormatTest extends TestCase { .addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build()) .build())); } + + public void testParseUnknownFields() throws Exception { + assertParseSuccessWithUnknownFields("unknown_field: 12345"); + assertParseSuccessWithUnknownFields("unknown_field: -12345"); + assertParseSuccessWithUnknownFields("unknown_field: 1.2345"); + assertParseSuccessWithUnknownFields("unknown_field: -1.2345"); + assertParseSuccessWithUnknownFields("unknown_field: 1.2345f"); + assertParseSuccessWithUnknownFields("unknown_field: -1.2345f"); + assertParseSuccessWithUnknownFields("unknown_field: inf"); + assertParseSuccessWithUnknownFields("unknown_field: -inf"); + assertParseSuccessWithUnknownFields("unknown_field: TYPE_STRING"); + assertParseSuccessWithUnknownFields("unknown_field: \"string value\""); + // Invalid field value + assertParseErrorWithUnknownFields( + "1:16: Invalid field value: -TYPE_STRING", + "unknown_field: -TYPE_STRING"); + // Two or more unknown fields + assertParseSuccessWithUnknownFields("unknown_field1: TYPE_STRING\n" + + "unknown_field2: 12345"); + // Unknown nested message + assertParseSuccessWithUnknownFields("unknown_message1: {}\n" + + "unknown_message2 {\n" + + " unknown_field: 12345\n" + + "}\n" + + "unknown_message3 <\n" + + " unknown_nested_message {\n" + + " unknown_field: 12345\n" + + " }\n" + + ">"); + // Unmatched delimeters for message body + assertParseErrorWithUnknownFields( + "1:19: Expected \"}\".", "unknown_message: {>"); + // Unknown extension + assertParseSuccessWithUnknownFields( + "[somewhere.unknown_extension1]: 12345\n" + + "[somewhere.unknown_extension2] {\n" + + " unknown_field: 12345\n" + + "}"); + // Unknown fields between known fields. + TestAllTypes expected = TestAllTypes.newBuilder() + .setOptionalInt32(1) + .setOptionalString("string") + .setOptionalNestedMessage(NestedMessage.newBuilder() + .setBb(2)) + .build(); + assertEquals(expected, assertParseSuccessWithUnknownFields( + "optional_int32: 1\n" + + "unknown_field: 12345\n" + + "optional_string: \"string\"\n" + + "unknown_message { unknown : 0 }\n" + + "optional_nested_message { bb: 2 }")); + // Nested unknown extensions. + assertParseSuccessWithUnknownFields( + "[test.extension1] <\n" + + " unknown_nested_message <\n" + + " [test.extension2] <\n" + + " unknown_field: 12345\n" + + " >\n" + + " >\n" + + ">"); + assertParseSuccessWithUnknownFields( + "[test.extension1] {\n" + + " unknown_nested_message {\n" + + " [test.extension2] {\n" + + " unknown_field: 12345\n" + + " }\n" + + " }\n" + + "}"); + assertParseSuccessWithUnknownFields( + "[test.extension1] <\n" + + " some_unknown_fields: <\n" + + " unknown_field: 12345\n" + + " >\n" + + ">"); + assertParseSuccessWithUnknownFields( + "[test.extension1] {\n" + + " some_unknown_fields: {\n" + + " unknown_field: 12345\n" + + " }\n" + + "}"); + } + + public void testParseNonRepeatedFields() throws Exception { + assertParseSuccessWithOverwriteForbidden( + "repeated_int32: 1\n" + + "repeated_int32: 2\n"); + assertParseSuccessWithOverwriteForbidden( + "RepeatedGroup { a: 1 }\n" + + "RepeatedGroup { a: 2 }\n"); + assertParseSuccessWithOverwriteForbidden( + "repeated_nested_message { bb: 1 }\n" + + "repeated_nested_message { bb: 2 }\n"); + assertParseErrorWithOverwriteForbidden( + "3:17: Non-repeated field " + + "\"protobuf_unittest.TestAllTypes.optional_int32\" " + + "cannot be overwritten.", + "optional_int32: 1\n" + + "optional_bool: true\n" + + "optional_int32: 1\n"); + assertParseErrorWithOverwriteForbidden( + "2:17: Non-repeated field " + + "\"protobuf_unittest.TestAllTypes.optionalgroup\" " + + "cannot be overwritten.", + "OptionalGroup { a: 1 }\n" + + "OptionalGroup { }\n"); + assertParseErrorWithOverwriteForbidden( + "2:33: Non-repeated field " + + "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " + + "cannot be overwritten.", + "optional_nested_message { }\n" + + "optional_nested_message { bb: 3 }\n"); + assertParseErrorWithOverwriteForbidden( + "2:16: Non-repeated field " + + "\"protobuf_unittest.TestAllTypes.default_int32\" " + + "cannot be overwritten.", + "default_int32: 41\n" + // the default value + "default_int32: 41\n"); + assertParseErrorWithOverwriteForbidden( + "2:17: Non-repeated field " + + "\"protobuf_unittest.TestAllTypes.default_string\" " + + "cannot be overwritten.", + "default_string: \"zxcv\"\n" + + "default_string: \"asdf\"\n"); + } + + public void testParseShortRepeatedFormOfRepeatedFields() throws Exception { + assertParseSuccessWithOverwriteForbidden("repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR]"); + assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n"); + assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n"); + assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n"); + } + + public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception { + assertParseErrorWithOverwriteForbidden( + "1:17: Couldn't parse integer: For input string: \"[\"", + "optional_int32: [1]\n"); + } + + // ======================================================================= + // test oneof + + public void testOneofTextFormat() throws Exception { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestUtil.setOneof(builder); + TestOneof2 message = builder.build(); + TestOneof2.Builder dest = TestOneof2.newBuilder(); + TextFormat.merge(TextFormat.printToUnicodeString(message), dest); + TestUtil.assertOneofSet(dest.build()); + } + + public void testOneofOverwriteForbidden() throws Exception { + String input = "foo_string: \"stringvalue\" foo_int: 123"; + TestOneof2.Builder builder = TestOneof2.newBuilder(); + try { + parserWithOverwriteForbidden.merge( + input, TestUtil.getExtensionRegistry(), builder); + fail("Expected parse exception."); + } catch (TextFormat.ParseException e) { + assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\"" + + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\"," + + " another member of oneof \"foo\".", e.getMessage()); + } + } + + public void testOneofOverwriteAllowed() throws Exception { + String input = "foo_string: \"stringvalue\" foo_int: 123"; + TestOneof2.Builder builder = TestOneof2.newBuilder(); + defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder); + // Only the last value sticks. + TestOneof2 oneof = builder.build(); + assertFalse(oneof.hasFooString()); + assertTrue(oneof.hasFooInt()); + } } diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java index ea088b32..d4139d20 100644 --- a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java +++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java @@ -31,10 +31,13 @@ package com.google.protobuf; import protobuf_unittest.UnittestProto; +import protobuf_unittest.UnittestProto.ForeignEnum; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestEmptyMessage; import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions; +import protobuf_unittest.UnittestProto.TestPackedExtensions; +import protobuf_unittest.UnittestProto.TestPackedTypes; import junit.framework.TestCase; @@ -204,6 +207,13 @@ public class UnknownFieldSetTest extends TestCase { TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build(); assertEquals(0, message.getSerializedSize()); } + + public void testClearField() throws Exception { + int fieldNumber = unknownFields.asMap().keySet().iterator().next(); + UnknownFieldSet fields = + UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build(); + assertFalse(fields.hasField(fieldNumber)); + } public void testParseKnownAndUnknown() throws Exception { // Test mixing known and unknown fields when parsing. @@ -434,4 +444,210 @@ public class UnknownFieldSetTest extends TestCase { assertEquals(copy, set); assertEquals(set.hashCode(), copy.hashCode()); } + + // ================================================================= + + public void testSerializeLite() throws Exception { + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); + assertEquals(allFieldsData.size(), emptyMessageLite.getSerializedSize()); + ByteString data = emptyMessageLite.toByteString(); + TestAllTypes message = TestAllTypes.parseFrom(data); + TestUtil.assertAllFieldsSet(message); + assertEquals(allFieldsData, data); + } + + public void testAllExtensionsLite() throws Exception { + TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet(); + ByteString allExtensionsData = allExtensions.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.PARSER.parseFrom(allExtensionsData); + ByteString data = emptyMessageLite.toByteString(); + TestAllExtensions message = + TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); + TestUtil.assertAllExtensionsSet(message); + assertEquals(allExtensionsData, data); + } + + public void testAllPackedFieldsLite() throws Exception { + TestPackedTypes allPackedFields = TestUtil.getPackedSet(); + ByteString allPackedData = allPackedFields.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData); + ByteString data = emptyMessageLite.toByteString(); + TestPackedTypes message = + TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry()); + TestUtil.assertPackedFieldsSet(message); + assertEquals(allPackedData, data); + } + + public void testAllPackedExtensionsLite() throws Exception { + TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet(); + ByteString allPackedExtensionsData = allPackedExtensions.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData); + ByteString data = emptyMessageLite.toByteString(); + TestPackedExtensions message = + TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); + TestUtil.assertPackedExtensionsSet(message); + assertEquals(allPackedExtensionsData, data); + } + + public void testCopyFromLite() throws Exception { + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); + UnittestLite.TestEmptyMessageLite emptyMessageLite2 = + UnittestLite.TestEmptyMessageLite.newBuilder() + .mergeFrom(emptyMessageLite).build(); + assertEquals(emptyMessageLite.toByteString(), emptyMessageLite2.toByteString()); + } + + public void testMergeFromLite() throws Exception { + TestAllTypes message1 = TestAllTypes.newBuilder() + .setOptionalInt32(1) + .setOptionalString("foo") + .addRepeatedString("bar") + .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ) + .build(); + + TestAllTypes message2 = TestAllTypes.newBuilder() + .setOptionalInt64(2) + .setOptionalString("baz") + .addRepeatedString("qux") + .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ) + .build(); + + ByteString data1 = message1.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite1 = + UnittestLite.TestEmptyMessageLite.parseFrom(data1); + ByteString data2 = message2.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite2 = + UnittestLite.TestEmptyMessageLite.parseFrom(data2); + + message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build(); + emptyMessageLite1 = UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1) + .mergeFrom(emptyMessageLite2).build(); + + data1 = emptyMessageLite1.toByteString(); + message2 = TestAllTypes.parseFrom(data1); + + assertEquals(message1, message2); + } + + public void testWrongTypeTreatedAsUnknownLite() throws Exception { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing. + + ByteString bizarroData = getBizarroData(); + TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData); + ByteString data = emptyMessageLite.toByteString(); + TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data); + + assertEquals(allTypesMessage.toString(), allTypesMessage2.toString()); + } + + public void testUnknownExtensionsLite() throws Exception { + // Make sure fields are properly parsed to the UnknownFieldSet even when + // they are declared as extension numbers. + + UnittestLite.TestEmptyMessageWithExtensionsLite message = + UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData); + + assertEquals(allFieldsData, message.toByteString()); + } + + public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing extensions. + + ByteString bizarroData = getBizarroData(); + TestAllExtensions allExtensionsMessage = + TestAllExtensions.parseFrom(bizarroData); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData); + + // All fields should have been interpreted as unknown, so the byte strings + // should be the same. + assertEquals(emptyMessageLite.toByteString(), + allExtensionsMessage.toByteString()); + } + + public void testParseUnknownEnumValueLite() throws Exception { + Descriptors.FieldDescriptor singularField = + TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum"); + Descriptors.FieldDescriptor repeatedField = + TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum"); + assertNotNull(singularField); + assertNotNull(repeatedField); + + ByteString data = + UnknownFieldSet.newBuilder() + .addField(singularField.getNumber(), + UnknownFieldSet.Field.newBuilder() + .addVarint(TestAllTypes.NestedEnum.BAR.getNumber()) + .addVarint(5) // not valid + .build()) + .addField(repeatedField.getNumber(), + UnknownFieldSet.Field.newBuilder() + .addVarint(TestAllTypes.NestedEnum.FOO.getNumber()) + .addVarint(4) // not valid + .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber()) + .addVarint(6) // not valid + .build()) + .build() + .toByteString(); + + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(data); + data = emptyMessageLite.toByteString(); + + { + TestAllTypes message = TestAllTypes.parseFrom(data); + assertEquals(TestAllTypes.NestedEnum.BAR, + message.getOptionalNestedEnum()); + assertEquals( + Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ), + message.getRepeatedNestedEnumList()); + assertEquals(Arrays.asList(5L), + message.getUnknownFields() + .getField(singularField.getNumber()) + .getVarintList()); + assertEquals(Arrays.asList(4L, 6L), + message.getUnknownFields() + .getField(repeatedField.getNumber()) + .getVarintList()); + } + + { + TestAllExtensions message = + TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); + assertEquals(TestAllTypes.NestedEnum.BAR, + message.getExtension(UnittestProto.optionalNestedEnumExtension)); + assertEquals( + Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ), + message.getExtension(UnittestProto.repeatedNestedEnumExtension)); + assertEquals(Arrays.asList(5L), + message.getUnknownFields() + .getField(singularField.getNumber()) + .getVarintList()); + assertEquals(Arrays.asList(4L, 6L), + message.getUnknownFields() + .getField(repeatedField.getNumber()) + .getVarintList()); + } + } + + public void testClearLite() throws Exception { + UnittestLite.TestEmptyMessageLite emptyMessageLite1 = + UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); + UnittestLite.TestEmptyMessageLite emptyMessageLite2 = + UnittestLite.TestEmptyMessageLite.newBuilder() + .mergeFrom(emptyMessageLite1).clear().build(); + assertEquals(0, emptyMessageLite2.getSerializedSize()); + ByteString data = emptyMessageLite2.toByteString(); + assertEquals(0, data.size()); + } + } diff --git a/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java index ed5d069e..ad4bbf8d 100644 --- a/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java +++ b/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java @@ -33,6 +33,7 @@ package com.google.protobuf; import junit.framework.TestCase; import java.util.Iterator; +import java.util.List; import java.util.ListIterator; /** @@ -60,6 +61,11 @@ public class UnmodifiableLazyStringListTest extends TestCase { assertEquals(BYTE_STRING_A, list.getByteString(0)); assertEquals(BYTE_STRING_B, list.getByteString(1)); assertEquals(BYTE_STRING_C, list.getByteString(2)); + + List<ByteString> byteStringList = list.asByteStringList(); + assertSame(list.getByteString(0), byteStringList.get(0)); + assertSame(list.getByteString(1), byteStringList.get(1)); + assertSame(list.getByteString(2), byteStringList.get(2)); } public void testModifyMethods() { @@ -88,6 +94,35 @@ public class UnmodifiableLazyStringListTest extends TestCase { } catch (UnsupportedOperationException e) { // expected } + assertEquals(3, list.size()); + + List<ByteString> byteStringList = list.asByteStringList(); + try { + byteStringList.remove(0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(3, list.size()); + assertEquals(3, byteStringList.size()); + + try { + byteStringList.add(BYTE_STRING_B); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(3, list.size()); + assertEquals(3, byteStringList.size()); + + try { + byteStringList.set(1, BYTE_STRING_B); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(3, list.size()); + assertEquals(3, byteStringList.size()); } public void testIterator() { @@ -108,6 +143,20 @@ public class UnmodifiableLazyStringListTest extends TestCase { } assertEquals(3, count); + List<ByteString> byteStringList = list.asByteStringList(); + Iterator<ByteString> byteIter = byteStringList.iterator(); + count = 0; + while (byteIter.hasNext()) { + byteIter.next(); + count++; + try { + byteIter.remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + assertEquals(3, count); } public void testListIterator() { @@ -140,6 +189,32 @@ public class UnmodifiableLazyStringListTest extends TestCase { } assertEquals(3, count); + List<ByteString> byteStringList = list.asByteStringList(); + ListIterator<ByteString> byteIter = byteStringList.listIterator(); + count = 0; + while (byteIter.hasNext()) { + byteIter.next(); + count++; + try { + byteIter.remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + byteIter.set(BYTE_STRING_A); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + byteIter.add(BYTE_STRING_A); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + assertEquals(3, count); } private LazyStringArrayList createSampleList() { diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java index 94f62134..146029df 100644 --- a/java/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java @@ -40,6 +40,8 @@ import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestFieldOrderings; +import protobuf_unittest.UnittestProto.TestOneof2; +import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible; import protobuf_unittest.UnittestProto.TestPackedExtensions; import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestMset.TestMessageSet; @@ -218,8 +220,8 @@ public class WireFormatTest extends TestCase { } public void testExtensionsSerializedSize() throws Exception { - assertEquals(TestUtil.getAllSet().getSerializedSize(), - TestUtil.getAllExtensionsSet().getSerializedSize()); + assertNotSame(TestUtil.getAllSet().getSerializedSize(), + TestUtil.getAllExtensionsSet().getSerializedSize()); } public void testSerializeDelimited() throws Exception { @@ -577,4 +579,28 @@ public class WireFormatTest extends TestCase { assertEquals(123, messageSet.getExtension( TestMessageSetExtension1.messageSetExtension).getI()); } + + // ================================================================ + // oneof + public void testOneofWireFormat() throws Exception { + TestOneof2.Builder builder = TestOneof2.newBuilder(); + TestUtil.setOneof(builder); + TestOneof2 message = builder.build(); + ByteString rawBytes = message.toByteString(); + + assertEquals(rawBytes.size(), message.getSerializedSize()); + + TestOneof2 message2 = TestOneof2.parseFrom(rawBytes); + TestUtil.assertOneofSet(message2); + } + + public void testOneofOnlyLastSet() throws Exception { + TestOneofBackwardsCompatible source = TestOneofBackwardsCompatible + .newBuilder().setFooInt(100).setFooString("101").build(); + + ByteString rawBytes = source.toByteString(); + TestOneof2 message = TestOneof2.parseFrom(rawBytes); + assertFalse(message.hasFooInt()); + assertTrue(message.hasFooString()); + } } diff --git a/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto b/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto new file mode 100644 index 00000000..8801db90 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto @@ -0,0 +1,61 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Naoki Iwasaki (niwasaki@google.com) +// +// A proto file with lazy fields + + +package protobuf_unittest; + +option optimize_for = LITE_RUNTIME; + +message LazyMessageLite { + optional int32 num = 1; + optional int32 num_with_default = 2 [default = 421]; + optional LazyInnerMessageLite inner = 3 [lazy = true]; + repeated LazyInnerMessageLite repeated_inner = 4 [lazy = true]; + + oneof oneof_field { + int32 oneof_num = 5; + LazyInnerMessageLite oneof_inner = 6 [lazy = true]; + } +} + +message LazyInnerMessageLite { + optional int32 num = 1; + optional int32 num_with_default = 2 [default = 42]; + optional LazyNestedInnerMessageLite nested = 3 [lazy = true]; +} + +message LazyNestedInnerMessageLite { + optional int32 num = 1; + optional int32 num_with_default = 2 [default = 4]; +} diff --git a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto b/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto new file mode 100644 index 00000000..8b18f078 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto @@ -0,0 +1,55 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: pbogle@google.com (Phil Bogle) + + +package protobuf_unittest.lite_equals_and_hash; + +// This proto definition is used to test that java_generate_equals_and_hash +// works correctly with the LITE_RUNTIME. +option java_generate_equals_and_hash = true; +option optimize_for = LITE_RUNTIME; + +message Foo { + optional int32 value = 1; + repeated Bar bar = 2; +} + +message Bar { + optional string name = 1; +} + +message BarPrime { + optional string name = 1; +} + +message Empty { +} diff --git a/java/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/src/test/java/com/google/protobuf/multiple_files_test.proto index 9a040145..401e1681 100644 --- a/java/src/test/java/com/google/protobuf/multiple_files_test.proto +++ b/java/src/test/java/com/google/protobuf/multiple_files_test.proto @@ -38,12 +38,14 @@ option java_generic_services = true; // auto-added import "google/protobuf/unittest.proto"; +import "google/protobuf/descriptor.proto"; package protobuf_unittest; option java_multiple_files = true; option java_outer_classname = "MultipleFilesTestProto"; + message MessageWithNoOuter { message NestedMessage { optional int32 i = 1; @@ -57,8 +59,12 @@ message MessageWithNoOuter { optional EnumWithNoOuter foreign_enum = 4; } +extend google.protobuf.EnumValueOptions { + optional int32 enum_value_option = 7654321; +} + enum EnumWithNoOuter { - FOO = 1; + FOO = 1 [(enum_value_option) = 12345]; BAR = 2; } diff --git a/java/src/test/java/com/google/protobuf/nested_extension.proto b/java/src/test/java/com/google/protobuf/nested_extension.proto index 9fe5d560..777db032 100644 --- a/java/src/test/java/com/google/protobuf/nested_extension.proto +++ b/java/src/test/java/com/google/protobuf/nested_extension.proto @@ -38,6 +38,7 @@ import "com/google/protobuf/non_nested_extension.proto"; package protobuf_unittest; + message MyNestedExtension { extend MessageToBeExtended { optional MessageToBeExtended recursiveExtension = 2; diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension.proto b/java/src/test/java/com/google/protobuf/non_nested_extension.proto index f61b419b..17c0b623 100644 --- a/java/src/test/java/com/google/protobuf/non_nested_extension.proto +++ b/java/src/test/java/com/google/protobuf/non_nested_extension.proto @@ -35,6 +35,7 @@ package protobuf_unittest; + message MessageToBeExtended { extensions 1 to max; } diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test.proto new file mode 100644 index 00000000..2c251e5d --- /dev/null +++ b/java/src/test/java/com/google/protobuf/outer_class_name_test.proto @@ -0,0 +1,38 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package protobuf_unittest; + + +// This message's name is the same with the default outer class name of this +// proto file. It's used to test if the compiler can avoid this conflict +// correctly. +message OuterClassNameTest { +} diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto new file mode 100644 index 00000000..98b5b7a9 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto @@ -0,0 +1,42 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package protobuf_unittest; + + +message TestMessage2 { + message NestedMessage { + // This message's name is the same with the default outer class name of this + // proto file. It's used to test if the compiler can avoid this conflict + // correctly. + message OuterClassNameTest2 { + } + } +} diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto b/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto new file mode 100644 index 00000000..22fb1e65 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto @@ -0,0 +1,43 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package protobuf_unittest; + + +message TestMessage3 { + message NestedMessage { + // This enum's name is the same with the default outer class name of this + // proto file. It's used to test if the compiler can avoid this conflict + // correctly. + enum OuterClassNameTest3 { + DUMMY_VALUE = 1; + } + } +} diff --git a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto index 6e67d97a..97f27129 100644 --- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto +++ b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto @@ -42,8 +42,12 @@ package io_protocol_tests; option java_package = "com.google.protobuf"; option java_outer_classname = "TestBadIdentifiersProto"; +option java_generate_equals_and_hash = true; message TestMessage { + optional string cached_size = 1; + optional string serialized_size = 2; + optional string class = 3; } message Descriptor { @@ -54,6 +58,9 @@ message Descriptor { optional string descriptor = 1; } optional NestedDescriptor nested_descriptor = 2; + enum NestedEnum { + FOO = 1; + } } message Parser { @@ -66,6 +73,9 @@ message Parser { message Deprecated { enum TestEnum { FOO = 1; + + // Test if @Deprecated annotation conflicts with Deprecated message name. + BAR = 2 [ deprecated = true ]; } optional int32 field1 = 1 [deprecated=true]; @@ -106,3 +116,42 @@ service TestConflictingMethodNames { rpc Override(TestMessage) returns (TestMessage); } +message TestConflictingFieldNames { + enum TestEnum { + FOO = 1; + } + message TestMessage { + } + repeated int32 int32_field = 1; + repeated TestEnum enum_field = 2; + repeated string string_field = 3; + repeated bytes bytes_field = 4; + repeated TestMessage message_field = 5; + + optional int32 int32_field_count = 11; + optional TestEnum enum_field_count = 12; + optional string string_field_count = 13; + optional bytes bytes_field_count = 14; + optional TestMessage message_field_count = 15; + + repeated int32 Int32Field = 21; + repeated TestEnum EnumField = 22; + repeated string StringField = 23; + repeated bytes BytesField = 24; + repeated TestMessage MessageField = 25; + + // This field conflicts with "int32_field" as they both generate + // the method getInt32FieldList(). + required int32 int32_field_list = 31; + + extensions 1000 to max; + + repeated int64 int64_field = 41; + extend TestConflictingFieldNames { + // We don't generate accessors for extensions so the following extension + // fields don't conflict with the repeated field "int64_field". + optional int64 int64_field_count = 1001; + optional int64 int64_field_list = 1002; + } +} + diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8.proto b/java/src/test/java/com/google/protobuf/test_check_utf8.proto new file mode 100644 index 00000000..c327ed67 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/test_check_utf8.proto @@ -0,0 +1,50 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Jacob Butcher (jbaum@google.com) +// +// Test file option java_string_check_utf8. + +package proto2_test_check_utf8; + +option java_outer_classname = "TestCheckUtf8"; +option java_string_check_utf8 = true; + +message StringWrapper { + required string req = 1; + optional string opt = 2; + repeated string rep = 3; +} + +message BytesWrapper { + required bytes req = 1; + optional bytes opt = 2; + repeated bytes rep = 3; +} diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto b/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto new file mode 100644 index 00000000..591bc563 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Jacob Butcher (jbaum@google.com) +// +// Test file option java_string_check_utf8. + +package proto2_test_check_utf8_size; + +option java_outer_classname = "TestCheckUtf8Size"; +option java_string_check_utf8 = true; +option optimize_for = CODE_SIZE; + +message StringWrapperSize { + required string req = 1; + optional string opt = 2; + repeated string rep = 3; +} + +message BytesWrapperSize { + required bytes req = 1; + optional bytes opt = 2; + repeated bytes rep = 3; +} diff --git a/java/src/test/java/com/google/protobuf/test_custom_options.proto b/java/src/test/java/com/google/protobuf/test_custom_options.proto new file mode 100644 index 00000000..f509d29e --- /dev/null +++ b/java/src/test/java/com/google/protobuf/test_custom_options.proto @@ -0,0 +1,43 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Feng Xiao (xiaofeng@google.com) +// +// Test that custom options defined in a proto file's dependencies are properly +// initialized. + +package protobuf_unittest; + + +import "google/protobuf/unittest_custom_options.proto"; + +message TestMessageWithCustomOptionsContainer { + optional TestMessageWithCustomOptions field = 1; +} diff --git a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto b/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto new file mode 100644 index 00000000..3d6ce0c7 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto @@ -0,0 +1,60 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Darick Tong (darick@google.com) + +package protobuf_unittest; + +message Proto1 { + option experimental_java_message_interface = + "com.google.protobuf.ExtraInterfaces.HasBoolValue"; + + option experimental_java_interface_extends = + "com.google.protobuf.ExtraInterfaces.HasByteValue"; + + option experimental_java_message_interface = + "com.google.protobuf.ExtraInterfaces.HasStringValue<Proto1>"; + + option experimental_java_builder_interface = + "com.google.protobuf.ExtraInterfaces.HasStringValueBuilder" + "<Proto1, Builder>"; + + optional string string_value = 1; + optional bool bool_value = 2; + optional bytes byte_value = 3; + optional int32 int_value = 4; +} + +message Proto2 { + option experimental_java_message_interface = + "com.google.protobuf.ExtraInterfaces.HasBoolValue"; + + optional bool bool_value = 1; +} |