Integrated internal changes from Google

pull/5332/head
Adam Cozzette 6 years ago
parent d52f2bb9e4
commit 0894e07536
  1. 1
      cmake/libprotoc.cmake
  2. 5
      java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
  3. 56
      java/core/src/main/java/com/google/protobuf/ByteString.java
  4. 29
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  5. 7
      java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
  6. 7
      java/core/src/main/java/com/google/protobuf/FloatArrayList.java
  7. 74
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  8. 5
      java/core/src/main/java/com/google/protobuf/IntArrayList.java
  9. 5
      java/core/src/main/java/com/google/protobuf/LongArrayList.java
  10. 8
      java/core/src/main/java/com/google/protobuf/Message.java
  11. 38
      java/core/src/main/java/com/google/protobuf/MessageReflection.java
  12. 7
      java/core/src/main/java/com/google/protobuf/NioByteString.java
  13. 48
      java/core/src/main/java/com/google/protobuf/RopeByteString.java
  14. 197
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  15. 9
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  16. 4
      java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
  17. 31
      java/core/src/test/java/com/google/protobuf/AnyTest.java
  18. 60
      java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
  19. 91
      java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
  20. 381
      java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
  21. 20
      java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
  22. 2
      java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
  23. 20
      java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
  24. 18
      java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
  25. 2
      java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
  26. 6
      java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
  27. 15
      java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
  28. 78
      java/core/src/test/java/com/google/protobuf/LiteTest.java
  29. 8
      java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
  30. 18
      java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
  31. 15
      java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  32. 175
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  33. 37
      java/core/src/test/java/com/google/protobuf/MapTest.java
  34. 4
      java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
  35. 141
      java/core/src/test/java/com/google/protobuf/ParserTest.java
  36. 91
      java/core/src/test/java/com/google/protobuf/ServiceTest.java
  37. 36
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  38. 82
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  39. 4
      java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
  40. 12
      java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
  41. 4
      java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
  42. 3
      java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
  43. 35
      java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
  44. 35
      java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
  45. 3
      java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
  46. 39
      java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
  47. 34
      java/core/src/test/proto/com/google/protobuf/map_test.proto
  48. 1
      java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
  49. 4
      java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
  50. 4
      java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
  51. 3
      java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
  52. 3
      java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
  53. 4
      java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
  54. 6
      java/pom.xml
  55. 5
      java/util/pom.xml
  56. 161
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  57. 84
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  58. 1
      java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
  59. 9
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java
  60. 49
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  61. 1
      js/binary/proto_test.js
  62. 11
      js/debug.js
  63. 72
      js/debug_test.js
  64. 24
      js/maps_test.js
  65. 26
      js/message.js
  66. 461
      js/message_test.js
  67. 10
      js/proto3_test.js
  68. 11
      js/test.proto
  69. 52
      js/test11.proto
  70. 119
      js/test12.proto
  71. 70
      js/test13.proto
  72. 43
      js/test14.proto
  73. 39
      js/test15.proto
  74. 2
      python/google/protobuf/internal/containers.py
  75. 4
      python/google/protobuf/internal/descriptor_pool_test.py
  76. 8
      python/google/protobuf/internal/descriptor_test.py
  77. 4
      python/google/protobuf/internal/enum_type_wrapper.py
  78. 3
      python/google/protobuf/internal/json_format_test.py
  79. 26
      python/google/protobuf/internal/message_test.py
  80. 39
      python/google/protobuf/internal/python_message.py
  81. 90
      python/google/protobuf/internal/text_format_test.py
  82. 6
      python/google/protobuf/internal/well_known_types.py
  83. 26
      python/google/protobuf/internal/well_known_types_test.py
  84. 36
      python/google/protobuf/pyext/descriptor.cc
  85. 20
      python/google/protobuf/pyext/map_container.cc
  86. 23
      python/google/protobuf/pyext/message.cc
  87. 10
      python/google/protobuf/text_format.py
  88. 2
      src/Makefile.am
  89. 47
      src/google/protobuf/any.pb.cc
  90. 2
      src/google/protobuf/any.pb.h
  91. 151
      src/google/protobuf/api.pb.cc
  92. 6
      src/google/protobuf/api.pb.h
  93. 29
      src/google/protobuf/arena.cc
  94. 6
      src/google/protobuf/arena_impl.h
  95. 2
      src/google/protobuf/arena_unittest.cc
  96. 133
      src/google/protobuf/compiler/command_line_interface.cc
  97. 16
      src/google/protobuf/compiler/command_line_interface.h
  98. 50
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  99. 4
      src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
  100. 60
      src/google/protobuf/compiler/cpp/cpp_file.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -78,7 +78,6 @@ set(libprotoc_files
${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/scc.cc
${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
) )

@ -46,7 +46,6 @@ final class BooleanArrayList extends AbstractProtobufList<Boolean>
implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection { implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(); private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
static { static {
EMPTY_LIST.makeImmutable(); EMPTY_LIST.makeImmutable();
} }
@ -237,7 +236,7 @@ final class BooleanArrayList extends AbstractProtobufList<Boolean>
ensureIsMutable(); ensureIsMutable();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (o.equals(array[i])) { if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i); System.arraycopy(array, i + 1, array, i, size - i - 1);
size--; size--;
modCount++; modCount++;
return true; return true;
@ -252,7 +251,7 @@ final class BooleanArrayList extends AbstractProtobufList<Boolean>
ensureIndexInRange(index); ensureIndexInRange(index);
boolean value = array[index]; boolean value = array[index];
if (index < size - 1) { if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index); System.arraycopy(array, index + 1, array, index, size - index - 1);
} }
size--; size--;
modCount++; modCount++;

@ -146,6 +146,15 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
*/ */
public abstract byte byteAt(int index); public abstract byte byteAt(int index);
/**
* Gets the byte at the given index, assumes bounds checking has already been performed.
*
* @param index index of byte
* @return the value
* @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
*/
abstract byte internalByteAt(int index);
/** /**
* Return a {@link ByteString.ByteIterator} over the bytes in the ByteString. To avoid * Return a {@link ByteString.ByteIterator} over the bytes in the ByteString. To avoid
* auto-boxing, you may get the iterator manually and call {@link ByteIterator#nextByte()}. * auto-boxing, you may get the iterator manually and call {@link ByteIterator#nextByte()}.
@ -153,8 +162,8 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
* @return the iterator * @return the iterator
*/ */
@Override @Override
public final ByteIterator iterator() { public ByteIterator iterator() {
return new ByteIterator() { return new AbstractByteIterator() {
private int position = 0; private int position = 0;
private final int limit = size(); private final int limit = size();
@ -163,24 +172,14 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
return position < limit; return position < limit;
} }
@Override
public Byte next() {
// Boxing calls Byte.valueOf(byte), which does not instantiate.
return nextByte();
}
@Override @Override
public byte nextByte() { public byte nextByte() {
try { int currentPos = position;
return byteAt(position++); if (currentPos >= limit) {
} catch (IndexOutOfBoundsException e) { throw new NoSuchElementException();
throw new NoSuchElementException(e.getMessage());
} }
} position = currentPos + 1;
return internalByteAt(currentPos);
@Override
public void remove() {
throw new UnsupportedOperationException();
} }
}; };
} }
@ -198,6 +197,19 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
byte nextByte(); byte nextByte();
} }
abstract static class AbstractByteIterator implements ByteIterator {
@Override
public final Byte next() {
// Boxing calls Byte.valueOf(byte), which does not instantiate.
return nextByte();
}
@Override
public final void remove() {
throw new UnsupportedOperationException();
}
}
/** /**
* Gets the number of bytes. * Gets the number of bytes.
* *
@ -1280,6 +1292,11 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
return bytes[index]; return bytes[index];
} }
@Override
byte internalByteAt(int index) {
return bytes[index];
}
@Override @Override
public int size() { public int size() {
return bytes.length; return bytes.length;
@ -1521,6 +1538,11 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
return bytes[bytesOffset + index]; return bytes[bytesOffset + index];
} }
@Override
byte internalByteAt(int index) {
return bytes[bytesOffset + index];
}
@Override @Override
public int size() { public int size() {
return bytesLength; return bytesLength;

@ -2783,7 +2783,8 @@ public abstract class CodedInputStream {
sizeLimit - totalBytesRetired - bufferSize)); sizeLimit - totalBytesRetired - bufferSize));
if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
throw new IllegalStateException( throw new IllegalStateException(
"InputStream#read(byte[]) returned invalid result: " input.getClass()
+ "#read(byte[]) returned invalid result: "
+ bytesRead + bytesRead
+ "\nThe InputStream implementation is buggy."); + "\nThe InputStream implementation is buggy.");
} }
@ -3005,6 +3006,7 @@ public abstract class CodedInputStream {
throw InvalidProtocolBufferException.truncatedMessage(); throw InvalidProtocolBufferException.truncatedMessage();
} }
if (refillCallback != null) {
// Skipping more bytes than are in the buffer. First skip what we have. // Skipping more bytes than are in the buffer. First skip what we have.
int tempPos = bufferSize - pos; int tempPos = bufferSize - pos;
pos = bufferSize; pos = bufferSize;
@ -3019,6 +3021,31 @@ public abstract class CodedInputStream {
} }
pos = size - tempPos; pos = size - tempPos;
} else {
// Skipping more bytes than are in the buffer. First skip what we have.
totalBytesRetired += pos;
int totalSkipped = bufferSize - pos;
bufferSize = 0;
pos = 0;
try {
while (totalSkipped < size) {
int toSkip = size - totalSkipped;
long skipped = input.skip(toSkip);
if (skipped < 0 || skipped > toSkip) {
throw new IllegalStateException(
input.getClass()
+ "#skip returned invalid result: "
+ skipped
+ "\nThe InputStream implementation is buggy.");
}
totalSkipped += (int) skipped;
}
} finally {
totalBytesRetired += totalSkipped;
recomputeBufferSizeAfterLimit();
}
}
} }
} }

@ -46,7 +46,6 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection { implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(); private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
static { static {
EMPTY_LIST.makeImmutable(); EMPTY_LIST.makeImmutable();
} }
@ -104,7 +103,7 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
final double[] arr = other.array; final double[] arr = other.array;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (array[i] != arr[i]) { if (Double.doubleToLongBits(array[i]) != Double.doubleToLongBits(arr[i])) {
return false; return false;
} }
} }
@ -237,7 +236,7 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
ensureIsMutable(); ensureIsMutable();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (o.equals(array[i])) { if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i); System.arraycopy(array, i + 1, array, i, size - i - 1);
size--; size--;
modCount++; modCount++;
return true; return true;
@ -252,7 +251,7 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
ensureIndexInRange(index); ensureIndexInRange(index);
double value = array[index]; double value = array[index];
if (index < size - 1) { if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index); System.arraycopy(array, index + 1, array, index, size - index - 1);
} }
size--; size--;
modCount++; modCount++;

@ -46,7 +46,6 @@ final class FloatArrayList extends AbstractProtobufList<Float>
implements FloatList, RandomAccess, PrimitiveNonBoxingCollection { implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
private static final FloatArrayList EMPTY_LIST = new FloatArrayList(); private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
static { static {
EMPTY_LIST.makeImmutable(); EMPTY_LIST.makeImmutable();
} }
@ -104,7 +103,7 @@ final class FloatArrayList extends AbstractProtobufList<Float>
final float[] arr = other.array; final float[] arr = other.array;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (array[i] != arr[i]) { if (Float.floatToIntBits(array[i]) != Float.floatToIntBits(arr[i])) {
return false; return false;
} }
} }
@ -236,7 +235,7 @@ final class FloatArrayList extends AbstractProtobufList<Float>
ensureIsMutable(); ensureIsMutable();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (o.equals(array[i])) { if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i); System.arraycopy(array, i + 1, array, i, size - i - 1);
size--; size--;
modCount++; modCount++;
return true; return true;
@ -251,7 +250,7 @@ final class FloatArrayList extends AbstractProtobufList<Float>
ensureIndexInRange(index); ensureIndexInRange(index);
float value = array[index]; float value = array[index];
if (index < size - 1) { if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index); System.arraycopy(array, index + 1, array, index, size - index - 1);
} }
size--; size--;
modCount++; modCount++;

@ -451,16 +451,18 @@ public abstract class GeneratedMessageLite<
} }
@Override @Override
public BuilderType mergeFrom(byte[] input, int offset, int length) public BuilderType mergeFrom(
byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException { throws InvalidProtocolBufferException {
// BEGIN REGULAR // BEGIN REGULAR
return super.mergeFrom(input, offset, length); return super.mergeFrom(input, offset, length, extensionRegistry);
// END REGULAR // END REGULAR
// BEGIN EXPERIMENTAL // BEGIN EXPERIMENTAL
// copyOnWrite(); // copyOnWrite();
// try { // try {
// Protobuf.getInstance().schemaFor(instance).mergeFrom( // Protobuf.getInstance().schemaFor(instance).mergeFrom(
// instance, input, offset, offset + length, new ArrayDecoders.Registers()); // instance, input, offset, offset + length,
// new ArrayDecoders.Registers(extensionRegistry));
// } catch (InvalidProtocolBufferException e) { // } catch (InvalidProtocolBufferException e) {
// throw e; // throw e;
// } catch (IndexOutOfBoundsException e) { // } catch (IndexOutOfBoundsException e) {
@ -472,6 +474,18 @@ public abstract class GeneratedMessageLite<
// END EXPERIMENTAL // END EXPERIMENTAL
} }
@Override
public BuilderType mergeFrom(
byte[] input, int offset, int length)
throws InvalidProtocolBufferException {
// BEGIN REGULAR
return super.mergeFrom(input, offset, length);
// END REGULAR
// BEGIN EXPERIMENTAL
// return mergeFrom(input, offset, length, ExtensionRegistryLite.getEmptyRegistry());
// END EXPERIMENTAL
}
@Override @Override
public BuilderType mergeFrom( public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input, com.google.protobuf.CodedInputStream input,
@ -483,6 +497,8 @@ public abstract class GeneratedMessageLite<
instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry); instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
// END REGULAR // END REGULAR
// BEGIN EXPERIMENTAL // BEGIN EXPERIMENTAL
// // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
// // fast path.
// Protobuf.getInstance().schemaFor(instance).mergeFrom( // Protobuf.getInstance().schemaFor(instance).mergeFrom(
// instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry); // instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
// END EXPERIMENTAL // END EXPERIMENTAL
@ -814,7 +830,7 @@ public abstract class GeneratedMessageLite<
.setField(extension.descriptor, extension.singularToFieldSetType(value)); .setField(extension.descriptor, extension.singularToFieldSetType(value));
} }
private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() { FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
if (extensions.isImmutable()) { if (extensions.isImmutable()) {
extensions = extensions.clone(); extensions = extensions.clone();
} }
@ -1558,8 +1574,11 @@ public abstract class GeneratedMessageLite<
} }
@Override @Override
public T parsePartialFrom(byte[] input) throws InvalidProtocolBufferException { public T parsePartialFrom(
return GeneratedMessageLite.parsePartialFrom(defaultInstance, input); byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return GeneratedMessageLite.parsePartialFrom(
defaultInstance, input, offset, length, extensionRegistry);
} }
} }
@ -1578,6 +1597,8 @@ public abstract class GeneratedMessageLite<
result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry); result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
// END REGULAR // END REGULAR
// BEGIN EXPERIMENTAL // BEGIN EXPERIMENTAL
// // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
// // fast path.
// Protobuf.getInstance().schemaFor(result).mergeFrom( // Protobuf.getInstance().schemaFor(result).mergeFrom(
// result, CodedInputStreamReader.forCodedInput(input), extensionRegistry); // result, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
// END EXPERIMENTAL // END EXPERIMENTAL
@ -1599,17 +1620,31 @@ public abstract class GeneratedMessageLite<
} }
/** A static helper method for parsing a partial from byte array. */ /** A static helper method for parsing a partial from byte array. */
static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(T instance, byte[] input) static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException { throws InvalidProtocolBufferException {
// BEGIN REGULAR // BEGIN REGULAR
return parsePartialFrom(instance, input, ExtensionRegistryLite.getEmptyRegistry()); T message;
try {
CodedInputStream cis = CodedInputStream.newInstance(input, offset, length);
message = parsePartialFrom(instance, cis, extensionRegistry);
try {
cis.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
} catch (InvalidProtocolBufferException e) {
throw e;
}
// END REGULAR // END REGULAR
// BEGIN EXPERIMENTAL // BEGIN EXPERIMENTAL
// @SuppressWarnings("unchecked") // Guaranteed by protoc // @SuppressWarnings("unchecked") // Guaranteed by protoc
// T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); // T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
// try { // try {
// Protobuf.getInstance().schemaFor(result).mergeFrom( // Protobuf.getInstance().schemaFor(result).mergeFrom(
// result, input, 0, input.length, new ArrayDecoders.Registers()); // result, input, offset, offset + length,
// new ArrayDecoders.Registers(extensionRegistry));
// result.makeImmutable(); // result.makeImmutable();
// if (result.memoizedHashCode != 0) { // if (result.memoizedHashCode != 0) {
// throw new RuntimeException(); // throw new RuntimeException();
@ -1701,32 +1736,23 @@ public abstract class GeneratedMessageLite<
private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom( private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry) T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException { throws InvalidProtocolBufferException {
T message; return checkMessageInitialized(
try { parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
CodedInputStream input = CodedInputStream.newInstance(data);
message = parsePartialFrom(defaultInstance, input, extensionRegistry);
try {
input.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
} catch (InvalidProtocolBufferException e) {
throw e;
}
} }
// Validates last tag. // Validates last tag.
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom( protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, byte[] data) throws InvalidProtocolBufferException { T defaultInstance, byte[] data) throws InvalidProtocolBufferException {
return checkMessageInitialized(parsePartialFrom(defaultInstance, data)); return checkMessageInitialized(parsePartialFrom(
defaultInstance, data, 0, data.length, ExtensionRegistryLite.getEmptyRegistry()));
} }
// Validates last tag. // Validates last tag.
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom( protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry) T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException { throws InvalidProtocolBufferException {
return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry)); return checkMessageInitialized(
parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
} }
// Does not validate last tag. // Does not validate last tag.

@ -46,7 +46,6 @@ final class IntArrayList extends AbstractProtobufList<Integer>
implements IntList, RandomAccess, PrimitiveNonBoxingCollection { implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
private static final IntArrayList EMPTY_LIST = new IntArrayList(); private static final IntArrayList EMPTY_LIST = new IntArrayList();
static { static {
EMPTY_LIST.makeImmutable(); EMPTY_LIST.makeImmutable();
} }
@ -236,7 +235,7 @@ final class IntArrayList extends AbstractProtobufList<Integer>
ensureIsMutable(); ensureIsMutable();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (o.equals(array[i])) { if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i); System.arraycopy(array, i + 1, array, i, size - i - 1);
size--; size--;
modCount++; modCount++;
return true; return true;
@ -251,7 +250,7 @@ final class IntArrayList extends AbstractProtobufList<Integer>
ensureIndexInRange(index); ensureIndexInRange(index);
int value = array[index]; int value = array[index];
if (index < size - 1) { if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index); System.arraycopy(array, index + 1, array, index, size - index - 1);
} }
size--; size--;
modCount++; modCount++;

@ -46,7 +46,6 @@ final class LongArrayList extends AbstractProtobufList<Long>
implements LongList, RandomAccess, PrimitiveNonBoxingCollection { implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
private static final LongArrayList EMPTY_LIST = new LongArrayList(); private static final LongArrayList EMPTY_LIST = new LongArrayList();
static { static {
EMPTY_LIST.makeImmutable(); EMPTY_LIST.makeImmutable();
} }
@ -236,7 +235,7 @@ final class LongArrayList extends AbstractProtobufList<Long>
ensureIsMutable(); ensureIsMutable();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (o.equals(array[i])) { if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i); System.arraycopy(array, i + 1, array, i, size - i - 1);
size--; size--;
modCount++; modCount++;
return true; return true;
@ -251,7 +250,7 @@ final class LongArrayList extends AbstractProtobufList<Long>
ensureIndexInRange(index); ensureIndexInRange(index);
long value = array[index]; long value = array[index];
if (index < size - 1) { if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index); System.arraycopy(array, index + 1, array, index, size - index - 1);
} }
size--; size--;
modCount++; modCount++;

@ -149,8 +149,12 @@ public interface Message extends MessageLite, MessageOrBuilder {
Descriptors.Descriptor getDescriptorForType(); Descriptors.Descriptor getDescriptorForType();
/** /**
* Create a Builder for messages of the appropriate type for the given field. Messages built * Create a builder for messages of the appropriate type for the given field. The
* with this can then be passed to setField(), setRepeatedField(), or addRepeatedField(). * builder is NOT nested in the current builder. However, messages built with the
* builder can then be passed to the {@link #setField()}, {@link #setRepeatedField()}, or {@link
* #addRepeatedField()} method of the current builder.
*
* <p>To obtain a builder nested in the current builder, use {@link #getFieldBuilder()} instead.
*/ */
Builder newBuilderForField(Descriptors.FieldDescriptor field); Builder newBuilderForField(Descriptors.FieldDescriptor field);

@ -334,6 +334,14 @@ class MessageReflection {
MergeTarget newMergeTargetForField( MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance); Descriptors.FieldDescriptor descriptor, Message defaultInstance);
/**
* Returns an empty merge target for a sub-field. When defaultInstance is provided, it indicates
* the descriptor is for an extension type, and implementations should create a new instance
* from the defaultInstance prototype directly.
*/
MergeTarget newEmptyTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance);
/** Finishes the merge and returns the underlying object. */ /** Finishes the merge and returns the underlying object. */
Object finish(); Object finish();
} }
@ -494,11 +502,31 @@ class MessageReflection {
@Override @Override
public MergeTarget newMergeTargetForField( public MergeTarget newMergeTargetForField(
Descriptors.FieldDescriptor field, Message defaultInstance) { Descriptors.FieldDescriptor field, Message defaultInstance) {
Message.Builder subBuilder;
if (defaultInstance != null) { if (defaultInstance != null) {
return new BuilderAdapter(defaultInstance.newBuilderForType()); subBuilder = defaultInstance.newBuilderForType();
} else { } else {
return new BuilderAdapter(builder.newBuilderForField(field)); subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
Message originalMessage = (Message) getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
} }
return new BuilderAdapter(subBuilder);
}
@Override
public MergeTarget newEmptyTargetForField(
Descriptors.FieldDescriptor field, Message defaultInstance) {
Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
return new BuilderAdapter(subBuilder);
} }
@Override @Override
@ -661,6 +689,12 @@ class MessageReflection {
throw new UnsupportedOperationException("newMergeTargetForField() called on FieldSet object"); throw new UnsupportedOperationException("newMergeTargetForField() called on FieldSet object");
} }
@Override
public MergeTarget newEmptyTargetForField(
Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
throw new UnsupportedOperationException("newEmptyTargetForField() called on FieldSet object");
}
@Override @Override
public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
if (descriptor.needsUtf8Check()) { if (descriptor.needsUtf8Check()) {

@ -81,6 +81,13 @@ final class NioByteString extends ByteString.LeafByteString {
} }
} }
@Override
public byte internalByteAt(int index) {
// it isn't possible to avoid the bounds checking inside of ByteBuffer, so just use the default
// implementation.
return byteAt(index);
}
@Override @Override
public int size() { public int size() {
return buffer.remaining(); return buffer.remaining();

@ -38,12 +38,12 @@ import java.io.ObjectInputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Stack;
/** /**
* Class to represent {@code ByteStrings} formed by concatenation of other ByteStrings, without * Class to represent {@code ByteStrings} formed by concatenation of other ByteStrings, without
@ -240,13 +240,17 @@ final class RopeByteString extends ByteString {
@Override @Override
public byte byteAt(int index) { public byte byteAt(int index) {
checkIndex(index, totalLength); checkIndex(index, totalLength);
return internalByteAt(index);
}
@Override
byte internalByteAt(int index) {
// Find the relevant piece by recursive descent // Find the relevant piece by recursive descent
if (index < leftLength) { if (index < leftLength) {
return left.byteAt(index); return left.internalByteAt(index);
} }
return right.byteAt(index - leftLength); return right.internalByteAt(index - leftLength);
} }
@Override @Override
@ -254,6 +258,37 @@ final class RopeByteString extends ByteString {
return totalLength; return totalLength;
} }
@Override
public ByteIterator iterator() {
return new AbstractByteIterator() {
final PieceIterator pieces = new PieceIterator(RopeByteString.this);
ByteIterator current = nextPiece();
private ByteIterator nextPiece() {
// NOTE: PieceIterator is guaranteed to return non-empty pieces, so this method will always
// return non-empty iterators (or null)
return pieces.hasNext() ? pieces.next().iterator() : null;
}
@Override
public boolean hasNext() {
return current != null;
}
@Override
public byte nextByte() {
if (current == null) {
throw new NoSuchElementException();
}
byte b = current.nextByte();
if (!current.hasNext()) {
current = nextPiece();
}
return b;
}
};
}
// ================================================================= // =================================================================
// Pieces // Pieces
@ -546,7 +581,7 @@ final class RopeByteString extends ByteString {
// Stack containing the part of the string, starting from the left, that // Stack containing the part of the string, starting from the left, that
// we've already traversed. The final string should be the equivalent of // we've already traversed. The final string should be the equivalent of
// concatenating the strings on the stack from bottom to top. // concatenating the strings on the stack from bottom to top.
private final Stack<ByteString> prefixesStack = new Stack<ByteString>(); private final ArrayDeque<ByteString> prefixesStack = new ArrayDeque<>();
private ByteString balance(ByteString left, ByteString right) { private ByteString balance(ByteString left, ByteString right) {
doBalance(left); doBalance(left);
@ -650,9 +685,8 @@ final class RopeByteString extends ByteString {
* *
* <p>This iterator is used to implement {@link RopeByteString#equalsFragments(ByteString)}. * <p>This iterator is used to implement {@link RopeByteString#equalsFragments(ByteString)}.
*/ */
private static class PieceIterator implements Iterator<LeafByteString> { private static final class PieceIterator implements Iterator<LeafByteString> {
private final ArrayDeque<RopeByteString> breadCrumbs = new ArrayDeque<>();
private final Stack<RopeByteString> breadCrumbs = new Stack<RopeByteString>();
private LeafByteString next; private LeafByteString next;
private PieceIterator(ByteString root) { private PieceIterator(ByteString root) {

@ -1127,6 +1127,7 @@ public final class TextFormat {
PARSER.merge(input, builder); PARSER.merge(input, builder);
} }
/** /**
* Parse a text-format message from {@code input}. * Parse a text-format message from {@code input}.
* *
@ -1166,6 +1167,7 @@ public final class TextFormat {
PARSER.merge(input, extensionRegistry, builder); PARSER.merge(input, extensionRegistry, builder);
} }
/** /**
* Parse a text-format message from {@code input}. Extensions will be recognized if they are * Parse a text-format message from {@code input}. Extensions will be recognized if they are
* registered in {@code extensionRegistry}. * registered in {@code extensionRegistry}.
@ -1185,6 +1187,7 @@ public final class TextFormat {
} }
/** /**
* Parser for text-format proto2 instances. This class is thread-safe. The implementation largely * Parser for text-format proto2 instances. This class is thread-safe. The implementation largely
* follows google/protobuf/text_format.cc. * follows google/protobuf/text_format.cc.
@ -1205,24 +1208,60 @@ public final class TextFormat {
* </ul> * </ul>
*/ */
public enum SingularOverwritePolicy { public enum SingularOverwritePolicy {
/** The last value is retained. */ /**
* Later values are merged with earlier values. For primitive fields or conflicting oneofs,
* the last value is retained.
*/
ALLOW_SINGULAR_OVERWRITES, ALLOW_SINGULAR_OVERWRITES,
/** An error is issued. */ /** An error is issued. */
FORBID_SINGULAR_OVERWRITES FORBID_SINGULAR_OVERWRITES
} }
/**
* Determines how to deal with repeated values for singular Message fields. For example,
* given a field "foo" containing subfields "baz" and "qux":
*
* <ul>
* <li>"foo { baz: 1 } foo { baz: 2 }", or
* <li>"foo { baz: 1 } foo { qux: 2 }"
* </ul>
*/
public enum MergingStyle {
/**
* Merge the values in standard protobuf fashion:
*
* <ul>
* <li>"foo { baz: 2 }" and
* <li>"foo { baz: 1, qux: 2 }", respectively.
* </ul>
*/
RECURSIVE,
/**
* Later values overwrite ("clobber") previous values:
*
* <ul>
* <li>"foo { baz: 2 }" and
* <li>"foo { qux: 2 }", respectively.
* </ul>
*/
NON_RECURSIVE
}
private final boolean allowUnknownFields; private final boolean allowUnknownFields;
private final boolean allowUnknownEnumValues; private final boolean allowUnknownEnumValues;
private final boolean allowUnknownExtensions;
private final SingularOverwritePolicy singularOverwritePolicy; private final SingularOverwritePolicy singularOverwritePolicy;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder; private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
private Parser( private Parser(
boolean allowUnknownFields, boolean allowUnknownFields,
boolean allowUnknownEnumValues, boolean allowUnknownEnumValues,
boolean allowUnknownExtensions,
SingularOverwritePolicy singularOverwritePolicy, SingularOverwritePolicy singularOverwritePolicy,
TextFormatParseInfoTree.Builder parseInfoTreeBuilder) { TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
this.allowUnknownFields = allowUnknownFields; this.allowUnknownFields = allowUnknownFields;
this.allowUnknownEnumValues = allowUnknownEnumValues; this.allowUnknownEnumValues = allowUnknownEnumValues;
this.allowUnknownExtensions = allowUnknownExtensions;
this.singularOverwritePolicy = singularOverwritePolicy; this.singularOverwritePolicy = singularOverwritePolicy;
this.parseInfoTreeBuilder = parseInfoTreeBuilder; this.parseInfoTreeBuilder = parseInfoTreeBuilder;
} }
@ -1236,11 +1275,23 @@ public final class TextFormat {
public static class Builder { public static class Builder {
private boolean allowUnknownFields = false; private boolean allowUnknownFields = false;
private boolean allowUnknownEnumValues = false; private boolean allowUnknownEnumValues = false;
private boolean allowUnknownExtensions = false;
private SingularOverwritePolicy singularOverwritePolicy = private SingularOverwritePolicy singularOverwritePolicy =
SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES; SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null; private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
/**
* Set whether this parser will allow unknown extensions. By default, an
* exception is thrown if unknown extension is encountered. If this is set true,
* the parser will only log a warning. Allow unknown extensions does not mean
* allow normal unknown fields.
*/
public Builder setAllowUnknownExtensions(boolean allowUnknownExtensions) {
this.allowUnknownExtensions = allowUnknownExtensions;
return this;
}
/** Sets parser behavior when a non-repeated field appears more than once. */ /** Sets parser behavior when a non-repeated field appears more than once. */
public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) { public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
this.singularOverwritePolicy = p; this.singularOverwritePolicy = p;
@ -1256,6 +1307,7 @@ public final class TextFormat {
return new Parser( return new Parser(
allowUnknownFields, allowUnknownFields,
allowUnknownEnumValues, allowUnknownEnumValues,
allowUnknownExtensions,
singularOverwritePolicy, singularOverwritePolicy,
parseInfoTreeBuilder); parseInfoTreeBuilder);
} }
@ -1297,6 +1349,7 @@ public final class TextFormat {
} }
private static final int BUFFER_SIZE = 4096; private static final int BUFFER_SIZE = 4096;
// TODO(chrisn): See if working around java.io.Reader#read(CharBuffer) // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
@ -1315,26 +1368,57 @@ public final class TextFormat {
return text; return text;
} }
static final class UnknownField {
static enum Type {
FIELD, EXTENSION;
}
final String message;
final Type type;
UnknownField(String message, Type type) {
this.message = message;
this.type = type;
}
}
// Check both unknown fields and unknown extensions and log warning messages // Check both unknown fields and unknown extensions and log warning messages
// or throw exceptions according to the flag. // or throw exceptions according to the flag.
private void checkUnknownFields(final List<String> unknownFields) throws ParseException { private void checkUnknownFields(final List<UnknownField> unknownFields) throws ParseException {
if (unknownFields.isEmpty()) { if (unknownFields.isEmpty()) {
return; return;
} }
StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:"); StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:");
for (String field : unknownFields) { for (UnknownField field : unknownFields) {
msg.append('\n').append(field); msg.append('\n').append(field.message);
} }
if (allowUnknownFields) { if (allowUnknownFields) {
logger.warning(msg.toString()); logger.warning(msg.toString());
} else { return;
String[] lineColumn = unknownFields.get(0).split(":"); }
int firstErrorIndex = 0;
if (allowUnknownExtensions) {
boolean allUnknownExtensions = true;
for (UnknownField field : unknownFields) {
if (field.type == UnknownField.Type.FIELD) {
allUnknownExtensions = false;
break;
}
++firstErrorIndex;
}
if (allUnknownExtensions) {
logger.warning(msg.toString());
return;
}
}
String[] lineColumn = unknownFields.get(firstErrorIndex).message.split(":");
throw new ParseException( throw new ParseException(
Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString()); Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString());
} }
}
/** /**
* Parse a text-format message from {@code input} and merge the contents into {@code builder}. * Parse a text-format message from {@code input} and merge the contents into {@code builder}.
@ -1348,24 +1432,32 @@ public final class TextFormat {
final Tokenizer tokenizer = new Tokenizer(input); final Tokenizer tokenizer = new Tokenizer(input);
MessageReflection.BuilderAdapter target = new MessageReflection.BuilderAdapter(builder); MessageReflection.BuilderAdapter target = new MessageReflection.BuilderAdapter(builder);
List<String> unknownFields = new ArrayList<String>(); List<UnknownField> unknownFields = new ArrayList<UnknownField>();
while (!tokenizer.atEnd()) { while (!tokenizer.atEnd()) {
mergeField(tokenizer, extensionRegistry, target, unknownFields); mergeField(tokenizer, extensionRegistry, target, MergingStyle.RECURSIVE, unknownFields);
} }
checkUnknownFields(unknownFields); checkUnknownFields(unknownFields);
} }
/** Parse a single field from {@code tokenizer} and merge it into {@code builder}. */ /** Parse a single field from {@code tokenizer} and merge it into {@code builder}. */
private void mergeField( private void mergeField(
final Tokenizer tokenizer, final Tokenizer tokenizer,
final ExtensionRegistry extensionRegistry, final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target, final MessageReflection.MergeTarget target,
List<String> unknownFields) final MergingStyle mergingStyle,
List<UnknownField> unknownFields)
throws ParseException { throws ParseException {
mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder, unknownFields); mergeField(
tokenizer,
extensionRegistry,
target,
parseInfoTreeBuilder,
mergingStyle,
unknownFields);
} }
/** Parse a single field from {@code tokenizer} and merge it into {@code target}. */ /** Parse a single field from {@code tokenizer} and merge it into {@code target}. */
@ -1374,7 +1466,8 @@ public final class TextFormat {
final ExtensionRegistry extensionRegistry, final ExtensionRegistry extensionRegistry,
final MessageReflection.MergeTarget target, final MessageReflection.MergeTarget target,
TextFormatParseInfoTree.Builder parseTreeBuilder, TextFormatParseInfoTree.Builder parseTreeBuilder,
List<String> unknownFields) final MergingStyle mergingStyle,
List<UnknownField> unknownFields)
throws ParseException { throws ParseException {
FieldDescriptor field = null; FieldDescriptor field = null;
int startLine = tokenizer.getLine(); int startLine = tokenizer.getLine();
@ -1393,15 +1486,15 @@ public final class TextFormat {
extension = target.findExtensionByName(extensionRegistry, name.toString()); extension = target.findExtensionByName(extensionRegistry, name.toString());
if (extension == null) { if (extension == null) {
unknownFields.add( String message = (tokenizer.getPreviousLine() + 1)
(tokenizer.getPreviousLine() + 1)
+ ":" + ":"
+ (tokenizer.getPreviousColumn() + 1) + (tokenizer.getPreviousColumn() + 1)
+ ":\t" + ":\t"
+ type.getFullName() + type.getFullName()
+ ".[" + ".["
+ name + name
+ "]"); + "]";
unknownFields.add(new UnknownField(message, UnknownField.Type.EXTENSION));
} else { } else {
if (extension.descriptor.getContainingType() != type) { if (extension.descriptor.getContainingType() != type) {
throw tokenizer.parseExceptionPreviousToken( throw tokenizer.parseExceptionPreviousToken(
@ -1440,14 +1533,14 @@ public final class TextFormat {
} }
if (field == null) { if (field == null) {
unknownFields.add( String message = (tokenizer.getPreviousLine() + 1)
(tokenizer.getPreviousLine() + 1)
+ ":" + ":"
+ (tokenizer.getPreviousColumn() + 1) + (tokenizer.getPreviousColumn() + 1)
+ ":\t" + ":\t"
+ type.getFullName() + type.getFullName()
+ "." + "."
+ name); + name;
unknownFields.add(new UnknownField(message, UnknownField.Type.FIELD));
} }
} }
@ -1480,6 +1573,7 @@ public final class TextFormat {
field, field,
extension, extension,
childParseTreeBuilder, childParseTreeBuilder,
mergingStyle,
unknownFields); unknownFields);
} else { } else {
consumeFieldValues( consumeFieldValues(
@ -1489,6 +1583,7 @@ public final class TextFormat {
field, field,
extension, extension,
parseTreeBuilder, parseTreeBuilder,
mergingStyle,
unknownFields); unknownFields);
} }
} else { } else {
@ -1500,6 +1595,7 @@ public final class TextFormat {
field, field,
extension, extension,
parseTreeBuilder, parseTreeBuilder,
mergingStyle,
unknownFields); unknownFields);
} }
@ -1524,7 +1620,8 @@ public final class TextFormat {
final FieldDescriptor field, final FieldDescriptor field,
final ExtensionRegistry.ExtensionInfo extension, final ExtensionRegistry.ExtensionInfo extension,
final TextFormatParseInfoTree.Builder parseTreeBuilder, final TextFormatParseInfoTree.Builder parseTreeBuilder,
List<String> unknownFields) final MergingStyle mergingStyle,
List<UnknownField> unknownFields)
throws ParseException { throws ParseException {
// Support specifying repeated field values as a comma-separated list. // Support specifying repeated field values as a comma-separated list.
// Ex."foo: [1, 2, 3]" // Ex."foo: [1, 2, 3]"
@ -1538,6 +1635,7 @@ public final class TextFormat {
field, field,
extension, extension,
parseTreeBuilder, parseTreeBuilder,
mergingStyle,
unknownFields); unknownFields);
if (tokenizer.tryConsume("]")) { if (tokenizer.tryConsume("]")) {
// End of list. // End of list.
@ -1554,6 +1652,7 @@ public final class TextFormat {
field, field,
extension, extension,
parseTreeBuilder, parseTreeBuilder,
mergingStyle,
unknownFields); unknownFields);
} }
} }
@ -1566,8 +1665,28 @@ public final class TextFormat {
final FieldDescriptor field, final FieldDescriptor field,
final ExtensionRegistry.ExtensionInfo extension, final ExtensionRegistry.ExtensionInfo extension,
final TextFormatParseInfoTree.Builder parseTreeBuilder, final TextFormatParseInfoTree.Builder parseTreeBuilder,
List<String> unknownFields) final MergingStyle mergingStyle,
List<UnknownField> unknownFields)
throws ParseException { throws ParseException {
if (singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES
&& !field.isRepeated()) {
if (target.hasField(field)) {
throw tokenizer.parseExceptionPreviousToken(
"Non-repeated field \"" + field.getFullName() + "\" cannot be overwritten.");
} else if (field.getContainingOneof() != null
&& target.hasOneof(field.getContainingOneof())) {
Descriptors.OneofDescriptor oneof = field.getContainingOneof();
throw tokenizer.parseExceptionPreviousToken(
"Field \""
+ field.getFullName()
+ "\" is specified along with field \""
+ target.getOneofFieldDescriptor(oneof).getFullName()
+ "\", another member of oneof \""
+ oneof.getName()
+ "\".");
}
}
Object value = null; Object value = null;
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
@ -1580,15 +1699,29 @@ public final class TextFormat {
} }
final MessageReflection.MergeTarget subField; final MessageReflection.MergeTarget subField;
subField = Message defaultInstance = (extension == null) ? null : extension.defaultInstance;
target.newMergeTargetForField( switch (mergingStyle) {
field, (extension == null) ? null : extension.defaultInstance); case RECURSIVE:
subField = target.newMergeTargetForField(field, defaultInstance);
break;
case NON_RECURSIVE:
subField = target.newEmptyTargetForField(field, defaultInstance);
break;
default:
throw new AssertionError();
}
while (!tokenizer.tryConsume(endToken)) { while (!tokenizer.tryConsume(endToken)) {
if (tokenizer.atEnd()) { if (tokenizer.atEnd()) {
throw tokenizer.parseException("Expected \"" + endToken + "\"."); throw tokenizer.parseException("Expected \"" + endToken + "\".");
} }
mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, unknownFields); mergeField(
tokenizer,
extensionRegistry,
subField,
parseTreeBuilder,
mergingStyle,
unknownFields);
} }
value = subField.finish(); value = subField.finish();
@ -1693,22 +1826,6 @@ public final class TextFormat {
// TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode, // TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
// check for duplicate map keys here. // check for duplicate map keys here.
target.addRepeatedField(field, value); target.addRepeatedField(field, value);
} else if ((singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
&& target.hasField(field)) {
throw tokenizer.parseExceptionPreviousToken(
"Non-repeated field \"" + field.getFullName() + "\" cannot be overwritten.");
} else if ((singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
&& field.getContainingOneof() != null
&& target.hasOneof(field.getContainingOneof())) {
Descriptors.OneofDescriptor oneof = field.getContainingOneof();
throw tokenizer.parseExceptionPreviousToken(
"Field \""
+ field.getFullName()
+ "\" is specified along with field \""
+ target.getOneofFieldDescriptor(oneof).getFullName()
+ "\", another member of oneof \""
+ oneof.getName()
+ "\".");
} else { } else {
target.setField(field, value); target.setField(field, value);
} }

@ -83,6 +83,15 @@ final class UnsafeUtil {
} }
@SuppressWarnings("unchecked") // safe by method contract
static <T> T allocateInstance(Class<T> clazz) {
try {
return (T) UNSAFE.allocateInstance(clazz);
} catch (InstantiationException e) {
throw new IllegalStateException(e);
}
}
static long objectFieldOffset(Field field) { static long objectFieldOffset(Field field) {
return MEMORY_ACCESSOR.objectFieldOffset(field); return MEMORY_ACCESSOR.objectFieldOffset(field);
} }

@ -522,8 +522,8 @@ public class AbstractMessageTest extends TestCase {
/** /**
* Asserts that the given protos are not equal and have different hash codes. * Asserts that the given protos are not equal and have different hash codes.
* *
* @warning It's valid for non-equal objects to have the same hash code, so this test is stricter * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
* than it needs to be. However, this should happen relatively rarely. * stricter than it needs to be. However, this should happen relatively rarely.
*/ */
private void checkNotEqual(Message m1, Message m2) { private void checkNotEqual(Message m1, Message m2) {
String equalsError = String.format("%s should not be equal to %s", m1, m2); String equalsError = String.format("%s should not be equal to %s", m1, m2);

@ -35,17 +35,14 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
import java.util.Objects; import java.util.Objects;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /** Unit tests for Any message. */
* Unit tests for Any message.
*/
public class AnyTest extends TestCase { public class AnyTest extends TestCase {
public void testAnyGeneratedApi() throws Exception { public void testAnyGeneratedApi() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestUtil.setAllFields(builder); TestUtil.setAllFields(builder);
TestAllTypes message = builder.build(); TestAllTypes message = builder.build();
TestAny container = TestAny.newBuilder() TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
.setValue(Any.pack(message)).build();
assertTrue(container.getValue().is(TestAllTypes.class)); assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class)); assertFalse(container.getValue().is(TestAny.class));
@ -64,8 +61,7 @@ public class AnyTest extends TestCase {
// Test that unpacking throws an exception if parsing fails. // Test that unpacking throws an exception if parsing fails.
TestAny.Builder containerBuilder = container.toBuilder(); TestAny.Builder containerBuilder = container.toBuilder();
containerBuilder.getValueBuilder().setValue( containerBuilder.getValueBuilder().setValue(ByteString.copyFrom(new byte[] {0x11}));
ByteString.copyFrom(new byte[]{0x11}));
container = containerBuilder.build(); container = containerBuilder.build();
try { try {
container.getValue().unpack(TestAllTypes.class); container.getValue().unpack(TestAllTypes.class);
@ -80,12 +76,10 @@ public class AnyTest extends TestCase {
TestUtil.setAllFields(builder); TestUtil.setAllFields(builder);
TestAllTypes message = builder.build(); TestAllTypes message = builder.build();
TestAny container = TestAny.newBuilder() TestAny container = TestAny.newBuilder().setValue(Any.pack(message, "xxx.com")).build();
.setValue(Any.pack(message, "xxx.com")).build();
assertEquals( assertEquals(
"xxx.com/" + TestAllTypes.getDescriptor().getFullName(), "xxx.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
container.getValue().getTypeUrl());
assertTrue(container.getValue().is(TestAllTypes.class)); assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class)); assertFalse(container.getValue().is(TestAny.class));
@ -93,12 +87,10 @@ public class AnyTest extends TestCase {
TestAllTypes result = container.getValue().unpack(TestAllTypes.class); TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
TestUtil.assertAllFieldsSet(result); TestUtil.assertAllFieldsSet(result);
container = TestAny.newBuilder() container = TestAny.newBuilder().setValue(Any.pack(message, "yyy.com/")).build();
.setValue(Any.pack(message, "yyy.com/")).build();
assertEquals( assertEquals(
"yyy.com/" + TestAllTypes.getDescriptor().getFullName(), "yyy.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
container.getValue().getTypeUrl());
assertTrue(container.getValue().is(TestAllTypes.class)); assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class)); assertFalse(container.getValue().is(TestAny.class));
@ -106,12 +98,10 @@ public class AnyTest extends TestCase {
result = container.getValue().unpack(TestAllTypes.class); result = container.getValue().unpack(TestAllTypes.class);
TestUtil.assertAllFieldsSet(result); TestUtil.assertAllFieldsSet(result);
container = TestAny.newBuilder() container = TestAny.newBuilder().setValue(Any.pack(message, "")).build();
.setValue(Any.pack(message, "")).build();
assertEquals( assertEquals(
"/" + TestAllTypes.getDescriptor().getFullName(), "/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
container.getValue().getTypeUrl());
assertTrue(container.getValue().is(TestAllTypes.class)); assertTrue(container.getValue().is(TestAllTypes.class));
assertFalse(container.getValue().is(TestAny.class)); assertFalse(container.getValue().is(TestAny.class));
@ -125,8 +115,7 @@ public class AnyTest extends TestCase {
TestUtil.setAllFields(builder); TestUtil.setAllFields(builder);
TestAllTypes message = builder.build(); TestAllTypes message = builder.build();
TestAny container = TestAny.newBuilder() TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
.setValue(Any.pack(message)).build();
assertTrue(container.getValue().is(TestAllTypes.class)); assertTrue(container.getValue().is(TestAllTypes.class));

@ -77,10 +77,10 @@ public class BooleanArrayListTest extends TestCase {
list.addAll(asList(true, false, true, false)); list.addAll(asList(true, false, true, false));
Iterator<Boolean> iterator = list.iterator(); Iterator<Boolean> iterator = list.iterator();
assertEquals(4, list.size()); assertEquals(4, list.size());
assertTrue(list.get(0)); assertEquals(true, (boolean) list.get(0));
assertTrue(iterator.next()); assertEquals(true, (boolean) iterator.next());
list.set(0, true); list.set(0, true);
assertFalse(iterator.next()); assertEquals(false, (boolean) iterator.next());
list.remove(0); list.remove(0);
try { try {
@ -101,9 +101,9 @@ public class BooleanArrayListTest extends TestCase {
} }
public void testGet() { public void testGet() {
assertTrue(TERTIARY_LIST.get(0)); assertEquals(true, (boolean) TERTIARY_LIST.get(0));
assertFalse(TERTIARY_LIST.get(1)); assertEquals(false, (boolean) TERTIARY_LIST.get(1));
assertTrue(TERTIARY_LIST.get(2)); assertEquals(true, (boolean) TERTIARY_LIST.get(2));
try { try {
TERTIARY_LIST.get(-1); TERTIARY_LIST.get(-1);
@ -121,9 +121,9 @@ public class BooleanArrayListTest extends TestCase {
} }
public void testGetBoolean() { public void testGetBoolean() {
assertTrue(TERTIARY_LIST.getBoolean(0)); assertEquals(true, TERTIARY_LIST.getBoolean(0));
assertFalse(TERTIARY_LIST.getBoolean(1)); assertEquals(false, TERTIARY_LIST.getBoolean(1));
assertTrue(TERTIARY_LIST.getBoolean(2)); assertEquals(true, TERTIARY_LIST.getBoolean(2));
try { try {
TERTIARY_LIST.get(-1); TERTIARY_LIST.get(-1);
@ -162,11 +162,11 @@ public class BooleanArrayListTest extends TestCase {
list.addBoolean(false); list.addBoolean(false);
list.addBoolean(false); list.addBoolean(false);
assertFalse(list.set(0, true)); assertEquals(false, (boolean) list.set(0, true));
assertTrue(list.getBoolean(0)); assertEquals(true, list.getBoolean(0));
assertFalse(list.set(1, false)); assertEquals(false, (boolean) list.set(1, false));
assertFalse(list.getBoolean(1)); assertEquals(false, list.getBoolean(1));
try { try {
list.set(-1, false); list.set(-1, false);
@ -187,11 +187,11 @@ public class BooleanArrayListTest extends TestCase {
list.addBoolean(true); list.addBoolean(true);
list.addBoolean(true); list.addBoolean(true);
assertTrue(list.setBoolean(0, false)); assertEquals(true, list.setBoolean(0, false));
assertFalse(list.getBoolean(0)); assertEquals(false, list.getBoolean(0));
assertTrue(list.setBoolean(1, false)); assertEquals(true, list.setBoolean(1, false));
assertFalse(list.getBoolean(1)); assertEquals(false, list.getBoolean(1));
try { try {
list.setBoolean(-1, false); list.setBoolean(-1, false);
@ -255,8 +255,8 @@ public class BooleanArrayListTest extends TestCase {
assertTrue(list.addAll(Collections.singleton(true))); assertTrue(list.addAll(Collections.singleton(true)));
assertEquals(1, list.size()); assertEquals(1, list.size());
assertTrue(list.get(0)); assertEquals(true, (boolean) list.get(0));
assertTrue(list.getBoolean(0)); assertEquals(true, list.getBoolean(0));
assertTrue(list.addAll(asList(false, true, false, true, false))); assertTrue(list.addAll(asList(false, true, false, true, false)));
assertEquals(asList(true, false, true, false, true, false), list); assertEquals(asList(true, false, true, false, true, false), list);
@ -268,9 +268,16 @@ public class BooleanArrayListTest extends TestCase {
assertFalse(list.addAll(BooleanArrayList.emptyList())); assertFalse(list.addAll(BooleanArrayList.emptyList()));
} }
public void testEquals() {
BooleanArrayList list1 = new BooleanArrayList();
BooleanArrayList list2 = new BooleanArrayList();
assertEquals(list1, list2);
}
public void testRemove() { public void testRemove() {
list.addAll(TERTIARY_LIST); list.addAll(TERTIARY_LIST);
assertTrue(list.remove(0)); assertEquals(true, (boolean) list.remove(0));
assertEquals(asList(false, true), list); assertEquals(asList(false, true), list);
assertTrue(list.remove(Boolean.TRUE)); assertTrue(list.remove(Boolean.TRUE));
@ -279,7 +286,7 @@ public class BooleanArrayListTest extends TestCase {
assertFalse(list.remove(Boolean.TRUE)); assertFalse(list.remove(Boolean.TRUE));
assertEquals(asList(false), list); assertEquals(asList(false), list);
assertFalse(list.remove(0)); assertEquals(false, (boolean) list.remove(0));
assertEquals(asList(), list); assertEquals(asList(), list);
try { try {
@ -296,13 +303,22 @@ public class BooleanArrayListTest extends TestCase {
} }
} }
public void testRemoveEndOfCapacity() { public void testRemoveEnd_listAtCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1); BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addBoolean(true); toRemove.addBoolean(true);
toRemove.remove(0); toRemove.remove(0);
assertEquals(0, toRemove.size()); assertEquals(0, toRemove.size());
} }
public void testRemove_listAtCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(2);
toRemove.addBoolean(true);
toRemove.addBoolean(false);
toRemove.remove(0);
assertEquals(1, toRemove.size());
assertEquals(false, (boolean) toRemove.get(0));
}
public void testSublistRemoveEndOfCapacity() { public void testSublistRemoveEndOfCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1); BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addBoolean(true); toRemove.addBoolean(true);

@ -30,6 +30,7 @@
package com.google.protobuf; package com.google.protobuf;
import static org.junit.Assert.assertArrayEquals;
import protobuf_unittest.UnittestProto.BoolMessage; import protobuf_unittest.UnittestProto.BoolMessage;
import protobuf_unittest.UnittestProto.Int32Message; import protobuf_unittest.UnittestProto.Int32Message;
import protobuf_unittest.UnittestProto.Int64Message; import protobuf_unittest.UnittestProto.Int64Message;
@ -88,7 +89,7 @@ public class CodedInputStreamTest extends TestCase {
if (blockSize > DEFAULT_BLOCK_SIZE) { if (blockSize > DEFAULT_BLOCK_SIZE) {
blockSize = DEFAULT_BLOCK_SIZE; blockSize = DEFAULT_BLOCK_SIZE;
} }
ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>(); ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
for (int i = 0; i < data.length; i += blockSize) { for (int i = 0; i < data.length; i += blockSize) {
int rl = Math.min(blockSize, data.length - i); int rl = Math.min(blockSize, data.length - i);
ByteBuffer rb = ByteBuffer.allocateDirect(rl); ByteBuffer rb = ByteBuffer.allocateDirect(rl);
@ -105,7 +106,7 @@ public class CodedInputStreamTest extends TestCase {
if (blockSize > DEFAULT_BLOCK_SIZE) { if (blockSize > DEFAULT_BLOCK_SIZE) {
blockSize = DEFAULT_BLOCK_SIZE; blockSize = DEFAULT_BLOCK_SIZE;
} }
ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>(); ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
for (int i = 0; i < data.length; i += blockSize) { for (int i = 0; i < data.length; i += blockSize) {
int rl = Math.min(blockSize, data.length - i); int rl = Math.min(blockSize, data.length - i);
ByteBuffer rb = ByteBuffer.allocateDirect(rl); ByteBuffer rb = ByteBuffer.allocateDirect(rl);
@ -117,8 +118,6 @@ public class CodedInputStreamTest extends TestCase {
} }
}; };
CodedInputStream newDecoder(byte[] data) { CodedInputStream newDecoder(byte[] data) {
return newDecoder(data, data.length); return newDecoder(data, data.length);
} }
@ -144,21 +143,37 @@ public class CodedInputStreamTest extends TestCase {
*/ */
private static final class SmallBlockInputStream extends FilterInputStream { private static final class SmallBlockInputStream extends FilterInputStream {
private final int blockSize; private final int blockSize;
private int skipCalls;
private int readCalls;
public SmallBlockInputStream(byte[] data, int blockSize) { public SmallBlockInputStream(byte[] data, int blockSize) {
super(new ByteArrayInputStream(data)); super(new ByteArrayInputStream(data));
this.blockSize = blockSize; this.blockSize = blockSize;
} }
@Override
public int read() throws IOException {
readCalls++;
return super.read();
}
@Override @Override
public int read(byte[] b) throws IOException { public int read(byte[] b) throws IOException {
readCalls++;
return super.read(b, 0, Math.min(b.length, blockSize)); return super.read(b, 0, Math.min(b.length, blockSize));
} }
@Override @Override
public int read(byte[] b, int off, int len) throws IOException { public int read(byte[] b, int off, int len) throws IOException {
readCalls++;
return super.read(b, off, Math.min(len, blockSize)); return super.read(b, off, Math.min(len, blockSize));
} }
@Override
public long skip(long len) throws IOException {
skipCalls++;
return super.skip(Math.min(len, blockSize));
}
} }
private void assertDataConsumed(String msg, byte[] data, CodedInputStream input) private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
@ -430,6 +445,41 @@ public class CodedInputStreamTest extends TestCase {
} }
} }
/**
* Test that calling skipRawBytes (when not merging a message) actually skips from the underlying
* inputstream, regardless of the buffer size used.
*/
public void testSkipRawBytesActuallySkips() throws Exception {
SmallBlockInputStream bytes = new SmallBlockInputStream(new byte[] {1, 2, 3, 4, 5}, 3);
CodedInputStream input = CodedInputStream.newInstance(bytes, 1); // Tiny buffer
input.skipRawBytes(3);
input.skipRawBytes(2);
assertEquals(2, bytes.skipCalls);
assertEquals(0, bytes.readCalls);
}
public void testSkipHugeBlob() throws Exception {
// Allocate and initialize a 1MB blob.
int blobSize = 1 << 20;
byte[] blob = new byte[blobSize];
for (int i = 0; i < blob.length; i++) {
blob[i] = (byte) i;
}
for (InputType inputType : InputType.values()) {
CodedInputStream decoder = inputType.newDecoder(blob);
decoder.skipRawBytes(blobSize - 10);
byte[] remaining = decoder.readRawBytes(10);
assertArrayEquals(Arrays.copyOfRange(blob, blobSize - 10, blobSize), remaining);
}
}
/** Skipping a huge blob should not allocate excessive memory, so there should be no limit */
public void testSkipMaliciouslyHugeBlob() throws Exception {
InputStream is = new RepeatingInputStream(new byte[]{1}, Integer.MAX_VALUE);
CodedInputStream.newInstance(is).skipRawBytes(Integer.MAX_VALUE);
}
public void testReadHugeBlob() throws Exception { public void testReadHugeBlob() throws Exception {
// Allocate and initialize a 1MB blob. // Allocate and initialize a 1MB blob.
byte[] blob = new byte[1 << 20]; byte[] blob = new byte[1 << 20];
@ -485,8 +535,9 @@ public class CodedInputStreamTest extends TestCase {
} }
/** /**
* Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or
* in size (2G or Integer#MAX_SIZE). * Integer#MAX_SIZE).
*
* @throws IOException * @throws IOException
*/ */
public void testParseMessagesCloseTo2G() throws IOException { public void testParseMessagesCloseTo2G() throws IOException {
@ -501,8 +552,9 @@ public class CodedInputStreamTest extends TestCase {
} }
/** /**
* Test there is an exception if a message exceeds * Test there is an exception if a message exceeds CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G
* CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or Integer#MAX_SIZE). * or Integer#MAX_SIZE).
*
* @throws IOException * @throws IOException
*/ */
public void testParseMessagesOver2G() throws IOException { public void testParseMessagesOver2G() throws IOException {
@ -674,9 +726,10 @@ public class CodedInputStreamTest extends TestCase {
// Input is two string with length 9 and one raw byte. // Input is two string with length 9 and one raw byte.
byte[] rawInput = rawOutput.toByteArray(); byte[] rawInput = rawOutput.toByteArray();
for (int inputStreamBufferLength = 8; for (int inputStreamBufferLength = 8;
inputStreamBufferLength <= rawInput.length + 1; inputStreamBufferLength++) { inputStreamBufferLength <= rawInput.length + 1;
CodedInputStream input = CodedInputStream.newInstance( inputStreamBufferLength++) {
new ByteArrayInputStream(rawInput), inputStreamBufferLength); CodedInputStream input =
CodedInputStream.newInstance(new ByteArrayInputStream(rawInput), inputStreamBufferLength);
input.setSizeLimit(rawInput.length - 1); input.setSizeLimit(rawInput.length - 1);
input.readString(); input.readString();
input.readString(); input.readString();
@ -690,8 +743,7 @@ public class CodedInputStreamTest extends TestCase {
} }
public void testIsAtEnd() throws Exception { public void testIsAtEnd() throws Exception {
CodedInputStream input = CodedInputStream.newInstance( CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(new byte[5]));
new ByteArrayInputStream(new byte[5]));
try { try {
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
assertEquals(false, input.isAtEnd()); assertEquals(false, input.isAtEnd());
@ -715,8 +767,7 @@ public class CodedInputStreamTest extends TestCase {
output.flush(); output.flush();
byte[] rawInput = rawOutput.toByteArray(); byte[] rawInput = rawOutput.toByteArray();
CodedInputStream input = CodedInputStream.newInstance( CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(rawInput));
new ByteArrayInputStream(rawInput));
// The length of the whole rawInput // The length of the whole rawInput
input.setSizeLimit(11); input.setSizeLimit(11);
// Some number that is smaller than the rawInput's length // Some number that is smaller than the rawInput's length
@ -726,8 +777,8 @@ public class CodedInputStreamTest extends TestCase {
input.readString(); input.readString();
fail("Should have thrown an exception"); fail("Should have thrown an exception");
} catch (InvalidProtocolBufferException expected) { } catch (InvalidProtocolBufferException expected) {
assertEquals(expected.getMessage(), assertEquals(
InvalidProtocolBufferException.truncatedMessage().getMessage()); expected.getMessage(), InvalidProtocolBufferException.truncatedMessage().getMessage());
} }
} }
@ -936,7 +987,8 @@ public class CodedInputStreamTest extends TestCase {
output.flush(); output.flush();
byte[] data = rawOutput.toByteString().toByteArray(); byte[] data = rawOutput.toByteString().toByteArray();
CodedInputStream input = CodedInputStream.newInstance( CodedInputStream input =
CodedInputStream.newInstance(
new ByteArrayInputStream(data) { new ByteArrayInputStream(data) {
@Override @Override
public synchronized int available() { public synchronized int available() {
@ -959,7 +1011,8 @@ public class CodedInputStreamTest extends TestCase {
output.flush(); output.flush();
byte[] data = rawOutput.toByteString().toByteArray(); byte[] data = rawOutput.toByteString().toByteArray();
CodedInputStream input = CodedInputStream.newInstance( CodedInputStream input =
CodedInputStream.newInstance(
new ByteArrayInputStream(data) { new ByteArrayInputStream(data) {
@Override @Override
public synchronized int available() { public synchronized int available() {

@ -79,8 +79,7 @@ public class DescriptorsTest extends TestCase {
private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL; private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
public void testFieldTypeEnumMapping() throws Exception { public void testFieldTypeEnumMapping() throws Exception {
assertEquals(FieldDescriptor.Type.values().length, assertEquals(FieldDescriptor.Type.values().length, FieldDescriptorProto.Type.values().length);
FieldDescriptorProto.Type.values().length);
for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) { for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
FieldDescriptorProto.Type protoType = type.toProto(); FieldDescriptorProto.Type protoType = type.toProto();
assertEquals("TYPE_" + type.name(), protoType.name()); assertEquals("TYPE_" + type.name(), protoType.name());
@ -95,11 +94,9 @@ public class DescriptorsTest extends TestCase {
assertEquals("protobuf_unittest", file.getPackage()); assertEquals("protobuf_unittest", file.getPackage());
assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname()); assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
assertEquals("google/protobuf/unittest.proto", assertEquals("google/protobuf/unittest.proto", file.toProto().getName());
file.toProto().getName());
assertEquals(Arrays.asList(UnittestImport.getDescriptor()), assertEquals(Arrays.asList(UnittestImport.getDescriptor()), file.getDependencies());
file.getDependencies());
Descriptor messageType = TestAllTypes.getDescriptor(); Descriptor messageType = TestAllTypes.getDescriptor();
assertEquals(messageType, file.getMessageTypes().get(0)); assertEquals(messageType, file.getMessageTypes().get(0));
@ -115,8 +112,8 @@ public class DescriptorsTest extends TestCase {
assertEquals(enumType, file.findEnumTypeByName("ForeignEnum")); assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
assertNull(file.findEnumTypeByName("NoSuchType")); assertNull(file.findEnumTypeByName("NoSuchType"));
assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")); assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
assertEquals(Arrays.asList(ImportEnum.getDescriptor(), assertEquals(
ImportEnumForMap.getDescriptor()), Arrays.asList(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()),
UnittestImport.getDescriptor().getEnumTypes()); UnittestImport.getDescriptor().getEnumTypes());
for (int i = 0; i < file.getEnumTypes().size(); i++) { for (int i = 0; i < file.getEnumTypes().size(); i++) {
assertEquals(i, file.getEnumTypes().get(i).getIndex()); assertEquals(i, file.getEnumTypes().get(i).getIndex());
@ -127,22 +124,17 @@ public class DescriptorsTest extends TestCase {
assertEquals(service, file.findServiceByName("TestService")); assertEquals(service, file.findServiceByName("TestService"));
assertNull(file.findServiceByName("NoSuchType")); assertNull(file.findServiceByName("NoSuchType"));
assertNull(file.findServiceByName("protobuf_unittest.TestService")); assertNull(file.findServiceByName("protobuf_unittest.TestService"));
assertEquals(Collections.emptyList(), assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getServices());
UnittestImport.getDescriptor().getServices());
for (int i = 0; i < file.getServices().size(); i++) { for (int i = 0; i < file.getServices().size(); i++) {
assertEquals(i, file.getServices().get(i).getIndex()); assertEquals(i, file.getServices().get(i).getIndex());
} }
FieldDescriptor extension = FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
UnittestProto.optionalInt32Extension.getDescriptor();
assertEquals(extension, file.getExtensions().get(0)); assertEquals(extension, file.getExtensions().get(0));
assertEquals(extension, assertEquals(extension, file.findExtensionByName("optional_int32_extension"));
file.findExtensionByName("optional_int32_extension"));
assertNull(file.findExtensionByName("no_such_ext")); assertNull(file.findExtensionByName("no_such_ext"));
assertNull(file.findExtensionByName( assertNull(file.findExtensionByName("protobuf_unittest.optional_int32_extension"));
"protobuf_unittest.optional_int32_extension")); assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getExtensions());
assertEquals(Collections.emptyList(),
UnittestImport.getDescriptor().getExtensions());
for (int i = 0; i < file.getExtensions().size(); i++) { for (int i = 0; i < file.getExtensions().size(); i++) {
assertEquals(i, file.getExtensions().get(i).getIndex()); assertEquals(i, file.getExtensions().get(i).getIndex());
} }
@ -156,13 +148,11 @@ public class DescriptorsTest extends TestCase {
assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName()); assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
assertEquals(UnittestProto.getDescriptor(), messageType.getFile()); assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
assertNull(messageType.getContainingType()); assertNull(messageType.getContainingType());
assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(), assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(), messageType.getOptions());
messageType.getOptions());
assertEquals("TestAllTypes", messageType.toProto().getName()); assertEquals("TestAllTypes", messageType.toProto().getName());
assertEquals("NestedMessage", nestedType.getName()); assertEquals("NestedMessage", nestedType.getName());
assertEquals("protobuf_unittest.TestAllTypes.NestedMessage", assertEquals("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.getFullName());
nestedType.getFullName());
assertEquals(UnittestProto.getDescriptor(), nestedType.getFile()); assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
assertEquals(messageType, nestedType.getContainingType()); assertEquals(messageType, nestedType.getContainingType());
@ -194,36 +184,28 @@ public class DescriptorsTest extends TestCase {
public void testFieldDescriptor() throws Exception { public void testFieldDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor(); Descriptor messageType = TestAllTypes.getDescriptor();
FieldDescriptor primitiveField = FieldDescriptor primitiveField = messageType.findFieldByName("optional_int32");
messageType.findFieldByName("optional_int32"); FieldDescriptor enumField = messageType.findFieldByName("optional_nested_enum");
FieldDescriptor enumField = FieldDescriptor messageField = messageType.findFieldByName("optional_foreign_message");
messageType.findFieldByName("optional_nested_enum"); FieldDescriptor cordField = messageType.findFieldByName("optional_cord");
FieldDescriptor messageField = FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
messageType.findFieldByName("optional_foreign_message");
FieldDescriptor cordField =
messageType.findFieldByName("optional_cord");
FieldDescriptor extension =
UnittestProto.optionalInt32Extension.getDescriptor();
FieldDescriptor nestedExtension = TestRequired.single.getDescriptor(); FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
assertEquals("optional_int32", primitiveField.getName()); assertEquals("optional_int32", primitiveField.getName());
assertEquals("protobuf_unittest.TestAllTypes.optional_int32", assertEquals("protobuf_unittest.TestAllTypes.optional_int32", primitiveField.getFullName());
primitiveField.getFullName());
assertEquals(1, primitiveField.getNumber()); assertEquals(1, primitiveField.getNumber());
assertEquals(messageType, primitiveField.getContainingType()); assertEquals(messageType, primitiveField.getContainingType());
assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile()); assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType()); assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType()); assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), primitiveField.getOptions());
primitiveField.getOptions());
assertFalse(primitiveField.isExtension()); assertFalse(primitiveField.isExtension());
assertEquals("optional_int32", primitiveField.toProto().getName()); assertEquals("optional_int32", primitiveField.toProto().getName());
assertEquals("optional_nested_enum", enumField.getName()); assertEquals("optional_nested_enum", enumField.getName());
assertEquals(FieldDescriptor.Type.ENUM, enumField.getType()); assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType()); assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
assertEquals(TestAllTypes.NestedEnum.getDescriptor(), assertEquals(TestAllTypes.NestedEnum.getDescriptor(), enumField.getEnumType());
enumField.getEnumType());
assertEquals("optional_foreign_message", messageField.getName()); assertEquals("optional_foreign_message", messageField.getName());
assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType()); assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
@ -233,38 +215,29 @@ public class DescriptorsTest extends TestCase {
assertEquals("optional_cord", cordField.getName()); assertEquals("optional_cord", cordField.getName());
assertEquals(FieldDescriptor.Type.STRING, cordField.getType()); assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType()); assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
assertEquals(DescriptorProtos.FieldOptions.CType.CORD, assertEquals(DescriptorProtos.FieldOptions.CType.CORD, cordField.getOptions().getCtype());
cordField.getOptions().getCtype());
assertEquals("optional_int32_extension", extension.getName()); assertEquals("optional_int32_extension", extension.getName());
assertEquals("protobuf_unittest.optional_int32_extension", assertEquals("protobuf_unittest.optional_int32_extension", extension.getFullName());
extension.getFullName());
assertEquals(1, extension.getNumber()); assertEquals(1, extension.getNumber());
assertEquals(TestAllExtensions.getDescriptor(), assertEquals(TestAllExtensions.getDescriptor(), extension.getContainingType());
extension.getContainingType());
assertEquals(UnittestProto.getDescriptor(), extension.getFile()); assertEquals(UnittestProto.getDescriptor(), extension.getFile());
assertEquals(FieldDescriptor.Type.INT32, extension.getType()); assertEquals(FieldDescriptor.Type.INT32, extension.getType());
assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType()); assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), extension.getOptions());
extension.getOptions());
assertTrue(extension.isExtension()); assertTrue(extension.isExtension());
assertEquals(null, extension.getExtensionScope()); assertEquals(null, extension.getExtensionScope());
assertEquals("optional_int32_extension", extension.toProto().getName()); assertEquals("optional_int32_extension", extension.toProto().getName());
assertEquals("single", nestedExtension.getName()); assertEquals("single", nestedExtension.getName());
assertEquals("protobuf_unittest.TestRequired.single", assertEquals("protobuf_unittest.TestRequired.single", nestedExtension.getFullName());
nestedExtension.getFullName()); assertEquals(TestRequired.getDescriptor(), nestedExtension.getExtensionScope());
assertEquals(TestRequired.getDescriptor(),
nestedExtension.getExtensionScope());
} }
public void testFieldDescriptorLabel() throws Exception { public void testFieldDescriptorLabel() throws Exception {
FieldDescriptor requiredField = FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
TestRequired.getDescriptor().findFieldByName("a"); FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
FieldDescriptor optionalField = FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
TestAllTypes.getDescriptor().findFieldByName("optional_int32");
FieldDescriptor repeatedField =
TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
assertTrue(requiredField.isRequired()); assertTrue(requiredField.isRequired());
assertFalse(requiredField.isRepeated()); assertFalse(requiredField.isRepeated());
@ -292,8 +265,7 @@ public class DescriptorsTest extends TestCase {
d = TestExtremeDefaultValues.getDescriptor(); d = TestExtremeDefaultValues.getDescriptor();
assertEquals( assertEquals(
ByteString.copyFrom( ByteString.copyFrom("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
"\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
d.findFieldByName("escaped_bytes").getDefaultValue()); d.findFieldByName("escaped_bytes").getDefaultValue());
assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue()); assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue()); assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
@ -307,12 +279,10 @@ public class DescriptorsTest extends TestCase {
assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName()); assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
assertEquals(UnittestProto.getDescriptor(), enumType.getFile()); assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
assertNull(enumType.getContainingType()); assertNull(enumType.getContainingType());
assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(), assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(), enumType.getOptions());
enumType.getOptions());
assertEquals("NestedEnum", nestedType.getName()); assertEquals("NestedEnum", nestedType.getName());
assertEquals("protobuf_unittest.TestAllTypes.NestedEnum", assertEquals("protobuf_unittest.TestAllTypes.NestedEnum", nestedType.getFullName());
nestedType.getFullName());
assertEquals(UnittestProto.getDescriptor(), nestedType.getFile()); assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType()); assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
@ -339,18 +309,14 @@ public class DescriptorsTest extends TestCase {
MethodDescriptor fooMethod = service.getMethods().get(0); MethodDescriptor fooMethod = service.getMethods().get(0);
assertEquals("Foo", fooMethod.getName()); assertEquals("Foo", fooMethod.getName());
assertEquals(UnittestProto.FooRequest.getDescriptor(), assertEquals(UnittestProto.FooRequest.getDescriptor(), fooMethod.getInputType());
fooMethod.getInputType()); assertEquals(UnittestProto.FooResponse.getDescriptor(), fooMethod.getOutputType());
assertEquals(UnittestProto.FooResponse.getDescriptor(),
fooMethod.getOutputType());
assertEquals(fooMethod, service.findMethodByName("Foo")); assertEquals(fooMethod, service.findMethodByName("Foo"));
MethodDescriptor barMethod = service.getMethods().get(1); MethodDescriptor barMethod = service.getMethods().get(1);
assertEquals("Bar", barMethod.getName()); assertEquals("Bar", barMethod.getName());
assertEquals(UnittestProto.BarRequest.getDescriptor(), assertEquals(UnittestProto.BarRequest.getDescriptor(), barMethod.getInputType());
barMethod.getInputType()); assertEquals(UnittestProto.BarResponse.getDescriptor(), barMethod.getOutputType());
assertEquals(UnittestProto.BarResponse.getDescriptor(),
barMethod.getOutputType());
assertEquals(barMethod, service.findMethodByName("Bar")); assertEquals(barMethod, service.findMethodByName("Bar"));
assertNull(service.findMethodByName("NoSuchMethod")); assertNull(service.findMethodByName("NoSuchMethod"));
@ -367,58 +333,53 @@ public class DescriptorsTest extends TestCase {
// dependencies are also properly initialized. // dependencies are also properly initialized.
Descriptor descriptor = Descriptor descriptor =
TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor() TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
.findFieldByName("field").getMessageType(); .findFieldByName("field")
.getMessageType();
assertTrue( assertTrue(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1)); assertEquals(
assertEquals(Integer.valueOf(-56), Integer.valueOf(-56),
descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1)); descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
FieldDescriptor field = descriptor.findFieldByName("field1"); FieldDescriptor field = descriptor.findFieldByName("field1");
assertNotNull(field); assertNotNull(field);
assertTrue( assertTrue(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1)); assertEquals(
assertEquals(Long.valueOf(8765432109L), Long.valueOf(8765432109L),
field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1)); field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
OneofDescriptor oneof = descriptor.getOneofs().get(0); OneofDescriptor oneof = descriptor.getOneofs().get(0);
assertNotNull(oneof); assertNotNull(oneof);
assertTrue( assertTrue(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1)); assertEquals(
assertEquals(Integer.valueOf(-99), Integer.valueOf(-99), oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
EnumDescriptor enumType = EnumDescriptor enumType =
UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor(); UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
assertTrue( assertTrue(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1)); assertEquals(
assertEquals(Integer.valueOf(-789), Integer.valueOf(-789), enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
ServiceDescriptor service = ServiceDescriptor service = UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
assertTrue( assertTrue(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1)); assertEquals(
assertEquals(Long.valueOf(-9876543210L), Long.valueOf(-9876543210L),
service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1)); service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
MethodDescriptor method = service.findMethodByName("Foo"); MethodDescriptor method = service.findMethodByName("Foo");
assertNotNull(method); assertNotNull(method);
assertTrue( assertTrue(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1)); assertEquals(
assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2, UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
method.getOptions().getExtension(UnittestCustomOptions.methodOpt1)); method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
} }
/** /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */
* Test that the FieldDescriptor.Type enum is the same as the
* WireFormat.FieldType enum.
*/
public void testFieldTypeTablesMatch() throws Exception { public void testFieldTypeTablesMatch() throws Exception {
FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values(); FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
WireFormat.FieldType[] values2 = WireFormat.FieldType.values(); WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
@ -430,10 +391,7 @@ public class DescriptorsTest extends TestCase {
} }
} }
/** /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */
* Test that the FieldDescriptor.JavaType enum is the same as the
* WireFormat.JavaType enum.
*/
public void testJavaTypeTablesMatch() throws Exception { public void testJavaTypeTablesMatch() throws Exception {
FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values(); FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
WireFormat.JavaType[] values2 = WireFormat.JavaType.values(); WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
@ -448,20 +406,19 @@ public class DescriptorsTest extends TestCase {
public void testEnormousDescriptor() throws Exception { public void testEnormousDescriptor() throws Exception {
// The descriptor for this file is larger than 64k, yet it did not cause // The descriptor for this file is larger than 64k, yet it did not cause
// a compiler error due to an over-long string literal. // a compiler error due to an over-long string literal.
assertTrue( assertTrue(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize() > 65536);
UnittestEnormousDescriptor.getDescriptor()
.toProto().getSerializedSize() > 65536);
} }
/** /** Tests that the DescriptorValidationException works as intended. */
* Tests that the DescriptorValidationException works as intended.
*/
public void testDescriptorValidatorException() throws Exception { public void testDescriptorValidatorException() throws Exception {
FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder() FileDescriptorProto fileDescriptorProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Foo") .setName("Foo")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_INT32) .setType(FieldDescriptorProto.Type.TYPE_INT32)
.setName("foo") .setName("foo")
@ -471,8 +428,7 @@ public class DescriptorsTest extends TestCase {
.build()) .build())
.build(); .build();
try { try {
Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
new FileDescriptor[0]);
fail("DescriptorValidationException expected"); fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) { } catch (DescriptorValidationException e) {
// Expected; check that the error message contains some useful hints // Expected; check that the error message contains some useful hints
@ -485,24 +441,29 @@ public class DescriptorsTest extends TestCase {
} }
/** /**
* Tests the translate/crosslink for an example where a message field's name * Tests the translate/crosslink for an example where a message field's name and type name are the
* and type name are the same. * same.
*/ */
public void testDescriptorComplexCrosslink() throws Exception { public void testDescriptorComplexCrosslink() throws Exception {
FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder() FileDescriptorProto fileDescriptorProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Foo") .setName("Foo")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_INT32) .setType(FieldDescriptorProto.Type.TYPE_INT32)
.setName("foo") .setName("foo")
.setNumber(1) .setNumber(1)
.build()) .build())
.build()) .build())
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Bar") .setName("Bar")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Foo") .setTypeName("Foo")
.setName("Foo") .setName("Foo")
@ -512,8 +473,7 @@ public class DescriptorsTest extends TestCase {
.build(); .build();
// translate and crosslink // translate and crosslink
FileDescriptor file = FileDescriptor file =
Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
new FileDescriptor[0]);
// verify resulting descriptors // verify resulting descriptors
assertNotNull(file); assertNotNull(file);
List<Descriptor> msglist = file.getMessageTypes(); List<Descriptor> msglist = file.getMessageTypes();
@ -535,57 +495,52 @@ public class DescriptorsTest extends TestCase {
} }
public void testDependencyOrder() throws Exception { public void testDependencyOrder() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
.setName("foo.proto").build(); FileDescriptorProto barProto =
FileDescriptorProto barProto = FileDescriptorProto.newBuilder() FileDescriptorProto.newBuilder().setName("bar.proto").addDependency("foo.proto").build();
.setName("bar.proto") FileDescriptorProto bazProto =
.addDependency("foo.proto") FileDescriptorProto.newBuilder()
.build();
FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
.setName("baz.proto") .setName("baz.proto")
.addDependency("foo.proto") .addDependency("foo.proto")
.addDependency("bar.proto") .addDependency("bar.proto")
.addPublicDependency(0) .addPublicDependency(0)
.addPublicDependency(1) .addPublicDependency(1)
.build(); .build();
FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
new FileDescriptor[0]); FileDescriptor barFile =
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
new FileDescriptor[] {fooFile});
// Items in the FileDescriptor array can be in any order. // Items in the FileDescriptor array can be in any order.
Descriptors.FileDescriptor.buildFrom(bazProto, Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile});
new FileDescriptor[] {fooFile, barFile}); Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile});
Descriptors.FileDescriptor.buildFrom(bazProto,
new FileDescriptor[] {barFile, fooFile});
} }
public void testInvalidPublicDependency() throws Exception { public void testInvalidPublicDependency() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
.setName("foo.proto").build(); FileDescriptorProto barProto =
FileDescriptorProto barProto = FileDescriptorProto.newBuilder() FileDescriptorProto.newBuilder()
.setName("boo.proto") .setName("boo.proto")
.addDependency("foo.proto") .addDependency("foo.proto")
.addPublicDependency(1) // Error, should be 0. .addPublicDependency(1) // Error, should be 0.
.build(); .build();
FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
new FileDescriptor[0]);
try { try {
Descriptors.FileDescriptor.buildFrom(barProto, Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
new FileDescriptor[] {fooFile});
fail("DescriptorValidationException expected"); fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) { } catch (DescriptorValidationException e) {
assertTrue( assertTrue(e.getMessage().indexOf("Invalid public dependency index.") != -1);
e.getMessage().indexOf("Invalid public dependency index.") != -1);
} }
} }
public void testUnknownFieldsDenied() throws Exception { public void testUnknownFieldsDenied() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Foo") .setName("Foo")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar") .setTypeName("Bar")
.setName("bar") .setName("bar")
@ -602,12 +557,15 @@ public class DescriptorsTest extends TestCase {
} }
public void testUnknownFieldsAllowed() throws Exception { public void testUnknownFieldsAllowed() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addDependency("bar.proto") .addDependency("bar.proto")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Foo") .setName("Foo")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar") .setTypeName("Bar")
.setName("bar") .setName("bar")
@ -617,33 +575,36 @@ public class DescriptorsTest extends TestCase {
} }
public void testHiddenDependency() throws Exception { public void testHiddenDependency() throws Exception {
FileDescriptorProto barProto = FileDescriptorProto.newBuilder() FileDescriptorProto barProto =
FileDescriptorProto.newBuilder()
.setName("bar.proto") .setName("bar.proto")
.addMessageType(DescriptorProto.newBuilder().setName("Bar")) .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
.build(); .build();
FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder() FileDescriptorProto forwardProto =
FileDescriptorProto.newBuilder()
.setName("forward.proto") .setName("forward.proto")
.addDependency("bar.proto") .addDependency("bar.proto")
.build(); .build();
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addDependency("forward.proto") .addDependency("forward.proto")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Foo") .setName("Foo")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar") .setTypeName("Bar")
.setName("bar") .setName("bar")
.setNumber(1))) .setNumber(1)))
.build(); .build();
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom( FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
barProto, new FileDescriptor[0]); FileDescriptor forwardFile =
FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom( Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
forwardProto, new FileDescriptor[] {barFile});
try { try {
Descriptors.FileDescriptor.buildFrom( Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
fooProto, new FileDescriptor[] {forwardFile});
fail("DescriptorValidationException expected"); fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) { } catch (DescriptorValidationException e) {
assertTrue(e.getMessage().indexOf("Bar") != -1); assertTrue(e.getMessage().indexOf("Bar") != -1);
@ -652,65 +613,67 @@ public class DescriptorsTest extends TestCase {
} }
public void testPublicDependency() throws Exception { public void testPublicDependency() throws Exception {
FileDescriptorProto barProto = FileDescriptorProto.newBuilder() FileDescriptorProto barProto =
FileDescriptorProto.newBuilder()
.setName("bar.proto") .setName("bar.proto")
.addMessageType(DescriptorProto.newBuilder().setName("Bar")) .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
.build(); .build();
FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder() FileDescriptorProto forwardProto =
FileDescriptorProto.newBuilder()
.setName("forward.proto") .setName("forward.proto")
.addDependency("bar.proto") .addDependency("bar.proto")
.addPublicDependency(0) .addPublicDependency(0)
.build(); .build();
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addDependency("forward.proto") .addDependency("forward.proto")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Foo") .setName("Foo")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar") .setTypeName("Bar")
.setName("bar") .setName("bar")
.setNumber(1))) .setNumber(1)))
.build(); .build();
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom( FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
barProto, new FileDescriptor[0]); FileDescriptor forwardFile =
FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom( Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
forwardProto, new FileDescriptor[]{barFile}); Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
Descriptors.FileDescriptor.buildFrom(
fooProto, new FileDescriptor[] {forwardFile});
} }
/** /** Tests the translate/crosslink for an example with a more complex namespace referencing. */
* Tests the translate/crosslink for an example with a more complex namespace
* referencing.
*/
public void testComplexNamespacePublicDependency() throws Exception { public void testComplexNamespacePublicDependency() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() FileDescriptorProto fooProto =
FileDescriptorProto.newBuilder()
.setName("bar.proto") .setName("bar.proto")
.setPackage("a.b.c.d.bar.shared") .setPackage("a.b.c.d.bar.shared")
.addEnumType(EnumDescriptorProto.newBuilder() .addEnumType(
EnumDescriptorProto.newBuilder()
.setName("MyEnum") .setName("MyEnum")
.addValue(EnumValueDescriptorProto.newBuilder() .addValue(EnumValueDescriptorProto.newBuilder().setName("BLAH").setNumber(1)))
.setName("BLAH")
.setNumber(1)))
.build(); .build();
FileDescriptorProto barProto = FileDescriptorProto.newBuilder() FileDescriptorProto barProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addDependency("bar.proto") .addDependency("bar.proto")
.setPackage("a.b.c.d.foo.shared") .setPackage("a.b.c.d.foo.shared")
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("MyMessage") .setName("MyMessage")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_REPEATED) .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
.setTypeName("bar.shared.MyEnum") .setTypeName("bar.shared.MyEnum")
.setName("MyField") .setName("MyField")
.setNumber(1))) .setNumber(1)))
.build(); .build();
// translate and crosslink // translate and crosslink
FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom( FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
fooProto, new FileDescriptor[0]); FileDescriptor barFile =
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom( Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
barProto, new FileDescriptor[]{fooFile});
// verify resulting descriptors // verify resulting descriptors
assertNotNull(barFile); assertNotNull(barFile);
List<Descriptor> msglist = barFile.getMessageTypes(); List<Descriptor> msglist = barFile.getMessageTypes();
@ -726,15 +689,13 @@ public class DescriptorsTest extends TestCase {
assertTrue(field.getType() == FieldDescriptor.Type.ENUM); assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
assertTrue(field.getEnumType().getName().equals("MyEnum")); assertTrue(field.getEnumType().getName().equals("MyEnum"));
assertTrue(field.getEnumType().getFile().getName().equals("bar.proto")); assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
assertTrue(field.getEnumType().getFile().getPackage().equals( assertTrue(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared"));
"a.b.c.d.bar.shared"));
} }
} }
public void testOneofDescriptor() throws Exception { public void testOneofDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor(); Descriptor messageType = TestAllTypes.getDescriptor();
FieldDescriptor field = FieldDescriptor field = messageType.findFieldByName("oneof_nested_message");
messageType.findFieldByName("oneof_nested_message");
OneofDescriptor oneofDescriptor = field.getContainingOneof(); OneofDescriptor oneofDescriptor = field.getContainingOneof();
assertNotNull(oneofDescriptor); assertNotNull(oneofDescriptor);
assertSame(oneofDescriptor, messageType.getOneofs().get(0)); assertSame(oneofDescriptor, messageType.getOneofs().get(0));
@ -774,36 +735,38 @@ public class DescriptorsTest extends TestCase {
} }
public void testToString() { public void testToString() {
assertEquals("protobuf_unittest.TestAllTypes.optional_uint64", assertEquals(
UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber( "protobuf_unittest.TestAllTypes.optional_uint64",
UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER).toString()); UnittestProto.TestAllTypes.getDescriptor()
.findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
.toString());
} }
public void testPackedEnumField() throws Exception { public void testPackedEnumField() throws Exception {
FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder() FileDescriptorProto fileDescriptorProto =
FileDescriptorProto.newBuilder()
.setName("foo.proto") .setName("foo.proto")
.addEnumType(EnumDescriptorProto.newBuilder() .addEnumType(
EnumDescriptorProto.newBuilder()
.setName("Enum") .setName("Enum")
.addValue(EnumValueDescriptorProto.newBuilder() .addValue(
.setName("FOO") EnumValueDescriptorProto.newBuilder().setName("FOO").setNumber(1).build())
.setNumber(1)
.build())
.build()) .build())
.addMessageType(DescriptorProto.newBuilder() .addMessageType(
DescriptorProto.newBuilder()
.setName("Message") .setName("Message")
.addField(FieldDescriptorProto.newBuilder() .addField(
FieldDescriptorProto.newBuilder()
.setName("foo") .setName("foo")
.setTypeName("Enum") .setTypeName("Enum")
.setNumber(1) .setNumber(1)
.setLabel(FieldDescriptorProto.Label.LABEL_REPEATED) .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
.setOptions(DescriptorProtos.FieldOptions.newBuilder() .setOptions(
.setPacked(true) DescriptorProtos.FieldOptions.newBuilder().setPacked(true).build())
.build())
.build()) .build())
.build()) .build())
.build(); .build();
Descriptors.FileDescriptor.buildFrom( Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
fileDescriptorProto, new FileDescriptor[0]);
} }
public void testFieldJsonName() throws Exception { public void testFieldJsonName() throws Exception {

@ -266,6 +266,15 @@ public class DoubleArrayListTest extends TestCase {
assertFalse(list.addAll(DoubleArrayList.emptyList())); assertFalse(list.addAll(DoubleArrayList.emptyList()));
} }
public void testEquals() {
DoubleArrayList list1 = new DoubleArrayList();
DoubleArrayList list2 = new DoubleArrayList();
list1.addDouble(Double.longBitsToDouble(0x7ff0000000000001L));
list2.addDouble(Double.longBitsToDouble(0x7ff0000000000002L));
assertEquals(list1, list2);
}
public void testRemove() { public void testRemove() {
list.addAll(TERTIARY_LIST); list.addAll(TERTIARY_LIST);
assertEquals(1D, (double) list.remove(0), 0.0); assertEquals(1D, (double) list.remove(0), 0.0);
@ -294,13 +303,22 @@ public class DoubleArrayListTest extends TestCase {
} }
} }
public void testRemoveEndOfCapacity() { public void testRemoveEnd_listAtCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1); DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addDouble(3); toRemove.addDouble(3);
toRemove.remove(0); toRemove.remove(0);
assertEquals(0, toRemove.size()); assertEquals(0, toRemove.size());
} }
public void testRemove_listAtCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(2);
toRemove.addDouble(3);
toRemove.addDouble(4);
toRemove.remove(0);
assertEquals(1, toRemove.size());
assertEquals(4D, (double) toRemove.get(0));
}
public void testSublistRemoveEndOfCapacity() { public void testSublistRemoveEndOfCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1); DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addDouble(3); toRemove.addDouble(3);

@ -238,7 +238,7 @@ public class ExtensionRegistryFactoryTest extends TestCase {
classLoader.loadClass(ExtensionRegistryFactory.class.getName()); classLoader.loadClass(ExtensionRegistryFactory.class.getName());
Class<?> test = classLoader.loadClass(testClass.getName()); Class<?> test = classLoader.loadClass(testClass.getName());
String testName = getName(); String testName = getName();
test.getMethod(testName).invoke(test.newInstance()); test.getMethod(testName).invoke(test.getDeclaredConstructor().newInstance());
} }
/** /**

@ -266,6 +266,15 @@ public class FloatArrayListTest extends TestCase {
assertFalse(list.addAll(FloatArrayList.emptyList())); assertFalse(list.addAll(FloatArrayList.emptyList()));
} }
public void testEquals() {
FloatArrayList list1 = new FloatArrayList();
FloatArrayList list2 = new FloatArrayList();
list1.addFloat(Float.intBitsToFloat(0xff800001));
list2.addFloat(Float.intBitsToFloat(0xff800002));
assertEquals(list1, list2);
}
public void testRemove() { public void testRemove() {
list.addAll(TERTIARY_LIST); list.addAll(TERTIARY_LIST);
assertEquals(1F, (float) list.remove(0), 0.0f); assertEquals(1F, (float) list.remove(0), 0.0f);
@ -294,13 +303,22 @@ public class FloatArrayListTest extends TestCase {
} }
} }
public void testRemoveEndOfCapacity() { public void testRemoveEnd_listAtCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1); FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addFloat(3); toRemove.addFloat(3);
toRemove.remove(0); toRemove.remove(0);
assertEquals(0, toRemove.size()); assertEquals(0, toRemove.size());
} }
public void testRemove_listAtCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(2);
toRemove.addFloat(3);
toRemove.addFloat(4);
toRemove.remove(0);
assertEquals(1, toRemove.size());
assertEquals(4F, (float) toRemove.get(0));
}
public void testSublistRemoveEndOfCapacity() { public void testSublistRemoveEndOfCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1); FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addFloat(3); toRemove.addFloat(3);

@ -266,6 +266,13 @@ public class IntArrayListTest extends TestCase {
assertFalse(list.addAll(IntArrayList.emptyList())); assertFalse(list.addAll(IntArrayList.emptyList()));
} }
public void testEquals() {
IntArrayList list1 = new IntArrayList();
IntArrayList list2 = new IntArrayList();
assertEquals(list1, list2);
}
public void testRemove() { public void testRemove() {
list.addAll(TERTIARY_LIST); list.addAll(TERTIARY_LIST);
assertEquals(1, (int) list.remove(0)); assertEquals(1, (int) list.remove(0));
@ -294,13 +301,22 @@ public class IntArrayListTest extends TestCase {
} }
} }
public void testRemoveEndOfCapacity() { public void testRemoveEnd_listAtCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1); IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addInt(3); toRemove.addInt(3);
toRemove.remove(0); toRemove.remove(0);
assertEquals(0, toRemove.size()); assertEquals(0, toRemove.size());
} }
public void testRemove_listAtCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(2);
toRemove.addInt(3);
toRemove.addInt(4);
toRemove.remove(0);
assertEquals(1, toRemove.size());
assertEquals(4, (int) toRemove.get(0));
}
public void testSublistRemoveEndOfCapacity() { public void testSublistRemoveEndOfCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1); IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addInt(3); toRemove.addInt(3);

@ -168,7 +168,7 @@ public class IsValidUtf8Test extends TestCase {
// A sanity check. // A sanity check.
int actual = 0; int actual = 0;
for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) { for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
actual += shard.expected; actual = (int) (actual + shard.expected);
} }
assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual); assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual);
} }

@ -218,9 +218,9 @@ final class IsValidUtf8TestUtil {
private static List<Shard> generateFourByteShards(int numShards, long[] expected) { private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
assertEquals(numShards, expected.length); assertEquals(numShards, expected.length);
List<Shard> shards = new ArrayList<Shard>(numShards); List<Shard> shards = new ArrayList<Shard>(numShards);
long LIM = 1L << 32; long lim = 1L << 32;
long increment = LIM / numShards; long increment = lim / numShards;
assertTrue(LIM % numShards == 0); assertTrue(lim % numShards == 0);
for (int i = 0; i < numShards; i++) { for (int i = 0; i < numShards; i++) {
shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i])); shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
} }

@ -117,8 +117,8 @@ public class LazyFieldLiteTest extends TestCase {
LazyFieldLite original = createLazyFieldLiteFromMessage(message); LazyFieldLite original = createLazyFieldLiteFromMessage(message);
LazyFieldLite merged = new LazyFieldLite(); LazyFieldLite merged = new LazyFieldLite();
merged.merge(original); merged.merge(original);
TestAllExtensions value = (TestAllExtensions) merged.getValue( TestAllExtensions value =
TestAllExtensions.getDefaultInstance()); (TestAllExtensions) merged.getValue(TestAllExtensions.getDefaultInstance());
assertEquals(message, value); assertEquals(message, value);
} }
@ -130,8 +130,8 @@ public class LazyFieldLiteTest extends TestCase {
public void testInvalidProto() throws Exception { public void testInvalidProto() throws Exception {
// Silently fails and uses the default instance. // Silently fails and uses the default instance.
LazyFieldLite field = new LazyFieldLite( LazyFieldLite field =
TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid")); new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
assertEquals( assertEquals(
TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance())); TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
assertEquals(0, field.getSerializedSize()); assertEquals(0, field.getSerializedSize());
@ -175,8 +175,8 @@ public class LazyFieldLiteTest extends TestCase {
// Test a few different paths that involve one message that was not parsed. // Test a few different paths that involve one message that was not parsed.
TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build(); TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
LazyFieldLite valid = LazyFieldLite.fromValue(message); LazyFieldLite valid = LazyFieldLite.fromValue(message);
LazyFieldLite invalid = new LazyFieldLite( LazyFieldLite invalid =
TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid")); new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
invalid.merge(valid); invalid.merge(valid);
// We swallow the exception and just use the set field. // We swallow the exception and just use the set field.
@ -239,8 +239,7 @@ public class LazyFieldLiteTest extends TestCase {
} }
private void assertNotEqual(Object unexpected, Object actual) { private void assertNotEqual(Object unexpected, Object actual) {
assertFalse(unexpected == actual assertFalse(unexpected == actual || (unexpected != null && unexpected.equals(actual)));
|| (unexpected != null && unexpected.equals(actual)));
} }
} }

@ -81,7 +81,7 @@ public class LiteTest extends TestCase {
// //
// We put this in setUp() rather than in its own test method because we // We put this in setUp() rather than in its own test method because we
// need to make sure it runs before any actual tests. // need to make sure it runs before any actual tests.
assertTrue(TestNestedExtensionLite.nestedExtension != null); assertNotNull(TestNestedExtensionLite.nestedExtension);
} }
public void testLite() throws Exception { public void testLite() throws Exception {
@ -320,16 +320,16 @@ public class LiteTest extends TestCase {
assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage()); assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
message = builder.build(); message = builder.build();
ForeignMessageLite.Builder foreignMessageBuilder = ForeignMessageLite.newBuilder().setC(3); ForeignMessageLite foreignMessageC3 = ForeignMessageLite.newBuilder().setC(3).build();
builder.setOptionalForeignMessage(foreignMessageBuilder); builder.setOptionalForeignMessage(foreignMessageC3);
assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage()); assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage()); assertEquals(foreignMessageC3, builder.getOptionalForeignMessage());
messageAfterBuild = builder.build(); messageAfterBuild = builder.build();
assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage()); assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage()); assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
builder.clearOptionalForeignMessage(); builder.clearOptionalForeignMessage();
assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage()); assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage()); assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
message = builder.build(); message = builder.build();
OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build(); OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build();
@ -1033,11 +1033,11 @@ public class LiteTest extends TestCase {
builder.clearRepeatedForeignMessage(); builder.clearRepeatedForeignMessage();
message = builder.build(); message = builder.build();
builder.addRepeatedForeignMessage(foreignMessageBuilder); builder.addRepeatedForeignMessage(foreignMessageC3);
messageAfterBuild = builder.build(); messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount()); assertEquals(0, message.getRepeatedForeignMessageCount());
builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance()); builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0)); assertEquals(foreignMessageC3, messageAfterBuild.getRepeatedForeignMessage(0));
assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0)); assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage(); builder.clearRepeatedForeignMessage();
@ -1045,9 +1045,9 @@ public class LiteTest extends TestCase {
builder.addRepeatedForeignMessage(0, foreignMessage); builder.addRepeatedForeignMessage(0, foreignMessage);
messageAfterBuild = builder.build(); messageAfterBuild = builder.build();
assertEquals(0, message.getRepeatedForeignMessageCount()); assertEquals(0, message.getRepeatedForeignMessageCount());
builder.setRepeatedForeignMessage(0, foreignMessageBuilder); builder.setRepeatedForeignMessage(0, foreignMessageC3);
assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0)); assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0)); assertEquals(foreignMessageC3, builder.getRepeatedForeignMessage(0));
builder.clearRepeatedForeignMessage(); builder.clearRepeatedForeignMessage();
message = builder.build(); message = builder.build();
@ -1533,7 +1533,7 @@ public class LiteTest extends TestCase {
private static void assertToStringEquals(String expected, MessageLite message) { private static void assertToStringEquals(String expected, MessageLite message) {
String toString = message.toString(); String toString = message.toString();
assertEquals('#', toString.charAt(0)); assertEquals('#', toString.charAt(0));
if (toString.indexOf("\n") >= 0) { if (toString.contains("\n")) {
toString = toString.substring(toString.indexOf("\n") + 1); toString = toString.substring(toString.indexOf("\n") + 1);
} else { } else {
toString = ""; toString = "";
@ -2210,29 +2210,29 @@ public class LiteTest extends TestCase {
public void testAddAllIteratesOnce() { public void testAddAllIteratesOnce() {
TestAllTypesLite.newBuilder() TestAllTypesLite.newBuilder()
.addAllRepeatedBool(new OneTimeIterableList(false)) .addAllRepeatedBool(new OneTimeIterableList<>(false))
.addAllRepeatedInt32(new OneTimeIterableList(0)) .addAllRepeatedInt32(new OneTimeIterableList<>(0))
.addAllRepeatedInt64(new OneTimeIterableList(0L)) .addAllRepeatedInt64(new OneTimeIterableList<>(0L))
.addAllRepeatedFloat(new OneTimeIterableList(0f)) .addAllRepeatedFloat(new OneTimeIterableList<>(0f))
.addAllRepeatedDouble(new OneTimeIterableList(0d)) .addAllRepeatedDouble(new OneTimeIterableList<>(0d))
.addAllRepeatedBytes(new OneTimeIterableList(ByteString.EMPTY)) .addAllRepeatedBytes(new OneTimeIterableList<>(ByteString.EMPTY))
.addAllRepeatedString(new OneTimeIterableList("")) .addAllRepeatedString(new OneTimeIterableList<>(""))
.addAllRepeatedNestedMessage(new OneTimeIterableList(NestedMessage.getDefaultInstance())) .addAllRepeatedNestedMessage(new OneTimeIterableList<>(NestedMessage.getDefaultInstance()))
.addAllRepeatedBool(new OneTimeIterable(false)) .addAllRepeatedBool(new OneTimeIterable<>(false))
.addAllRepeatedInt32(new OneTimeIterable(0)) .addAllRepeatedInt32(new OneTimeIterable<>(0))
.addAllRepeatedInt64(new OneTimeIterable(0L)) .addAllRepeatedInt64(new OneTimeIterable<>(0L))
.addAllRepeatedFloat(new OneTimeIterable(0f)) .addAllRepeatedFloat(new OneTimeIterable<>(0f))
.addAllRepeatedDouble(new OneTimeIterable(0d)) .addAllRepeatedDouble(new OneTimeIterable<>(0d))
.addAllRepeatedBytes(new OneTimeIterable(ByteString.EMPTY)) .addAllRepeatedBytes(new OneTimeIterable<>(ByteString.EMPTY))
.addAllRepeatedString(new OneTimeIterable("")) .addAllRepeatedString(new OneTimeIterable<>(""))
.addAllRepeatedNestedMessage(new OneTimeIterable(NestedMessage.getDefaultInstance())) .addAllRepeatedNestedMessage(new OneTimeIterable<>(NestedMessage.getDefaultInstance()))
.build(); .build();
} }
public void testAddAllIteratesOnce_throwsOnNull() { public void testAddAllIteratesOnce_throwsOnNull() {
TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder(); TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
try { try {
builder.addAllRepeatedBool(new OneTimeIterableList(true, false, (Boolean) null)); builder.addAllRepeatedBool(new OneTimeIterableList<>(true, false, null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage()); assertEquals("Element at index 2 is null.", expected.getMessage());
@ -2240,7 +2240,7 @@ public class LiteTest extends TestCase {
} }
try { try {
builder.addAllRepeatedBool(new OneTimeIterable(true, false, (Boolean) null)); builder.addAllRepeatedBool(new OneTimeIterable<>(true, false, null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage()); assertEquals("Element at index 2 is null.", expected.getMessage());
@ -2249,7 +2249,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedBool(new OneTimeIterableList((Boolean) null)); builder.addAllRepeatedBool(new OneTimeIterableList<>((Boolean) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2258,7 +2258,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedInt32(new OneTimeIterableList((Integer) null)); builder.addAllRepeatedInt32(new OneTimeIterableList<>((Integer) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2267,7 +2267,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedInt64(new OneTimeIterableList((Long) null)); builder.addAllRepeatedInt64(new OneTimeIterableList<>((Long) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2276,7 +2276,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedFloat(new OneTimeIterableList((Float) null)); builder.addAllRepeatedFloat(new OneTimeIterableList<>((Float) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2285,7 +2285,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedDouble(new OneTimeIterableList((Double) null)); builder.addAllRepeatedDouble(new OneTimeIterableList<>((Double) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2294,7 +2294,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedBytes(new OneTimeIterableList((ByteString) null)); builder.addAllRepeatedBytes(new OneTimeIterableList<>((ByteString) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2303,7 +2303,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedString(new OneTimeIterableList("", "", (String) null, "")); builder.addAllRepeatedString(new OneTimeIterableList<>("", "", null, ""));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage()); assertEquals("Element at index 2 is null.", expected.getMessage());
@ -2312,7 +2312,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedString(new OneTimeIterable("", "", (String) null, "")); builder.addAllRepeatedString(new OneTimeIterable<>("", "", null, ""));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage()); assertEquals("Element at index 2 is null.", expected.getMessage());
@ -2321,7 +2321,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedString(new OneTimeIterableList((String) null)); builder.addAllRepeatedString(new OneTimeIterableList<>((String) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());
@ -2330,7 +2330,7 @@ public class LiteTest extends TestCase {
try { try {
builder = TestAllTypesLite.newBuilder(); builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedNestedMessage(new OneTimeIterableList((NestedMessage) null)); builder.addAllRepeatedNestedMessage(new OneTimeIterableList<>((NestedMessage) null));
fail(); fail();
} catch (NullPointerException expected) { } catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage()); assertEquals("Element at index 0 is null.", expected.getMessage());

@ -369,13 +369,13 @@ public class LiteralByteStringTest extends TestCase {
} }
@Override @Override
public void writeLazy(byte[] value, int offset, int length) throws IOException { public void write(ByteBuffer value) throws IOException {
Arrays.fill(value, offset, offset + length, (byte) 0); throw new UnsupportedOperationException();
} }
@Override @Override
public void write(ByteBuffer value) throws IOException { public void writeLazy(byte[] value, int offset, int length) throws IOException {
throw new UnsupportedOperationException(); Arrays.fill(value, offset, offset + length, (byte) 0);
} }
@Override @Override

@ -266,6 +266,13 @@ public class LongArrayListTest extends TestCase {
assertFalse(list.addAll(LongArrayList.emptyList())); assertFalse(list.addAll(LongArrayList.emptyList()));
} }
public void testEquals() {
LongArrayList list1 = new LongArrayList();
LongArrayList list2 = new LongArrayList();
assertEquals(list1, list2);
}
public void testRemove() { public void testRemove() {
list.addAll(TERTIARY_LIST); list.addAll(TERTIARY_LIST);
assertEquals(1L, (long) list.remove(0)); assertEquals(1L, (long) list.remove(0));
@ -294,13 +301,22 @@ public class LongArrayListTest extends TestCase {
} }
} }
public void testRemoveEndOfCapacity() { public void testRemoveEnd_listAtCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1); LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addLong(3); toRemove.addLong(3);
toRemove.remove(0); toRemove.remove(0);
assertEquals(0, toRemove.size()); assertEquals(0, toRemove.size());
} }
public void testRemove_listAtCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(2);
toRemove.addLong(3);
toRemove.addLong(4);
toRemove.remove(0);
assertEquals(1, toRemove.size());
assertEquals(4L, (long) toRemove.get(0));
}
public void testSublistRemoveEndOfCapacity() { public void testSublistRemoveEndOfCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1); LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addLong(3); toRemove.addLong(3);

@ -440,12 +440,12 @@ public final class MapForProto2LiteTest extends TestCase {
// We can't control the order of elements in a HashMap. The best we can do // We can't control the order of elements in a HashMap. The best we can do
// here is to add elements in different order. // here is to add elements in different order.
TestMap.Builder b1 = TestMap m1 =
TestMap.newBuilder() TestMap.newBuilder()
.putInt32ToInt32Field(1, 2) .putInt32ToInt32Field(1, 2)
.putInt32ToInt32Field(3, 4) .putInt32ToInt32Field(3, 4)
.putInt32ToInt32Field(5, 6); .putInt32ToInt32Field(5, 6)
TestMap m1 = b1.build(); .build();
TestMap.Builder b2 = TestMap.Builder b2 =
TestMap.newBuilder() TestMap.newBuilder()
@ -466,9 +466,12 @@ public final class MapForProto2LiteTest extends TestCase {
} }
public void testUnknownEnumValues() throws Exception { public void testUnknownEnumValues() throws Exception {
TestUnknownEnumValue.Builder builder = ByteString data =
TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321); TestUnknownEnumValue.newBuilder()
ByteString data = builder.build().toByteString(); .putInt32ToInt32Field(1, 1)
.putInt32ToInt32Field(2, 54321)
.build()
.toByteString();
TestMap message = TestMap.parseFrom(data); TestMap message = TestMap.parseFrom(data);
// Entries with unknown enum values will be stored into UnknownFieldSet so // Entries with unknown enum values will be stored into UnknownFieldSet so

@ -49,9 +49,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /** Unit tests for map fields in proto2 protos. */
* Unit tests for map fields in proto2 protos.
*/
public class MapForProto2Test extends TestCase { public class MapForProto2Test extends TestCase {
private void setMapValuesUsingMutableMap(TestMap.Builder builder) { private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
@ -88,23 +86,18 @@ public class MapForProto2Test extends TestCase {
.putInt32ToInt32Field(1, 11) .putInt32ToInt32Field(1, 11)
.putInt32ToInt32Field(2, 22) .putInt32ToInt32Field(2, 22)
.putInt32ToInt32Field(3, 33) .putInt32ToInt32Field(3, 33)
.putInt32ToStringField(1, "11") .putInt32ToStringField(1, "11")
.putInt32ToStringField(2, "22") .putInt32ToStringField(2, "22")
.putInt32ToStringField(3, "33") .putInt32ToStringField(3, "33")
.putInt32ToBytesField(1, TestUtil.toBytes("11")) .putInt32ToBytesField(1, TestUtil.toBytes("11"))
.putInt32ToBytesField(2, TestUtil.toBytes("22")) .putInt32ToBytesField(2, TestUtil.toBytes("22"))
.putInt32ToBytesField(3, TestUtil.toBytes("33")) .putInt32ToBytesField(3, TestUtil.toBytes("33"))
.putInt32ToEnumField(1, TestMap.EnumValue.FOO) .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
.putInt32ToEnumField(2, TestMap.EnumValue.BAR) .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
.putInt32ToEnumField(3, TestMap.EnumValue.BAZ) .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
.putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build()) .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
.putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build()) .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
.putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build()) .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
.putStringToInt32Field("1", 11) .putStringToInt32Field("1", 11)
.putStringToInt32Field("2", 22) .putStringToInt32Field("2", 22)
.putStringToInt32Field("3", 33); .putStringToInt32Field("3", 33);
@ -199,23 +192,18 @@ public class MapForProto2Test extends TestCase {
.putInt32ToInt32Field(1, 111) .putInt32ToInt32Field(1, 111)
.removeInt32ToInt32Field(2) .removeInt32ToInt32Field(2)
.putInt32ToInt32Field(4, 44) .putInt32ToInt32Field(4, 44)
.putInt32ToStringField(1, "111") .putInt32ToStringField(1, "111")
.removeInt32ToStringField(2) .removeInt32ToStringField(2)
.putInt32ToStringField(4, "44") .putInt32ToStringField(4, "44")
.putInt32ToBytesField(1, TestUtil.toBytes("111")) .putInt32ToBytesField(1, TestUtil.toBytes("111"))
.removeInt32ToBytesField(2) .removeInt32ToBytesField(2)
.putInt32ToBytesField(4, TestUtil.toBytes("44")) .putInt32ToBytesField(4, TestUtil.toBytes("44"))
.putInt32ToEnumField(1, TestMap.EnumValue.BAR) .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
.removeInt32ToEnumField(2) .removeInt32ToEnumField(2)
.putInt32ToEnumField(4, TestMap.EnumValue.QUX) .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
.putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build()) .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
.removeInt32ToMessageField(2) .removeInt32ToMessageField(2)
.putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build()) .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
.putStringToInt32Field("1", 111) .putStringToInt32Field("1", 111)
.removeStringToInt32Field("2") .removeStringToInt32Field("2")
.putStringToInt32Field("4", 44); .putStringToInt32Field("4", 44);
@ -432,7 +420,19 @@ public class MapForProto2Test extends TestCase {
assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
} }
//
private static <K, V> Map<K, V> newMap(K key1, V value1) {
Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);
return map;
}
//
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);
map.put(key2, value2);
return map;
}
public void testGettersAndSetters() throws Exception { public void testGettersAndSetters() throws Exception {
TestMap.Builder builder = TestMap.newBuilder(); TestMap.Builder builder = TestMap.newBuilder();
@ -543,30 +543,22 @@ public class MapForProto2Test extends TestCase {
ByteString bytes = TestUtil.toBytes("SOME BYTES"); ByteString bytes = TestUtil.toBytes("SOME BYTES");
String stringKey = "a string key"; String stringKey = "a string key";
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder() TestMap map =
.putInt32ToInt32Field(5, bytes) tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
.build());
assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1)); assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
.putInt32ToStringField(stringKey, 5)
.build());
assertEquals("", map.getInt32ToStringFieldOrDefault(0, null)); assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
.putInt32ToBytesField(stringKey, 5)
.build());
assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY); assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
map = tryParseTestMap(BizarroTestMap.newBuilder() map =
.putInt32ToEnumField(stringKey, bytes) tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
.build());
assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null)); assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try { try {
tryParseTestMap(BizarroTestMap.newBuilder() tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
.putInt32ToMessageField(stringKey, bytes)
.build());
fail(); fail();
} catch (InvalidProtocolBufferException expected) { } catch (InvalidProtocolBufferException expected) {
assertTrue(expected.getUnfinishedMessage() instanceof TestMap); assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
@ -574,9 +566,9 @@ public class MapForProto2Test extends TestCase {
assertTrue(map.getInt32ToMessageField().isEmpty()); assertTrue(map.getInt32ToMessageField().isEmpty());
} }
map = tryParseTestMap(BizarroTestMap.newBuilder() map =
.putStringToInt32Field(stringKey, bytes) tryParseTestMap(
.build()); BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1)); assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
} }
@ -657,8 +649,7 @@ public class MapForProto2Test extends TestCase {
} }
} }
private static <KeyType, ValueType> private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) {
Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
Message.Builder entryBuilder = builder.newBuilderForField(field); Message.Builder entryBuilder = builder.newBuilderForField(field);
FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
@ -677,9 +668,8 @@ public class MapForProto2Test extends TestCase {
builder.setField(field, entryList); builder.setField(field, entryList);
} }
private static <KeyType, ValueType> Map<KeyType, ValueType> mapForValues( private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
KeyType key1, ValueType value1, KeyType key2, ValueType value2) { Map<K, V> map = new HashMap<K, V>();
Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
map.put(key1, value1); map.put(key1, value1);
map.put(key2, value2); map.put(key2, value2);
return map; return map;
@ -687,7 +677,8 @@ public class MapForProto2Test extends TestCase {
public void testReflectionApi() throws Exception { public void testReflectionApi() throws Exception {
// In reflection API, map fields are just repeated message fields. // In reflection API, map fields are just repeated message fields.
TestMap.Builder builder = TestMap.newBuilder() TestMap.Builder builder =
TestMap.newBuilder()
.putInt32ToInt32Field(1, 2) .putInt32ToInt32Field(1, 2)
.putInt32ToInt32Field(3, 4) .putInt32ToInt32Field(3, 4)
.putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build()) .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
@ -695,9 +686,10 @@ public class MapForProto2Test extends TestCase {
TestMap message = builder.build(); TestMap message = builder.build();
// Test getField(), getRepeatedFieldCount(), getRepeatedField(). // Test getField(), getRepeatedFieldCount(), getRepeatedField().
assertHasMapValues(message, "int32_to_int32_field", assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4));
mapForValues(1, 2, 3, 4)); assertHasMapValues(
assertHasMapValues(message, "int32_to_message_field", message,
"int32_to_message_field",
mapForValues( mapForValues(
11, MessageValue.newBuilder().setValue(22).build(), 11, MessageValue.newBuilder().setValue(22).build(),
33, MessageValue.newBuilder().setValue(44).build())); 33, MessageValue.newBuilder().setValue(44).build()));
@ -710,9 +702,10 @@ public class MapForProto2Test extends TestCase {
assertEquals(0, message.getInt32ToMessageField().size()); assertEquals(0, message.getInt32ToMessageField().size());
// Test setField() // Test setField()
setMapValues(builder, "int32_to_int32_field", setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
mapForValues(11, 22, 33, 44)); setMapValues(
setMapValues(builder, "int32_to_message_field", builder,
"int32_to_message_field",
mapForValues( mapForValues(
111, MessageValue.newBuilder().setValue(222).build(), 111, MessageValue.newBuilder().setValue(222).build(),
333, MessageValue.newBuilder().setValue(444).build())); 333, MessageValue.newBuilder().setValue(444).build()));
@ -723,20 +716,28 @@ public class MapForProto2Test extends TestCase {
assertEquals(444, message.getInt32ToMessageField().get(333).getValue()); assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
// Test addRepeatedField // Test addRepeatedField
builder.addRepeatedField(f("int32_to_int32_field"), builder.addRepeatedField(
newMapEntry(builder, "int32_to_int32_field", 55, 66)); f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66));
builder.addRepeatedField(f("int32_to_message_field"), builder.addRepeatedField(
newMapEntry(builder, "int32_to_message_field", 555, f("int32_to_message_field"),
newMapEntry(
builder,
"int32_to_message_field",
555,
MessageValue.newBuilder().setValue(666).build())); MessageValue.newBuilder().setValue(666).build()));
message = builder.build(); message = builder.build();
assertEquals(66, message.getInt32ToInt32Field().get(55).intValue()); assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
assertEquals(666, message.getInt32ToMessageField().get(555).getValue()); assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
// Test addRepeatedField (overriding existing values) // Test addRepeatedField (overriding existing values)
builder.addRepeatedField(f("int32_to_int32_field"), builder.addRepeatedField(
newMapEntry(builder, "int32_to_int32_field", 55, 55)); f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55));
builder.addRepeatedField(f("int32_to_message_field"), builder.addRepeatedField(
newMapEntry(builder, "int32_to_message_field", 555, f("int32_to_message_field"),
newMapEntry(
builder,
"int32_to_message_field",
555,
MessageValue.newBuilder().setValue(555).build())); MessageValue.newBuilder().setValue(555).build()));
message = builder.build(); message = builder.build();
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
@ -779,10 +780,9 @@ public class MapForProto2Test extends TestCase {
setMapValuesUsingAccessors(builder); setMapValuesUsingAccessors(builder);
TestMap message = builder.build(); TestMap message = builder.build();
Message dynamicDefaultInstance = Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); Message dynamicMessage =
Message dynamicMessage = dynamicDefaultInstance dynamicDefaultInstance.newBuilderForType().mergeFrom(message.toByteString()).build();
.newBuilderForType().mergeFrom(message.toByteString()).build();
assertEquals(message, dynamicMessage); assertEquals(message, dynamicMessage);
assertEquals(message.hashCode(), dynamicMessage.hashCode()); assertEquals(message.hashCode(), dynamicMessage.hashCode());
@ -793,8 +793,7 @@ public class MapForProto2Test extends TestCase {
public void testDynamicMessageUnsetKeyAndValue() throws Exception { public void testDynamicMessageUnsetKeyAndValue() throws Exception {
FieldDescriptor field = f("int32_to_int32_field"); FieldDescriptor field = f("int32_to_int32_field");
Message dynamicDefaultInstance = Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
Message.Builder builder = dynamicDefaultInstance.newBuilderForType(); Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
// Add an entry without key and value. // Add an entry without key and value.
builder.addRepeatedField(field, builder.newBuilderForField(field).build()); builder.addRepeatedField(field, builder.newBuilderForField(field).build());
@ -811,8 +810,7 @@ public class MapForProto2Test extends TestCase {
// of map entries when comparing/hashing map fields. // of map entries when comparing/hashing map fields.
// We use DynamicMessage to test reflection based equals()/hashCode(). // We use DynamicMessage to test reflection based equals()/hashCode().
Message dynamicDefaultInstance = Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
FieldDescriptor field = f("int32_to_int32_field"); FieldDescriptor field = f("int32_to_int32_field");
Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
@ -839,9 +837,8 @@ public class MapForProto2Test extends TestCase {
} }
public void testUnknownEnumValues() throws Exception { public void testUnknownEnumValues() throws Exception {
TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder() TestUnknownEnumValue.Builder builder =
.putInt32ToInt32Field(1, 1) TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321);
.putInt32ToInt32Field(2, 54321);
ByteString data = builder.build().toByteString(); ByteString data = builder.build().toByteString();
TestMap message = TestMap.parseFrom(data); TestMap message = TestMap.parseFrom(data);
@ -853,8 +850,7 @@ public class MapForProto2Test extends TestCase {
assertFalse(message.getUnknownFields().asMap().isEmpty()); assertFalse(message.getUnknownFields().asMap().isEmpty());
// Serializing and parsing should preserve the unknown entry. // Serializing and parsing should preserve the unknown entry.
data = message.toByteString(); data = message.toByteString();
TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
TestUnknownEnumValue.parseFrom(data);
assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
@ -887,7 +883,8 @@ public class MapForProto2Test extends TestCase {
setMapValuesUsingAccessors(builder); setMapValuesUsingAccessors(builder);
TestMap message = builder.build(); TestMap message = builder.build();
assertEquals(Arrays.asList("1", "2", "3"), assertEquals(
Arrays.asList("1", "2", "3"),
new ArrayList<String>(message.getStringToInt32Field().keySet())); new ArrayList<String>(message.getStringToInt32Field().keySet()));
} }
@ -979,7 +976,8 @@ public class MapForProto2Test extends TestCase {
assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null)); assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)); assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
assertEquals(MessageValue.newBuilder().setValue(11).build(), assertEquals(
MessageValue.newBuilder().setValue(11).build(),
testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null)); testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)); assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
@ -1037,7 +1035,8 @@ public class MapForProto2Test extends TestCase {
// expected // expected
} }
assertEquals(MessageValue.newBuilder().setValue(11).build(), assertEquals(
MessageValue.newBuilder().setValue(11).build(),
testMapOrBuilder.getInt32ToMessageFieldOrThrow(1)); testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
try { try {
testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1); testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
@ -1146,14 +1145,19 @@ public class MapForProto2Test extends TestCase {
// Regression test for b/20494788 // Regression test for b/20494788
public void testMapInitializationOrder() throws Exception { public void testMapInitializationOrder() throws Exception {
assertEquals("RedactAllTypes", map_test.RedactAllTypes assertEquals(
.getDefaultInstance().getDescriptorForType().getName()); "RedactAllTypes",
map_test.RedactAllTypes.getDefaultInstance()
.getDescriptorForType()
.getName());
map_test.Message1.Builder builder = map_test.Message1.Builder builder =
map_test.Message1.newBuilder(); map_test.Message1.newBuilder();
builder.putMapField("key", true); builder.putMapField("key", true);
map_test.Message1 message = builder.build(); map_test.Message1 message = builder.build();
Message mapEntry = (Message) message.getRepeatedField( Message mapEntry =
(Message)
message.getRepeatedField(
message.getDescriptorForType().findFieldByName("map_field"), 0); message.getDescriptorForType().findFieldByName("map_field"), 0);
assertEquals(2, mapEntry.getAllFields().size()); assertEquals(2, mapEntry.getAllFields().size());
} }
@ -1163,35 +1167,14 @@ public class MapForProto2Test extends TestCase {
ReservedAsMapFieldWithEnumValue.newBuilder().build(); ReservedAsMapFieldWithEnumValue.newBuilder().build();
} }
private static <K, V> Map<K, V> newMap(K key1, V value1) {
Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);
return map;
}
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
Map<K, V> map = new HashMap<K, V>();
map.put(key1, value1);
map.put(key2, value2);
return map;
}
public void testGetMap() { public void testGetMap() {
TestMap.Builder builder = TestMap.newBuilder(); TestMap.Builder builder = TestMap.newBuilder();
setMapValuesUsingAccessors(builder); setMapValuesUsingAccessors(builder);
assertMapValuesSet(builder); assertMapValuesSet(builder);
TestMap message = builder.build(); TestMap message = builder.build();
assertEquals( assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
message.getStringToInt32Field(), assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
message.getStringToInt32FieldMap()); assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
assertEquals( assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
message.getInt32ToBytesField(),
message.getInt32ToBytesFieldMap());
assertEquals(
message.getInt32ToEnumField(),
message.getInt32ToEnumFieldMap());
assertEquals(
message.getInt32ToMessageField(),
message.getInt32ToMessageFieldMap());
} }
} }

@ -477,12 +477,12 @@ public class MapTest extends TestCase {
} }
public void testPutForUnknownEnumValues() throws Exception { public void testPutForUnknownEnumValues() throws Exception {
TestMap.Builder builder = TestMap message =
TestMap.newBuilder() TestMap.newBuilder()
.putInt32ToEnumFieldValue(0, 0) .putInt32ToEnumFieldValue(0, 0)
.putInt32ToEnumFieldValue(1, 1) .putInt32ToEnumFieldValue(1, 1)
.putInt32ToEnumFieldValue(2, 1000); // unknown value. .putInt32ToEnumFieldValue(2, 1000) // unknown value.
TestMap message = builder.build(); .build();
assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0)); assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1)); assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2)); assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
@ -608,12 +608,12 @@ public class MapTest extends TestCase {
// We can't control the order of elements in a HashMap. The best we can do // We can't control the order of elements in a HashMap. The best we can do
// here is to add elements in different order. // here is to add elements in different order.
TestMap.Builder b1 = TestMap m1 =
TestMap.newBuilder() TestMap.newBuilder()
.putInt32ToInt32Field(1, 2) .putInt32ToInt32Field(1, 2)
.putInt32ToInt32Field(3, 4) .putInt32ToInt32Field(3, 4)
.putInt32ToInt32Field(5, 6); .putInt32ToInt32Field(5, 6)
TestMap m1 = b1.build(); .build();
TestMap.Builder b2 = TestMap.Builder b2 =
TestMap.newBuilder() TestMap.newBuilder()
@ -654,8 +654,8 @@ public class MapTest extends TestCase {
assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue()); assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
// Make another change using mergeFrom() // Make another change using mergeFrom()
TestMap.Builder other = TestMap.newBuilder().putInt32ToInt32Field(1, 4); TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build();
parent.getOptionalMessageBuilder().mergeFrom(other.build()); parent.getOptionalMessageBuilder().mergeFrom(other);
// Should be able to observe the change. // Should be able to observe the change.
message = parent.build(); message = parent.build();
@ -751,7 +751,7 @@ public class MapTest extends TestCase {
} }
private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) { private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
List<Message> entryList = new ArrayList<Message>(); List<Message> entryList = new ArrayList<>();
for (Map.Entry<?, ?> entry : values.entrySet()) { for (Map.Entry<?, ?> entry : values.entrySet()) {
entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
} }
@ -760,7 +760,7 @@ public class MapTest extends TestCase {
} }
private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) { private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
Map<K, V> map = new HashMap<K, V>(); Map<K, V> map = new HashMap<>();
map.put(key1, value1); map.put(key1, value1);
map.put(key2, value2); map.put(key2, value2);
return map; return map;
@ -1002,8 +1002,7 @@ public class MapTest extends TestCase {
TestMap message = builder.build(); TestMap message = builder.build();
assertEquals( assertEquals(
Arrays.asList("1", "2", "3"), Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet()));
new ArrayList<String>(message.getStringToInt32Field().keySet()));
} }
public void testGetMap() { public void testGetMap() {
@ -1336,10 +1335,10 @@ public class MapTest extends TestCase {
output.flush(); output.flush();
CodedInputStream input = CodedInputStream.newInstance(serialized); CodedInputStream input = CodedInputStream.newInstance(serialized);
List<Integer> int32Keys = new ArrayList<Integer>(); List<Integer> int32Keys = new ArrayList<>();
List<Integer> uint32Keys = new ArrayList<Integer>(); List<Integer> uint32Keys = new ArrayList<>();
List<Long> int64Keys = new ArrayList<Long>(); List<Long> int64Keys = new ArrayList<>();
List<String> stringKeys = new ArrayList<String>(); List<String> stringKeys = new ArrayList<>();
int tag; int tag;
while (true) { while (true) {
tag = input.readTag(); tag = input.readTag();
@ -1450,20 +1449,20 @@ public class MapTest extends TestCase {
} }
private static <K, V> Map<K, V> newMap(K key1, V value1) { private static <K, V> Map<K, V> newMap(K key1, V value1) {
Map<K, V> map = new HashMap<K, V>(); Map<K, V> map = new HashMap<>();
map.put(key1, value1); map.put(key1, value1);
return map; return map;
} }
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
Map<K, V> map = new HashMap<K, V>(); Map<K, V> map = new HashMap<>();
map.put(key1, value1); map.put(key1, value1);
map.put(key2, value2); map.put(key2, value2);
return map; return map;
} }
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) { private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) {
Map<K, V> map = new HashMap<K, V>(); Map<K, V> map = new HashMap<>();
map.put(key1, value1); map.put(key1, value1);
map.put(key2, value2); map.put(key2, value2);
map.put(key3, value3); map.put(key3, value3);

@ -385,12 +385,12 @@ public class NioByteStringTest extends TestCase {
} }
@Override @Override
public void writeLazy(byte[] value, int offset, int length) throws IOException { public void write(ByteBuffer value) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void write(ByteBuffer value) throws IOException { public void writeLazy(byte[] value, int offset, int length) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

@ -58,8 +58,7 @@ public class ParserTest extends TestCase {
} }
} }
private void assertRoundTripEquals(MessageLite message, private void assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry)
ExtensionRegistryLite registry)
throws Exception { throws Exception {
final byte[] data = message.toByteArray(); final byte[] data = message.toByteArray();
final int offset = 20; final int offset = 20;
@ -67,15 +66,12 @@ public class ParserTest extends TestCase {
final int padding = 30; final int padding = 30;
Parser<? extends MessageLite> parser = message.getParserForType(); Parser<? extends MessageLite> parser = message.getParserForType();
assertMessageEquals(message, parser.parseFrom(data, registry)); assertMessageEquals(message, parser.parseFrom(data, registry));
assertMessageEquals(message, parser.parseFrom( assertMessageEquals(
generatePaddingArray(data, offset, padding), message,
offset, length, registry)); parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length, registry));
assertMessageEquals(message, parser.parseFrom( assertMessageEquals(message, parser.parseFrom(message.toByteString(), registry));
message.toByteString(), registry)); assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data), registry));
assertMessageEquals(message, parser.parseFrom( assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data), registry));
new ByteArrayInputStream(data), registry));
assertMessageEquals(message, parser.parseFrom(
CodedInputStream.newInstance(data), registry));
assertMessageEquals( assertMessageEquals(
message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry)); message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
} }
@ -87,23 +83,17 @@ public class ParserTest extends TestCase {
final int length = data.length; final int length = data.length;
final int padding = 30; final int padding = 30;
Parser<MessageLite> parser = Parser<MessageLite> parser = (Parser<MessageLite>) message.getParserForType();
(Parser<MessageLite>) message.getParserForType();
assertMessageEquals(message, parser.parseFrom(data)); assertMessageEquals(message, parser.parseFrom(data));
assertMessageEquals(message, parser.parseFrom( assertMessageEquals(
generatePaddingArray(data, offset, padding), message, parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length));
offset, length));
assertMessageEquals(message, parser.parseFrom(message.toByteString())); assertMessageEquals(message, parser.parseFrom(message.toByteString()));
assertMessageEquals(message, parser.parseFrom( assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data)));
new ByteArrayInputStream(data))); assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data)));
assertMessageEquals(message, parser.parseFrom(
CodedInputStream.newInstance(data)));
assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer())); assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
} }
private void assertMessageEquals( private void assertMessageEquals(MessageLite expected, MessageLite actual) throws Exception {
MessageLite expected, MessageLite actual)
throws Exception {
if (expected instanceof Message) { if (expected instanceof Message) {
assertEquals(expected, actual); assertEquals(expected, actual);
} else { } else {
@ -126,20 +116,16 @@ public class ParserTest extends TestCase {
assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial()); assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial());
} }
private <T extends MessageLite> void assertParsePartial( private <T extends MessageLite> void assertParsePartial(Parser<T> parser, T partialMessage)
Parser<T> parser, T partialMessage) throws Exception { throws Exception {
final String errorString = final String errorString = "Should throw exceptions when the parsed message isn't initialized.";
"Should throw exceptions when the parsed message isn't initialized.";
// parsePartialFrom should pass. // parsePartialFrom should pass.
byte[] data = partialMessage.toByteArray(); byte[] data = partialMessage.toByteArray();
assertEquals(partialMessage, parser.parsePartialFrom(data)); assertEquals(partialMessage, parser.parsePartialFrom(data));
assertEquals(partialMessage, parser.parsePartialFrom( assertEquals(partialMessage, parser.parsePartialFrom(partialMessage.toByteString()));
partialMessage.toByteString())); assertEquals(partialMessage, parser.parsePartialFrom(new ByteArrayInputStream(data)));
assertEquals(partialMessage, parser.parsePartialFrom( assertEquals(partialMessage, parser.parsePartialFrom(CodedInputStream.newInstance(data)));
new ByteArrayInputStream(data)));
assertEquals(partialMessage, parser.parsePartialFrom(
CodedInputStream.newInstance(data)));
// parseFrom(ByteArray) // parseFrom(ByteArray)
try { try {
@ -167,8 +153,7 @@ public class ParserTest extends TestCase {
// parseFrom(CodedInputStream) // parseFrom(CodedInputStream)
try { try {
parser.parseFrom(CodedInputStream.newInstance( parser.parseFrom(CodedInputStream.newInstance(partialMessage.toByteArray()));
partialMessage.toByteArray()));
fail(errorString); fail(errorString);
} catch (IOException e) { } catch (IOException e) {
// pass. // pass.
@ -176,14 +161,12 @@ public class ParserTest extends TestCase {
} }
public void testParseExtensions() throws Exception { public void testParseExtensions() throws Exception {
assertRoundTripEquals(TestUtil.getAllExtensionsSet(), assertRoundTripEquals(TestUtil.getAllExtensionsSet(), TestUtil.getExtensionRegistry());
TestUtil.getExtensionRegistry());
} }
public void testParsePacked() throws Exception { public void testParsePacked() throws Exception {
assertRoundTripEquals(TestUtil.getPackedSet()); assertRoundTripEquals(TestUtil.getPackedSet());
assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry());
TestUtil.getExtensionRegistry());
} }
public void testParseDelimitedTo() throws Exception { public void testParseDelimitedTo() throws Exception {
@ -202,9 +185,7 @@ public class ParserTest extends TestCase {
// All fields will be treated as unknown fields in emptyMessage. // All fields will be treated as unknown fields in emptyMessage.
TestEmptyMessage emptyMessage = TestEmptyMessage emptyMessage =
TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString()); TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString());
assertEquals( assertEquals(TestUtil.getAllSet().toByteString(), emptyMessage.toByteString());
TestUtil.getAllSet().toByteString(),
emptyMessage.toByteString());
} }
@ -212,7 +193,8 @@ public class ParserTest extends TestCase {
TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder(); TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build()); builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
builder.setExtension(TestOptimizedForSize.testExtension, 56); builder.setExtension(TestOptimizedForSize.testExtension, 56);
builder.setExtension(TestOptimizedForSize.testExtension2, builder.setExtension(
TestOptimizedForSize.testExtension2,
TestRequiredOptimizedForSize.newBuilder().setX(78).build()); TestRequiredOptimizedForSize.newBuilder().setX(78).build());
TestOptimizedForSize message = builder.build(); TestOptimizedForSize message = builder.build();
@ -222,9 +204,8 @@ public class ParserTest extends TestCase {
assertRoundTripEquals(message, registry); assertRoundTripEquals(message, registry);
} }
/** Helper method for {@link #testParsingMerge()}.*/ /** Helper method for {@link #testParsingMerge()}. */
private void assertMessageMerged(TestAllTypes allTypes) private void assertMessageMerged(TestAllTypes allTypes) throws Exception {
throws Exception {
assertEquals(3, allTypes.getOptionalInt32()); assertEquals(3, allTypes.getOptionalInt32());
assertEquals(2, allTypes.getOptionalInt64()); assertEquals(2, allTypes.getOptionalInt64());
assertEquals("hello", allTypes.getOptionalString()); assertEquals("hello", allTypes.getOptionalString());
@ -237,39 +218,48 @@ public class ParserTest extends TestCase {
builder.clear(); builder.clear();
TestAllTypes msg2 = builder.setOptionalInt64(2).build(); TestAllTypes msg2 = builder.setOptionalInt64(2).build();
builder.clear(); builder.clear();
TestAllTypes msg3 = builder.setOptionalInt32(3) TestAllTypes msg3 = builder.setOptionalInt32(3).setOptionalString("hello").build();
.setOptionalString("hello").build();
// Build groups. // Build groups.
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 = TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder() TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg1).build();
.setField1(msg1).build();
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 = TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder() TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg2).build();
.setField1(msg2).build();
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 = TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder() TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg3).build();
.setField1(msg3).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 = TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder() TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg1).build();
.setField1(msg1).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 = TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder() TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg2).build();
.setField1(msg2).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 = TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder() TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg3).build();
.setField1(msg3).build();
// Assign and serialize RepeatedFieldsGenerator. // Assign and serialize RepeatedFieldsGenerator.
ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder() ByteString data =
.addField1(msg1).addField1(msg2).addField1(msg3) TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
.addField2(msg1).addField2(msg2).addField2(msg3) .addField1(msg1)
.addField3(msg1).addField3(msg2).addField3(msg3) .addField1(msg2)
.addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3) .addField1(msg3)
.addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3) .addField2(msg1)
.addExt1(msg1).addExt1(msg2).addExt1(msg3) .addField2(msg2)
.addExt2(msg1).addExt2(msg2).addExt2(msg3) .addField2(msg3)
.build().toByteString(); .addField3(msg1)
.addField3(msg2)
.addField3(msg3)
.addGroup1(optionalG1)
.addGroup1(optionalG2)
.addGroup1(optionalG3)
.addGroup2(repeatedG1)
.addGroup2(repeatedG2)
.addGroup2(repeatedG3)
.addExt1(msg1)
.addExt1(msg2)
.addExt1(msg3)
.addExt2(msg1)
.addExt2(msg2)
.addExt2(msg3)
.build()
.toByteString();
// Parse TestParsingMerge. // Parse TestParsingMerge.
ExtensionRegistry registry = ExtensionRegistry.newInstance(); ExtensionRegistry registry = ExtensionRegistry.newInstance();
@ -279,21 +269,18 @@ public class ParserTest extends TestCase {
// Required and optional fields should be merged. // Required and optional fields should be merged.
assertMessageMerged(parsingMerge.getRequiredAllTypes()); assertMessageMerged(parsingMerge.getRequiredAllTypes());
assertMessageMerged(parsingMerge.getOptionalAllTypes()); assertMessageMerged(parsingMerge.getOptionalAllTypes());
assertMessageMerged( assertMessageMerged(parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
parsingMerge.getOptionalGroup().getOptionalGroupAllTypes()); assertMessageMerged(parsingMerge.getExtension(TestParsingMerge.optionalExt));
assertMessageMerged(parsingMerge.getExtension(
TestParsingMerge.optionalExt));
// Repeated fields should not be merged. // Repeated fields should not be merged.
assertEquals(3, parsingMerge.getRepeatedAllTypesCount()); assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
assertEquals(3, parsingMerge.getRepeatedGroupCount()); assertEquals(3, parsingMerge.getRepeatedGroupCount());
assertEquals(3, parsingMerge.getExtensionCount( assertEquals(3, parsingMerge.getExtensionCount(TestParsingMerge.repeatedExt));
TestParsingMerge.repeatedExt));
} }
public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() { public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
try { try {
TestUtil.getAllSet().parseDelimitedFrom( TestAllTypes.parseDelimitedFrom(
new InputStream() { new InputStream() {
@Override @Override
public int read() throws IOException { public int read() throws IOException {
@ -308,7 +295,7 @@ public class ParserTest extends TestCase {
public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() { public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() {
try { try {
TestUtil.getAllSet().parseDelimitedFrom( TestAllTypes.parseDelimitedFrom(
new InputStream() { new InputStream() {
private int i; private int i;

@ -79,15 +79,21 @@ public class ServiceTest extends TestCase {
MockCallback<Message> barCallback = new MockCallback<Message>(); MockCallback<Message> barCallback = new MockCallback<Message>();
TestService mockService = control.createMock(TestService.class); TestService mockService = control.createMock(TestService.class);
mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest), mockService.foo(
EasyMock.same(mockController),
EasyMock.same(fooRequest),
this.<FooResponse>wrapsCallback(fooCallback)); this.<FooResponse>wrapsCallback(fooCallback));
mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest), mockService.bar(
EasyMock.same(mockController),
EasyMock.same(barRequest),
this.<BarResponse>wrapsCallback(barCallback)); this.<BarResponse>wrapsCallback(barCallback));
control.replay(); control.replay();
mockService.callMethod(fooDescriptor, mockController, mockService.callMethod(
fooDescriptor, mockController,
fooRequest, fooCallback); fooRequest, fooCallback);
mockService.callMethod(barDescriptor, mockController, mockService.callMethod(
barDescriptor, mockController,
barRequest, barCallback); barRequest, barCallback);
control.verify(); control.verify();
} }
@ -96,14 +102,10 @@ public class ServiceTest extends TestCase {
public void testGetPrototype() throws Exception { public void testGetPrototype() throws Exception {
TestService mockService = control.createMock(TestService.class); TestService mockService = control.createMock(TestService.class);
assertSame(mockService.getRequestPrototype(fooDescriptor), assertSame(mockService.getRequestPrototype(fooDescriptor), FooRequest.getDefaultInstance());
FooRequest.getDefaultInstance()); assertSame(mockService.getResponsePrototype(fooDescriptor), FooResponse.getDefaultInstance());
assertSame(mockService.getResponsePrototype(fooDescriptor), assertSame(mockService.getRequestPrototype(barDescriptor), BarRequest.getDefaultInstance());
FooResponse.getDefaultInstance()); assertSame(mockService.getResponsePrototype(barDescriptor), BarResponse.getDefaultInstance());
assertSame(mockService.getRequestPrototype(barDescriptor),
BarRequest.getDefaultInstance());
assertSame(mockService.getResponsePrototype(barDescriptor),
BarResponse.getDefaultInstance());
} }
/** Tests generated stubs. */ /** Tests generated stubs. */
@ -138,24 +140,26 @@ public class ServiceTest extends TestCase {
public void testBlockingStub() throws Exception { public void testBlockingStub() throws Exception {
FooRequest fooRequest = FooRequest.newBuilder().build(); FooRequest fooRequest = FooRequest.newBuilder().build();
BarRequest barRequest = BarRequest.newBuilder().build(); BarRequest barRequest = BarRequest.newBuilder().build();
BlockingRpcChannel mockChannel = BlockingRpcChannel mockChannel = control.createMock(BlockingRpcChannel.class);
control.createMock(BlockingRpcChannel.class); TestService.BlockingInterface stub = TestService.newBlockingStub(mockChannel);
TestService.BlockingInterface stub =
TestService.newBlockingStub(mockChannel);
FooResponse fooResponse = FooResponse.newBuilder().build(); FooResponse fooResponse = FooResponse.newBuilder().build();
BarResponse barResponse = BarResponse.newBuilder().build(); BarResponse barResponse = BarResponse.newBuilder().build();
EasyMock.expect(mockChannel.callBlockingMethod( EasyMock.expect(
mockChannel.callBlockingMethod(
EasyMock.same(fooDescriptor), EasyMock.same(fooDescriptor),
EasyMock.same(mockController), EasyMock.same(mockController),
EasyMock.same(fooRequest), EasyMock.same(fooRequest),
EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse); EasyMock.same(FooResponse.getDefaultInstance())))
EasyMock.expect(mockChannel.callBlockingMethod( .andReturn(fooResponse);
EasyMock.expect(
mockChannel.callBlockingMethod(
EasyMock.same(barDescriptor), EasyMock.same(barDescriptor),
EasyMock.same(mockController), EasyMock.same(mockController),
EasyMock.same(barRequest), EasyMock.same(barRequest),
EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse); EasyMock.same(BarResponse.getDefaultInstance())))
.andReturn(barResponse);
control.replay(); control.replay();
assertSame(fooResponse, stub.foo(mockController, fooRequest)); assertSame(fooResponse, stub.foo(mockController, fooRequest));
@ -164,13 +168,11 @@ public class ServiceTest extends TestCase {
} }
public void testNewReflectiveService() { public void testNewReflectiveService() {
ServiceWithNoOuter.Interface impl = ServiceWithNoOuter.Interface impl = control.createMock(ServiceWithNoOuter.Interface.class);
control.createMock(ServiceWithNoOuter.Interface.class);
RpcController controller = control.createMock(RpcController.class); RpcController controller = control.createMock(RpcController.class);
Service service = ServiceWithNoOuter.newReflectiveService(impl); Service service = ServiceWithNoOuter.newReflectiveService(impl);
MethodDescriptor fooMethod = MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
RpcCallback<Message> callback = RpcCallback<Message> callback =
new RpcCallback<Message>() { new RpcCallback<Message>() {
@ -180,11 +182,9 @@ public class ServiceTest extends TestCase {
fail(); fail();
} }
}; };
RpcCallback<TestAllTypes> specializedCallback = RpcCallback<TestAllTypes> specializedCallback = RpcUtil.specializeCallback(callback);
RpcUtil.specializeCallback(callback);
impl.foo(EasyMock.same(controller), EasyMock.same(request), impl.foo(EasyMock.same(controller), EasyMock.same(request), EasyMock.same(specializedCallback));
EasyMock.same(specializedCallback));
EasyMock.expectLastCall(); EasyMock.expectLastCall();
control.replay(); control.replay();
@ -198,11 +198,9 @@ public class ServiceTest extends TestCase {
ServiceWithNoOuter.BlockingInterface impl = ServiceWithNoOuter.BlockingInterface impl =
control.createMock(ServiceWithNoOuter.BlockingInterface.class); control.createMock(ServiceWithNoOuter.BlockingInterface.class);
RpcController controller = control.createMock(RpcController.class); RpcController controller = control.createMock(RpcController.class);
BlockingService service = BlockingService service = ServiceWithNoOuter.newReflectiveBlockingService(impl);
ServiceWithNoOuter.newReflectiveBlockingService(impl);
MethodDescriptor fooMethod = MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance(); TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
@ -211,8 +209,7 @@ public class ServiceTest extends TestCase {
control.replay(); control.replay();
Message response = Message response = service.callBlockingMethod(fooMethod, controller, request);
service.callBlockingMethod(fooMethod, controller, request);
assertEquals(expectedResponse, response); assertEquals(expectedResponse, response);
control.verify(); control.verify();
@ -229,8 +226,8 @@ public class ServiceTest extends TestCase {
assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber()); assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
// Build a list of the class names nested in UnittestNoGenericServices. // Build a list of the class names nested in UnittestNoGenericServices.
String outerName = "google.protobuf.no_generic_services_test." + String outerName =
"UnittestNoGenericServices"; "google.protobuf.no_generic_services_test.UnittestNoGenericServices";
Class<?> outerClass = Class.forName(outerName); Class<?> outerClass = Class.forName(outerName);
Set<String> innerClassNames = new HashSet<String>(); Set<String> innerClassNames = new HashSet<String>();
@ -244,9 +241,9 @@ public class ServiceTest extends TestCase {
// separator. // separator.
assertTrue(fullName.startsWith(outerName)); assertTrue(fullName.startsWith(outerName));
if (!Service.class.isAssignableFrom(innerClass) && if (!Service.class.isAssignableFrom(innerClass)
!Message.class.isAssignableFrom(innerClass) && && !Message.class.isAssignableFrom(innerClass)
!ProtocolMessageEnum.class.isAssignableFrom(innerClass)) { && !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
// Ignore any classes not generated by the base code generator. // Ignore any classes not generated by the base code generator.
continue; continue;
} }
@ -264,8 +261,7 @@ public class ServiceTest extends TestCase {
assertEquals(1, file.getServices().size()); assertEquals(1, file.getServices().size());
assertEquals("TestService", file.getServices().get(0).getName()); assertEquals("TestService", file.getServices().get(0).getName());
assertEquals(1, file.getServices().get(0).getMethods().size()); assertEquals(1, file.getServices().get(0).getMethods().size());
assertEquals("Foo", assertEquals("Foo", file.getServices().get(0).getMethods().get(0).getName());
file.getServices().get(0).getMethods().get(0).getName());
} }
@ -284,13 +280,18 @@ public class ServiceTest extends TestCase {
private static class MockCallback<T extends Message> implements RpcCallback<T> { private static class MockCallback<T extends Message> implements RpcCallback<T> {
private boolean called = false; private boolean called = false;
public boolean isCalled() { return called; } public boolean isCalled() {
return called;
}
public void reset() { called = false; } public void reset() {
called = false;
}
@Override @Override
public void run(T message) { public void run(T message) {
called = true; } called = true;
}
} }
/** Implementation of the wrapsCallback() argument matcher. */ /** Implementation of the wrapsCallback() argument matcher. */
@ -307,7 +308,7 @@ public class ServiceTest extends TestCase {
if (!(actual instanceof RpcCallback)) { if (!(actual instanceof RpcCallback)) {
return false; return false;
} }
RpcCallback actualCallback = (RpcCallback)actual; RpcCallback actualCallback = (RpcCallback) actual;
callback.reset(); callback.reset();
actualCallback.run(null); actualCallback.run(null);

@ -119,8 +119,6 @@ import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite; import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite; import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite; import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
import static protobuf_unittest.UnittestProto.defaultBoolExtension; import static protobuf_unittest.UnittestProto.defaultBoolExtension;
import static protobuf_unittest.UnittestProto.defaultBytesExtension; import static protobuf_unittest.UnittestProto.defaultBytesExtension;
import static protobuf_unittest.UnittestProto.defaultCordExtension; import static protobuf_unittest.UnittestProto.defaultCordExtension;
@ -222,6 +220,8 @@ import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage;
import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignEnum; import protobuf_unittest.UnittestProto.ForeignEnum;
import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.OptionalGroup_extension;
import protobuf_unittest.UnittestProto.RepeatedGroup_extension;
import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder; import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes;
@ -234,6 +234,11 @@ import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import junit.framework.Assert; import junit.framework.Assert;
/** /**
@ -2634,7 +2639,6 @@ public final class TestUtil {
break; break;
case FOO_NOT_SET: case FOO_NOT_SET:
break; break;
default:
// TODO(b/18683919): go/enum-switch-lsc // TODO(b/18683919): go/enum-switch-lsc
} }
} }
@ -2702,7 +2706,7 @@ public final class TestUtil {
this.publicImportFile = importFile.getDependencies().get(0); this.publicImportFile = importFile.getDependencies().get(0);
Descriptors.Descriptor testAllTypes; Descriptors.Descriptor testAllTypes;
if (baseDescriptor.getName() == "TestAllTypes") { if ("TestAllTypes".equals(baseDescriptor.getName())) {
testAllTypes = baseDescriptor; testAllTypes = baseDescriptor;
} else { } else {
testAllTypes = file.findMessageTypeByName("TestAllTypes"); testAllTypes = file.findMessageTypeByName("TestAllTypes");
@ -3857,4 +3861,28 @@ public final class TestUtil {
} }
} }
// END FULL-RUNTIME // END FULL-RUNTIME
/** Helper class to test logged messages */
public static class TestLogHandler extends Handler {
/** We will keep a private list of all logged records */
private final List<LogRecord> list = new ArrayList<>();
/** Adds the most recently logged record to our list. */
@Override
public synchronized void publish(LogRecord record) {
list.add(record);
}
@Override
public void flush() {}
@Override
public void close() {}
/** Returns a snapshot of the logged records. */
public synchronized List<LogRecord> getStoredLogRecords() {
List<LogRecord> result = new ArrayList<>(list);
return Collections.unmodifiableList(result);
}
}
} }

@ -49,6 +49,7 @@ import protobuf_unittest.UnittestProto.TestRequired;
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import java.io.StringReader; import java.io.StringReader;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -131,6 +132,8 @@ public class TextFormatTest extends TestCase {
+ " i: 456\n" + " i: 456\n"
+ "}\n"; + "}\n";
private final TextFormat.Parser parserAllowingUnknownExtensions =
TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build();
private final TextFormat.Parser parserWithOverwriteForbidden = private final TextFormat.Parser parserWithOverwriteForbidden =
TextFormat.Parser.newBuilder() TextFormat.Parser.newBuilder()
@ -467,7 +470,7 @@ public class TextFormatTest extends TestCase {
fail("expected parse exception"); fail("expected parse exception");
} catch (TextFormat.ParseException e) { } catch (TextFormat.ParseException e) {
assertEquals( assertEquals(
"6:1: Non-repeated field " "4:44: Non-repeated field "
+ "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\"" + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
+ " cannot be overwritten.", + " cannot be overwritten.",
e.getMessage()); e.getMessage());
@ -519,6 +522,23 @@ public class TextFormatTest extends TestCase {
} }
private void assertParseErrorWithUnknownExtensions(String error, String text) {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
parserAllowingUnknownExtensions.merge(text, builder);
fail("Expected parse exception.");
} catch (TextFormat.ParseException e) {
assertEquals(error, e.getMessage());
}
}
private TestAllTypes assertParseSuccessWithUnknownExtensions(String text)
throws TextFormat.ParseException {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
parserAllowingUnknownExtensions.merge(text, builder);
return builder.build();
}
private void assertParseErrorWithOverwriteForbidden(String error, String text) { private void assertParseErrorWithOverwriteForbidden(String error, String text) {
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try { try {
@ -954,6 +974,54 @@ public class TextFormatTest extends TestCase {
} }
public void testParseUnknownExtensions() throws Exception {
TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler();
Logger logger = Logger.getLogger(TextFormat.class.getName());
logger.addHandler(logHandler);
// Test unknown extension can pass.
assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123");
assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123\n"
+ "[unknown_ext]: inf\n"
+ "[unknown]: 1.234");
// Test warning messages.
assertEquals("Input contains unknown fields and/or extensions:\n"
+ "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]",
logHandler.getStoredLogRecords().get(0).getMessage());
assertEquals("Input contains unknown fields and/or extensions:\n"
+ "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+ "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n"
+ "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]",
logHandler.getStoredLogRecords().get(1).getMessage());
// Test unknown field can not pass.
assertParseErrorWithUnknownExtensions(
"2:1: Input contains unknown fields and/or extensions:\n"
+ "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+ "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field",
"[unknown_extension]: 1\n"
+ "unknown_field: 12345");
assertParseErrorWithUnknownExtensions(
"3:1: Input contains unknown fields and/or extensions:\n"
+ "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension1]\n"
+ "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension2]\n"
+ "3:1:\tprotobuf_unittest.TestAllTypes.unknown_field\n"
+ "4:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension3]",
"[unknown_extension1]: 1\n"
+ "[unknown_extension2]: 2\n"
+ "unknown_field: 12345\n"
+ "[unknown_extension3]: 3\n");
assertParseErrorWithUnknownExtensions(
"1:1: Input contains unknown fields and/or extensions:\n"
+ "1:1:\tprotobuf_unittest.TestAllTypes.unknown_field1\n"
+ "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field2\n"
+ "3:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+ "4:1:\tprotobuf_unittest.TestAllTypes.unknown_field3",
"unknown_field1: 1\n"
+ "unknown_field2: 2\n"
+ "[unknown_extension]: 12345\n"
+ "unknown_field3: 3\n");
}
// See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden. // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
public void testParseNonRepeatedFields() throws Exception { public void testParseNonRepeatedFields() throws Exception {
assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n"); assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n");
@ -962,29 +1030,29 @@ public class TextFormatTest extends TestCase {
"repeated_nested_message { bb: 1 }\nrepeated_nested_message { bb: 2 }\n"); "repeated_nested_message { bb: 1 }\nrepeated_nested_message { bb: 2 }\n");
assertParseErrorWithOverwriteForbidden( assertParseErrorWithOverwriteForbidden(
"3:17: Non-repeated field " "3:15: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.optional_int32\" " + "\"protobuf_unittest.TestAllTypes.optional_int32\" "
+ "cannot be overwritten.", + "cannot be overwritten.",
"optional_int32: 1\noptional_bool: true\noptional_int32: 1\n"); "optional_int32: 1\noptional_bool: true\noptional_int32: 1\n");
assertParseErrorWithOverwriteForbidden( assertParseErrorWithOverwriteForbidden(
"2:17: Non-repeated field " "2:1: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.optionalgroup\" " + "\"protobuf_unittest.TestAllTypes.optionalgroup\" "
+ "cannot be overwritten.", + "cannot be overwritten.",
"OptionalGroup { a: 1 }\nOptionalGroup { }\n"); "OptionalGroup { a: 1 }\nOptionalGroup { }\n");
assertParseErrorWithOverwriteForbidden( assertParseErrorWithOverwriteForbidden(
"2:33: Non-repeated field " "2:1: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.optional_nested_message\" " + "\"protobuf_unittest.TestAllTypes.optional_nested_message\" "
+ "cannot be overwritten.", + "cannot be overwritten.",
"optional_nested_message { }\noptional_nested_message { bb: 3 }\n"); "optional_nested_message { }\noptional_nested_message { bb: 3 }\n");
assertParseErrorWithOverwriteForbidden( assertParseErrorWithOverwriteForbidden(
"2:16: Non-repeated field " "2:14: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.default_int32\" " + "\"protobuf_unittest.TestAllTypes.default_int32\" "
+ "cannot be overwritten.", + "cannot be overwritten.",
"default_int32: 41\n" "default_int32: 41\n"
+ // the default value + // the default value
"default_int32: 41\n"); "default_int32: 41\n");
assertParseErrorWithOverwriteForbidden( assertParseErrorWithOverwriteForbidden(
"2:17: Non-repeated field " "2:15: Non-repeated field "
+ "\"protobuf_unittest.TestAllTypes.default_string\" " + "\"protobuf_unittest.TestAllTypes.default_string\" "
+ "cannot be overwritten.", + "cannot be overwritten.",
"default_string: \"zxcv\"\ndefault_string: \"asdf\"\n"); "default_string: \"zxcv\"\ndefault_string: \"asdf\"\n");
@ -1044,7 +1112,7 @@ public class TextFormatTest extends TestCase {
fail("Expected parse exception."); fail("Expected parse exception.");
} catch (TextFormat.ParseException e) { } catch (TextFormat.ParseException e) {
assertEquals( assertEquals(
"1:36: Field \"protobuf_unittest.TestOneof2.foo_int\"" "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\""
+ " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\"," + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
+ " another member of oneof \"foo\".", + " another member of oneof \"foo\".",
e.getMessage()); e.getMessage());

@ -353,8 +353,8 @@ public class UnknownFieldSetTest extends TestCase {
/** /**
* Asserts that the given field sets are not equal and have different hash codes. * Asserts that the given field sets are not equal and have different hash codes.
* *
* @warning It's valid for non-equal objects to have the same hash code, so this test is stricter * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
* than it needs to be. However, this should happen relatively rarely. * stricter than it needs to be. However, this should happen relatively rarely.
*/ */
private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) { private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
String equalsError = String.format("%s should not be equal to %s", s1, s2); String equalsError = String.format("%s should not be equal to %s", s1, s2);

@ -42,13 +42,13 @@ import junit.framework.TestCase;
*/ */
public class UnmodifiableLazyStringListTest extends TestCase { public class UnmodifiableLazyStringListTest extends TestCase {
private static String STRING_A = "A"; private static final String STRING_A = "A";
private static String STRING_B = "B"; private static final String STRING_B = "B";
private static String STRING_C = "C"; private static final String STRING_C = "C";
private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A"); private static final ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B"); private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C"); private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
public void testReadOnlyMethods() { public void testReadOnlyMethods() {
LazyStringArrayList rawList = createSampleList(); LazyStringArrayList rawList = createSampleList();

@ -53,7 +53,7 @@ message TestAllTypes {
NestedEnum optional_nested_enum = 4; NestedEnum optional_nested_enum = 4;
NestedMessage optional_nested_message = 5; NestedMessage optional_nested_message = 5;
protobuf_unittest.TestRequired optional_proto2_message = 6; protobuf_unittest.TestRequired optional_proto2_message = 6;
NestedMessage optional_lazy_message = 7 [lazy=true]; NestedMessage optional_lazy_message = 7 [lazy = true];
oneof oneof_field { oneof oneof_field {
int32 oneof_int32 = 11; int32 oneof_int32 = 11;
@ -81,7 +81,7 @@ message TestOptionalFieldsOnly {
TestAllTypes.NestedEnum optional_nested_enum = 4; TestAllTypes.NestedEnum optional_nested_enum = 4;
TestAllTypes.NestedMessage optional_nested_message = 5; TestAllTypes.NestedMessage optional_nested_message = 5;
protobuf_unittest.TestRequired optional_proto2_message = 6; protobuf_unittest.TestRequired optional_proto2_message = 6;
TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy=true]; TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy = true];
} }
message TestRepeatedFieldsOnly { message TestRepeatedFieldsOnly {

@ -69,8 +69,7 @@ message BarPrime {
optional string name = 1; optional string name = 1;
} }
message Empty { message Empty {}
}
extend Foo { extend Foo {
optional int32 varint = 101; optional int32 varint = 101;

@ -70,15 +70,20 @@ message TestRecursiveMap {
map<int32, TestRecursiveMap> recursive_map_field = 2; map<int32, TestRecursiveMap> recursive_map_field = 2;
} }
// a decoy of TestMap for testing parsing errors // a decoy of TestMap for testing parsing errors
message BizarroTestMap { message BizarroTestMap {
map<int32, bytes> int32_to_int32_field = 1; // same key type, different value // same key type, different value
map<string, int32> int32_to_string_field = 2; // different key and value types map<int32, bytes> int32_to_int32_field = 1;
map<string, int32> int32_to_bytes_field = 3; // different key types, same value // different key and value types
map<string, bytes> int32_to_enum_field = 4; // different key and value types map<string, int32> int32_to_string_field = 2;
map<string, bytes> int32_to_message_field = 5; // different key and value types // different key types, same value
map<string, bytes> string_to_int32_field = 6; // same key type, different value map<string, int32> int32_to_bytes_field = 3;
// different key and value types
map<string, bytes> int32_to_enum_field = 4;
// different key and value types
map<string, bytes> int32_to_message_field = 5;
// same key type, different value
map<string, bytes> string_to_int32_field = 6;
} }
// Used to test that java reserved words can be used as protobuf field names // Used to test that java reserved words can be used as protobuf field names
@ -92,11 +97,13 @@ message ReservedAsMapField {
map<string, uint32> class = 4; map<string, uint32> class = 4;
map<string, uint32> int = 5; map<string, uint32> int = 5;
map<string, uint32> void = 6; map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords // These are also proto keywords
map<string, uint32> string = 7;
map<string, uint32> package = 8; map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, uint32> null = 10; map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, uint32> null = 10;
} }
message ReservedAsMapFieldWithEnumValue { message ReservedAsMapFieldWithEnumValue {
@ -110,11 +117,13 @@ message ReservedAsMapFieldWithEnumValue {
map<string, SampleEnum> class = 4; map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5; map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6; map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords // These are also proto keywords
map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8; map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, SampleEnum> null = 10; map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, SampleEnum> null = 10;
} }
package map_for_proto2_lite_test; package map_for_proto2_lite_test;
option java_package = "map_lite_test"; option java_package = "map_lite_test";

@ -72,15 +72,20 @@ message TestRecursiveMap {
map<int32, TestRecursiveMap> recursive_map_field = 2; map<int32, TestRecursiveMap> recursive_map_field = 2;
} }
// a decoy of TestMap for testing parsing errors // a decoy of TestMap for testing parsing errors
message BizarroTestMap { message BizarroTestMap {
map<int32, bytes> int32_to_int32_field = 1; // same key type, different value // same key type, different value
map<string, int32> int32_to_string_field = 2; // different key and value types map<int32, bytes> int32_to_int32_field = 1;
map<string, int32> int32_to_bytes_field = 3; // different key types, same value // different key and value types
map<string, bytes> int32_to_enum_field = 4; // different key and value types map<string, int32> int32_to_string_field = 2;
map<string, bytes> int32_to_message_field = 5; // different key and value types // different key types, same value
map<string, bytes> string_to_int32_field = 6; // same key type, different value map<string, int32> int32_to_bytes_field = 3;
// different key and value types
map<string, bytes> int32_to_enum_field = 4;
// different key and value types
map<string, bytes> int32_to_message_field = 5;
// same key type, different value
map<string, bytes> string_to_int32_field = 6;
} }
// Used to test that java reserved words can be used as protobuf field names // Used to test that java reserved words can be used as protobuf field names
@ -94,11 +99,13 @@ message ReservedAsMapField {
map<string, uint32> class = 4; map<string, uint32> class = 4;
map<string, uint32> int = 5; map<string, uint32> int = 5;
map<string, uint32> void = 6; map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords // These are also proto keywords
map<string, uint32> string = 7;
map<string, uint32> package = 8; map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, uint32> null = 10; map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, uint32> null = 10;
} }
message ReservedAsMapFieldWithEnumValue { message ReservedAsMapFieldWithEnumValue {
@ -112,9 +119,11 @@ message ReservedAsMapFieldWithEnumValue {
map<string, SampleEnum> class = 4; map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5; map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6; map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords // These are also proto keywords
map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8; map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, SampleEnum> null = 10; map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, SampleEnum> null = 10;
} }

@ -57,5 +57,4 @@ extend Message1 {
optional Message1 recursive_extension = 1001; optional Message1 recursive_extension = 1001;
} }
message RedactAllTypes { message RedactAllTypes {}
}

@ -30,10 +30,9 @@
syntax = "proto3"; syntax = "proto3";
package map_lite_test; package map_test;
option optimize_for = LITE_RUNTIME; option java_package = "map_test";
option java_package = "map_lite_test";
option java_outer_classname = "MapTestProto"; option java_outer_classname = "MapTestProto";
message TestMap { message TestMap {
@ -66,12 +65,18 @@ message TestOnChangeEventPropagation {
// a decoy of TestMap for testing parsing errors // a decoy of TestMap for testing parsing errors
message BizarroTestMap { message BizarroTestMap {
map<int32, bytes> int32_to_int32_field = 1; // same key type, different value // same key type, different value
map<string, int32> int32_to_string_field = 2; // different key and value types map<int32, bytes> int32_to_int32_field = 1;
map<string, int32> int32_to_bytes_field = 3; // different key types, same value // different key and value types
map<string, bytes> int32_to_enum_field = 4; // different key and value types map<string, int32> int32_to_string_field = 2;
map<string, bytes> int32_to_message_field = 5; // different key and value types // different key types, same value
map<string, bytes> string_to_int32_field = 6; // same key type, different value map<string, int32> int32_to_bytes_field = 3;
// different key and value types
map<string, bytes> int32_to_enum_field = 4;
// different key and value types
map<string, bytes> int32_to_message_field = 5;
// same key type, different value
map<string, bytes> string_to_int32_field = 6;
} }
// Used to test that java reserved words can be used as protobuf field names // Used to test that java reserved words can be used as protobuf field names
@ -85,11 +90,13 @@ message ReservedAsMapField {
map<string, uint32> class = 4; map<string, uint32> class = 4;
map<string, uint32> int = 5; map<string, uint32> int = 5;
map<string, uint32> void = 6; map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords // These are also proto keywords
map<string, uint32> string = 7;
map<string, uint32> package = 8; map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, uint32> null = 10; map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, uint32> null = 10;
} }
message ReservedAsMapFieldWithEnumValue { message ReservedAsMapFieldWithEnumValue {
@ -103,9 +110,11 @@ message ReservedAsMapFieldWithEnumValue {
map<string, SampleEnum> class = 4; map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5; map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6; map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords // These are also proto keywords
map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8; map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, SampleEnum> null = 10; map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, SampleEnum> null = 10;
} }

@ -65,12 +65,18 @@ message TestOnChangeEventPropagation {
// a decoy of TestMap for testing parsing errors // a decoy of TestMap for testing parsing errors
message BizarroTestMap { message BizarroTestMap {
map<int32, bytes> int32_to_int32_field = 1; // same key type, different value // same key type, different value
map<string, int32> int32_to_string_field = 2; // different key and value types map<int32, bytes> int32_to_int32_field = 1;
map<string, int32> int32_to_bytes_field = 3; // different key types, same value // different key and value types
map<string, bytes> int32_to_enum_field = 4; // different key and value types map<string, int32> int32_to_string_field = 2;
map<string, bytes> int32_to_message_field = 5; // different key and value types // different key types, same value
map<string, bytes> string_to_int32_field = 6; // same key type, different value map<string, int32> int32_to_bytes_field = 3;
// different key and value types
map<string, bytes> int32_to_enum_field = 4;
// different key and value types
map<string, bytes> int32_to_message_field = 5;
// same key type, different value
map<string, bytes> string_to_int32_field = 6;
} }
// Used to test that java reserved words can be used as protobuf field names // Used to test that java reserved words can be used as protobuf field names
@ -84,11 +90,13 @@ message ReservedAsMapField {
map<string, uint32> class = 4; map<string, uint32> class = 4;
map<string, uint32> int = 5; map<string, uint32> int = 5;
map<string, uint32> void = 6; map<string, uint32> void = 6;
map<string, uint32> string = 7; // These are also proto keywords // These are also proto keywords
map<string, uint32> string = 7;
map<string, uint32> package = 8; map<string, uint32> package = 8;
map<string, uint32> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, uint32> null = 10; map<string, uint32> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, uint32> null = 10;
} }
message ReservedAsMapFieldWithEnumValue { message ReservedAsMapFieldWithEnumValue {
@ -102,9 +110,11 @@ message ReservedAsMapFieldWithEnumValue {
map<string, SampleEnum> class = 4; map<string, SampleEnum> class = 4;
map<string, SampleEnum> int = 5; map<string, SampleEnum> int = 5;
map<string, SampleEnum> void = 6; map<string, SampleEnum> void = 6;
map<string, SampleEnum> string = 7; // These are also proto keywords // These are also proto keywords
map<string, SampleEnum> string = 7;
map<string, SampleEnum> package = 8; map<string, SampleEnum> package = 8;
map<string, SampleEnum> enum = 9; // Most recent Java reserved word // Most recent Java reserved word
map<string, SampleEnum> null = 10; map<string, SampleEnum> enum = 9;
// null is not a 'reserved word' per se but as a literal needs similar care // null is not a 'reserved word' per se but as a literal needs similar care
map<string, SampleEnum> null = 10;
} }

@ -37,7 +37,6 @@ package protobuf_unittest;
option java_multiple_files = true; option java_multiple_files = true;
option java_outer_classname = "NestedBuilders"; option java_outer_classname = "NestedBuilders";
message Vehicle { message Vehicle {
optional Engine engine = 1; optional Engine engine = 1;
repeated Wheel wheel = 2; repeated Wheel wheel = 2;

@ -41,10 +41,8 @@ message MessageToBeExtended {
extensions 1 to max; extensions 1 to max;
} }
message MyNonNestedExtension { message MyNonNestedExtension {}
}
extend MessageToBeExtended { extend MessageToBeExtended {
optional MyNonNestedExtension nonNestedExtension = 1; optional MyNonNestedExtension nonNestedExtension = 1;
} }

@ -42,10 +42,8 @@ message MessageLiteToBeExtended {
extensions 1 to max; extensions 1 to max;
} }
message MyNonNestedExtensionLite { message MyNonNestedExtensionLite {}
}
extend MessageLiteToBeExtended { extend MessageLiteToBeExtended {
optional MyNonNestedExtensionLite nonNestedExtensionLite = 1; optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
} }

@ -36,5 +36,4 @@ package protobuf_unittest;
// This message's name is the same with the default outer class name of this // 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 // proto file. It's used to test if the compiler can avoid this conflict
// correctly. // correctly.
message OuterClassNameTest { message OuterClassNameTest {}
}

@ -38,7 +38,6 @@ message TestMessage2 {
// This message's name is the same with the default outer class name of this // 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 // proto file. It's used to test if the compiler can avoid this conflict
// correctly. // correctly.
message OuterClassNameTest2 { message OuterClassNameTest2 {}
}
} }
} }

@ -38,8 +38,6 @@ message TestMessage3 {
// This enum's name is the same with the default outer class name of this // 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 // proto file. It's used to test if the compiler can avoid this conflict
// correctly. // correctly.
enum OuterClassNameTest3 { enum OuterClassNameTest3 { DUMMY_VALUE = 1; }
DUMMY_VALUE = 1;
}
} }
} }

@ -79,6 +79,12 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>20.0</version> <version>20.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>26.0</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

@ -25,6 +25,11 @@
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>

@ -30,6 +30,7 @@
package com.google.protobuf.util; package com.google.protobuf.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.IntMath.checkedAdd; import static com.google.common.math.IntMath.checkedAdd;
import static com.google.common.math.IntMath.checkedSubtract; import static com.google.common.math.IntMath.checkedSubtract;
import static com.google.common.math.LongMath.checkedAdd; import static com.google.common.math.LongMath.checkedAdd;
@ -53,6 +54,10 @@ public final class Durations {
static final long DURATION_SECONDS_MIN = -315576000000L; static final long DURATION_SECONDS_MIN = -315576000000L;
static final long DURATION_SECONDS_MAX = 315576000000L; static final long DURATION_SECONDS_MAX = 315576000000L;
private static final long SECONDS_PER_MINUTE = 60L;
private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 60;
private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
/** A constant holding the minimum valid {@link Duration}, approximately {@code -10,000} years. */ /** A constant holding the minimum valid {@link Duration}, approximately {@code -10,000} years. */
public static final Duration MIN_VALUE = public static final Duration MIN_VALUE =
Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build(); Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build();
@ -118,6 +123,7 @@ public final class Durations {
* and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero * and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
* value for the {@code nanos} field must be of the same sign as the {@code seconds} field. * value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static boolean isValid(long seconds, int nanos) { public static boolean isValid(long seconds, int nanos) {
if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) { if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
return false; return false;
@ -133,6 +139,39 @@ public final class Durations {
return true; return true;
} }
/** Returns whether the given {@link Duration} is negative or not. */
public static boolean isNegative(Duration duration) {
checkValid(duration);
return (duration.getSeconds() == 0) ? duration.getNanos() < 0 : duration.getSeconds() < 0;
}
/**
* Ensures that the given {@link Duration} is not negative.
*
* @throws IllegalArgumentException if {@code duration} is negative or invalid
* @throws NullPointerException if {@code duration} is {@code null}
*/
public static Duration checkNotNegative(Duration duration) {
checkValid(duration);
checkArgument(!isNegative(duration), "duration (%s) must not be negative", toString(duration));
return duration;
}
/**
* Ensures that the given {@link Duration} is positive.
*
* @throws IllegalArgumentException if {@code duration} is negative, {@code ZERO}, or invalid
* @throws NullPointerException if {@code duration} is {@code null}
*/
public static Duration checkPositive(Duration duration) {
checkValid(duration);
checkArgument(
!isNegative(duration) && !duration.equals(ZERO),
"duration (%s) must be positive",
toString(duration));
return duration;
}
/** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */ /** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
public static Duration checkValid(Duration duration) { public static Duration checkValid(Duration duration) {
long seconds = duration.getSeconds(); long seconds = duration.getSeconds();
@ -216,30 +255,125 @@ public final class Durations {
} }
} }
// Static factories
/** Create a Duration from the number of days. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromDays(long days) {
return Duration.newBuilder()
.setSeconds(checkedMultiply(days, SECONDS_PER_DAY))
.setNanos(0)
.build();
}
/** Create a Duration from the number of hours. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromHours(long hours) {
return Duration.newBuilder()
.setSeconds(checkedMultiply(hours, SECONDS_PER_HOUR))
.setNanos(0)
.build();
}
/** Create a Duration from the number of minutes. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromMinutes(long minutes) {
return Duration.newBuilder()
.setSeconds(checkedMultiply(minutes, SECONDS_PER_MINUTE))
.setNanos(0)
.build();
}
/** Create a Duration from the number of seconds. */ /** Create a Duration from the number of seconds. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromSeconds(long seconds) { public static Duration fromSeconds(long seconds) {
return normalizedDuration(seconds, 0); return normalizedDuration(seconds, 0);
} }
/** Create a Duration from the number of milliseconds. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromMillis(long milliseconds) {
return normalizedDuration(
milliseconds / MILLIS_PER_SECOND,
(int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
}
/** Create a Duration from the number of microseconds. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromMicros(long microseconds) {
return normalizedDuration(
microseconds / MICROS_PER_SECOND,
(int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
}
/** Create a Duration from the number of nanoseconds. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Duration fromNanos(long nanoseconds) {
return normalizedDuration(
nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
}
// Conversion APIs
/**
* Convert a Duration to the number of days. The result will be rounded towards 0 to the nearest
* day.
*/
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toDays(Duration duration) {
return checkValid(duration).getSeconds() / SECONDS_PER_DAY;
}
/**
* Convert a Duration to the number of hours. The result will be rounded towards 0 to the nearest
* hour.
*/
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toHours(Duration duration) {
return checkValid(duration).getSeconds() / SECONDS_PER_HOUR;
}
/**
* Convert a Duration to the number of minutes. The result will be rounded towards 0 to the
* nearest minute.
*/
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMinutes(Duration duration) {
return checkValid(duration).getSeconds() / SECONDS_PER_MINUTE;
}
/** /**
* Convert a Duration to the number of seconds. The result will be rounded towards 0 to the * Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
* nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0. * nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toSeconds(Duration duration) { public static long toSeconds(Duration duration) {
return checkValid(duration).getSeconds(); return checkValid(duration).getSeconds();
} }
/** Create a Duration from the number of milliseconds. */ /**
public static Duration fromMillis(long milliseconds) { * Returns the number of seconds of the given duration as a {@code double}. This method should be
return normalizedDuration( * used to accommodate APIs that <b>only</b> accept durations as {@code double} values.
milliseconds / MILLIS_PER_SECOND, *
(int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND)); * <p>This conversion may lose precision.
*
* <p>If you need the number of seconds in this duration as a {@code long} (not a {@code double}),
* simply use {@code duration.getSeconds()} or {@link #toSeconds} (which includes validation).
*/
@SuppressWarnings({
"DurationSecondsToDouble", // that's the whole point of this method
"GoodTime" // this is a legacy conversion API
})
public static double toSecondsAsDouble(Duration duration) {
checkValid(duration);
return duration.getSeconds() + duration.getNanos() / 1e9;
} }
/** /**
* Convert a Duration to the number of milliseconds. The result will be rounded towards 0 to the * Convert a Duration to the number of milliseconds. The result will be rounded towards 0 to the
* nearest millisecond. E.g., if the duration represents -1 nanosecond, it will be rounded to 0. * nearest millisecond. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMillis(Duration duration) { public static long toMillis(Duration duration) {
checkValid(duration); checkValid(duration);
return checkedAdd( return checkedAdd(
@ -247,17 +381,11 @@ public final class Durations {
duration.getNanos() / NANOS_PER_MILLISECOND); duration.getNanos() / NANOS_PER_MILLISECOND);
} }
/** Create a Duration from the number of microseconds. */
public static Duration fromMicros(long microseconds) {
return normalizedDuration(
microseconds / MICROS_PER_SECOND,
(int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
}
/** /**
* Convert a Duration to the number of microseconds. The result will be rounded towards 0 to the * Convert a Duration to the number of microseconds. The result will be rounded towards 0 to the
* nearest microseconds. E.g., if the duration represents -1 nanosecond, it will be rounded to 0. * nearest microseconds. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMicros(Duration duration) { public static long toMicros(Duration duration) {
checkValid(duration); checkValid(duration);
return checkedAdd( return checkedAdd(
@ -265,19 +393,16 @@ public final class Durations {
duration.getNanos() / NANOS_PER_MICROSECOND); duration.getNanos() / NANOS_PER_MICROSECOND);
} }
/** Create a Duration from the number of nanoseconds. */
public static Duration fromNanos(long nanoseconds) {
return normalizedDuration(
nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
}
/** Convert a Duration to the number of nanoseconds. */ /** Convert a Duration to the number of nanoseconds. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toNanos(Duration duration) { public static long toNanos(Duration duration) {
checkValid(duration); checkValid(duration);
return checkedAdd( return checkedAdd(
checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos()); checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos());
} }
// Math operations
/** Add two durations. */ /** Add two durations. */
public static Duration add(Duration d1, Duration d2) { public static Duration add(Duration d1, Duration d2) {
checkValid(d1); checkValid(d1);

@ -77,7 +77,9 @@ import java.io.StringReader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.text.ParseException; import java.text.ParseException;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -106,7 +108,7 @@ public class JsonFormat {
public static Printer printer() { public static Printer printer() {
return new Printer( return new Printer(
TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(), TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
false, false, false); false, false, false, false);
} }
/** /**
@ -127,6 +129,7 @@ public class JsonFormat {
private final boolean preservingProtoFieldNames; private final boolean preservingProtoFieldNames;
private final boolean omittingInsignificantWhitespace; private final boolean omittingInsignificantWhitespace;
private final boolean printingEnumsAsInts; private final boolean printingEnumsAsInts;
private final boolean sortingMapKeys;
private Printer( private Printer(
TypeRegistry registry, TypeRegistry registry,
@ -134,13 +137,15 @@ public class JsonFormat {
Set<FieldDescriptor> includingDefaultValueFields, Set<FieldDescriptor> includingDefaultValueFields,
boolean preservingProtoFieldNames, boolean preservingProtoFieldNames,
boolean omittingInsignificantWhitespace, boolean omittingInsignificantWhitespace,
boolean printingEnumsAsInts) { boolean printingEnumsAsInts,
boolean sortingMapKeys) {
this.registry = registry; this.registry = registry;
this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields; this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
this.includingDefaultValueFields = includingDefaultValueFields; this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames; this.preservingProtoFieldNames = preservingProtoFieldNames;
this.omittingInsignificantWhitespace = omittingInsignificantWhitespace; this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
this.printingEnumsAsInts = printingEnumsAsInts; this.printingEnumsAsInts = printingEnumsAsInts;
this.sortingMapKeys = sortingMapKeys;
} }
/** /**
@ -159,7 +164,8 @@ public class JsonFormat {
includingDefaultValueFields, includingDefaultValueFields,
preservingProtoFieldNames, preservingProtoFieldNames,
omittingInsignificantWhitespace, omittingInsignificantWhitespace,
printingEnumsAsInts); printingEnumsAsInts,
sortingMapKeys);
} }
/** /**
@ -176,7 +182,8 @@ public class JsonFormat {
Collections.<FieldDescriptor>emptySet(), Collections.<FieldDescriptor>emptySet(),
preservingProtoFieldNames, preservingProtoFieldNames,
omittingInsignificantWhitespace, omittingInsignificantWhitespace,
printingEnumsAsInts); printingEnumsAsInts,
sortingMapKeys);
} }
/** /**
@ -193,7 +200,8 @@ public class JsonFormat {
Collections.<FieldDescriptor>emptySet(), Collections.<FieldDescriptor>emptySet(),
preservingProtoFieldNames, preservingProtoFieldNames,
omittingInsignificantWhitespace, omittingInsignificantWhitespace,
true); true,
sortingMapKeys);
} }
private void checkUnsetPrintingEnumsAsInts() { private void checkUnsetPrintingEnumsAsInts() {
@ -221,7 +229,8 @@ public class JsonFormat {
fieldsToAlwaysOutput, fieldsToAlwaysOutput,
preservingProtoFieldNames, preservingProtoFieldNames,
omittingInsignificantWhitespace, omittingInsignificantWhitespace,
printingEnumsAsInts); printingEnumsAsInts,
sortingMapKeys);
} }
private void checkUnsetIncludingDefaultValueFields() { private void checkUnsetIncludingDefaultValueFields() {
@ -244,7 +253,8 @@ public class JsonFormat {
includingDefaultValueFields, includingDefaultValueFields,
true, true,
omittingInsignificantWhitespace, omittingInsignificantWhitespace,
printingEnumsAsInts); printingEnumsAsInts,
sortingMapKeys);
} }
@ -272,7 +282,31 @@ public class JsonFormat {
includingDefaultValueFields, includingDefaultValueFields,
preservingProtoFieldNames, preservingProtoFieldNames,
true, true,
printingEnumsAsInts); printingEnumsAsInts,
sortingMapKeys);
}
/**
* Create a new {@link Printer} that will sort the map keys in the JSON output.
*
* Use of this modifier is discouraged, the generated JSON messages are equivalent
* with and without this option set, but there are some corner caseuse cases that
* demand a stable output, while order of map keys is otherwise arbitrary.
*
* The generated order is not well-defined and should not be depended on, but
* it's stable.
*
* This new Printer clones all other configurations from the current {@link Printer}.
*/
public Printer sortingMapKeys() {
return new Printer(
registry,
alwaysOutputDefaultValueFields,
includingDefaultValueFields,
preservingProtoFieldNames,
omittingInsignificantWhitespace,
printingEnumsAsInts,
true);
} }
/** /**
@ -292,7 +326,8 @@ public class JsonFormat {
preservingProtoFieldNames, preservingProtoFieldNames,
output, output,
omittingInsignificantWhitespace, omittingInsignificantWhitespace,
printingEnumsAsInts) printingEnumsAsInts,
sortingMapKeys)
.print(message); .print(message);
} }
@ -604,6 +639,7 @@ public class JsonFormat {
private final Set<FieldDescriptor> includingDefaultValueFields; private final Set<FieldDescriptor> includingDefaultValueFields;
private final boolean preservingProtoFieldNames; private final boolean preservingProtoFieldNames;
private final boolean printingEnumsAsInts; private final boolean printingEnumsAsInts;
private final boolean sortingMapKeys;
private final TextGenerator generator; private final TextGenerator generator;
// We use Gson to help handle string escapes. // We use Gson to help handle string escapes.
private final Gson gson; private final Gson gson;
@ -621,12 +657,14 @@ public class JsonFormat {
boolean preservingProtoFieldNames, boolean preservingProtoFieldNames,
Appendable jsonOutput, Appendable jsonOutput,
boolean omittingInsignificantWhitespace, boolean omittingInsignificantWhitespace,
boolean printingEnumsAsInts) { boolean printingEnumsAsInts,
boolean sortingMapKeys) {
this.registry = registry; this.registry = registry;
this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields; this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
this.includingDefaultValueFields = includingDefaultValueFields; this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames; this.preservingProtoFieldNames = preservingProtoFieldNames;
this.printingEnumsAsInts = printingEnumsAsInts; this.printingEnumsAsInts = printingEnumsAsInts;
this.sortingMapKeys = sortingMapKeys;
this.gson = GsonHolder.DEFAULT_GSON; this.gson = GsonHolder.DEFAULT_GSON;
// json format related properties, determined by printerType // json format related properties, determined by printerType
if (omittingInsignificantWhitespace) { if (omittingInsignificantWhitespace) {
@ -957,8 +995,32 @@ public class JsonFormat {
} }
generator.print("{" + blankOrNewLine); generator.print("{" + blankOrNewLine);
generator.indent(); generator.indent();
@SuppressWarnings("unchecked") // Object guaranteed to be a List for a map field.
Collection<Object> elements = (List<Object>) value;
if (sortingMapKeys && !elements.isEmpty()) {
Comparator<Object> cmp = null;
if (keyField.getType() == FieldDescriptor.Type.STRING) {
cmp = new Comparator<Object>() {
@Override
public int compare(final Object o1, final Object o2) {
ByteString s1 = ByteString.copyFromUtf8((String) o1);
ByteString s2 = ByteString.copyFromUtf8((String) o2);
return ByteString.unsignedLexicographicalComparator().compare(s1, s2);
}
};
}
TreeMap<Object, Object> tm = new TreeMap<Object, Object>(cmp);
for (Object element : elements) {
Message entry = (Message) element;
Object entryKey = entry.getField(keyField);
tm.put(entryKey, element);
}
elements = tm.values();
}
boolean printedElement = false; boolean printedElement = false;
for (Object element : (List) value) { for (Object element : elements) {
Message entry = (Message) element; Message entry = (Message) element;
Object entryKey = entry.getField(keyField); Object entryKey = entry.getField(keyField);
Object entryValue = entry.getField(valueField); Object entryValue = entry.getField(valueField);

@ -325,6 +325,7 @@ public final class TimeUtil {
// Multiplications and divisions. // Multiplications and divisions.
// TODO(kak): Delete this. // TODO(kak): Delete this.
@SuppressWarnings("DurationSecondsToDouble")
public static Duration multiply(Duration duration, double times) { public static Duration multiply(Duration duration, double times) {
double result = duration.getSeconds() * times + duration.getNanos() * times / 1000000000.0; double result = duration.getSeconds() * times + duration.getNanos() * times / 1000000000.0;
if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) { if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) {

@ -150,6 +150,7 @@ public final class Timestamps {
* <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative * <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
* nanos values that count forward in time. * nanos values that count forward in time.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static boolean isValid(long seconds, int nanos) { public static boolean isValid(long seconds, int nanos) {
if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) { if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
return false; return false;
@ -266,6 +267,7 @@ public final class Timestamps {
} }
/** Create a Timestamp from the number of seconds elapsed from the epoch. */ /** Create a Timestamp from the number of seconds elapsed from the epoch. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromSeconds(long seconds) { public static Timestamp fromSeconds(long seconds) {
return normalizedTimestamp(seconds, 0); return normalizedTimestamp(seconds, 0);
} }
@ -276,11 +278,13 @@ public final class Timestamps {
* <p>The result will be rounded down to the nearest second. E.g., if the timestamp represents * <p>The result will be rounded down to the nearest second. E.g., if the timestamp represents
* "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 second. * "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 second.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toSeconds(Timestamp timestamp) { public static long toSeconds(Timestamp timestamp) {
return checkValid(timestamp).getSeconds(); return checkValid(timestamp).getSeconds();
} }
/** Create a Timestamp from the number of milliseconds elapsed from the epoch. */ /** Create a Timestamp from the number of milliseconds elapsed from the epoch. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromMillis(long milliseconds) { public static Timestamp fromMillis(long milliseconds) {
return normalizedTimestamp( return normalizedTimestamp(
milliseconds / MILLIS_PER_SECOND, milliseconds / MILLIS_PER_SECOND,
@ -293,6 +297,7 @@ public final class Timestamps {
* <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp * <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond. * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMillis(Timestamp timestamp) { public static long toMillis(Timestamp timestamp) {
checkValid(timestamp); checkValid(timestamp);
return checkedAdd( return checkedAdd(
@ -301,6 +306,7 @@ public final class Timestamps {
} }
/** Create a Timestamp from the number of microseconds elapsed from the epoch. */ /** Create a Timestamp from the number of microseconds elapsed from the epoch. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromMicros(long microseconds) { public static Timestamp fromMicros(long microseconds) {
return normalizedTimestamp( return normalizedTimestamp(
microseconds / MICROS_PER_SECOND, microseconds / MICROS_PER_SECOND,
@ -313,6 +319,7 @@ public final class Timestamps {
* <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp * <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 microsecond. * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 microsecond.
*/ */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toMicros(Timestamp timestamp) { public static long toMicros(Timestamp timestamp) {
checkValid(timestamp); checkValid(timestamp);
return checkedAdd( return checkedAdd(
@ -321,12 +328,14 @@ public final class Timestamps {
} }
/** Create a Timestamp from the number of nanoseconds elapsed from the epoch. */ /** Create a Timestamp from the number of nanoseconds elapsed from the epoch. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static Timestamp fromNanos(long nanoseconds) { public static Timestamp fromNanos(long nanoseconds) {
return normalizedTimestamp( return normalizedTimestamp(
nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND)); nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
} }
/** Convert a Timestamp to the number of nanoseconds elapsed from the epoch. */ /** Convert a Timestamp to the number of nanoseconds elapsed from the epoch. */
@SuppressWarnings("GoodTime") // this is a legacy conversion API
public static long toNanos(Timestamp timestamp) { public static long toNanos(Timestamp timestamp) {
checkValid(timestamp); checkValid(timestamp);
return checkedAdd( return checkedAdd(

@ -156,6 +156,9 @@ public class JsonFormatTest extends TestCase {
private String toCompactJsonString(Message message) throws IOException { private String toCompactJsonString(Message message) throws IOException {
return JsonFormat.printer().omittingInsignificantWhitespace().print(message); return JsonFormat.printer().omittingInsignificantWhitespace().print(message);
} }
private String toSortedJsonString(Message message) throws IOException {
return JsonFormat.printer().sortingMapKeys().print(message);
}
private void mergeFromJson(String json, Message.Builder builder) throws IOException { private void mergeFromJson(String json, Message.Builder builder) throws IOException {
JsonFormat.parser().merge(json, builder); JsonFormat.parser().merge(json, builder);
@ -1635,4 +1638,50 @@ public class JsonFormatTest extends TestCase {
// Expected. // Expected.
} }
} }
public void testSortedMapKeys() throws Exception {
TestMap.Builder mapBuilder = TestMap.newBuilder();
mapBuilder.putStringToInt32Map("\ud834\udd20", 3); // utf-8 F0 9D 84 A0
mapBuilder.putStringToInt32Map("foo", 99);
mapBuilder.putStringToInt32Map("xxx", 123);
mapBuilder.putStringToInt32Map("\u20ac", 1); // utf-8 E2 82 AC
mapBuilder.putStringToInt32Map("abc", 20);
mapBuilder.putStringToInt32Map("19", 19);
mapBuilder.putStringToInt32Map("8", 8);
mapBuilder.putStringToInt32Map("\ufb00", 2); // utf-8 EF AC 80
mapBuilder.putInt32ToInt32Map(3, 3);
mapBuilder.putInt32ToInt32Map(10, 10);
mapBuilder.putInt32ToInt32Map(5, 5);
mapBuilder.putInt32ToInt32Map(4, 4);
mapBuilder.putInt32ToInt32Map(1, 1);
mapBuilder.putInt32ToInt32Map(2, 2);
mapBuilder.putInt32ToInt32Map(-3, -3);
TestMap mapMessage = mapBuilder.build();
assertEquals(
"{\n"
+ " \"int32ToInt32Map\": {\n"
+ " \"-3\": -3,\n"
+ " \"1\": 1,\n"
+ " \"2\": 2,\n"
+ " \"3\": 3,\n"
+ " \"4\": 4,\n"
+ " \"5\": 5,\n"
+ " \"10\": 10\n"
+ " },\n"
+ " \"stringToInt32Map\": {\n"
+ " \"19\": 19,\n"
+ " \"8\": 8,\n"
+ " \"abc\": 20,\n"
+ " \"foo\": 99,\n"
+ " \"xxx\": 123,\n"
+ " \"\u20ac\": 1,\n"
+ " \"\ufb00\": 2,\n"
+ " \"\ud834\udd20\": 3\n"
+ " }\n"
+ "}",
toSortedJsonString(mapMessage));
TestMap emptyMap = TestMap.getDefaultInstance();
assertEquals("{\n}", toSortedJsonString(emptyMap));
}
} }

@ -659,5 +659,6 @@ describe('protoBinaryTest', function() {
'jspb.test.TestAllTypes'); 'jspb.test.TestAllTypes');
checkAllFields(msg, msg2); checkAllFields(msg, msg2);
}); });
}); });

@ -37,6 +37,7 @@ goog.provide('jspb.debug');
goog.require('goog.array'); goog.require('goog.array');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.object'); goog.require('goog.object');
goog.require('jspb.Map');
goog.require('jspb.Message'); goog.require('jspb.Message');
@ -90,6 +91,16 @@ jspb.debug.dump_ = function(thing) {
goog.asserts.assertArray(thing); goog.asserts.assertArray(thing);
return goog.array.map(thing, jspb.debug.dump_); return goog.array.map(thing, jspb.debug.dump_);
} }
if (message instanceof jspb.Map) {
var mapObject = {};
var entries = message.entries();
for (var entry = entries.next(); !entry.done; entry = entries.next()) {
mapObject[entry.value[0]] = jspb.debug.dump_(entry.value[1]);
}
return mapObject;
}
goog.asserts.assert(message instanceof jspb.Message, goog.asserts.assert(message instanceof jspb.Message,
'Only messages expected: ' + thing); 'Only messages expected: ' + thing);
var ctor = message.constructor; var ctor = message.constructor;

@ -38,7 +38,9 @@ goog.require('jspb.debug');
// CommonJS-LoadFromFile: test_pb // CommonJS-LoadFromFile: test_pb
goog.require('proto.jspb.test.HasExtensions'); goog.require('proto.jspb.test.HasExtensions');
goog.require('proto.jspb.test.IsExtension'); goog.require('proto.jspb.test.IsExtension');
goog.require('proto.jspb.test.MapValueMessageNoBinary');
goog.require('proto.jspb.test.Simple1'); goog.require('proto.jspb.test.Simple1');
goog.require('proto.jspb.test.TestMapFieldsNoBinary');
// CommonJS-LoadFromFile: testbinary_pb // CommonJS-LoadFromFile: testbinary_pb
@ -113,4 +115,74 @@ describe('debugTest', function() {
}, jspb.debug.dump(extendable)); }, jspb.debug.dump(extendable));
}); });
it('testMapsBasicTypes', function() {
if (COMPILED) {
return;
}
var message = new proto.jspb.test.TestMapFieldsNoBinary();
message.getMapBoolStringMap().set(true, 'bool_string_value1');
message.getMapBoolStringMap().set(false, 'bool_string_value2');
message.getMapStringInt32Map().set('key', 111);
assertObjectEquals({
'$name': 'proto.jspb.test.TestMapFieldsNoBinary',
'mapBoolStringMap': {
true: 'bool_string_value1',
false: 'bool_string_value2'
},
'mapInt32StringMap': {},
'mapInt64StringMap': {},
'mapStringBoolMap': {},
'mapStringDoubleMap': {},
'mapStringEnumMap': {},
'mapStringInt32Map': {
'key': 111
},
'mapStringInt64Map': {},
'mapStringMsgMap': {},
'mapStringStringMap': {},
'mapStringTestmapfieldsMap': {}
}, jspb.debug.dump(message));
});
it('testMapsMessageValues', function() {
if (COMPILED) {
return;
}
var value1 = new proto.jspb.test.MapValueMessageNoBinary();
value1.setFoo(1111);
var value2 = new proto.jspb.test.MapValueMessageNoBinary();
value2.setFoo(2222);
var message = new proto.jspb.test.TestMapFieldsNoBinary();
message.getMapStringMsgMap().set('key1', value1);
message.getMapStringMsgMap().set('key2', value2);
assertObjectEquals({
'$name': 'proto.jspb.test.TestMapFieldsNoBinary',
'mapBoolStringMap': {},
'mapInt32StringMap': {},
'mapInt64StringMap': {},
'mapStringBoolMap': {},
'mapStringDoubleMap': {},
'mapStringEnumMap': {},
'mapStringInt32Map': {},
'mapStringInt64Map': {},
'mapStringMsgMap': {
'key1': {
'$name': 'proto.jspb.test.MapValueMessageNoBinary',
'foo': 1111
},
'key2': {
'$name': 'proto.jspb.test.MapValueMessageNoBinary',
'foo': 2222
}
},
'mapStringStringMap': {},
'mapStringTestmapfieldsMap': {}
}, jspb.debug.dump(message));
});
}); });

@ -340,11 +340,17 @@ function makeTests(msgInfo, submessageCtor, suffix) {
assertElementsEquals(entryIterator.next().value, ['key2', 'value2']); assertElementsEquals(entryIterator.next().value, ['key2', 'value2']);
assertEquals(entryIterator.next().done, true); assertEquals(entryIterator.next().done, true);
if (typeof(Symbol) != 'undefined') { try {
var entryIterable = m.entries()[Symbol.iterator](); var entryIterable = m.entries()[Symbol.iterator]();
assertElementsEquals(entryIterable.next().value, ['key1', 'value1']); assertElementsEquals(entryIterable.next().value, ['key1', 'value1']);
assertElementsEquals(entryIterable.next().value, ['key2', 'value2']); assertElementsEquals(entryIterable.next().value, ['key2', 'value2']);
assertEquals(entryIterable.next().done, true); assertEquals(entryIterable.next().done, true);
} catch (err) {
// jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
// undefined in some environment.
if (err.name != 'TypeError' && err.name != 'ReferenceError') {
throw err;
}
} }
var keyIterator = m.keys(); var keyIterator = m.keys();
@ -352,22 +358,34 @@ function makeTests(msgInfo, submessageCtor, suffix) {
assertEquals(keyIterator.next().value, 'key2'); assertEquals(keyIterator.next().value, 'key2');
assertEquals(keyIterator.next().done, true); assertEquals(keyIterator.next().done, true);
if (typeof(Symbol) != 'undefined') { try {
var keyIterable = m.keys()[Symbol.iterator](); var keyIterable = m.keys()[Symbol.iterator]();
assertEquals(keyIterable.next().value, 'key1'); assertEquals(keyIterable.next().value, 'key1');
assertEquals(keyIterable.next().value, 'key2'); assertEquals(keyIterable.next().value, 'key2');
assertEquals(keyIterable.next().done, true); assertEquals(keyIterable.next().done, true);
} catch (err) {
// jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
// undefined in some environment.
if (err.name != 'TypeError' && err.name != 'ReferenceError') {
throw err;
}
} }
var valueIterator = m.values(); var valueIterator = m.values();
assertEquals(valueIterator.next().value, 'value1'); assertEquals(valueIterator.next().value, 'value1');
assertEquals(valueIterator.next().value, 'value2'); assertEquals(valueIterator.next().value, 'value2');
assertEquals(valueIterator.next().done, true); assertEquals(valueIterator.next().done, true);
if (typeof(Symbol) != 'undefined') { try {
var valueIterable = m.values()[Symbol.iterator](); var valueIterable = m.values()[Symbol.iterator]();
assertEquals(valueIterable.next().value, 'value1'); assertEquals(valueIterable.next().value, 'value1');
assertEquals(valueIterable.next().value, 'value2'); assertEquals(valueIterable.next().value, 'value2');
assertEquals(valueIterable.next().done, true); assertEquals(valueIterable.next().done, true);
} catch (err) {
// jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
// undefined in some environment.
if (err.name != 'TypeError' && err.name != 'ReferenceError') {
throw err;
}
} }
}); });
} }

@ -427,6 +427,24 @@ jspb.Message.isArray_ = function(o) {
goog.isArray(o); goog.isArray(o);
}; };
/**
* Returns true if the provided argument is an extension object.
* @param {*} o The object to classify as array or not.
* @return {boolean} True if the provided object is an extension object.
* @private
*/
jspb.Message.isExtensionObject_ = function(o) {
// Normal fields are never objects, so we can be sure that if we find an
// object here, then it's the extension object. However, we must ensure that
// the object is not an array, since arrays are valid field values (bytes
// fields can also be array).
// NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
// in Safari on iOS 8. See the description of CL/86511464 for details.
return (o !== null && typeof o == 'object' &&
!jspb.Message.isArray_(o) &&
!(jspb.Message.SUPPORTS_UINT8ARRAY_ && o instanceof Uint8Array));
};
/** /**
* If the array contains an extension object in its last position, then the * If the array contains an extension object in its last position, then the
@ -452,13 +470,7 @@ jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
if (msgLength) { if (msgLength) {
lastIndex = msgLength - 1; lastIndex = msgLength - 1;
var obj = msg.array[lastIndex]; var obj = msg.array[lastIndex];
// Normal fields are never objects, so we can be sure that if we find an if (jspb.Message.isExtensionObject_(obj)) {
// object here, then it's the extension object. However, we must ensure that
// the object is not an array, since arrays are valid field values.
// NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
// in Safari on iOS 8. See the description of CL/86511464 for details.
if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
!(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex); msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex);
msg.extensionObject_ = obj; msg.extensionObject_ = obj;
return; return;

@ -33,7 +33,6 @@
goog.setTestOnly(); goog.setTestOnly();
goog.require('goog.json'); goog.require('goog.json');
goog.require('goog.string');
goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.asserts'); goog.require('goog.testing.asserts');
goog.require('goog.userAgent'); goog.require('goog.userAgent');
@ -41,6 +40,38 @@ goog.require('goog.userAgent');
// CommonJS-LoadFromFile: google-protobuf jspb // CommonJS-LoadFromFile: google-protobuf jspb
goog.require('jspb.Message'); goog.require('jspb.Message');
// CommonJS-LoadFromFile: test15_pb proto.jspb.filenametest.package1
goog.require('proto.jspb.filenametest.package1.b');
// CommonJS-LoadFromFile: test14_pb proto.jspb.filenametest.package2
goog.require('proto.jspb.filenametest.package2.TestMessage');
// CommonJS-LoadFromFile: test13_pb proto.jspb.filenametest.package1
goog.require('proto.jspb.filenametest.package1.a');
goog.require('proto.jspb.filenametest.package1.TestMessage');
// CommonJS-LoadFromFile: test12_pb proto.jspb.circulartest
goog.require('proto.jspb.circulartest.ExtensionContainingType1');
goog.require('proto.jspb.circulartest.ExtensionContainingType2');
goog.require('proto.jspb.circulartest.ExtensionField1');
goog.require('proto.jspb.circulartest.ExtensionField2');
goog.require('proto.jspb.circulartest.ExtensionField3');
goog.require('proto.jspb.circulartest.MapField1');
goog.require('proto.jspb.circulartest.MapField2');
goog.require('proto.jspb.circulartest.MessageField1');
goog.require('proto.jspb.circulartest.MessageField2');
goog.require('proto.jspb.circulartest.NestedEnum1');
goog.require('proto.jspb.circulartest.NestedEnum2');
goog.require('proto.jspb.circulartest.NestedMessage1');
goog.require('proto.jspb.circulartest.NestedMessage2');
goog.require('proto.jspb.circulartest.RepeatedMessageField1');
goog.require('proto.jspb.circulartest.RepeatedMessageField2');
// CommonJS-LoadFromFile: test11_pb proto.jspb.exttest.reverse
goog.require('proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1');
goog.require('proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage2');
goog.require('proto.jspb.exttest.reverse.c');
// CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested // CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested
goog.require('proto.jspb.exttest.nested.TestNestedExtensionsMessage'); goog.require('proto.jspb.exttest.nested.TestNestedExtensionsMessage');
goog.require('proto.jspb.exttest.nested.TestOuterMessage'); goog.require('proto.jspb.exttest.nested.TestOuterMessage');
@ -77,6 +108,7 @@ goog.require('proto.jspb.test.TestCloneExtension');
goog.require('proto.jspb.test.TestEndsWithBytes'); goog.require('proto.jspb.test.TestEndsWithBytes');
goog.require('proto.jspb.test.TestGroup'); goog.require('proto.jspb.test.TestGroup');
goog.require('proto.jspb.test.TestGroup1'); goog.require('proto.jspb.test.TestGroup1');
goog.require('proto.jspb.test.TestLastFieldBeforePivot');
goog.require('proto.jspb.test.TestMessageWithOneof'); goog.require('proto.jspb.test.TestMessageWithOneof');
goog.require('proto.jspb.test.TestReservedNames'); goog.require('proto.jspb.test.TestReservedNames');
goog.require('proto.jspb.test.TestReservedNamesExtension'); goog.require('proto.jspb.test.TestReservedNamesExtension');
@ -284,42 +316,6 @@ describe('Message test suite', function() {
assertFalse(response.hasEnumField()); assertFalse(response.hasEnumField());
}); });
it('testClearFields', function() {
var data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
var foo = new proto.jspb.test.OptionalFields(data);
foo.clearAString();
foo.clearABool();
foo.clearANestedMessage();
foo.clearARepeatedMessageList();
foo.clearARepeatedStringList();
assertEquals('', foo.getAString());
assertEquals(false, foo.getABool());
assertUndefined(foo.getANestedMessage());
assertFalse(foo.hasAString());
assertFalse(foo.hasABool());
assertObjectEquals([], foo.getARepeatedMessageList());
assertObjectEquals([], foo.getARepeatedStringList());
// NOTE: We want the missing fields in 'expected' to be undefined,
// but we actually get a sparse array instead. We could use something
// like [1,undefined,2] to avoid this, except that this is still
// sparse on IE. No comment...
var expected = [,,, [], []];
expected[0] = expected[1] = expected[2] = undefined;
assertObjectEquals(expected, foo.toArray());
});
it('testDifferenceRawObject', /** @suppress {visibility} */ function() {
var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]);
var p2 = new proto.jspb.test.HasExtensions(['hi', 'what',
{1000: 'unique'}]);
var diff = /** @type {proto.jspb.test.HasExtensions} */
(jspb.Message.difference(p1, p2));
assertEquals('', diff.getStr1());
assertEquals('what', diff.getStr2());
assertEquals('', diff.getStr3());
assertEquals('unique', diff.extensionObject_[1000]);
});
it('testEqualsSimple', function() { it('testEqualsSimple', function() {
var s1 = new proto.jspb.test.Simple1(['hi']); var s1 = new proto.jspb.test.Simple1(['hi']);
assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi']))); assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi'])));
@ -419,6 +415,12 @@ describe('Message test suite', function() {
['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}])); ['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
}); });
it('testInitializeMessageWithLastFieldNull', function() {
// This tests for regression to bug http://b/117298778
var msg = new proto.jspb.test.TestLastFieldBeforePivot([null]);
assertNotUndefined(msg.getLastFieldBeforePivot());
});
it('testEqualsNonFinite', function() { it('testEqualsNonFinite', function() {
assertTrue(jspb.Message.compareFields(NaN, NaN)); assertTrue(jspb.Message.compareFields(NaN, NaN));
assertTrue(jspb.Message.compareFields(NaN, 'NaN')); assertTrue(jspb.Message.compareFields(NaN, 'NaN'));
@ -787,71 +789,6 @@ describe('Message test suite', function() {
message.getRecursiveOneofCase()); message.getRecursiveOneofCase());
}); });
it('testInitializeMessageWithSingleValueSetInOneof', function() {
var message = new proto.jspb.test.TestMessageWithOneof([,, 'x']);
assertEquals('x', message.getPone());
assertEquals('', message.getPthree());
assertEquals(
proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
message.getPartialOneofCase());
});
it('testKeepsLastWireValueSetInUnion_multipleValues', function() {
var message = new proto.jspb.test.TestMessageWithOneof([,, 'x',, 'y']);
assertEquals('', message.getPone());
assertEquals('y', message.getPthree());
assertEquals(
proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
message.getPartialOneofCase());
});
it('testSettingOneofFieldClearsOthers', function() {
var message = new proto.jspb.test.TestMessageWithOneof;
assertEquals('', message.getPone());
assertEquals('', message.getPthree());
assertFalse(message.hasPone());
assertFalse(message.hasPthree());
message.setPone('hi');
assertEquals('hi', message.getPone());
assertEquals('', message.getPthree());
assertTrue(message.hasPone());
assertFalse(message.hasPthree());
message.setPthree('bye');
assertEquals('', message.getPone());
assertEquals('bye', message.getPthree());
assertFalse(message.hasPone());
assertTrue(message.hasPthree());
});
it('testSettingOneofFieldDoesNotClearFieldsFromOtherUnions', function() {
var other = new proto.jspb.test.TestMessageWithOneof;
var message = new proto.jspb.test.TestMessageWithOneof;
assertEquals('', message.getPone());
assertEquals('', message.getPthree());
assertUndefined(message.getRone());
assertFalse(message.hasPone());
assertFalse(message.hasPthree());
message.setPone('hi');
message.setRone(other);
assertEquals('hi', message.getPone());
assertEquals('', message.getPthree());
assertEquals(other, message.getRone());
assertTrue(message.hasPone());
assertFalse(message.hasPthree());
message.setPthree('bye');
assertEquals('', message.getPone());
assertEquals('bye', message.getPthree());
assertEquals(other, message.getRone());
assertFalse(message.hasPone());
assertTrue(message.hasPthree());
});
it('testUnsetsOneofCaseWhenFieldIsCleared', function() { it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
var message = new proto.jspb.test.TestMessageWithOneof; var message = new proto.jspb.test.TestMessageWithOneof;
assertEquals( assertEquals(
@ -871,198 +808,192 @@ describe('Message test suite', function() {
message.getPartialOneofCase()); message.getPartialOneofCase());
}); });
it('testMessageWithDefaultOneofValues', function() { it('testFloatingPointFieldsSupportNan', function() {
var message = new proto.jspb.test.TestMessageWithOneof; var assertNan = function(x) {
assertEquals(1234, message.getAone()); assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.',
assertEquals(0, message.getAtwo()); goog.isNumber(x) && isNaN(x));
assertEquals( };
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
.DEFAULT_ONEOF_A_NOT_SET,
message.getDefaultOneofACase());
message.setAone(567); var message = new proto.jspb.test.FloatingPointFields([
assertEquals(567, message.getAone()); 'NaN', 'NaN', ['NaN', 'NaN'], 'NaN',
assertEquals(0, message.getAtwo()); 'NaN', 'NaN', ['NaN', 'NaN'], 'NaN'
assertEquals( ]);
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE, assertNan(message.getOptionalFloatField());
message.getDefaultOneofACase()); assertNan(message.getRequiredFloatField());
assertNan(message.getRepeatedFloatFieldList()[0]);
assertNan(message.getRepeatedFloatFieldList()[1]);
assertNan(message.getDefaultFloatField());
assertNan(message.getOptionalDoubleField());
assertNan(message.getRequiredDoubleField());
assertNan(message.getRepeatedDoubleFieldList()[0]);
assertNan(message.getRepeatedDoubleFieldList()[1]);
assertNan(message.getDefaultDoubleField());
});
message.setAtwo(890); it('testExtensionReverseOrder', function() {
assertEquals(1234, message.getAone()); var message2 =
assertEquals(890, message.getAtwo()); new proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage2;
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
message.getDefaultOneofACase());
message.clearAtwo(); message2.setExtension(
assertEquals(1234, message.getAone()); proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a, 233);
assertEquals(0, message.getAtwo()); message2.setExtension(
assertEquals( proto
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase .jspb
.DEFAULT_ONEOF_A_NOT_SET, .exttest
message.getDefaultOneofACase()); .reverse
}); .TestExtensionReverseOrderMessage1
.TestExtensionReverseOrderNestedMessage1.b, 2333);
message2.setExtension(proto.jspb.exttest.reverse.c, 23333);
it('testMessageWithDefaultOneofValues_defaultNotOnFirstField', function() {
var message = new proto.jspb.test.TestMessageWithOneof;
assertEquals(0, message.getBone());
assertEquals(1234, message.getBtwo());
assertFalse(message.hasBone());
assertFalse(message.hasBtwo());
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
.DEFAULT_ONEOF_B_NOT_SET,
message.getDefaultOneofBCase());
message.setBone(2);
assertEquals(2, message.getBone());
assertEquals(1234, message.getBtwo());
assertTrue(message.hasBone());
assertFalse(message.hasBtwo());
assertEquals( assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE, 233,
message.getDefaultOneofBCase()); message2.getExtension(
proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a));
message.setBtwo(3);
assertEquals(0, message.getBone());
assertFalse(message.hasBone());
assertTrue(message.hasBtwo());
assertEquals(3, message.getBtwo());
assertEquals( assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO, 2333,
message.getDefaultOneofBCase()); message2.getExtension(
proto
message.clearBtwo(); .jspb
assertEquals(0, message.getBone()); .exttest
assertFalse(message.hasBone()); .reverse
assertFalse(message.hasBtwo()); .TestExtensionReverseOrderMessage1
assertEquals(1234, message.getBtwo()); .TestExtensionReverseOrderNestedMessage1.b));
assertEquals( assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase 23333,
.DEFAULT_ONEOF_B_NOT_SET, message2.getExtension(proto.jspb.exttest.reverse.c));
message.getDefaultOneofBCase());
}); });
it('testInitializeMessageWithOneofDefaults', function() { it('testCircularDepsBaseOnMessageField', function() {
var message = var nestMessage1 = new proto.jspb.circulartest.MessageField1;
new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567)); var nestMessage2 = new proto.jspb.circulartest.MessageField2;
assertEquals(567, message.getAone()); var message1 = new proto.jspb.circulartest.MessageField1;
assertEquals(0, message.getAtwo()); var message2 = new proto.jspb.circulartest.MessageField2;
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
message.getDefaultOneofACase());
message = nestMessage1.setA(1);
new proto.jspb.test.TestMessageWithOneof(new Array(10).concat(890)); nestMessage2.setA(2);
assertEquals(1234, message.getAone()); message1.setB(nestMessage2);
assertEquals(890, message.getAtwo()); message2.setB(nestMessage1);
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
message.getDefaultOneofACase());
message =
new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567, 890)); assertEquals(2, message1.getB().getA());
assertEquals(1234, message.getAone()); assertEquals(1, message2.getB().getA());
assertEquals(890, message.getAtwo());
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
message.getDefaultOneofACase());
}); });
it('testInitializeMessageWithOneofDefaults_defaultNotSetOnFirstField',
function() {
var message;
message = it('testCircularDepsBaseOnRepeatedMessageField', function() {
new proto.jspb.test.TestMessageWithOneof(new Array(11).concat(567)); var nestMessage1 = new proto.jspb.circulartest.RepeatedMessageField1;
assertEquals(567, message.getBone()); var nestMessage2 = new proto.jspb.circulartest.RepeatedMessageField2;
assertEquals(1234, message.getBtwo()); var message1 = new proto.jspb.circulartest.RepeatedMessageField1;
assertEquals( var message2 = new proto.jspb.circulartest.RepeatedMessageField2;
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
message.getDefaultOneofBCase());
message = nestMessage1.setA(1);
new proto.jspb.test.TestMessageWithOneof(new Array(12).concat(890)); nestMessage2.setA(2);
assertEquals(0, message.getBone()); message1.setB(nestMessage2);
assertEquals(890, message.getBtwo()); message2.addB(nestMessage1);
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
message.getDefaultOneofBCase());
message = new proto.jspb.test.TestMessageWithOneof(
new Array(11).concat(567, 890)); assertEquals(2, message1.getB().getA());
assertEquals(0, message.getBone()); assertEquals(1, message2.getBList()[0].getA());
assertEquals(890, message.getBtwo());
assertEquals(
proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
message.getDefaultOneofBCase());
}); });
it('testOneofContainingAnotherMessage', function() { it('testCircularDepsBaseOnMapField', function() {
var message = new proto.jspb.test.TestMessageWithOneof; var nestMessage1 = new proto.jspb.circulartest.MapField1;
assertEquals( var nestMessage2 = new proto.jspb.circulartest.MapField2;
proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase. var message1 = new proto.jspb.circulartest.MapField1;
RECURSIVE_ONEOF_NOT_SET, var message2 = new proto.jspb.circulartest.MapField2;
message.getRecursiveOneofCase());
var other = new proto.jspb.test.TestMessageWithOneof; nestMessage1.setA(1);
message.setRone(other); nestMessage2.setA(2);
assertEquals(other, message.getRone()); message1.setB(nestMessage2);
assertEquals('', message.getRtwo()); message2.getBMap().set(1, nestMessage1);
assertEquals(
proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RONE,
message.getRecursiveOneofCase());
message.setRtwo('hi');
assertUndefined(message.getRone()); assertEquals(2, message1.getB().getA());
assertEquals('hi', message.getRtwo()); assertEquals(1, message2.getBMap().get(1).getA());
assertEquals(
proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RTWO,
message.getRecursiveOneofCase());
}); });
it('testQueryingOneofCaseEnsuresOnlyOneFieldIsSetInUnderlyingArray', it('testCircularDepsBaseOnNestedMessage', function() {
function() { var nestMessage1 =
var message = new proto.jspb.test.TestMessageWithOneof; new proto.jspb.circulartest.NestedMessage1.NestedNestedMessage;
message.setPone('x'); var nestMessage2 = new proto.jspb.circulartest.NestedMessage2;
assertEquals('x', message.getPone()); var message1 = new proto.jspb.circulartest.NestedMessage1;
assertEquals('', message.getPthree()); var message2 = new proto.jspb.circulartest.NestedMessage2;
nestMessage1.setA(1);
nestMessage2.setA(2);
message1.setB(nestMessage2);
message2.setB(nestMessage1);
assertEquals(2, message1.getB().getA());
assertEquals(1, message2.getB().getA());
});
it('testCircularDepsBaseOnNestedEnum', function() {
var nestMessage2 = new proto.jspb.circulartest.NestedEnum2;
var message1 = new proto.jspb.circulartest.NestedEnum1;
var message2 = new proto.jspb.circulartest.NestedEnum2;
nestMessage2.setA(2);
message1.setB(nestMessage2);
message2.setB(proto.jspb.circulartest.NestedEnum1.NestedNestedEnum.VALUE_1);
assertEquals(2, message1.getB().getA());
assertEquals( assertEquals(
proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE, proto.jspb.circulartest.NestedEnum1.NestedNestedEnum.VALUE_1,
message.getPartialOneofCase()); message2.getB());
});
it('testCircularDepsBaseOnExtensionContainingType', function() {
var nestMessage2 = new proto.jspb.circulartest.ExtensionContainingType2;
var message1 = new proto.jspb.circulartest.ExtensionContainingType1;
nestMessage2.setA(2);
message1.setB(nestMessage2);
message1.setExtension(
proto.jspb.circulartest.ExtensionContainingType2.c, 1);
var array = message.toArray();
assertEquals('x', array[2]);
assertUndefined(array[4]);
array[4] = 'y';
assertEquals(2, message1.getB().getA());
assertEquals( assertEquals(
proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE, 1,
message.getPartialOneofCase()); message1.getExtension(
assertUndefined(array[2]); proto.jspb.circulartest.ExtensionContainingType2.c));
assertEquals('y', array[4]);
}); });
it('testFloatingPointFieldsSupportNan', function() { it('testCircularDepsBaseOnExtensionField', function() {
var assertNan = function(x) { var nestMessage2 = new proto.jspb.circulartest.ExtensionField2;
assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.', var message1 = new proto.jspb.circulartest.ExtensionField1;
goog.isNumber(x) && isNaN(x)); var message3 = new proto.jspb.circulartest.ExtensionField3;
};
var message = new proto.jspb.test.FloatingPointFields([ nestMessage2.setA(2);
'NaN', 'NaN', ['NaN', 'NaN'], 'NaN', message1.setB(nestMessage2);
'NaN', 'NaN', ['NaN', 'NaN'], 'NaN' message3.setExtension(proto.jspb.circulartest.ExtensionField2.c, message1);
]);
assertNan(message.getOptionalFloatField());
assertNan(message.getRequiredFloatField()); assertEquals(
assertNan(message.getRepeatedFloatFieldList()[0]); 2,
assertNan(message.getRepeatedFloatFieldList()[1]); message3.getExtension(proto.jspb.circulartest.ExtensionField2.c)
assertNan(message.getDefaultFloatField()); .getB()
assertNan(message.getOptionalDoubleField()); .getA());
assertNan(message.getRequiredDoubleField()); });
assertNan(message.getRepeatedDoubleFieldList()[0]);
assertNan(message.getRepeatedDoubleFieldList()[1]); it('testSameMessageNameOuputs', function() {
assertNan(message.getDefaultDoubleField()); var package1Message = new proto.jspb.filenametest.package1.TestMessage;
var package2Message = new proto.jspb.filenametest.package2.TestMessage;
package1Message.setExtension(
proto.jspb.filenametest.package1.a, 10);
package1Message.setExtension(
proto.jspb.filenametest.package1.b, 11);
package2Message.setA(12);
assertEquals(10,
package1Message.getExtension(proto.jspb.filenametest.package1.a));
assertEquals(11,
package1Message.getExtension(proto.jspb.filenametest.package1.b));
assertEquals(12, package2Message.getA());
}); });
}); });

@ -30,17 +30,15 @@
goog.require('goog.crypt.base64'); goog.require('goog.crypt.base64');
goog.require('goog.testing.asserts'); goog.require('goog.testing.asserts');
// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test // CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
goog.require('proto.jspb.test.ForeignMessage'); goog.require('proto.jspb.test.ForeignMessage');
// CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test // CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
goog.require('proto.jspb.test.Proto3Enum'); goog.require('proto.jspb.test.Proto3Enum');
goog.require('proto.jspb.test.TestProto3'); goog.require('proto.jspb.test.TestProto3');
// CommonJS-LoadFromFile: google/protobuf/any_pb proto.google.protobuf
goog.require('proto.google.protobuf.Any');
// CommonJS-LoadFromFile: google/protobuf/timestamp_pb proto.google.protobuf // CommonJS-LoadFromFile: google/protobuf/timestamp_pb proto.google.protobuf
goog.require('proto.google.protobuf.Timestamp'); goog.require('proto.google.protobuf.Timestamp');
// CommonJS-LoadFromFile: google/protobuf/struct_pb proto.google.protobuf // CommonJS-LoadFromFile: google/protobuf/struct_pb proto.google.protobuf
goog.require('proto.google.protobuf.Struct'); goog.require('proto.google.protobuf.Struct');
@ -377,6 +375,7 @@ describe('proto3Test', function() {
}); });
it('testTimestampWellKnownType', function() { it('testTimestampWellKnownType', function() {
var msg = new proto.google.protobuf.Timestamp(); var msg = new proto.google.protobuf.Timestamp();
msg.fromDate(new Date(123456789)); msg.fromDate(new Date(123456789));
@ -384,6 +383,9 @@ describe('proto3Test', function() {
assertEquals(789000000, msg.getNanos()); assertEquals(789000000, msg.getNanos());
var date = msg.toDate(); var date = msg.toDate();
assertEquals(123456789, date.getTime()); assertEquals(123456789, date.getTime());
var anotherMsg = proto.google.protobuf.Timestamp.fromDate(date);
assertEquals(msg.getSeconds(), anotherMsg.getSeconds());
assertEquals(msg.getNanos(), anotherMsg.getNanos());
}); });
it('testStructWellKnownType', function() { it('testStructWellKnownType', function() {

@ -241,6 +241,17 @@ message TestEndsWithBytes {
optional bytes data = 2; optional bytes data = 2;
} }
// This message is for testing extension handling doesn't affect fields before
// pivot. Don't add new field to this message. See b/117298778 for more detail.
message TestLastFieldBeforePivot {
optional int32 last_field_before_pivot = 1;
extensions 100 to max;
}
extend TestLastFieldBeforePivot {
optional int32 extend_test_last_field_before_pivot_field = 101;
}
message Int64Types { message Int64Types {
optional int64 int64_normal = 1 [jstype=JS_NORMAL]; optional int64 int64_normal = 1 [jstype=JS_NORMAL];

@ -0,0 +1,52 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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.
syntax = "proto2";
package jspb.exttest.reverse;
message TestExtensionReverseOrderMessage1 {
extend TestExtensionReverseOrderMessage2 {
optional int32 a = 1;
}
message TestExtensionReverseOrderNestedMessage1 {
extend TestExtensionReverseOrderMessage2 {
optional int32 b = 2;
}
}
}
extend TestExtensionReverseOrderMessage2 {
optional int32 c = 3;
}
message TestExtensionReverseOrderMessage2 {
extensions 1 to 100;
}

@ -0,0 +1,119 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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.
syntax = "proto2";
package jspb.circulartest;
message MessageField1 {
optional int32 a = 1;
optional MessageField2 b = 2;
}
message MessageField2 {
optional int32 a = 1;
optional MessageField1 b = 2;
}
message RepeatedMessageField1 {
optional int32 a = 1;
optional RepeatedMessageField2 b = 2;
}
message RepeatedMessageField2 {
optional int32 a = 1;
repeated RepeatedMessageField1 b = 2;
}
message MapField1 {
optional int32 a = 1;
optional MapField2 b = 2;
}
message MapField2 {
optional int32 a = 1;
map<int32, MapField1> b = 2;
}
message NestedMessage1 {
optional NestedMessage2 b = 2;
message NestedNestedMessage {
optional int32 a = 1;
}
}
message NestedMessage2 {
optional int32 a = 1;
optional NestedMessage1.NestedNestedMessage b = 2;
}
message NestedEnum1 {
optional NestedEnum2 b = 2;
enum NestedNestedEnum {
UNDEFINED = 0;
VALUE_1 = 1;
}
}
message NestedEnum2 {
optional int32 a = 1;
optional NestedEnum1.NestedNestedEnum b = 2;
}
message ExtensionContainingType1 {
optional int32 a = 1;
optional ExtensionContainingType2 b = 2;
extensions 99 to 100;
}
message ExtensionContainingType2 {
optional int32 a = 1;
extend ExtensionContainingType1 {
optional int32 c = 99;
}
}
message ExtensionField1 {
optional int32 a = 1;
optional ExtensionField2 b = 2;
}
message ExtensionField2 {
optional int32 a = 1;
extend ExtensionField3 {
optional ExtensionField1 c = 99;
}
}
message ExtensionField3 {
extensions 99 to 100;
}

@ -0,0 +1,70 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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.
syntax = "proto2";
package jspb.filenametest.package1;
message TestMessage {
extensions 1 to 100;
}
extend TestMessage {
optional int32 a = 1;
}
enum TestEnum {
VALUE_0 = 0;
VALUE_1 = 1;
}
message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1 {
optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2
a = 1;
optional int32 b = 2;
}
message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2 {
optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3
a = 1;
optional int32 b = 2;
}
message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3 {
optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4
a = 1;
optional int32 b = 2;
}
message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4 {
optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1
a = 1;
optional int32 b = 2;
}

@ -0,0 +1,43 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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.
syntax = "proto2";
package jspb.filenametest.package2;
message TestMessage {
optional int32 a = 1;
}
enum TestEnum {
VALUE_0 = 0;
VALUE_1 = 1;
VALUE_2 = 2;
}

@ -0,0 +1,39 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// 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.
syntax = "proto2";
import "test13.proto";
package jspb.filenametest.package1;
extend TestMessage {
optional int32 b = 2;
}

@ -41,12 +41,12 @@ are:
__author__ = 'petar@google.com (Petar Petrov)' __author__ = 'petar@google.com (Petar Petrov)'
import sys
try: try:
# This fallback applies for all versions of Python before 3.3 # This fallback applies for all versions of Python before 3.3
import collections.abc as collections_abc import collections.abc as collections_abc
except ImportError: except ImportError:
import collections as collections_abc import collections as collections_abc
import sys
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
# We would use collections_abc.MutableMapping all the time, but in Python 2 # We would use collections_abc.MutableMapping all the time, but in Python 2

@ -529,10 +529,6 @@ class DescriptorPoolTestBase(object):
conflict_fd = copy.deepcopy(unittest_fd) conflict_fd = copy.deepcopy(unittest_fd)
conflict_fd.name = 'other_file' conflict_fd.name = 'other_file'
if api_implementation.Type() == 'cpp': if api_implementation.Type() == 'cpp':
try:
self.pool.Add(unittest_fd)
self.pool.Add(conflict_fd)
except TypeError:
pass pass
else: else:
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:

@ -192,6 +192,14 @@ class DescriptorTest(unittest.TestCase):
self.assertTrue(enum_value_descriptor.has_options) self.assertTrue(enum_value_descriptor.has_options)
self.assertFalse(other_enum_value_descriptor.has_options) self.assertFalse(other_enum_value_descriptor.has_options)
def testCustomOptionsCopyTo(self):
message_descriptor = (unittest_custom_options_pb2.
TestMessageWithCustomOptions.DESCRIPTOR)
message_proto = descriptor_pb2.DescriptorProto()
message_descriptor.CopyToProto(message_proto)
self.assertEqual(len(message_proto.options.ListFields()),
2)
def testDifferentCustomOptionTypes(self): def testDifferentCustomOptionTypes(self):
kint32min = -2**31 kint32min = -2**31
kint64min = -2**63 kint64min = -2**63

@ -46,7 +46,7 @@ class EnumTypeWrapper(object):
def __init__(self, enum_type): def __init__(self, enum_type):
"""Inits EnumTypeWrapper with an EnumDescriptor.""" """Inits EnumTypeWrapper with an EnumDescriptor."""
self._enum_type = enum_type self._enum_type = enum_type
self.DESCRIPTOR = enum_type; self.DESCRIPTOR = enum_type
def Name(self, number): def Name(self, number):
"""Returns a string containing the name of an enum value.""" """Returns a string containing the name of an enum value."""
@ -56,7 +56,7 @@ class EnumTypeWrapper(object):
self._enum_type.name, number)) self._enum_type.name, number))
def Value(self, name): def Value(self, name):
"""Returns the value coresponding to the given enum name.""" """Returns the value corresponding to the given enum name."""
if name in self._enum_type.values_by_name: if name in self._enum_type.values_by_name:
return self._enum_type.values_by_name[name].number return self._enum_type.values_by_name[name].number
raise ValueError('Enum %s has no value defined for name %s' % ( raise ValueError('Enum %s has no value defined for name %s' % (

@ -523,7 +523,8 @@ class JsonFormatTest(JsonFormatBase):
'}')) '}'))
parsed_message = json_format_proto3_pb2.TestStruct() parsed_message = json_format_proto3_pb2.TestStruct()
self.CheckParseBack(message, parsed_message) self.CheckParseBack(message, parsed_message)
parsed_message.value['empty_struct'] # check for regression; this used to raise # check for regression; this used to raise
parsed_message.value['empty_struct']
parsed_message.value['empty_list'] parsed_message.value['empty_list']
def testValueMessage(self): def testValueMessage(self):

@ -159,15 +159,6 @@ class MessageTest(BaseTestCase):
with self.assertRaises(message.DecodeError) as context: with self.assertRaises(message.DecodeError) as context:
msg.FromString(end_tag) msg.FromString(end_tag)
self.assertEqual('Unexpected end-group tag.', str(context.exception)) self.assertEqual('Unexpected end-group tag.', str(context.exception))
else:
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter('always')
msg.FromString(end_tag)
assert len(w) == 1
assert issubclass(w[-1].category, RuntimeWarning)
self.assertEqual('Unexpected end-group tag: Not all data was converted',
str(w[-1].message))
def testDeterminismParameters(self, message_module): def testDeterminismParameters(self, message_module):
# This message is always deterministically serialized, even if determinism # This message is always deterministically serialized, even if determinism
@ -1791,6 +1782,13 @@ class Proto3Test(BaseTestCase):
old_map_value = msg2.map_int32_foreign_message[222] old_map_value = msg2.map_int32_foreign_message[222]
msg2.MergeFrom(msg) msg2.MergeFrom(msg)
# Compare with expected message instead of call
# msg2.map_int32_foreign_message[222] to make sure MergeFrom does not
# sync with repeated field and there is no duplicated keys.
expected_msg = map_unittest_pb2.TestMap()
expected_msg.CopyFrom(msg)
expected_msg.map_int64_int64[88] = 99
self.assertEqual(msg2, expected_msg)
self.assertEqual(34, msg2.map_int32_int32[12]) self.assertEqual(34, msg2.map_int32_int32[12])
self.assertEqual(78, msg2.map_int32_int32[56]) self.assertEqual(78, msg2.map_int32_int32[56])
@ -1854,9 +1852,13 @@ class Proto3Test(BaseTestCase):
self.assertEqual(99, msg2.map_int64_int64[88]) self.assertEqual(99, msg2.map_int64_int64[88])
msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message) msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message)
self.assertEqual(5, msg2.map_int32_foreign_message[111].c) # Compare with expected message instead of call
self.assertEqual(10, msg2.map_int32_foreign_message[222].c) # msg.map_int32_foreign_message[222] to make sure MergeFrom does not
self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d')) # sync with repeated field and no duplicated keys.
expected_msg = map_unittest_pb2.TestMap()
expected_msg.CopyFrom(msg)
expected_msg.map_int64_int64[88] = 99
self.assertEqual(msg2, expected_msg)
# Test when cpp extension cache a map. # Test when cpp extension cache a map.
m1 = map_unittest_pb2.TestMap() m1 = map_unittest_pb2.TestMap()

@ -294,7 +294,7 @@ def _IsMapField(field):
def _IsMessageMapField(field): def _IsMessageMapField(field):
value_type = field.message_type.fields_by_name["value"] value_type = field.message_type.fields_by_name['value']
return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
@ -311,12 +311,12 @@ def _AttachFieldHelpers(cls, field_descriptor):
wire_format.IsTypePackable(field_descriptor.type)) wire_format.IsTypePackable(field_descriptor.type))
if not is_packable: if not is_packable:
is_packed = False is_packed = False
elif field_descriptor.containing_type.syntax == "proto2": elif field_descriptor.containing_type.syntax == 'proto2':
is_packed = (field_descriptor.has_options and is_packed = (field_descriptor.has_options and
field_descriptor.GetOptions().packed) field_descriptor.GetOptions().packed)
else: else:
has_packed_false = (field_descriptor.has_options and has_packed_false = (field_descriptor.has_options and
field_descriptor.GetOptions().HasField("packed") and field_descriptor.GetOptions().HasField('packed') and
field_descriptor.GetOptions().packed == False) field_descriptor.GetOptions().packed == False)
is_packed = not has_packed_false is_packed = not has_packed_false
is_map_entry = _IsMapField(field_descriptor) is_map_entry = _IsMapField(field_descriptor)
@ -529,7 +529,7 @@ def _AddInitMethod(message_descriptor, cls):
for field_name, field_value in kwargs.items(): for field_name, field_value in kwargs.items():
field = _GetFieldByName(message_descriptor, field_name) field = _GetFieldByName(message_descriptor, field_name)
if field is None: if field is None:
raise TypeError("%s() got an unexpected keyword argument '%s'" % raise TypeError('%s() got an unexpected keyword argument "%s"' %
(message_descriptor.name, field_name)) (message_descriptor.name, field_name))
if field_value is None: if field_value is None:
# field=None is the same as no field at all. # field=None is the same as no field at all.
@ -619,7 +619,7 @@ def _AddPropertiesForField(field, cls):
# handle specially here. # handle specially here.
assert _FieldDescriptor.MAX_CPPTYPE == 10 assert _FieldDescriptor.MAX_CPPTYPE == 10
constant_name = field.name.upper() + "_FIELD_NUMBER" constant_name = field.name.upper() + '_FIELD_NUMBER'
setattr(cls, constant_name, field.number) setattr(cls, constant_name, field.number)
if field.label == _FieldDescriptor.LABEL_REPEATED: if field.label == _FieldDescriptor.LABEL_REPEATED:
@ -698,7 +698,7 @@ def _AddPropertiesForNonRepeatedScalarField(field, cls):
type_checker = type_checkers.GetTypeChecker(field) type_checker = type_checkers.GetTypeChecker(field)
default_value = field.default_value default_value = field.default_value
valid_values = set() valid_values = set()
is_proto3 = field.containing_type.syntax == "proto3" is_proto3 = field.containing_type.syntax == 'proto3'
def getter(self): def getter(self):
# TODO(protobuf-team): This may be broken since there may not be # TODO(protobuf-team): This may be broken since there may not be
@ -786,7 +786,7 @@ def _AddPropertiesForExtensions(descriptor, cls):
"""Adds properties for all fields in this protocol message type.""" """Adds properties for all fields in this protocol message type."""
extension_dict = descriptor.extensions_by_name extension_dict = descriptor.extensions_by_name
for extension_name, extension_field in extension_dict.items(): for extension_name, extension_field in extension_dict.items():
constant_name = extension_name.upper() + "_FIELD_NUMBER" constant_name = extension_name.upper() + '_FIELD_NUMBER'
setattr(cls, constant_name, extension_field.number) setattr(cls, constant_name, extension_field.number)
# TODO(amauryfa): Migrate all users of these attributes to functions like # TODO(amauryfa): Migrate all users of these attributes to functions like
@ -835,14 +835,15 @@ def _AddListFieldsMethod(message_descriptor, cls):
cls.ListFields = ListFields cls.ListFields = ListFields
_Proto3HasError = 'Protocol message has no non-repeated submessage field "%s"' _PROTO3_ERROR_TEMPLATE = \
_Proto2HasError = 'Protocol message has no non-repeated field "%s"' 'Protocol message %s has no non-repeated submessage field "%s"'
_PROTO2_ERROR_TEMPLATE = 'Protocol message %s has no non-repeated field "%s"'
def _AddHasFieldMethod(message_descriptor, cls): def _AddHasFieldMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods().""" """Helper for _AddMessageMethods()."""
is_proto3 = (message_descriptor.syntax == "proto3") is_proto3 = (message_descriptor.syntax == "proto3")
error_msg = _Proto3HasError if is_proto3 else _Proto2HasError error_msg = _PROTO3_ERROR_TEMPLATE if is_proto3 else _PROTO2_ERROR_TEMPLATE
hassable_fields = {} hassable_fields = {}
for field in message_descriptor.fields: for field in message_descriptor.fields:
@ -863,7 +864,7 @@ def _AddHasFieldMethod(message_descriptor, cls):
try: try:
field = hassable_fields[field_name] field = hassable_fields[field_name]
except KeyError: except KeyError:
raise ValueError(error_msg % field_name) raise ValueError(error_msg % (message_descriptor.full_name, field_name))
if isinstance(field, descriptor_mod.OneofDescriptor): if isinstance(field, descriptor_mod.OneofDescriptor):
try: try:
@ -893,7 +894,7 @@ def _AddClearFieldMethod(message_descriptor, cls):
else: else:
return return
except KeyError: except KeyError:
raise ValueError('Protocol message %s() has no "%s" field.' % raise ValueError('Protocol message %s has no "%s" field.' %
(message_descriptor.name, field_name)) (message_descriptor.name, field_name))
if field in self._fields: if field in self._fields:
@ -1278,7 +1279,7 @@ def _AddIsInitializedMethod(message_descriptor, cls):
for field, value in self.ListFields(): for field, value in self.ListFields():
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
if field.is_extension: if field.is_extension:
name = "(%s)" % field.full_name name = '(%s)' % field.full_name
else: else:
name = field.name name = field.name
@ -1286,7 +1287,7 @@ def _AddIsInitializedMethod(message_descriptor, cls):
if _IsMessageMapField(field): if _IsMessageMapField(field):
for key in value: for key in value:
element = value[key] element = value[key]
prefix = "%s[%s]." % (name, key) prefix = '%s[%s].' % (name, key)
sub_errors = element.FindInitializationErrors() sub_errors = element.FindInitializationErrors()
errors += [prefix + error for error in sub_errors] errors += [prefix + error for error in sub_errors]
else: else:
@ -1295,11 +1296,11 @@ def _AddIsInitializedMethod(message_descriptor, cls):
elif field.label == _FieldDescriptor.LABEL_REPEATED: elif field.label == _FieldDescriptor.LABEL_REPEATED:
for i in range(len(value)): for i in range(len(value)):
element = value[i] element = value[i]
prefix = "%s[%d]." % (name, i) prefix = '%s[%d].' % (name, i)
sub_errors = element.FindInitializationErrors() sub_errors = element.FindInitializationErrors()
errors += [prefix + error for error in sub_errors] errors += [prefix + error for error in sub_errors]
else: else:
prefix = name + "." prefix = name + '.'
sub_errors = value.FindInitializationErrors() sub_errors = value.FindInitializationErrors()
errors += [prefix + error for error in sub_errors] errors += [prefix + error for error in sub_errors]
@ -1315,7 +1316,7 @@ def _AddMergeFromMethod(cls):
def MergeFrom(self, msg): def MergeFrom(self, msg):
if not isinstance(msg, cls): if not isinstance(msg, cls):
raise TypeError( raise TypeError(
"Parameter to MergeFrom() must be instance of same class: " 'Parameter to MergeFrom() must be instance of same class: '
'expected %s got %s.' % (cls.__name__, msg.__class__.__name__)) 'expected %s got %s.' % (cls.__name__, msg.__class__.__name__))
assert msg is not self assert msg is not self
@ -1611,8 +1612,8 @@ class _ExtensionDict(object):
other_fields = other._extended_message.ListFields() other_fields = other._extended_message.ListFields()
# Get rid of non-extension fields. # Get rid of non-extension fields.
my_fields = [ field for field in my_fields if field.is_extension ] my_fields = [field for field in my_fields if field.is_extension]
other_fields = [ field for field in other_fields if field.is_extension ] other_fields = [field for field in other_fields if field.is_extension]
return my_fields == other_fields return my_fields == other_fields

@ -50,9 +50,11 @@ except ImportError:
from google.protobuf import any_pb2 from google.protobuf import any_pb2
from google.protobuf import any_test_pb2 from google.protobuf import any_test_pb2
from google.protobuf import map_unittest_pb2 from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
from google.protobuf import unittest_proto3_arena_pb2 from google.protobuf import unittest_proto3_arena_pb2
from google.protobuf import descriptor_pb2
from google.protobuf.internal import any_test_pb2 as test_extend_any from google.protobuf.internal import any_test_pb2 as test_extend_any
from google.protobuf.internal import message_set_extensions_pb2 from google.protobuf.internal import message_set_extensions_pb2
from google.protobuf.internal import test_util from google.protobuf.internal import test_util
@ -175,7 +177,10 @@ class TextFormatMessageToStringTests(TextFormatBase):
'repeated_nested_message {\n bb: 32\n}\n' 'repeated_nested_message {\n bb: 32\n}\n'
'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n') 'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n')
if as_one_line: if as_one_line:
expected_ascii = expected_ascii.replace('\n ', '').replace('\n', '') expected_ascii = expected_ascii.replace('\n', ' ')
expected_ascii = re.sub(r'\s+', ' ', expected_ascii)
expected_ascii = re.sub(r'\s$', '', expected_ascii)
actual_ascii = text_format.MessageToString( actual_ascii = text_format.MessageToString(
message, use_short_repeated_primitives=True, message, use_short_repeated_primitives=True,
as_one_line=as_one_line) as_one_line=as_one_line)
@ -184,7 +189,7 @@ class TextFormatMessageToStringTests(TextFormatBase):
text_format.Parse(actual_ascii, parsed_message) text_format.Parse(actual_ascii, parsed_message)
self.assertEqual(parsed_message, message) self.assertEqual(parsed_message, message)
def tesPrintShortFormatRepeatedFields(self, message_module, as_one_line): def testPrintShortFormatRepeatedFields(self, message_module):
self.VerifyPrintShortFormatRepeatedFields(message_module, False) self.VerifyPrintShortFormatRepeatedFields(message_module, False)
self.VerifyPrintShortFormatRepeatedFields(message_module, True) self.VerifyPrintShortFormatRepeatedFields(message_module, True)
@ -358,6 +363,63 @@ class TextFormatMessageToStringTests(TextFormatBase):
self.assertEqual('0.0', out.getvalue()) self.assertEqual('0.0', out.getvalue())
out.close() out.close()
def testCustomOptions(self, message_module):
message_descriptor = (unittest_custom_options_pb2.
TestMessageWithCustomOptions.DESCRIPTOR)
message_proto = descriptor_pb2.DescriptorProto()
message_descriptor.CopyToProto(message_proto)
expected_text = (
'name: "TestMessageWithCustomOptions"\n'
'field {\n'
' name: "field1"\n'
' number: 1\n'
' label: LABEL_OPTIONAL\n'
' type: TYPE_STRING\n'
' options {\n'
' ctype: CORD\n'
' [protobuf_unittest.field_opt1]: 8765432109\n'
' }\n'
'}\n'
'field {\n'
' name: "oneof_field"\n'
' number: 2\n'
' label: LABEL_OPTIONAL\n'
' type: TYPE_INT32\n'
' oneof_index: 0\n'
'}\n'
'enum_type {\n'
' name: "AnEnum"\n'
' value {\n'
' name: "ANENUM_VAL1"\n'
' number: 1\n'
' }\n'
' value {\n'
' name: "ANENUM_VAL2"\n'
' number: 2\n'
' options {\n'
' [protobuf_unittest.enum_value_opt1]: 123\n'
' }\n'
' }\n'
' options {\n'
' [protobuf_unittest.enum_opt1]: -789\n'
' }\n'
'}\n'
'options {\n'
' message_set_wire_format: false\n'
' [protobuf_unittest.message_opt1]: -56\n'
'}\n'
'oneof_decl {\n'
' name: "AnOneof"\n'
' options {\n'
' [protobuf_unittest.oneof_opt1]: -99\n'
' }\n'
'}\n')
self.assertEqual(expected_text,
text_format.MessageToString(message_proto))
parsed_proto = descriptor_pb2.DescriptorProto()
text_format.Parse(expected_text, parsed_proto)
self.assertEqual(message_proto, parsed_proto)
@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2) @_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
class TextFormatMessageToTextBytesTests(TextFormatBase): class TextFormatMessageToTextBytesTests(TextFormatBase):
@ -1907,6 +1969,30 @@ class PrettyPrinterTest(TextFormatBase):
'repeated_nested_message { My lucky number is 42 } ' 'repeated_nested_message { My lucky number is 42 } '
'repeated_nested_message { My lucky number is 99 }')) 'repeated_nested_message { My lucky number is 99 }'))
out = text_format.TextWriter(False)
text_format.PrintField(
message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
'optional_nested_message'],
message.optional_nested_message,
out,
message_formatter=printer)
self.assertEqual(
'optional_nested_message {\n My lucky number is 1\n}\n',
out.getvalue())
out.close()
out = text_format.TextWriter(False)
text_format.PrintFieldValue(
message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
'optional_nested_message'],
message.optional_nested_message,
out,
message_formatter=printer)
self.assertEqual(
'{\n My lucky number is 1\n}',
out.getvalue())
out.close()
class WhitespaceTest(TextFormatBase): class WhitespaceTest(TextFormatBase):

@ -669,11 +669,7 @@ def _MergeMessage(
destination.ClearField(_StrConvert(name)) destination.ClearField(_StrConvert(name))
repeated_source = getattr(source, name) repeated_source = getattr(source, name)
repeated_destination = getattr(destination, name) repeated_destination = getattr(destination, name)
if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: repeated_destination.MergeFrom(repeated_source)
for item in repeated_source:
repeated_destination.add().MergeFrom(item)
else:
repeated_destination.extend(repeated_source)
else: else:
if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
if replace_message: if replace_message:

@ -47,6 +47,7 @@ from google.protobuf import duration_pb2
from google.protobuf import field_mask_pb2 from google.protobuf import field_mask_pb2
from google.protobuf import struct_pb2 from google.protobuf import struct_pb2
from google.protobuf import timestamp_pb2 from google.protobuf import timestamp_pb2
from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_pb2 from google.protobuf import unittest_pb2
from google.protobuf.internal import any_test_pb2 from google.protobuf.internal import any_test_pb2
from google.protobuf.internal import test_util from google.protobuf.internal import test_util
@ -526,7 +527,7 @@ class FieldMaskTest(unittest.TestCase):
out_mask.Intersect(mask1, mask2) out_mask.Intersect(mask1, mask2)
self.assertEqual('foo.bar.baz', out_mask.ToJsonString()) self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
def testMergeMessage(self): def testMergeMessageWithoutMapFields(self):
# Test merge one field. # Test merge one field.
src = unittest_pb2.TestAllTypes() src = unittest_pb2.TestAllTypes()
test_util.SetAllFields(src) test_util.SetAllFields(src)
@ -635,6 +636,29 @@ class FieldMaskTest(unittest.TestCase):
self.assertTrue(dst.HasField('foo_message')) self.assertTrue(dst.HasField('foo_message'))
self.assertFalse(dst.HasField('foo_lazy_message')) self.assertFalse(dst.HasField('foo_lazy_message'))
def testMergeMessageWithMapField(self):
empty_map = map_unittest_pb2.TestRecursiveMapMessage()
src_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
src_level_2.a['src level 2'].CopyFrom(empty_map)
src = map_unittest_pb2.TestRecursiveMapMessage()
src.a['common key'].CopyFrom(src_level_2)
src.a['src level 1'].CopyFrom(src_level_2)
dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
dst_level_2.a['dst level 2'].CopyFrom(empty_map)
dst = map_unittest_pb2.TestRecursiveMapMessage()
dst.a['common key'].CopyFrom(dst_level_2)
dst.a['dst level 1'].CopyFrom(empty_map)
mask = field_mask_pb2.FieldMask()
mask.FromJsonString('a')
mask.MergeMessage(src, dst)
# map from dst is replaced with map from src.
self.assertEqual(dst.a['common key'], src_level_2)
self.assertEqual(dst.a['src level 1'], src_level_2)
self.assertEqual(dst.a['dst level 1'], empty_map)
def testMergeErrors(self): def testMergeErrors(self):
src = unittest_pb2.TestAllTypes() src = unittest_pb2.TestAllTypes()
dst = unittest_pb2.TestAllTypes() dst = unittest_pb2.TestAllTypes()

@ -189,6 +189,21 @@ const FileDescriptor* GetFileDescriptor(const MethodDescriptor* descriptor) {
return descriptor->service()->file(); return descriptor->service()->file();
} }
bool Reparse(
PyMessageFactory* message_factory, const Message& from, Message* to) {
// Reparse message.
string serialized;
from.SerializeToString(&serialized);
io::CodedInputStream input(
reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
input.SetExtensionRegistry(message_factory->pool->pool,
message_factory->message_factory);
bool success = to->ParseFromCodedStream(&input);
if (!success) {
return false;
}
return true;
}
// Converts options into a Python protobuf, and cache the result. // Converts options into a Python protobuf, and cache the result.
// //
// This is a bit tricky because options can contain extension fields defined in // This is a bit tricky because options can contain extension fields defined in
@ -251,15 +266,8 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
cmsg->message->CopyFrom(options); cmsg->message->CopyFrom(options);
} else { } else {
// Reparse options string! XXX call cmessage::MergeFromString // Reparse options string! XXX call cmessage::MergeFromString
string serialized; if (!Reparse(message_factory, options, cmsg->message)) {
options.SerializeToString(&serialized); PyErr_Format(PyExc_ValueError, "Error reparsing Options message");
io::CodedInputStream input(
reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
input.SetExtensionRegistry(message_factory->pool->pool,
message_factory->message_factory);
bool success = cmsg->message->MergePartialFromCodedStream(&input);
if (!success) {
PyErr_Format(PyExc_ValueError, "Error parsing Options message");
return NULL; return NULL;
} }
} }
@ -290,6 +298,16 @@ static PyObject* CopyToPythonProto(const DescriptorClass *descriptor,
DescriptorProtoClass* descriptor_message = DescriptorProtoClass* descriptor_message =
static_cast<DescriptorProtoClass*>(message->message); static_cast<DescriptorProtoClass*>(message->message);
descriptor->CopyTo(descriptor_message); descriptor->CopyTo(descriptor_message);
// Custom options might in unknown extensions. Reparse
// the descriptor_message. Can't skip reparse when options unknown
// fields is empty, because they might in sub descriptors' options.
PyMessageFactory* message_factory =
GetDefaultDescriptorPool()->py_message_factory;
if (!Reparse(message_factory, *descriptor_message, descriptor_message)) {
PyErr_Format(PyExc_ValueError, "Error reparsing descriptor message");
return nullptr;
}
Py_RETURN_NONE; Py_RETURN_NONE;
} }

@ -62,6 +62,7 @@ class MapReflectionFriend {
static Py_ssize_t Length(PyObject* _self); static Py_ssize_t Length(PyObject* _self);
static PyObject* GetIterator(PyObject *_self); static PyObject* GetIterator(PyObject *_self);
static PyObject* IterNext(PyObject* _self); static PyObject* IterNext(PyObject* _self);
static PyObject* MergeFrom(PyObject* _self, PyObject* arg);
// Methods that differ between the map types. // Methods that differ between the map types.
static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key); static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key);
@ -338,20 +339,19 @@ PyObject* GetEntryClass(PyObject* _self) {
return reinterpret_cast<PyObject*>(message_class); return reinterpret_cast<PyObject*>(message_class);
} }
PyObject* MergeFrom(PyObject* _self, PyObject* arg) { PyObject* MapReflectionFriend::MergeFrom(PyObject* _self, PyObject* arg) {
MapContainer* self = GetMap(_self); MapContainer* self = GetMap(_self);
MapContainer* other_map = GetMap(arg); MapContainer* other_map = GetMap(arg);
Message* message = self->GetMutableMessage(); Message* message = self->GetMutableMessage();
const Message* other_message = other_map->message; const Message* other_message = other_map->message;
const Reflection* reflection = message->GetReflection(); const Reflection* reflection = message->GetReflection();
const Reflection* other_reflection = other_message->GetReflection(); const Reflection* other_reflection = other_message->GetReflection();
int count = other_reflection->FieldSize( internal::MapFieldBase* field = reflection->MapData(
*other_message, other_map->parent_field_descriptor); message, self->parent_field_descriptor);
for (int i = 0 ; i < count; i ++) { internal::MapFieldBase* other_field =
reflection->AddMessage(message, self->parent_field_descriptor)->MergeFrom( other_reflection->MapData(const_cast<Message*>(other_message),
other_reflection->GetRepeatedMessage( self->parent_field_descriptor);
*other_message, other_map->parent_field_descriptor, i)); field->MergeFrom(*other_field);
}
self->version++; self->version++;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@ -589,7 +589,7 @@ static PyMethodDef ScalarMapMethods[] = {
"Gets the value for the given key if present, or otherwise a default" }, "Gets the value for the given key if present, or otherwise a default" },
{ "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS, { "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
"Return the class used to build Entries of (key, value) pairs." }, "Return the class used to build Entries of (key, value) pairs." },
{ "MergeFrom", (PyCFunction)MergeFrom, METH_O, { "MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
"Merges a map into the current map." }, "Merges a map into the current map." },
/* /*
{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
@ -908,7 +908,7 @@ static PyMethodDef MessageMapMethods[] = {
"Alias for getitem, useful to make explicit that the map is mutated." }, "Alias for getitem, useful to make explicit that the map is mutated." },
{ "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS, { "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
"Return the class used to build Entries of (key, value) pairs." }, "Return the class used to build Entries of (key, value) pairs." },
{ "MergeFrom", (PyCFunction)MergeFrom, METH_O, { "MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
"Merges a map into the current map." }, "Merges a map into the current map." },
/* /*
{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,

@ -585,10 +585,6 @@ static int VisitCompositeField(const FieldDescriptor* descriptor,
// Returns -1 on error and 0 on success. // Returns -1 on error and 0 on success.
template<class Visitor> template<class Visitor>
int ForEachCompositeField(CMessage* self, Visitor visitor) { int ForEachCompositeField(CMessage* self, Visitor visitor) {
Py_ssize_t pos = 0;
PyObject* key;
PyObject* field;
// Visit normal fields. // Visit normal fields.
if (self->composite_fields) { if (self->composite_fields) {
for (CMessage::CompositeFieldsMap::iterator it = for (CMessage::CompositeFieldsMap::iterator it =
@ -1554,10 +1550,11 @@ const FieldDescriptor* FindFieldWithOneofs(
} }
bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) { bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
auto message_name = field_descriptor->containing_type()->name();
if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Protocol message has no singular \"%s\" field.", "Protocol message %s has no singular \"%s\" field.",
field_descriptor->name().c_str()); message_name.c_str(), field_descriptor->name().c_str());
return false; return false;
} }
@ -1565,8 +1562,8 @@ bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
// HasField() for a oneof *itself* isn't supported. // HasField() for a oneof *itself* isn't supported.
if (in_oneof) { if (in_oneof) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Can't test oneof field \"%s\" for presence in proto3, use " "Can't test oneof field \"%s.%s\" for presence in proto3, "
"WhichOneof instead.", "use WhichOneof instead.", message_name.c_str(),
field_descriptor->containing_oneof()->name().c_str()); field_descriptor->containing_oneof()->name().c_str());
return false; return false;
} }
@ -1579,8 +1576,8 @@ bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
PyErr_Format( PyErr_Format(
PyExc_ValueError, PyExc_ValueError,
"Can't test non-submessage field \"%s\" for presence in proto3.", "Can't test non-submessage field \"%s.%s\" for presence in proto3.",
field_descriptor->name().c_str()); message_name.c_str(), field_descriptor->name().c_str());
return false; return false;
} }
} }
@ -1608,7 +1605,8 @@ PyObject* HasField(CMessage* self, PyObject* arg) {
FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof); FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
if (field_descriptor == NULL) { if (field_descriptor == NULL) {
if (!is_in_oneof) { if (!is_in_oneof) {
PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name); PyErr_Format(PyExc_ValueError, "Protocol message %s has no field %s.",
message->GetDescriptor()->name().c_str(), field_name);
return NULL; return NULL;
} else { } else {
Py_RETURN_FALSE; Py_RETURN_FALSE;
@ -2140,6 +2138,7 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
reinterpret_cast<const uint8*>(data), data_length); reinterpret_cast<const uint8*>(data), data_length);
if (allow_oversize_protos) { if (allow_oversize_protos) {
input.SetTotalBytesLimit(INT_MAX, INT_MAX); input.SetTotalBytesLimit(INT_MAX, INT_MAX);
input.SetRecursionLimit(INT_MAX);
} }
PyMessageFactory* factory = GetFactoryForMessage(self); PyMessageFactory* factory = GetFactoryForMessage(self);
input.SetExtensionRegistry(factory->pool->pool, factory->message_factory); input.SetExtensionRegistry(factory->pool->pool, factory->message_factory);
@ -2822,8 +2821,6 @@ PyObject* GetFieldValue(CMessage* self,
} }
} }
const Descriptor* message_descriptor =
(reinterpret_cast<CMessageClass*>(Py_TYPE(self)))->message_descriptor;
if (self->message->GetDescriptor() != field_descriptor->containing_type()) { if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"descriptor to field '%s' doesn't apply to '%s' object", "descriptor to field '%s' doesn't apply to '%s' object",

@ -225,7 +225,8 @@ def PrintField(field,
"""Print a single field name/value pair.""" """Print a single field name/value pair."""
printer = _Printer(out, indent, as_utf8, as_one_line, printer = _Printer(out, indent, as_utf8, as_one_line,
use_short_repeated_primitives, pointy_brackets, use_short_repeated_primitives, pointy_brackets,
use_index_order, float_format, message_formatter) use_index_order, float_format,
message_formatter=message_formatter)
printer.PrintField(field, value) printer.PrintField(field, value)
@ -243,7 +244,8 @@ def PrintFieldValue(field,
"""Print a single field value (not including name).""" """Print a single field value (not including name)."""
printer = _Printer(out, indent, as_utf8, as_one_line, printer = _Printer(out, indent, as_utf8, as_one_line,
use_short_repeated_primitives, pointy_brackets, use_short_repeated_primitives, pointy_brackets,
use_index_order, float_format, message_formatter) use_index_order, float_format,
message_formatter=message_formatter)
printer.PrintFieldValue(field, value) printer.PrintFieldValue(field, value)
@ -427,8 +429,8 @@ class _Printer(object):
def _PrintShortRepeatedPrimitivesValue(self, field, value): def _PrintShortRepeatedPrimitivesValue(self, field, value):
# Note: this is called only when value has at least one element. # Note: this is called only when value has at least one element.
self._PrintFieldName(field) self._PrintFieldName(field)
self.out.write('[') self.out.write(' [')
for i in xrange(len(value) - 1): for i in six.moves.range(len(value) - 1):
self.PrintFieldValue(field, value[i]) self.PrintFieldValue(field, value[i])
self.out.write(', ') self.out.write(', ')
self.PrintFieldValue(field, value[-1]) self.PrintFieldValue(field, value[-1])

@ -74,7 +74,6 @@ nobase_include_HEADERS = \
google/protobuf/stubs/once.h \ google/protobuf/stubs/once.h \
google/protobuf/stubs/platform_macros.h \ google/protobuf/stubs/platform_macros.h \
google/protobuf/stubs/port.h \ google/protobuf/stubs/port.h \
google/protobuf/stubs/singleton.h \
google/protobuf/stubs/status.h \ google/protobuf/stubs/status.h \
google/protobuf/stubs/stl_util.h \ google/protobuf/stubs/stl_util.h \
google/protobuf/stubs/stringpiece.h \ google/protobuf/stubs/stringpiece.h \
@ -314,7 +313,6 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/command_line_interface.cc \ google/protobuf/compiler/command_line_interface.cc \
google/protobuf/compiler/plugin.cc \ google/protobuf/compiler/plugin.cc \
google/protobuf/compiler/plugin.pb.cc \ google/protobuf/compiler/plugin.pb.cc \
google/protobuf/compiler/scc.cc \
google/protobuf/compiler/scc.h \ google/protobuf/compiler/scc.h \
google/protobuf/compiler/subprocess.cc \ google/protobuf/compiler/subprocess.cc \
google/protobuf/compiler/subprocess.h \ google/protobuf/compiler/subprocess.h \

@ -69,15 +69,17 @@ static ::google::protobuf::Message const * const file_default_instances[] = {
file_level_metadata_google_2fprotobuf_2fany_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto, file_level_service_descriptors_google_2fprotobuf_2fany_2eproto, file_level_metadata_google_2fprotobuf_2fany_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto, file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
}; };
::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = { const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] =
false, InitDefaults_google_2fprotobuf_2fany_2eproto,
"\n\031google/protobuf/any.proto\022\017google.prot" "\n\031google/protobuf/any.proto\022\017google.prot"
"obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002" "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
" \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z" " \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
"%github.com/golang/protobuf/ptypes/any\242\002" "%github.com/golang/protobuf/ptypes/any\242\002"
"\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p" "\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
"roto3" "roto3"
, ;
::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
false, InitDefaults_google_2fprotobuf_2fany_2eproto,
descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
"google/protobuf/any.proto", &assign_descriptors_table_google_2fprotobuf_2fany_2eproto, 205, "google/protobuf/any.proto", &assign_descriptors_table_google_2fprotobuf_2fany_2eproto, 205,
}; };
@ -195,10 +197,10 @@ const char* Any::_InternalParse(const char* begin, const char* end, void* object
auto msg = static_cast<Any*>(object); auto msg = static_cast<Any*>(object);
::google::protobuf::uint32 size; (void)size; ::google::protobuf::uint32 size; (void)size;
int depth; (void)depth; int depth; (void)depth;
::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end; ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin; auto ptr = begin;
while (ptr < end) { while (ptr < end) {
::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag); ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) { switch (tag >> 3) {
@ -208,14 +210,17 @@ const char* Any::_InternalParse(const char* begin, const char* end, void* object
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Any.type_url"); ctx->extra_parse_data().SetFieldName("google.protobuf.Any.type_url");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_type_url();
::std::string* str = msg->mutable_type_url(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// bytes value = 2; // bytes value = 2;
@ -223,25 +228,29 @@ const char* Any::_InternalParse(const char* begin, const char* end, void* object
if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual; if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
parser_till_end = ::google::protobuf::internal::StringParser; auto str = msg->mutable_value();
::std::string* str = msg->mutable_value(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
str->append(ptr, size); str->reserve(size);
parser_till_end = ::google::protobuf::internal::GreedyStringParser;
goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size; ptr += size;
break; break;
} }
default: { default: {
handle_unusual: (void)&&handle_unusual; handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) { if ((tag & 7) == 4 || tag == 0) {
bool ok = ctx->ValidEndGroup(tag); ctx->EndGroup(tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
return ptr; return ptr;
} }
auto res = UnknownFieldParse(tag, {_InternalParse, msg}, auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx); ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first; ptr = res.first;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr; if (res.second) return ptr;
} }
} // switch } // switch
@ -252,7 +261,7 @@ len_delim_till_end: (void)&&len_delim_till_end;
{parser_till_end, object}, size); {parser_till_end, object}, size);
group_continues: (void)&&group_continues; group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end); GOOGLE_DCHECK(ptr >= end);
ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth); GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr; return ptr;
} }
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER #else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER

@ -134,7 +134,7 @@ class PROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_inser
void MergeFrom(const ::google::protobuf::Message& from) final; void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Any& from); void CopyFrom(const Any& from);
void MergeFrom(const Any& from); void MergeFrom(const Any& from);
void Clear() final; PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final; bool IsInitialized() const final;
size_t ByteSizeLong() const final; size_t ByteSizeLong() const final;

@ -144,8 +144,7 @@ static ::google::protobuf::Message const * const file_default_instances[] = {
file_level_metadata_google_2fprotobuf_2fapi_2eproto, 3, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_metadata_google_2fprotobuf_2fapi_2eproto, 3, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
}; };
::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = { const char descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto[] =
false, InitDefaults_google_2fprotobuf_2fapi_2eproto,
"\n\031google/protobuf/api.proto\022\017google.prot" "\n\031google/protobuf/api.proto\022\017google.prot"
"obuf\032$google/protobuf/source_context.pro" "obuf\032$google/protobuf/source_context.pro"
"to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014" "to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014"
@ -165,7 +164,10 @@ static ::google::protobuf::Message const * const file_default_instances[] = {
"otobufB\010ApiProtoP\001Z+google.golang.org/ge" "otobufB\010ApiProtoP\001Z+google.golang.org/ge"
"nproto/protobuf/api;api\242\002\003GPB\252\002\036Google.P" "nproto/protobuf/api;api\242\002\003GPB\252\002\036Google.P"
"rotobuf.WellKnownTypesb\006proto3" "rotobuf.WellKnownTypesb\006proto3"
, ;
::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
false, InitDefaults_google_2fprotobuf_2fapi_2eproto,
descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
"google/protobuf/api.proto", &assign_descriptors_table_google_2fprotobuf_2fapi_2eproto, 750, "google/protobuf/api.proto", &assign_descriptors_table_google_2fprotobuf_2fapi_2eproto, 750,
}; };
@ -301,10 +303,10 @@ const char* Api::_InternalParse(const char* begin, const char* end, void* object
auto msg = static_cast<Api*>(object); auto msg = static_cast<Api*>(object);
::google::protobuf::uint32 size; (void)size; ::google::protobuf::uint32 size; (void)size;
int depth; (void)depth; int depth; (void)depth;
::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end; ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin; auto ptr = begin;
while (ptr < end) { while (ptr < end) {
::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag); ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) { switch (tag >> 3) {
@ -314,14 +316,17 @@ const char* Api::_InternalParse(const char* begin, const char* end, void* object
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Api.name"); ctx->extra_parse_data().SetFieldName("google.protobuf.Api.name");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_name();
::std::string* str = msg->mutable_name(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// repeated .google.protobuf.Method methods = 2; // repeated .google.protobuf.Method methods = 2;
@ -366,14 +371,17 @@ const char* Api::_InternalParse(const char* begin, const char* end, void* object
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Api.version"); ctx->extra_parse_data().SetFieldName("google.protobuf.Api.version");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_version();
::std::string* str = msg->mutable_version(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// .google.protobuf.SourceContext source_context = 5; // .google.protobuf.SourceContext source_context = 5;
@ -422,13 +430,13 @@ const char* Api::_InternalParse(const char* begin, const char* end, void* object
default: { default: {
handle_unusual: (void)&&handle_unusual; handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) { if ((tag & 7) == 4 || tag == 0) {
bool ok = ctx->ValidEndGroup(tag); ctx->EndGroup(tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
return ptr; return ptr;
} }
auto res = UnknownFieldParse(tag, {_InternalParse, msg}, auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx); ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first; ptr = res.first;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr; if (res.second) return ptr;
} }
} // switch } // switch
@ -439,7 +447,7 @@ len_delim_till_end: (void)&&len_delim_till_end;
{parser_till_end, object}, size); {parser_till_end, object}, size);
group_continues: (void)&&group_continues; group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end); GOOGLE_DCHECK(ptr >= end);
ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth); GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr; return ptr;
} }
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER #else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@ -971,10 +979,10 @@ const char* Method::_InternalParse(const char* begin, const char* end, void* obj
auto msg = static_cast<Method*>(object); auto msg = static_cast<Method*>(object);
::google::protobuf::uint32 size; (void)size; ::google::protobuf::uint32 size; (void)size;
int depth; (void)depth; int depth; (void)depth;
::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end; ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin; auto ptr = begin;
while (ptr < end) { while (ptr < end) {
::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag); ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) { switch (tag >> 3) {
@ -984,14 +992,17 @@ const char* Method::_InternalParse(const char* begin, const char* end, void* obj
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Method.name"); ctx->extra_parse_data().SetFieldName("google.protobuf.Method.name");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_name();
::std::string* str = msg->mutable_name(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// string request_type_url = 2; // string request_type_url = 2;
@ -1000,14 +1011,17 @@ const char* Method::_InternalParse(const char* begin, const char* end, void* obj
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Method.request_type_url"); ctx->extra_parse_data().SetFieldName("google.protobuf.Method.request_type_url");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_request_type_url();
::std::string* str = msg->mutable_request_type_url(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// bool request_streaming = 3; // bool request_streaming = 3;
@ -1026,14 +1040,17 @@ const char* Method::_InternalParse(const char* begin, const char* end, void* obj
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Method.response_type_url"); ctx->extra_parse_data().SetFieldName("google.protobuf.Method.response_type_url");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_response_type_url();
::std::string* str = msg->mutable_response_type_url(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// bool response_streaming = 5; // bool response_streaming = 5;
@ -1077,13 +1094,13 @@ const char* Method::_InternalParse(const char* begin, const char* end, void* obj
default: { default: {
handle_unusual: (void)&&handle_unusual; handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) { if ((tag & 7) == 4 || tag == 0) {
bool ok = ctx->ValidEndGroup(tag); ctx->EndGroup(tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
return ptr; return ptr;
} }
auto res = UnknownFieldParse(tag, {_InternalParse, msg}, auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx); ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first; ptr = res.first;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr; if (res.second) return ptr;
} }
} // switch } // switch
@ -1094,7 +1111,7 @@ len_delim_till_end: (void)&&len_delim_till_end;
{parser_till_end, object}, size); {parser_till_end, object}, size);
group_continues: (void)&&group_continues; group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end); GOOGLE_DCHECK(ptr >= end);
ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth); GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr; return ptr;
} }
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER #else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@ -1596,10 +1613,10 @@ const char* Mixin::_InternalParse(const char* begin, const char* end, void* obje
auto msg = static_cast<Mixin*>(object); auto msg = static_cast<Mixin*>(object);
::google::protobuf::uint32 size; (void)size; ::google::protobuf::uint32 size; (void)size;
int depth; (void)depth; int depth; (void)depth;
::google::protobuf::uint32 tag;
::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end; ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
auto ptr = begin; auto ptr = begin;
while (ptr < end) { while (ptr < end) {
::google::protobuf::uint32 tag;
ptr = Varint::Parse32Inline(ptr, &tag); ptr = Varint::Parse32Inline(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
switch (tag >> 3) { switch (tag >> 3) {
@ -1609,14 +1626,17 @@ const char* Mixin::_InternalParse(const char* begin, const char* end, void* obje
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.name"); ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.name");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_name();
::std::string* str = msg->mutable_name(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
// string root = 2; // string root = 2;
@ -1625,26 +1645,29 @@ const char* Mixin::_InternalParse(const char* begin, const char* end, void* obje
ptr = Varint::Parse32Inline(ptr, &size); ptr = Varint::Parse32Inline(ptr, &size);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.root"); ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.root");
parser_till_end = ::google::protobuf::internal::StringParserUTF8; auto str = msg->mutable_root();
::std::string* str = msg->mutable_root(); if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
str->clear();
object = str; object = str;
if (size > end - ptr) goto len_delim_till_end; str->clear();
auto newend = ptr + size; str->reserve(size);
if (size) ptr = parser_till_end(ptr, newend, object, ctx); parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend); goto len_delim_till_end;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
ptr += size;
break; break;
} }
default: { default: {
handle_unusual: (void)&&handle_unusual; handle_unusual: (void)&&handle_unusual;
if ((tag & 7) == 4 || tag == 0) { if ((tag & 7) == 4 || tag == 0) {
bool ok = ctx->ValidEndGroup(tag); ctx->EndGroup(tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
return ptr; return ptr;
} }
auto res = UnknownFieldParse(tag, {_InternalParse, msg}, auto res = UnknownFieldParse(tag, {_InternalParse, msg},
ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx); ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
ptr = res.first; ptr = res.first;
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
if (res.second) return ptr; if (res.second) return ptr;
} }
} // switch } // switch
@ -1655,7 +1678,7 @@ len_delim_till_end: (void)&&len_delim_till_end;
{parser_till_end, object}, size); {parser_till_end, object}, size);
group_continues: (void)&&group_continues; group_continues: (void)&&group_continues;
GOOGLE_DCHECK(ptr >= end); GOOGLE_DCHECK(ptr >= end);
ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth); GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
return ptr; return ptr;
} }
#else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER #else // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER

@ -128,7 +128,7 @@ class PROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_inser
void MergeFrom(const ::google::protobuf::Message& from) final; void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Api& from); void CopyFrom(const Api& from);
void MergeFrom(const Api& from); void MergeFrom(const Api& from);
void Clear() final; PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final; bool IsInitialized() const final;
size_t ByteSizeLong() const final; size_t ByteSizeLong() const final;
@ -318,7 +318,7 @@ class PROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc_in
void MergeFrom(const ::google::protobuf::Message& from) final; void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Method& from); void CopyFrom(const Method& from);
void MergeFrom(const Method& from); void MergeFrom(const Method& from);
void Clear() final; PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final; bool IsInitialized() const final;
size_t ByteSizeLong() const final; size_t ByteSizeLong() const final;
@ -501,7 +501,7 @@ class PROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_ins
void MergeFrom(const ::google::protobuf::Message& from) final; void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Mixin& from); void CopyFrom(const Mixin& from);
void MergeFrom(const Mixin& from); void MergeFrom(const Mixin& from);
void Clear() final; PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final; bool IsInitialized() const final;
size_t ByteSizeLong() const final; size_t ByteSizeLong() const final;

@ -33,6 +33,7 @@
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <google/protobuf/stubs/mutex.h>
#ifdef ADDRESS_SANITIZER #ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h> #include <sanitizer/asan_interface.h>
@ -323,24 +324,22 @@ void ArenaImpl::SerialArena::CleanupList() {
} }
void ArenaImpl::SerialArena::CleanupListFallback() { void ArenaImpl::SerialArena::CleanupListFallback() {
// Cleanup newest chunk: ptrs give us length. // The first chunk might be only partially full, so calculate its size
// from cleanup_ptr_. Subsequent chunks are always full, so use list->size.
size_t n = cleanup_ptr_ - &cleanup_->nodes[0]; size_t n = cleanup_ptr_ - &cleanup_->nodes[0];
CleanupNode* node = cleanup_ptr_; CleanupChunk* list = cleanup_;
for (size_t i = 0; i < n; i++) { while (true) {
--node; CleanupNode* node = &list->nodes[0];
node->cleanup(node->elem); // Cleanup newest elements first (allocated last).
} for (size_t i = n; i > 0; i--) {
node[i - 1].cleanup(node[i - 1].elem);
// Cleanup older chunks, which are known to be full.
CleanupChunk* list = cleanup_->next;
while (list) {
size_t n = list->size;
CleanupNode* node = &list->nodes[list->size];
for (size_t i = 0; i < n; i++) {
--node;
node->cleanup(node->elem);
} }
list = list->next; list = list->next;
if (list == nullptr) {
break;
}
// All but the first chunk are always full.
n = list->size;
} }
} }

@ -306,8 +306,10 @@ class PROTOBUF_EXPORT ArenaImpl {
public: public:
// kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8 // kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
// to protect the invariant that pos is always at a multiple of 8. // to protect the invariant that pos is always at a multiple of 8.
static const size_t kBlockHeaderSize = (sizeof(Block) + 7) & static_cast<size_t>(-8); static const size_t kBlockHeaderSize =
static const size_t kSerialArenaSize = (sizeof(SerialArena) + 7) & static_cast<size_t>(-8); (sizeof(Block) + 7) & static_cast<size_t>(-8);
static const size_t kSerialArenaSize =
(sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
static_assert(kBlockHeaderSize % 8 == 0, static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8."); "kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0, static_assert(kSerialArenaSize % 8 == 0,

@ -55,7 +55,7 @@
#include <google/protobuf/unknown_field_set.h> #include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format_lite.h> #include <google/protobuf/wire_format_lite.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <google/protobuf/stubs/strutil.h>
using proto2_arena_unittest::ArenaMessage; using proto2_arena_unittest::ArenaMessage;

@ -834,35 +834,51 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
} }
std::vector<const FileDescriptor*> parsed_files; std::vector<const FileDescriptor*> parsed_files;
// null unless descriptor_set_in_names_.empty()
std::unique_ptr<DiskSourceTree> disk_source_tree; std::unique_ptr<DiskSourceTree> disk_source_tree;
std::unique_ptr<ErrorPrinter> error_collector; std::unique_ptr<ErrorPrinter> error_collector;
std::unique_ptr<DescriptorPool> descriptor_pool; std::unique_ptr<DescriptorPool> descriptor_pool;
std::unique_ptr<DescriptorDatabase> descriptor_database; std::unique_ptr<SimpleDescriptorDatabase> descriptor_set_in_database;
if (descriptor_set_in_names_.empty()) { std::unique_ptr<SourceTreeDescriptorDatabase> source_tree_database;
// Any --descriptor_set_in FileDescriptorSet objects will be used as a
// fallback to input_files on command line, so create that db first.
if (!descriptor_set_in_names_.empty()) {
descriptor_set_in_database.reset(new SimpleDescriptorDatabase());
if (!PopulateSimpleDescriptorDatabase(descriptor_set_in_database.get())) {
return 1;
}
}
if (proto_path_.empty()) {
// If there are no --proto_path flags, then just look in the specified
// --descriptor_set_in files. But first, verify that the input files are
// there.
if (!VerifyInputFilesInDescriptors(descriptor_set_in_database.get())) {
return 1;
}
error_collector.reset(new ErrorPrinter(error_format_));
descriptor_pool.reset(new DescriptorPool(descriptor_set_in_database.get(),
error_collector.get()));
} else {
disk_source_tree.reset(new DiskSourceTree()); disk_source_tree.reset(new DiskSourceTree());
if (!InitializeDiskSourceTree(disk_source_tree.get())) { if (!InitializeDiskSourceTree(disk_source_tree.get(),
descriptor_set_in_database.get())) {
return 1; return 1;
} }
error_collector.reset( error_collector.reset(
new ErrorPrinter(error_format_, disk_source_tree.get())); new ErrorPrinter(error_format_, disk_source_tree.get()));
SourceTreeDescriptorDatabase* database = source_tree_database.reset(new SourceTreeDescriptorDatabase(
new SourceTreeDescriptorDatabase(disk_source_tree.get()); disk_source_tree.get(), descriptor_set_in_database.get()));
database->RecordErrorsTo(error_collector.get()); source_tree_database->RecordErrorsTo(error_collector.get());
descriptor_database.reset(database);
descriptor_pool.reset(new DescriptorPool(
descriptor_database.get(), database->GetValidationErrorCollector()));
} else {
error_collector.reset(new ErrorPrinter(error_format_));
SimpleDescriptorDatabase* database = new SimpleDescriptorDatabase(); descriptor_pool.reset(new DescriptorPool(
descriptor_database.reset(database); source_tree_database.get(),
if (!PopulateSimpleDescriptorDatabase(database)) { source_tree_database->GetValidationErrorCollector()));
return 1;
}
descriptor_pool.reset(new DescriptorPool(database, error_collector.get()));
} }
descriptor_pool->EnforceWeakDependencies(true); descriptor_pool->EnforceWeakDependencies(true);
if (!ParseInputFiles(descriptor_pool.get(), &parsed_files)) { if (!ParseInputFiles(descriptor_pool.get(), &parsed_files)) {
return 1; return 1;
@ -980,7 +996,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
} }
bool CommandLineInterface::InitializeDiskSourceTree( bool CommandLineInterface::InitializeDiskSourceTree(
DiskSourceTree* source_tree) { DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
AddDefaultProtoPaths(&proto_path_); AddDefaultProtoPaths(&proto_path_);
// Set up the source tree. // Set up the source tree.
@ -989,7 +1005,7 @@ bool CommandLineInterface::InitializeDiskSourceTree(
} }
// Map input files to virtual paths if possible. // Map input files to virtual paths if possible.
if (!MakeInputsBeProtoPathRelative(source_tree)) { if (!MakeInputsBeProtoPathRelative(source_tree, fallback_database)) {
return false; return false;
} }
@ -1039,6 +1055,27 @@ bool CommandLineInterface::PopulateSimpleDescriptorDatabase(
return true; return true;
} }
bool CommandLineInterface::VerifyInputFilesInDescriptors(
DescriptorDatabase* database) {
for (const auto& input_file : input_files_) {
FileDescriptorProto file_descriptor;
if (!database->FindFileByName(input_file, &file_descriptor)) {
std::cerr << input_file << ": " << strerror(ENOENT) << std::endl;
return false;
}
// Enforce --disallow_services.
if (disallow_services_ && file_descriptor.service_size() > 0) {
std::cerr << file_descriptor.name()
<< ": This file contains services, but "
"--disallow_services was used."
<< std::endl;
return false;
}
}
return true;
}
bool CommandLineInterface::ParseInputFiles( bool CommandLineInterface::ParseInputFiles(
DescriptorPool* descriptor_pool, DescriptorPool* descriptor_pool,
std::vector<const FileDescriptor*>* parsed_files) { std::vector<const FileDescriptor*>* parsed_files) {
@ -1051,9 +1088,6 @@ bool CommandLineInterface::ParseInputFiles(
descriptor_pool->FindFileByName(input_file); descriptor_pool->FindFileByName(input_file);
descriptor_pool->ClearUnusedImportTrackFiles(); descriptor_pool->ClearUnusedImportTrackFiles();
if (parsed_file == NULL) { if (parsed_file == NULL) {
if (!descriptor_set_in_names_.empty()) {
std::cerr << input_file << ": " << strerror(ENOENT) << std::endl;
}
return false; return false;
} }
parsed_files->push_back(parsed_file); parsed_files->push_back(parsed_file);
@ -1111,18 +1145,27 @@ void CommandLineInterface::Clear() {
} }
bool CommandLineInterface::MakeProtoProtoPathRelative( bool CommandLineInterface::MakeProtoProtoPathRelative(
DiskSourceTree* source_tree, string* proto) { DiskSourceTree* source_tree, string* proto,
DescriptorDatabase* fallback_database) {
// If it's in the fallback db, don't report non-existent file errors.
FileDescriptorProto fallback_file;
bool in_fallback_database =
fallback_database != nullptr &&
fallback_database->FindFileByName(*proto, &fallback_file);
// If the input file path is not a physical file path, it must be a virtual // If the input file path is not a physical file path, it must be a virtual
// path. // path.
if (access(proto->c_str(), F_OK) < 0) { if (access(proto->c_str(), F_OK) < 0) {
string disk_file; string disk_file;
if (source_tree->VirtualFileToDiskFile(*proto, &disk_file)) { if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
in_fallback_database) {
return true; return true;
} else { } else {
std::cerr << *proto << ": " << strerror(ENOENT) << std::endl; std::cerr << *proto << ": " << strerror(ENOENT) << std::endl;
return false; return false;
} }
} }
string virtual_file, shadowing_disk_file; string virtual_file, shadowing_disk_file;
switch (source_tree->DiskFileToVirtualFile( switch (source_tree->DiskFileToVirtualFile(
*proto, &virtual_file, &shadowing_disk_file)) { *proto, &virtual_file, &shadowing_disk_file)) {
@ -1138,12 +1181,16 @@ bool CommandLineInterface::MakeProtoProtoPathRelative(
"comes first." << std::endl; "comes first." << std::endl;
return false; return false;
case DiskSourceTree::CANNOT_OPEN: case DiskSourceTree::CANNOT_OPEN:
if (in_fallback_database) {
return true;
}
std::cerr << *proto << ": " << strerror(errno) << std::endl; std::cerr << *proto << ": " << strerror(errno) << std::endl;
return false; return false;
case DiskSourceTree::NO_MAPPING: { case DiskSourceTree::NO_MAPPING: {
// Try to interpret the path as a virtual path. // Try to interpret the path as a virtual path.
string disk_file; string disk_file;
if (source_tree->VirtualFileToDiskFile(*proto, &disk_file)) { if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
in_fallback_database) {
return true; return true;
} else { } else {
// The input file path can't be mapped to any --proto_path and it also // The input file path can't be mapped to any --proto_path and it also
@ -1166,9 +1213,10 @@ bool CommandLineInterface::MakeProtoProtoPathRelative(
} }
bool CommandLineInterface::MakeInputsBeProtoPathRelative( bool CommandLineInterface::MakeInputsBeProtoPathRelative(
DiskSourceTree* source_tree) { DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
for (auto& input_file : input_files_) { for (auto& input_file : input_files_) {
if (!MakeProtoProtoPathRelative(source_tree, &input_file)) { if (!MakeProtoProtoPathRelative(source_tree, &input_file,
fallback_database)) {
return false; return false;
} }
} }
@ -1270,15 +1318,16 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
return PARSE_ARGUMENT_FAIL; return PARSE_ARGUMENT_FAIL;
} }
// If no --proto_path was given, use the current working directory. // The --proto_path & --descriptor_set_in flags both specify places to look
if (proto_path_.empty()) { // for proto files. If neither were given, use the current working directory.
if (proto_path_.empty() && descriptor_set_in_names_.empty()) {
// Don't use make_pair as the old/default standard library on Solaris // Don't use make_pair as the old/default standard library on Solaris
// doesn't support it without explicit template parameters, which are // doesn't support it without explicit template parameters, which are
// incompatible with C++0x's make_pair. // incompatible with C++0x's make_pair.
proto_path_.push_back(std::pair<string, string>("", ".")); proto_path_.push_back(std::pair<string, string>("", "."));
} }
// Check some errror cases. // Check some error cases.
bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty(); bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
if (decoding_raw && !input_files_.empty()) { if (decoding_raw && !input_files_.empty()) {
std::cerr << "When using --decode_raw, no input files should be given." std::cerr << "When using --decode_raw, no input files should be given."
@ -1395,13 +1444,6 @@ CommandLineInterface::InterpretArgument(const string& name,
input_files_.push_back(value); input_files_.push_back(value);
} else if (name == "-I" || name == "--proto_path") { } else if (name == "-I" || name == "--proto_path") {
if (!descriptor_set_in_names_.empty()) {
std::cerr << "Only one of " << name
<< " and --descriptor_set_in can be specified."
<< std::endl;
return PARSE_ARGUMENT_FAIL;
}
// Java's -classpath (and some other languages) delimits path components // Java's -classpath (and some other languages) delimits path components
// with colons. Let's accept that syntax too just to make things more // with colons. Let's accept that syntax too just to make things more
// intuitive. // intuitive.
@ -1477,12 +1519,6 @@ CommandLineInterface::InterpretArgument(const string& name,
std::cerr << name << " requires a non-empty value." << std::endl; std::cerr << name << " requires a non-empty value." << std::endl;
return PARSE_ARGUMENT_FAIL; return PARSE_ARGUMENT_FAIL;
} }
if (!proto_path_.empty()) {
std::cerr << "Only one of " << name
<< " and --proto_path can be specified."
<< std::endl;
return PARSE_ARGUMENT_FAIL;
}
if (!dependency_out_name_.empty()) { if (!dependency_out_name_.empty()) {
std::cerr << name << " cannot be used with --dependency_out." std::cerr << name << " cannot be used with --dependency_out."
<< std::endl; << std::endl;
@ -1698,13 +1734,18 @@ CommandLineInterface::InterpretArgument(const string& name,
void CommandLineInterface::PrintHelpText() { void CommandLineInterface::PrintHelpText() {
// Sorry for indentation here; line wrapping would be uglier. // Sorry for indentation here; line wrapping would be uglier.
std::cout << std::cout
"Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n" <<
"Usage: " << executable_name_
<< " [OPTION] PROTO_FILES\n"
"Parse PROTO_FILES and generate output based on the options given:\n" "Parse PROTO_FILES and generate output based on the options given:\n"
" -IPATH, --proto_path=PATH Specify the directory in which to search for\n" " -IPATH, --proto_path=PATH Specify the directory in which to search for\n"
" imports. May be specified multiple times;\n" " imports. May be specified multiple times;\n"
" directories will be searched in order. If not\n" " directories will be searched in order. If not\n"
" given, the current working directory is used.\n" " given, the current working directory is used.\n"
" If not found in any of the these directories,\n"
" the --descriptor_set_in descriptors will be\n"
" checked for required proto file.\n"
" --version Show version info and exit.\n" " --version Show version info and exit.\n"
" -h, --help Show this text and exit.\n" " -h, --help Show this text and exit.\n"
" --encode=MESSAGE_TYPE Read a text-format message of the given type\n" " --encode=MESSAGE_TYPE Read a text-format message of the given type\n"

@ -53,6 +53,7 @@ namespace google {
namespace protobuf { namespace protobuf {
class Descriptor; // descriptor.h class Descriptor; // descriptor.h
class DescriptorDatabase; // descriptor_database.h
class DescriptorPool; // descriptor.h class DescriptorPool; // descriptor.h
class FileDescriptor; // descriptor.h class FileDescriptor; // descriptor.h
class FileDescriptorSet; // descriptor.h class FileDescriptorSet; // descriptor.h
@ -214,14 +215,15 @@ class PROTOC_EXPORT CommandLineInterface {
// Clear state from previous Run(). // Clear state from previous Run().
void Clear(); void Clear();
// Remaps the proto file so that it is relative to one of the ddirectories // Remaps the proto file so that it is relative to one of the directories
// in proto_path_. Returns false if an error occurred. // in proto_path_. Returns false if an error occurred.
bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, std::string* proto); bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, std::string* proto,
DescriptorDatabase* fallback_database);
// Remaps each file in input_files_ so that it is relative to one of the // Remaps each file in input_files_ so that it is relative to one of the
// directories in proto_path_. Returns false if an error occurred. // directories in proto_path_. Returns false if an error occurred.
bool MakeInputsBeProtoPathRelative( bool MakeInputsBeProtoPathRelative(DiskSourceTree* source_tree,
DiskSourceTree* source_tree); DescriptorDatabase* fallback_database);
// Return status for ParseArguments() and InterpretArgument(). // Return status for ParseArguments() and InterpretArgument().
@ -259,7 +261,11 @@ class PROTOC_EXPORT CommandLineInterface {
void PrintHelpText(); void PrintHelpText();
// Loads proto_path_ into the provided source_tree. // Loads proto_path_ into the provided source_tree.
bool InitializeDiskSourceTree(DiskSourceTree* source_tree); bool InitializeDiskSourceTree(DiskSourceTree* source_tree,
DescriptorDatabase* fallback_database);
// Verify that all the input files exist in the given database.
bool VerifyInputFilesInDescriptors(DescriptorDatabase* fallback_database);
// Loads descriptor_set_in into the provided database // Loads descriptor_set_in into the provided database
bool PopulateSimpleDescriptorDatabase(SimpleDescriptorDatabase* database); bool PopulateSimpleDescriptorDatabase(SimpleDescriptorDatabase* database);

@ -299,7 +299,6 @@ void CommandLineInterfaceTest::Run(const string& command) {
void CommandLineInterfaceTest::RunWithArgs(std::vector<string> args) { void CommandLineInterfaceTest::RunWithArgs(std::vector<string> args) {
if (!disallow_plugins_) { if (!disallow_plugins_) {
cli_.AllowPlugins("prefix-"); cli_.AllowPlugins("prefix-");
#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
string plugin_path; string plugin_path;
#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH #ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH; plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
@ -330,11 +329,6 @@ void CommandLineInterfaceTest::RunWithArgs(std::vector<string> args) {
#endif #endif
if (plugin_path.empty()) { if (plugin_path.empty()) {
#else
string plugin_path = "third_party/protobuf/test_plugin";
if (access(plugin_path.c_str(), F_OK) != 0) {
#endif // GOOGLE_THIRD_PARTY_PROTOBUF
GOOGLE_LOG(ERROR) GOOGLE_LOG(ERROR)
<< "Plugin executable not found. Plugin tests are likely to fail."; << "Plugin executable not found. Plugin tests are likely to fail.";
} else { } else {
@ -1761,13 +1755,49 @@ TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) {
TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) { TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) {
Run("protocol_compiler --test_out=$tmpdir " Run("protocol_compiler --test_out=$tmpdir "
"--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto"); "--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto");
ExpectErrorText( ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
"Only one of --descriptor_set_in and --proto_path can be specified.\n");
Run("protocol_compiler --test_out=$tmpdir " Run("protocol_compiler --test_out=$tmpdir "
"--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto"); "--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto");
ExpectErrorText( ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
"Only one of --proto_path and --descriptor_set_in can be specified.\n"); }
TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) {
// Test what happens if a proto is in a --descriptor_set_in and also exists
// on disk.
FileDescriptorSet file_descriptor_set;
// NOTE: This file desc SHOULD be different from the one created as a temp
// to make it easier to test that the file was output instead of the
// contents of the --descriptor_set_in file.
FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
file_descriptor_proto->set_name("foo.proto");
file_descriptor_proto->add_message_type()->set_name("Foo");
WriteDescriptorSet("foo.bin", &file_descriptor_set);
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
"message FooBar { required string foo_message = 1; }\n");
Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
"--descriptor_set_in=$tmpdir/foo.bin "
"--include_source_info "
"--proto_path=$tmpdir foo.proto");
ExpectNoErrors();
FileDescriptorSet descriptor_set;
ReadDescriptorSet("descriptor_set", &descriptor_set);
EXPECT_EQ(1, descriptor_set.file_size());
EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
// Descriptor set SHOULD have source code info.
EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name());
EXPECT_EQ("foo_message",
descriptor_set.file(0).message_type(0).field(0).name());
} }
TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) { TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) {

@ -161,6 +161,10 @@ TEST(BootstrapTest, GeneratedFilesMatch) {
EXPECT_EQ("", error_collector.text_); EXPECT_EQ("", error_collector.text_);
CppGenerator generator; CppGenerator generator;
MockGeneratorContext context; MockGeneratorContext context;
#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
generator.set_opensource_runtime(true);
generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
#endif
string error; string error;
ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error)); ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error));

@ -256,8 +256,6 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer,
GenerateHeader(printer); GenerateHeader(printer);
IncludeFile("net/proto2/public/port_undef.inc", printer);
GenerateBottomHeaderGuard(printer, filename_identifier); GenerateBottomHeaderGuard(printer, filename_identifier);
} }
@ -320,13 +318,11 @@ void FileGenerator::DoIncludeFile(const string& google3_name, bool do_export,
path = StringReplace(path, "internal/", "", false); path = StringReplace(path, "internal/", "", false);
path = StringReplace(path, "proto/", "", false); path = StringReplace(path, "proto/", "", false);
path = StringReplace(path, "public/", "", false); path = StringReplace(path, "public/", "", false);
if (options_.opensource_include_paths) { if (options_.runtime_include_base.empty()) {
format("#include <google/protobuf/$1$>", path); format("#include <google/protobuf/$1$>", path);
} else { } else {
format( format("#include \"$1$google/protobuf/$2$\"",
"#include " options_.runtime_include_base, path);
"\"third_party/protobuf/testing/extracted/src/google/protobuf/$1$\"",
path);
} }
} else { } else {
format("#include \"$1$\"", google3_name); format("#include \"$1$\"", google3_name);
@ -346,10 +342,10 @@ string FileGenerator::CreateHeaderInclude(const string& basename,
if (options_.opensource_runtime) { if (options_.opensource_runtime) {
if (IsWellKnownMessage(file)) { if (IsWellKnownMessage(file)) {
if (options_.opensource_include_paths) { if (options_.runtime_include_base.empty()) {
use_system_include = true; use_system_include = true;
} else { } else {
name = "third_party/protobuf/testing/extracted/src/" + basename; name = options_.runtime_include_base + basename;
} }
} }
} }
@ -809,23 +805,33 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
"\n", "\n",
message_generators_.size()); message_generators_.size());
// Now generate the AddDescriptors() function.
format(
"::$proto_ns$::internal::DescriptorTable $1$ = {\n"
" false, $init_defaults$, \n",
UniqueName("descriptor_table", file_, options_));
format.Indent();
// Embed the descriptor. We simply serialize the entire // Embed the descriptor. We simply serialize the entire
// FileDescriptorProto // FileDescriptorProto/ and embed it as a string literal, which is parsed and
// and embed it as a string literal, which is parsed and built into real // built into real descriptors at initialization time.
// descriptors at initialization time. const string protodef_name =
UniqueName("descriptor_table_protodef", file_, options_);
format( "const char $1$[] =\n", protodef_name);
format.Indent();
FileDescriptorProto file_proto; FileDescriptorProto file_proto;
file_->CopyTo(&file_proto); file_->CopyTo(&file_proto);
string file_data; string file_data;
file_proto.SerializeToString(&file_data); file_proto.SerializeToString(&file_data);
{ {
if (file_data.size() > 65535) {
// Workaround for MSVC: "Error C1091: compiler limit: string exceeds
// 65535 bytes in length". Declare a static array of chars rather than
// use a string literal. Only write 25 bytes per line.
static const int kBytesPerLine = 25;
format("{ ");
for (int i = 0; i < file_data.size();) {
for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
format("'$1$', ", CEscape(file_data.substr(i, 1)));
}
format("\n");
}
format("'\\0' }"); // null-terminate
} else {
// Only write 40 bytes per line. // Only write 40 bytes per line.
static const int kBytesPerLine = 40; static const int kBytesPerLine = 40;
for (int i = 0; i < file_data.size(); i += kBytesPerLine) { for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
@ -834,11 +840,21 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
} }
} }
format(";\n");
}
format.Outdent(); format.Outdent();
// Now generate the AddDescriptors() function.
format(
"::$proto_ns$::internal::DescriptorTable $1$ = {\n"
" false, $init_defaults$, \n"
" $2$,\n",
UniqueName("descriptor_table", file_, options_),
protodef_name);
const int num_deps = file_->dependency_count(); const int num_deps = file_->dependency_count();
format( format(
",\n \"$filename$\", &$assign_desc_table$, $1$,\n" " \"$filename$\", &$assign_desc_table$, $1$,\n"
"};\n\n" "};\n\n"
"void $add_descriptors$() {\n" "void $add_descriptors$() {\n"
" static constexpr ::$proto_ns$::internal::InitFunc deps[$2$] =\n" " static constexpr ::$proto_ns$::internal::InitFunc deps[$2$] =\n"
@ -1277,7 +1293,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
IncludeFile("net/proto2/public/unknown_field_set.h", printer); IncludeFile("net/proto2/public/unknown_field_set.h", printer);
} }
if (IsAnyMessage(file_)) { if (IsAnyMessage(file_, options_)) {
IncludeFile("net/proto2/internal/any.h", printer); IncludeFile("net/proto2/internal/any.h", printer);
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save