diff options
author | Feng Xiao <xfxyjwf@gmail.com> | 2018-08-08 17:00:41 -0700 |
---|---|---|
committer | Feng Xiao <xfxyjwf@gmail.com> | 2018-08-08 17:00:41 -0700 |
commit | 6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3 (patch) | |
tree | e575738adf52d24b883cca5e8928a5ded31caba1 /java | |
parent | e7746f487cb9cca685ffb1b3d7dccc5554b618a4 (diff) | |
download | protobuf-6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3.tar.gz protobuf-6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3.tar.bz2 protobuf-6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3.zip |
Down-integrate from google3.
Diffstat (limited to 'java')
45 files changed, 797 insertions, 412 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java index fc3c2a5d..09aaed18 100644 --- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java @@ -32,7 +32,6 @@ package com.google.protobuf; import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; -import com.google.protobuf.Descriptors.FileDescriptor.Syntax; import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.protobuf.Internal.EnumLite; import java.io.IOException; @@ -446,10 +445,7 @@ public abstract class AbstractMessage final CodedInputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { - boolean discardUnknown = - getDescriptorForType().getFile().getSyntax() == Syntax.PROTO3 - ? input.shouldDiscardUnknownFieldsProto3() - : input.shouldDiscardUnknownFields(); + boolean discardUnknown = input.shouldDiscardUnknownFields(); final UnknownFieldSet.Builder unknownFields = discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields()); while (true) { diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java index 4d7a9727..0dedb173 100644 --- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java @@ -42,7 +42,8 @@ import java.util.RandomAccess; * * @author dweis@google.com (Daniel Weis) */ -final class BooleanArrayList extends AbstractProtobufList<Boolean> +final class BooleanArrayList + extends AbstractProtobufList<Boolean> implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection { private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(); diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java index d67bb54a..ddda0f26 100644 --- a/java/core/src/main/java/com/google/protobuf/ByteString.java +++ b/java/core/src/main/java/com/google/protobuf/ByteString.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -222,6 +223,67 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { } // ================================================================= + // Comparison + + private static final int UNSIGNED_BYTE_MASK = 0xFF; + + /** + * Returns the value of the given byte as an integer, interpreting the byte as an unsigned value. + * That is, returns {@code value + 256} if {@code value} is negative; {@code value} itself + * otherwise. + * + * <p>Note: This code was copied from {@link com.google.common.primitives.UnsignedBytes#toInt}, as + * Guava libraries cannot be used in the {@code com.google.protobuf} package. + */ + private static int toInt(byte value) { + return value & UNSIGNED_BYTE_MASK; + } + + /** + * Compares two {@link ByteString}s lexicographically, treating their contents as unsigned byte + * values between 0 and 255 (inclusive). + * + * <p>For example, {@code (byte) -1} is considered to be greater than {@code (byte) 1} because + * it is interpreted as an unsigned value, {@code 255}. + */ + private static final Comparator<ByteString> UNSIGNED_LEXICOGRAPHICAL_COMPARATOR = + new Comparator<ByteString>() { + @Override + public int compare(ByteString former, ByteString latter) { + ByteIterator formerBytes = former.iterator(); + ByteIterator latterBytes = latter.iterator(); + + while (formerBytes.hasNext() && latterBytes.hasNext()) { + // Note: This code was copied from com.google.common.primitives.UnsignedBytes#compare, + // as Guava libraries cannot be used in the {@code com.google.protobuf} package. + int result = + Integer.compare(toInt(formerBytes.nextByte()), toInt(latterBytes.nextByte())); + if (result != 0) { + return result; + } + } + + return Integer.compare(former.size(), latter.size()); + } + }; + + /** + * Returns a {@link Comparator<ByteString>} which compares {@link ByteString}-s lexicographically + * as sequences of unsigned bytes (i.e. values between 0 and 255, inclusive). + * + * <p>For example, {@code (byte) -1} is considered to be greater than {@code (byte) 1} because + * it is interpreted as an unsigned value, {@code 255}: + * + * <ul> + * <li>{@code `-1` -> 0b11111111 (two's complement) -> 255} + * <li>{@code `1` -> 0b00000001 -> 1} + * </ul> + */ + public static Comparator<ByteString> unsignedLexicographicalComparator() { + return UNSIGNED_LEXICOGRAPHICAL_COMPARATOR; + } + + // ================================================================= // ByteString -> substring /** @@ -287,8 +349,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { * @param offset offset in source array * @param size number of bytes to copy * @return new {@code ByteString} + * @throws IndexOutOfBoundsException if {@code offset} or {@code size} are out of bounds */ public static ByteString copyFrom(byte[] bytes, int offset, int size) { + checkRange(offset, offset + size, bytes.length); return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size)); } @@ -339,8 +403,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { * @param bytes source buffer * @param size number of bytes to copy * @return new {@code ByteString} + * @throws IndexOutOfBoundsException if {@code size > bytes.remaining()} */ public static ByteString copyFrom(ByteBuffer bytes, int size) { + checkRange(0, size, bytes.remaining()); byte[] copy = new byte[size]; bytes.get(copy); return new LiteralByteString(copy); @@ -578,6 +644,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { /** * Copies bytes into a buffer at the given offset. * + * <p>To copy a subset of bytes, you call this method on the return value of {@link + * #substring(int, int)}. Example: {@code byteString.substring(start, end).copyTo(target, offset)} + * * @param target buffer to copy into * @param offset in the target buffer * @throws IndexOutOfBoundsException if the offset is negative or too large @@ -589,15 +658,16 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { /** * Copies bytes into a buffer. * - * @param target buffer to copy into + * @param target buffer to copy into * @param sourceOffset offset within these bytes * @param targetOffset offset within the target buffer * @param numberToCopy number of bytes to copy - * @throws IndexOutOfBoundsException if an offset or size is negative or too - * large + * @throws IndexOutOfBoundsException if an offset or size is negative or too large + * @deprecation Instead, call {@code byteString.substring(sourceOffset, sourceOffset + + * numberToCopy).copyTo(target, targetOffset)} */ - public final void copyTo(byte[] target, int sourceOffset, int targetOffset, - int numberToCopy) { + @Deprecated + public final void copyTo(byte[] target, int sourceOffset, int targetOffset, int numberToCopy) { checkRange(sourceOffset, sourceOffset + numberToCopy, size()); checkRange(targetOffset, targetOffset + numberToCopy, target.length); if (numberToCopy > 0) { @@ -617,10 +687,13 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { /** * Copies bytes into a ByteBuffer. * + * <p>To copy a subset of bytes, you call this method on the return value of {@link + * #substring(int, int)}. Example: {@code byteString.substring(start, end).copyTo(target)} + * * @param target ByteBuffer to copy into. * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only - * @throws java.nio.BufferOverflowException if the {@code target}'s - * remaining() space is not large enough to hold the data. + * @throws java.nio.BufferOverflowException if the {@code target}'s remaining() space is not large + * enough to hold the data. */ public abstract void copyTo(ByteBuffer target); @@ -1258,6 +1331,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable { * @param bytes array to wrap */ LiteralByteString(byte[] bytes) { + if (bytes == null) { + throw new NullPointerException(); + } this.bytes = bytes; } diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java index 1297462e..4545d0ae 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java @@ -64,12 +64,6 @@ public abstract class CodedInputStream { // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE; - /** - * Whether to enable our custom UTF-8 decode codepath which does not use {@link StringCoding}. - * Currently disabled. - */ - private static final boolean ENABLE_CUSTOM_UTF8_DECODE = false; - /** Visible for subclasses. See setRecursionLimit() */ int recursionDepth; @@ -417,21 +411,7 @@ public abstract class CodedInputStream { } - private boolean explicitDiscardUnknownFields = false; - - private static volatile boolean proto3DiscardUnknownFieldsDefault = false; - - static void setProto3DiscardUnknownsByDefaultForTest() { - proto3DiscardUnknownFieldsDefault = true; - } - - static void setProto3KeepUnknownsByDefaultForTest() { - proto3DiscardUnknownFieldsDefault = false; - } - - static boolean getProto3DiscardUnknownFieldsDefault() { - return proto3DiscardUnknownFieldsDefault; - } + private boolean shouldDiscardUnknownFields = false; /** * Sets this {@code CodedInputStream} to discard unknown fields. Only applies to full runtime @@ -442,7 +422,7 @@ public abstract class CodedInputStream { * runtime. */ final void discardUnknownFields() { - explicitDiscardUnknownFields = true; + shouldDiscardUnknownFields = true; } /** @@ -450,7 +430,7 @@ public abstract class CodedInputStream { * default. */ final void unsetDiscardUnknownFields() { - explicitDiscardUnknownFields = false; + shouldDiscardUnknownFields = false; } /** @@ -458,19 +438,7 @@ public abstract class CodedInputStream { * runtime messages. */ final boolean shouldDiscardUnknownFields() { - return explicitDiscardUnknownFields; - } - - /** - * Whether unknown fields in this input stream should be discarded during parsing for proto3 full - * runtime messages. - * - * <p>This function was temporarily introduced before proto3 unknown fields behavior is changed. - * TODO(liujisi): remove this and related code in GeneratedMessage after proto3 unknown - * fields migration is done. - */ - final boolean shouldDiscardUnknownFieldsProto3() { - return explicitDiscardUnknownFields ? true : proto3DiscardUnknownFieldsDefault; + return shouldDiscardUnknownFields; } /** @@ -831,19 +799,9 @@ public abstract class CodedInputStream { public String readStringRequireUtf8() throws IOException { final int size = readRawVarint32(); if (size > 0 && size <= (limit - pos)) { - if (ENABLE_CUSTOM_UTF8_DECODE) { - String result = Utf8.decodeUtf8(buffer, pos, size); - pos += size; - return result; - } else { - // TODO(martinrb): We could save a pass by validating while decoding. - if (!Utf8.isValidUtf8(buffer, pos, pos + size)) { - throw InvalidProtocolBufferException.invalidUtf8(); - } - final int tempPos = pos; - pos += size; - return new String(buffer, tempPos, size, UTF_8); - } + String result = Utf8.decodeUtf8(buffer, pos, size); + pos += size; + return result; } if (size == 0) { @@ -1559,25 +1517,10 @@ public abstract class CodedInputStream { public String readStringRequireUtf8() throws IOException { final int size = readRawVarint32(); if (size > 0 && size <= remaining()) { - if (ENABLE_CUSTOM_UTF8_DECODE) { - final int bufferPos = bufferPos(pos); - String result = Utf8.decodeUtf8(buffer, bufferPos, size); - pos += size; - return result; - } else { - // TODO(nathanmittler): Is there a way to avoid this copy? - // The same as readBytes' logic - byte[] bytes = new byte[size]; - UnsafeUtil.copyMemory(pos, bytes, 0, size); - // TODO(martinrb): We could save a pass by validating while decoding. - if (!Utf8.isValidUtf8(bytes)) { - throw InvalidProtocolBufferException.invalidUtf8(); - } - - String result = new String(bytes, UTF_8); - pos += size; - return result; - } + final int bufferPos = bufferPos(pos); + String result = Utf8.decodeUtf8(buffer, bufferPos, size); + pos += size; + return result; } if (size == 0) { @@ -2345,15 +2288,7 @@ public abstract class CodedInputStream { bytes = readRawBytesSlowPath(size); tempPos = 0; } - if (ENABLE_CUSTOM_UTF8_DECODE) { - return Utf8.decodeUtf8(bytes, tempPos, size); - } else { - // TODO(martinrb): We could save a pass by validating while decoding. - if (!Utf8.isValidUtf8(bytes, tempPos, tempPos + size)) { - throw InvalidProtocolBufferException.invalidUtf8(); - } - return new String(bytes, tempPos, size, UTF_8); - } + return Utf8.decodeUtf8(bytes, tempPos, size); } @Override @@ -3373,34 +3308,15 @@ public abstract class CodedInputStream { public String readStringRequireUtf8() throws IOException { final int size = readRawVarint32(); if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) { - if (ENABLE_CUSTOM_UTF8_DECODE) { - final int bufferPos = (int) (currentByteBufferPos - currentByteBufferStartPos); - String result = Utf8.decodeUtf8(currentByteBuffer, bufferPos, size); - currentByteBufferPos += size; - return result; - } else { - byte[] bytes = new byte[size]; - UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size); - if (!Utf8.isValidUtf8(bytes)) { - throw InvalidProtocolBufferException.invalidUtf8(); - } - String result = new String(bytes, UTF_8); - currentByteBufferPos += size; - return result; - } + final int bufferPos = (int) (currentByteBufferPos - currentByteBufferStartPos); + String result = Utf8.decodeUtf8(currentByteBuffer, bufferPos, size); + currentByteBufferPos += size; + return result; } if (size >= 0 && size <= remaining()) { byte[] bytes = new byte[size]; readRawBytesTo(bytes, 0, size); - if (ENABLE_CUSTOM_UTF8_DECODE) { - return Utf8.decodeUtf8(bytes, 0, size); - } else { - if (!Utf8.isValidUtf8(bytes)) { - throw InvalidProtocolBufferException.invalidUtf8(); - } - String result = new String(bytes, UTF_8); - return result; - } + return Utf8.decodeUtf8(bytes, 0, size); } if (size == 0) { diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java index 5b28b4a8..8d987b2e 100644 --- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java @@ -42,7 +42,8 @@ import java.util.RandomAccess; * * @author dweis@google.com (Daniel Weis) */ -final class DoubleArrayList extends AbstractProtobufList<Double> +final class DoubleArrayList + extends AbstractProtobufList<Double> implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection { private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(); diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java index a6a774b7..2c346e03 100644 --- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java +++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java @@ -608,20 +608,12 @@ public final class DynamicMessage extends AbstractMessage { @Override public Builder setUnknownFields(UnknownFieldSet unknownFields) { - if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3 - && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) { - return this; - } this.unknownFields = unknownFields; return this; } @Override public Builder mergeUnknownFields(UnknownFieldSet unknownFields) { - if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3 - && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) { - return this; - } this.unknownFields = UnknownFieldSet.newBuilder(this.unknownFields) .mergeFrom(unknownFields) diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java index 7c080af3..41749f6d 100644 --- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java @@ -42,7 +42,8 @@ import java.util.RandomAccess; * * @author dweis@google.com (Daniel Weis) */ -final class FloatArrayList extends AbstractProtobufList<Float> +final class FloatArrayList + extends AbstractProtobufList<Float> implements FloatList, RandomAccess, PrimitiveNonBoxingCollection { private static final FloatArrayList EMPTY_LIST = new FloatArrayList(); diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java index df01547e..35b31f15 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -33,7 +33,6 @@ package com.google.protobuf; import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream; import com.google.protobuf.Internal.BooleanList; import com.google.protobuf.Internal.DoubleList; -import com.google.protobuf.Internal.EnumLiteMap; import com.google.protobuf.Internal.FloatList; import com.google.protobuf.Internal.IntList; import com.google.protobuf.Internal.LongList; @@ -1600,7 +1599,7 @@ public abstract class GeneratedMessageLite< protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>> extends AbstractParser<T> { - private T defaultInstance; + private final T defaultInstance; public DefaultInstanceBasedParser(T defaultInstance) { this.defaultInstance = defaultInstance; diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java index 4acd8f2f..53af544f 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java @@ -38,6 +38,11 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; +import com.google.protobuf.Internal.BooleanList; +import com.google.protobuf.Internal.DoubleList; +import com.google.protobuf.Internal.FloatList; +import com.google.protobuf.Internal.IntList; +import com.google.protobuf.Internal.LongList; // In opensource protobuf, we have versioned this GeneratedMessageV3 class to GeneratedMessageV3V3 and // in the future may have GeneratedMessageV3V4 etc. This allows us to change some aspects of this // class without breaking binary compatibility with old generated code that still subclasses @@ -293,16 +298,17 @@ public abstract class GeneratedMessageV3 extends AbstractMessage return unknownFields.mergeFieldFrom(tag, input); } + /** + * Delegates to parseUnknownField. This method is obsolete, but we must retain it for + * compatibility with older generated code. + */ protected boolean parseUnknownFieldProto3( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, int tag) throws IOException { - if (input.shouldDiscardUnknownFieldsProto3()) { - return input.skipField(tag); - } - return unknownFields.mergeFieldFrom(tag, input); + return parseUnknownField(input, unknownFields, extensionRegistry, tag); } protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input) @@ -363,6 +369,76 @@ public abstract class GeneratedMessageV3 extends AbstractMessage return UnsafeUtil.hasUnsafeArrayOperations() && UnsafeUtil.hasUnsafeByteBufferOperations(); } + protected static IntList emptyIntList() { + return IntArrayList.emptyList(); + } + + protected static IntList newIntList() { + return new IntArrayList(); + } + + protected static IntList mutableCopy(IntList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + + protected static LongList emptyLongList() { + return LongArrayList.emptyList(); + } + + protected static LongList newLongList() { + return new LongArrayList(); + } + + protected static LongList mutableCopy(LongList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + + protected static FloatList emptyFloatList() { + return FloatArrayList.emptyList(); + } + + protected static FloatList newFloatList() { + return new FloatArrayList(); + } + + protected static FloatList mutableCopy(FloatList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + + protected static DoubleList emptyDoubleList() { + return DoubleArrayList.emptyList(); + } + + protected static DoubleList newDoubleList() { + return new DoubleArrayList(); + } + + protected static DoubleList mutableCopy(DoubleList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + + protected static BooleanList emptyBooleanList() { + return BooleanArrayList.emptyList(); + } + + protected static BooleanList newBooleanList() { + return new BooleanArrayList(); + } + + protected static BooleanList mutableCopy(BooleanList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + @Override public void writeTo(final CodedOutputStream output) throws IOException { MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false); @@ -641,13 +717,12 @@ public abstract class GeneratedMessageV3 extends AbstractMessage return (BuilderType) this; } + /** + * Delegates to setUnknownFields. This method is obsolete, but we must retain it for + * compatibility with older generated code. + */ protected BuilderType setUnknownFieldsProto3(final UnknownFieldSet unknownFields) { - if (CodedInputStream.getProto3DiscardUnknownFieldsDefault()) { - return (BuilderType) this; - } - this.unknownFields = unknownFields; - onChanged(); - return (BuilderType) this; + return setUnknownFields(unknownFields); } @Override @@ -1009,19 +1084,17 @@ public abstract class GeneratedMessageV3 extends AbstractMessage getDescriptorForType(), new MessageReflection.ExtensionAdapter(extensions), tag); } + /** + * Delegates to parseUnknownField. This method is obsolete, but we must retain it for + * compatibility with older generated code. + */ @Override protected boolean parseUnknownFieldProto3( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, int tag) throws IOException { - return MessageReflection.mergeFieldFrom( - input, - input.shouldDiscardUnknownFieldsProto3() ? null : unknownFields, - extensionRegistry, - getDescriptorForType(), - new MessageReflection.ExtensionAdapter(extensions), - tag); + return parseUnknownField(input, unknownFields, extensionRegistry, tag); } diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java index aacd71e1..4993eea7 100644 --- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java @@ -42,7 +42,8 @@ import java.util.RandomAccess; * * @author dweis@google.com (Daniel Weis) */ -final class IntArrayList extends AbstractProtobufList<Integer> +final class IntArrayList + extends AbstractProtobufList<Integer> implements IntList, RandomAccess, PrimitiveNonBoxingCollection { private static final IntArrayList EMPTY_LIST = new IntArrayList(); diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java index 848cad03..878573d5 100644 --- a/java/core/src/main/java/com/google/protobuf/Internal.java +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -234,6 +234,11 @@ public final class Internal { T findValueByNumber(int number); } + /** Interface for an object which verifies integers are in range. */ + public interface EnumVerifier { + boolean isInRange(int number); + } + /** * Helper method for implementing {@link Message#hashCode()} for longs. * @see Long#hashCode() diff --git a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java index d474c51e..6cfc14a5 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java @@ -69,7 +69,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> static { EMPTY_LIST.makeImmutable(); } - + static LazyStringArrayList emptyList() { return EMPTY_LIST; } @@ -83,8 +83,8 @@ public class LazyStringArrayList extends AbstractProtobufList<String> this(DEFAULT_CAPACITY); } - public LazyStringArrayList(int intialCapacity) { - this(new ArrayList<Object>(intialCapacity)); + public LazyStringArrayList(int initialCapacity) { + this(new ArrayList<Object>(initialCapacity)); } public LazyStringArrayList(LazyStringList from) { @@ -95,7 +95,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> public LazyStringArrayList(List<String> from) { this(new ArrayList<Object>(from)); } - + private LazyStringArrayList(ArrayList<Object> list) { this.list = list; } @@ -150,13 +150,13 @@ public class LazyStringArrayList extends AbstractProtobufList<String> list.add(index, element); modCount++; } - + private void add(int index, ByteString element) { ensureIsMutable(); list.add(index, element); modCount++; } - + private void add(int index, byte[] element) { ensureIsMutable(); list.add(index, element); @@ -221,7 +221,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> list.add(element); modCount++; } - + @Override public void add(byte[] element) { ensureIsMutable(); @@ -233,7 +233,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> public Object getRaw(int index) { return list.get(index); } - + @Override public ByteString getByteString(int index) { Object o = list.get(index); @@ -243,7 +243,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> } return b; } - + @Override public byte[] getByteArray(int index) { Object o = list.get(index); @@ -258,7 +258,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> public void set(int index, ByteString s) { setAndReturn(index, s); } - + private Object setAndReturn(int index, ByteString s) { ensureIsMutable(); return list.set(index, s); @@ -268,7 +268,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> public void set(int index, byte[] s) { setAndReturn(index, s); } - + private Object setAndReturn(int index, byte[] s) { ensureIsMutable(); return list.set(index, s); @@ -283,7 +283,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> return Internal.toStringUtf8((byte[]) o); } } - + private static ByteString asByteString(Object o) { if (o instanceof ByteString) { return (ByteString) o; @@ -293,7 +293,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> return ByteString.copyFrom((byte[]) o); } } - + private static byte[] asByteArray(Object o) { if (o instanceof byte[]) { return (byte[]) o; @@ -327,11 +327,11 @@ public class LazyStringArrayList extends AbstractProtobufList<String> private static class ByteArrayListView extends AbstractList<byte[]> implements RandomAccess { private final LazyStringArrayList list; - + ByteArrayListView(LazyStringArrayList list) { this.list = list; } - + @Override public byte[] get(int index) { return list.getByteArray(index); @@ -362,7 +362,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String> return asByteArray(o); } } - + @Override public List<byte[]> asByteArrayList() { return new ByteArrayListView(this); diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java index 95945cb7..9a5056be 100644 --- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java @@ -42,7 +42,8 @@ import java.util.RandomAccess; * * @author dweis@google.com (Daniel Weis) */ -final class LongArrayList extends AbstractProtobufList<Long> +final class LongArrayList + extends AbstractProtobufList<Long> implements LongList, RandomAccess, PrimitiveNonBoxingCollection { private static final LongArrayList EMPTY_LIST = new LongArrayList(); diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java index 29f567dc..b593b566 100644 --- a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java +++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java @@ -30,6 +30,8 @@ package com.google.protobuf; +import static com.google.protobuf.Internal.checkNotNull; + import java.util.AbstractList; import java.util.ArrayList; import java.util.Collection; @@ -290,9 +292,7 @@ public class RepeatedFieldBuilder */ public RepeatedFieldBuilder<MType, BType, IType> setMessage( int index, MType message) { - if (message == null) { - throw new NullPointerException(); - } + checkNotNull(message); ensureMutableMessageList(); messages.set(index, message); if (builders != null) { @@ -315,9 +315,7 @@ public class RepeatedFieldBuilder */ public RepeatedFieldBuilder<MType, BType, IType> addMessage( MType message) { - if (message == null) { - throw new NullPointerException(); - } + checkNotNull(message); ensureMutableMessageList(); messages.add(message); if (builders != null) { @@ -339,9 +337,7 @@ public class RepeatedFieldBuilder */ public RepeatedFieldBuilder<MType, BType, IType> addMessage( int index, MType message) { - if (message == null) { - throw new NullPointerException(); - } + checkNotNull(message); ensureMutableMessageList(); messages.add(index, message); if (builders != null) { @@ -363,9 +359,7 @@ public class RepeatedFieldBuilder public RepeatedFieldBuilder<MType, BType, IType> addAllMessages( Iterable<? extends MType> values) { for (final MType value : values) { - if (value == null) { - throw new NullPointerException(); - } + checkNotNull(value); } // If we can inspect the size, we can more efficiently add messages. diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java index 941b5def..1f5ec8a2 100644 --- a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java +++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java @@ -30,6 +30,8 @@ package com.google.protobuf; +import static com.google.protobuf.Internal.checkNotNull; + /** * {@code SingleFieldBuilder} implements a structure that a protocol * message uses to hold a single field of another protocol message. It supports @@ -84,10 +86,7 @@ public class SingleFieldBuilder MType message, GeneratedMessage.BuilderParent parent, boolean isClean) { - if (message == null) { - throw new NullPointerException(); - } - this.message = message; + this.message = checkNotNull(message); this.parent = parent; this.isClean = isClean; } @@ -169,10 +168,7 @@ public class SingleFieldBuilder */ public SingleFieldBuilder<MType, BType, IType> setMessage( MType message) { - if (message == null) { - throw new NullPointerException(); - } - this.message = message; + this.message = checkNotNull(message); if (builder != null) { builder.dispose(); builder = null; diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java index 25c3474f..79962e08 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java @@ -1444,8 +1444,8 @@ public final class TextFormat { logger.warning(msg.toString()); } else { String[] lineColumn = unknownFields.get(0).split(":"); - throw new ParseException(Integer.valueOf(lineColumn[0]), - Integer.valueOf(lineColumn[1]), msg.toString()); + throw new ParseException( + Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString()); } } diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java index 37d64633..b3fdebcb 100644 --- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java @@ -786,6 +786,23 @@ public final class UnknownFieldSet implements MessageLite { } /** + * Serializes the message to a {@code ByteString} and returns it. This is just a trivial wrapper + * around {@link #writeTo(int, CodedOutputStream)}. + */ + public ByteString toByteString(int fieldNumber) { + try { + // TODO(lukes): consider caching serialized size in a volatile long + final ByteString.CodedBuilder out = + ByteString.newCodedBuilder(getSerializedSize(fieldNumber)); + writeTo(fieldNumber, out.getCodedOutput()); + return out.build(); + } catch (IOException e) { + throw new RuntimeException( + "Serializing to a ByteString should never fail with an IOException", e); + } + } + + /** * Serializes the field, including field number, and writes it to * {@code output}. */ diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java index d84ef3c5..f822ce51 100644 --- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java +++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java @@ -33,6 +33,7 @@ package com.google.protobuf; import java.lang.reflect.Field; import java.nio.Buffer; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.util.logging.Level; @@ -146,6 +147,10 @@ final class UnsafeUtil { return MEMORY_ACCESSOR.getObject(target, offset); } + static void putObject(Object target, long offset, Object value) { + MEMORY_ACCESSOR.putObject(target, offset, value); + } + static byte getByte(byte[] target, long index) { return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index); } @@ -370,12 +375,6 @@ final class UnsafeUtil { return field != null && field.getType() == long.class ? field : null; } - /** Finds the value field within a {@link String}. */ - private static Field stringValueField() { - Field field = field(String.class, "value"); - return field != null && field.getType() == char[].class ? field : null; - } - /** * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not * available. diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java index de75fe6b..b4a81ca3 100644 --- a/java/core/src/main/java/com/google/protobuf/Utf8.java +++ b/java/core/src/main/java/com/google/protobuf/Utf8.java @@ -42,7 +42,6 @@ import static java.lang.Character.isSurrogatePair; import static java.lang.Character.toCodePoint; import java.nio.ByteBuffer; -import java.util.Arrays; /** * A set of low-level, high-performance static utility methods related @@ -87,7 +86,9 @@ final class Utf8 { * delegate for which all methods are delegated directly to. */ private static final Processor processor = - UnsafeProcessor.isAvailable() ? new UnsafeProcessor() : new SafeProcessor(); + (UnsafeProcessor.isAvailable() && !Android.isOnAndroidDevice()) + ? new UnsafeProcessor() + : new SafeProcessor(); /** * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java index cb2d34eb..bb11bd0f 100644 --- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -210,8 +210,8 @@ public class AbstractMessageTest extends TestCase { new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null); TestUtil.ReflectionTester extensionsReflectionTester = - new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(), - TestUtil.getExtensionRegistry()); + new TestUtil.ReflectionTester( + TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry()); public void testClear() throws Exception { AbstractMessageWrapper message = diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java index 4906763c..febe8537 100644 --- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java @@ -299,20 +299,22 @@ public class BooleanArrayListTest extends TestCase { } public void testRemoveEndOfCapacity() { - BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1); + BooleanList toRemove = + BooleanArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addBoolean(true); toRemove.remove(0); assertEquals(0, toRemove.size()); } public void testSublistRemoveEndOfCapacity() { - BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1); + BooleanList toRemove = + BooleanArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addBoolean(true); toRemove.subList(0, 1).clear(); assertEquals(0, toRemove.size()); } - private void assertImmutable(BooleanArrayList list) { + private void assertImmutable(BooleanList list) { try { list.add(true); diff --git a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java index be71f1f5..fc22955d 100644 --- a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java +++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java @@ -41,6 +41,7 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -86,6 +87,40 @@ public class ByteStringTest extends TestCase { return left.length == right.length && isArrayRange(left, right, 0, left.length); } + public void testCompare_equalByteStrings_compareEqual() throws Exception { + byte[] referenceBytes = getTestBytes(); + ByteString string1 = ByteString.copyFrom(referenceBytes); + ByteString string2 = ByteString.copyFrom(referenceBytes); + + assertEquals( + "ByteString instances containing the same data must compare equal.", + 0, + ByteString.unsignedLexicographicalComparator().compare(string1, string2)); + } + + public void testCompare_byteStringsSortLexicographically() throws Exception { + ByteString app = ByteString.copyFromUtf8("app"); + ByteString apple = ByteString.copyFromUtf8("apple"); + ByteString banana = ByteString.copyFromUtf8("banana"); + + Comparator<ByteString> comparator = ByteString.unsignedLexicographicalComparator(); + + assertTrue("ByteString(app) < ByteString(apple)", comparator.compare(app, apple) < 0); + assertTrue("ByteString(app) < ByteString(banana)", comparator.compare(app, banana) < 0); + assertTrue("ByteString(apple) < ByteString(banana)", comparator.compare(apple, banana) < 0); + } + + public void testCompare_interpretsByteValuesAsUnsigned() throws Exception { + // Two's compliment of `-1` == 0b11111111 == 255 + ByteString twoHundredFiftyFive = ByteString.copyFrom(new byte[] {-1}); + // 0b00000001 == 1 + ByteString one = ByteString.copyFrom(new byte[] {1}); + + assertTrue( + "ByteString comparison treats bytes as unsigned values", + ByteString.unsignedLexicographicalComparator().compare(one, twoHundredFiftyFive) < 0); + } + public void testSubstring_BeginIndex() { byte[] bytes = getTestBytes(); ByteString substring = ByteString.copyFrom(bytes).substring(500); @@ -161,6 +196,34 @@ public class ByteStringTest extends TestCase { byteString, byteStringAlt); } + public void testCopyFrom_LengthTooBig() { + byte[] testBytes = getTestBytes(100); + try { + ByteString.copyFrom(testBytes, 0, 200); + fail("Should throw"); + } catch (IndexOutOfBoundsException expected) { + } + + try { + ByteString.copyFrom(testBytes, 99, 2); + fail(); + } catch (IndexOutOfBoundsException expected) { + } + + ByteBuffer buf = ByteBuffer.wrap(testBytes); + try { + ByteString.copyFrom(buf, 101); + fail(); + } catch (IndexOutOfBoundsException expected) { + } + + try { + ByteString.copyFrom(testBytes, -1, 10); + fail("Should throw"); + } catch (IndexOutOfBoundsException expected) { + } + } + public void testCopyTo_TargetOffset() { byte[] bytes = getTestBytes(); ByteString byteString = ByteString.copyFrom(bytes); @@ -761,6 +824,9 @@ public class ByteStringTest extends TestCase { * Tests ByteString uses Arrays based byte copier when running under Hotstop VM. */ public void testByteArrayCopier() throws Exception { + if (Android.isOnAndroidDevice()) { + return; + } Field field = ByteString.class.getDeclaredField("byteArrayCopier"); field.setAccessible(true); Object byteArrayCopier = field.get(null); diff --git a/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java index 0f09a51b..36c4611f 100644 --- a/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java +++ b/java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java @@ -62,22 +62,17 @@ public class DiscardUnknownFieldsTest { } private static void testProto2Message(Message message) throws Exception { - assertUnknownFieldsDefaultPreserved(message); + assertUnknownFieldsPreserved(message); assertUnknownFieldsExplicitlyDiscarded(message); assertReuseCodedInputStreamPreserve(message); assertUnknownFieldsInUnknownFieldSetArePreserve(message); } private static void testProto3Message(Message message) throws Exception { - CodedInputStream.setProto3KeepUnknownsByDefaultForTest(); - assertUnknownFieldsDefaultPreserved(message); + assertUnknownFieldsPreserved(message); assertUnknownFieldsExplicitlyDiscarded(message); assertReuseCodedInputStreamPreserve(message); assertUnknownFieldsInUnknownFieldSetArePreserve(message); - CodedInputStream.setProto3DiscardUnknownsByDefaultForTest(); - assertUnknownFieldsDefaultDiscarded(message); - assertUnknownFieldsExplicitlyDiscarded(message); - assertUnknownFieldsInUnknownFieldSetAreDiscarded(message); } private static void assertReuseCodedInputStreamPreserve(Message message) throws Exception { @@ -122,7 +117,7 @@ public class DiscardUnknownFieldsTest { assertEquals(message.getClass().getName(), 0, built.getSerializedSize()); } - private static void assertUnknownFieldsDefaultPreserved(MessageLite message) throws Exception { + private static void assertUnknownFieldsPreserved(MessageLite message) throws Exception { { MessageLite parsed = message.getParserForType().parseFrom(payload); assertEquals(message.getClass().getName(), payload, parsed.toByteString()); @@ -134,18 +129,6 @@ public class DiscardUnknownFieldsTest { } } - private static void assertUnknownFieldsDefaultDiscarded(MessageLite message) throws Exception { - { - MessageLite parsed = message.getParserForType().parseFrom(payload); - assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize()); - } - - { - MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build(); - assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize()); - } - } - private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception { Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload); diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java index 923d7f43..a4c2f5aa 100644 --- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java @@ -78,10 +78,10 @@ public class DoubleArrayListTest extends TestCase { list.addAll(asList(1D, 2D, 3D, 4D)); Iterator<Double> iterator = list.iterator(); assertEquals(4, list.size()); - assertEquals(1D, (double) list.get(0)); - assertEquals(1D, (double) iterator.next()); + assertEquals(1D, (double) list.get(0), 0.0); + assertEquals(1D, (double) iterator.next(), 0.0); list.set(0, 1D); - assertEquals(2D, (double) iterator.next()); + assertEquals(2D, (double) iterator.next(), 0.0); list.remove(0); try { @@ -102,9 +102,9 @@ public class DoubleArrayListTest extends TestCase { } public void testGet() { - assertEquals(1D, (double) TERTIARY_LIST.get(0)); - assertEquals(2D, (double) TERTIARY_LIST.get(1)); - assertEquals(3D, (double) TERTIARY_LIST.get(2)); + assertEquals(1D, (double) TERTIARY_LIST.get(0), 0.0); + assertEquals(2D, (double) TERTIARY_LIST.get(1), 0.0); + assertEquals(3D, (double) TERTIARY_LIST.get(2), 0.0); try { TERTIARY_LIST.get(-1); @@ -122,9 +122,9 @@ public class DoubleArrayListTest extends TestCase { } public void testGetDouble() { - assertEquals(1D, TERTIARY_LIST.getDouble(0)); - assertEquals(2D, TERTIARY_LIST.getDouble(1)); - assertEquals(3D, TERTIARY_LIST.getDouble(2)); + assertEquals(1D, TERTIARY_LIST.getDouble(0), 0.0); + assertEquals(2D, TERTIARY_LIST.getDouble(1), 0.0); + assertEquals(3D, TERTIARY_LIST.getDouble(2), 0.0); try { TERTIARY_LIST.get(-1); @@ -163,11 +163,11 @@ public class DoubleArrayListTest extends TestCase { list.addDouble(2); list.addDouble(4); - assertEquals(2D, (double) list.set(0, 3D)); - assertEquals(3D, list.getDouble(0)); + assertEquals(2D, (double) list.set(0, 3D), 0.0); + assertEquals(3D, list.getDouble(0), 0.0); - assertEquals(4D, (double) list.set(1, 0D)); - assertEquals(0D, list.getDouble(1)); + assertEquals(4D, (double) list.set(1, 0D), 0.0); + assertEquals(0D, list.getDouble(1), 0.0); try { list.set(-1, 0D); @@ -188,11 +188,11 @@ public class DoubleArrayListTest extends TestCase { list.addDouble(1); list.addDouble(3); - assertEquals(1D, list.setDouble(0, 0)); - assertEquals(0D, list.getDouble(0)); + assertEquals(1D, list.setDouble(0, 0), 0.0); + assertEquals(0D, list.getDouble(0), 0.0); - assertEquals(3D, list.setDouble(1, 0)); - assertEquals(0D, list.getDouble(1)); + assertEquals(3D, list.setDouble(1, 0), 0.0); + assertEquals(0D, list.getDouble(1), 0.0); try { list.setDouble(-1, 0); @@ -257,8 +257,8 @@ public class DoubleArrayListTest extends TestCase { assertTrue(list.addAll(Collections.singleton(1D))); assertEquals(1, list.size()); - assertEquals(1D, (double) list.get(0)); - assertEquals(1D, list.getDouble(0)); + assertEquals(1D, (double) list.get(0), 0.0); + assertEquals(1D, list.getDouble(0), 0.0); assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D))); assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list); @@ -272,7 +272,7 @@ public class DoubleArrayListTest extends TestCase { public void testRemove() { list.addAll(TERTIARY_LIST); - assertEquals(1D, (double) list.remove(0)); + assertEquals(1D, (double) list.remove(0), 0.0); assertEquals(asList(2D, 3D), list); assertTrue(list.remove(Double.valueOf(3))); @@ -281,7 +281,7 @@ public class DoubleArrayListTest extends TestCase { assertFalse(list.remove(Double.valueOf(3))); assertEquals(asList(2D), list); - assertEquals(2D, (double) list.remove(0)); + assertEquals(2D, (double) list.remove(0), 0.0); assertEquals(asList(), list); try { @@ -299,20 +299,22 @@ public class DoubleArrayListTest extends TestCase { } public void testRemoveEndOfCapacity() { - DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1); + DoubleList toRemove = + DoubleArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addDouble(3); toRemove.remove(0); assertEquals(0, toRemove.size()); } public void testSublistRemoveEndOfCapacity() { - DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1); + DoubleList toRemove = + DoubleArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addDouble(3); toRemove.subList(0, 1).clear(); assertEquals(0, toRemove.size()); } - private void assertImmutable(DoubleArrayList list) { + private void assertImmutable(DoubleList list) { if (list.contains(1D)) { throw new RuntimeException("Cannot test the immutability of lists that contain 1."); } diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java index 77d14f6b..346c1e6a 100644 --- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -51,8 +51,8 @@ public class DynamicMessageTest extends TestCase { new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null); TestUtil.ReflectionTester extensionsReflectionTester = - new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(), - TestUtil.getExtensionRegistry()); + new TestUtil.ReflectionTester( + TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry()); TestUtil.ReflectionTester packedReflectionTester = new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null); @@ -194,9 +194,9 @@ public class DynamicMessageTest extends TestCase { public void testDynamicMessageExtensionParsing() throws Exception { ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString(); - Message message = DynamicMessage.parseFrom( - TestAllExtensions.getDescriptor(), rawBytes, - TestUtil.getExtensionRegistry()); + Message message = + DynamicMessage.parseFrom( + TestAllExtensions.getDescriptor(), rawBytes, TestUtil.getFullExtensionRegistry()); extensionsReflectionTester.assertAllFieldsSetViaReflection(message); // Test Parser interface. diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java index 903a79db..38eccc93 100644 --- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java @@ -78,10 +78,10 @@ public class FloatArrayListTest extends TestCase { list.addAll(asList(1F, 2F, 3F, 4F)); Iterator<Float> iterator = list.iterator(); assertEquals(4, list.size()); - assertEquals(1F, (float) list.get(0)); - assertEquals(1F, (float) iterator.next()); + assertEquals(1F, (float) list.get(0), 0.0f); + assertEquals(1F, (float) iterator.next(), 0.0f); list.set(0, 1F); - assertEquals(2F, (float) iterator.next()); + assertEquals(2F, (float) iterator.next(), 0.0f); list.remove(0); try { @@ -102,9 +102,9 @@ public class FloatArrayListTest extends TestCase { } public void testGet() { - assertEquals(1F, (float) TERTIARY_LIST.get(0)); - assertEquals(2F, (float) TERTIARY_LIST.get(1)); - assertEquals(3F, (float) TERTIARY_LIST.get(2)); + assertEquals(1F, (float) TERTIARY_LIST.get(0), 0.0f); + assertEquals(2F, (float) TERTIARY_LIST.get(1), 0.0f); + assertEquals(3F, (float) TERTIARY_LIST.get(2), 0.0f); try { TERTIARY_LIST.get(-1); @@ -122,9 +122,9 @@ public class FloatArrayListTest extends TestCase { } public void testGetFloat() { - assertEquals(1F, TERTIARY_LIST.getFloat(0)); - assertEquals(2F, TERTIARY_LIST.getFloat(1)); - assertEquals(3F, TERTIARY_LIST.getFloat(2)); + assertEquals(1F, TERTIARY_LIST.getFloat(0), 0.0f); + assertEquals(2F, TERTIARY_LIST.getFloat(1), 0.0f); + assertEquals(3F, TERTIARY_LIST.getFloat(2), 0.0f); try { TERTIARY_LIST.get(-1); @@ -163,11 +163,11 @@ public class FloatArrayListTest extends TestCase { list.addFloat(2); list.addFloat(4); - assertEquals(2F, (float) list.set(0, 3F)); - assertEquals(3F, list.getFloat(0)); + assertEquals(2F, (float) list.set(0, 3F), 0.0f); + assertEquals(3F, list.getFloat(0), 0.0f); - assertEquals(4F, (float) list.set(1, 0F)); - assertEquals(0F, list.getFloat(1)); + assertEquals(4F, (float) list.set(1, 0F), 0.0f); + assertEquals(0F, list.getFloat(1), 0.0f); try { list.set(-1, 0F); @@ -188,11 +188,11 @@ public class FloatArrayListTest extends TestCase { list.addFloat(1); list.addFloat(3); - assertEquals(1F, list.setFloat(0, 0)); - assertEquals(0F, list.getFloat(0)); + assertEquals(1F, list.setFloat(0, 0), 0.0f); + assertEquals(0F, list.getFloat(0), 0.0f); - assertEquals(3F, list.setFloat(1, 0)); - assertEquals(0F, list.getFloat(1)); + assertEquals(3F, list.setFloat(1, 0), 0.0f); + assertEquals(0F, list.getFloat(1), 0.0f); try { list.setFloat(-1, 0); @@ -257,8 +257,8 @@ public class FloatArrayListTest extends TestCase { assertTrue(list.addAll(Collections.singleton(1F))); assertEquals(1, list.size()); - assertEquals(1F, (float) list.get(0)); - assertEquals(1F, list.getFloat(0)); + assertEquals(1F, (float) list.get(0), 0.0f); + assertEquals(1F, list.getFloat(0), 0.0f); assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F))); assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list); @@ -272,7 +272,7 @@ public class FloatArrayListTest extends TestCase { public void testRemove() { list.addAll(TERTIARY_LIST); - assertEquals(1F, (float) list.remove(0)); + assertEquals(1F, (float) list.remove(0), 0.0f); assertEquals(asList(2F, 3F), list); assertTrue(list.remove(Float.valueOf(3))); @@ -281,7 +281,7 @@ public class FloatArrayListTest extends TestCase { assertFalse(list.remove(Float.valueOf(3))); assertEquals(asList(2F), list); - assertEquals(2F, (float) list.remove(0)); + assertEquals(2F, (float) list.remove(0), 0.0f); assertEquals(asList(), list); try { @@ -299,20 +299,22 @@ public class FloatArrayListTest extends TestCase { } public void testRemoveEndOfCapacity() { - FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1); + FloatList toRemove = + FloatArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addFloat(3); toRemove.remove(0); assertEquals(0, toRemove.size()); } public void testSublistRemoveEndOfCapacity() { - FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1); + FloatList toRemove = + FloatArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addFloat(3); toRemove.subList(0, 1).clear(); assertEquals(0, toRemove.size()); } - private void assertImmutable(FloatArrayList list) { + private void assertImmutable(FloatList list) { if (list.contains(1F)) { throw new RuntimeException("Cannot test the immutability of lists that contain 1."); } diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java index c9ebe7f5..a4143cd4 100644 --- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -590,8 +590,8 @@ public class GeneratedMessageTest extends TestCase { // Extensions. TestUtil.ReflectionTester extensionsReflectionTester = - new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(), - TestUtil.getExtensionRegistry()); + new TestUtil.ReflectionTester( + TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry()); public void testExtensionMessageOrBuilder() throws Exception { TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java index d8e97d4f..9edc4344 100644 --- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java @@ -299,20 +299,22 @@ public class IntArrayListTest extends TestCase { } public void testRemoveEndOfCapacity() { - IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1); + IntList toRemove = + IntArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addInt(3); toRemove.remove(0); assertEquals(0, toRemove.size()); } public void testSublistRemoveEndOfCapacity() { - IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1); + IntList toRemove = + IntArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addInt(3); toRemove.subList(0, 1).clear(); assertEquals(0, toRemove.size()); } - private void assertImmutable(IntArrayList list) { + private void assertImmutable(IntList list) { if (list.contains(1)) { throw new RuntimeException("Cannot test the immutability of lists that contain 1."); } diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java index 5ab80ca2..b20114e0 100644 --- a/java/core/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java @@ -57,6 +57,8 @@ import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -2378,4 +2380,63 @@ public class LiteTest extends TestCase { } catch (NullPointerException expected) { } } + + public void testSerializeToOutputStreamThrowsIOException() { + try { + TestAllTypesLite.newBuilder() + .setOptionalBytes(ByteString.copyFromUtf8("hello")) + .build() + .writeTo( + new OutputStream() { + + @Override + public void write(int b) throws IOException { + throw new IOException(); + } + }); + fail(); + } catch (IOException expected) { + } + } + + public void testUnpairedSurrogatesReplacedByQuestionMark() throws InvalidProtocolBufferException { + String testString = "foo \ud83d bar"; + String expectedString = "foo ? bar"; + + TestAllTypesLite testMessage = + TestAllTypesLite.newBuilder().setOptionalString(testString).build(); + ByteString serializedMessage = testMessage.toByteString(); + + // Behavior is compatible with String.getBytes("UTF-8"), which replaces + // unpaired surrogates with a question mark. + TestAllTypesLite parsedMessage = TestAllTypesLite.parseFrom(serializedMessage); + assertEquals(expectedString, parsedMessage.getOptionalString()); + + // Conversion happens during serialization. + ByteString expectedBytes = ByteString.copyFromUtf8(expectedString); + assertTrue( + String.format( + "Expected serializedMessage (%s) to contain \"%s\" (%s).", + encodeHex(serializedMessage), expectedString, encodeHex(expectedBytes)), + contains(serializedMessage, expectedBytes)); + } + + private String encodeHex(ByteString bytes) { + String hexDigits = "0123456789abcdef"; + StringBuilder stringBuilder = new StringBuilder(bytes.size() * 2); + for (byte b : bytes) { + stringBuilder.append(hexDigits.charAt((b & 0xf0) >> 4)); + stringBuilder.append(hexDigits.charAt(b & 0x0f)); + } + return stringBuilder.toString(); + } + + private boolean contains(ByteString a, ByteString b) { + for (int i = 0; i <= a.size() - b.size(); ++i) { + if (a.substring(i, i + b.size()).equals(b)) { + return true; + } + } + return false; + } } diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java index e50c7d1e..14a8e159 100644 --- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java @@ -299,20 +299,22 @@ public class LongArrayListTest extends TestCase { } public void testRemoveEndOfCapacity() { - LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1); + LongList toRemove = + LongArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addLong(3); toRemove.remove(0); assertEquals(0, toRemove.size()); } public void testSublistRemoveEndOfCapacity() { - LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1); + LongList toRemove = + LongArrayList.emptyList().mutableCopyWithCapacity(1); toRemove.addLong(3); toRemove.subList(0, 1).clear(); assertEquals(0, toRemove.size()); } - private void assertImmutable(LongArrayList list) { + private void assertImmutable(LongList list) { if (list.contains(1L)) { throw new RuntimeException("Cannot test the immutability of lists that contain 1."); } diff --git a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java index af717bfd..0a2c3e37 100644 --- a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java @@ -42,33 +42,33 @@ import junit.framework.TestCase; * Tests for {@link ProtobufArrayList}. */ public class ProtobufArrayListTest extends TestCase { - + private static final ProtobufArrayList<Integer> UNARY_LIST = newImmutableProtoArrayList(1); private static final ProtobufArrayList<Integer> TERTIARY_LIST = newImmutableProtoArrayList(1, 2, 3); - + private ProtobufArrayList<Integer> list; - + @Override protected void setUp() throws Exception { list = new ProtobufArrayList<Integer>(); } - + public void testEmptyListReturnsSameInstance() { assertSame(ProtobufArrayList.emptyList(), ProtobufArrayList.emptyList()); } - + public void testEmptyListIsImmutable() { assertImmutable(ProtobufArrayList.<Integer>emptyList()); } - + public void testModificationWithIteration() { list.addAll(asList(1, 2, 3, 4)); Iterator<Integer> iterator = list.iterator(); assertEquals(4, list.size()); assertEquals(1, (int) list.get(0)); assertEquals(1, (int) iterator.next()); - + list.remove(0); try { iterator.next(); @@ -76,7 +76,7 @@ public class ProtobufArrayListTest extends TestCase { } catch (ConcurrentModificationException e) { // expected } - + iterator = list.iterator(); list.set(0, 1); try { @@ -85,7 +85,7 @@ public class ProtobufArrayListTest extends TestCase { } catch (ConcurrentModificationException e) { // expected } - + iterator = list.iterator(); list.add(0, 0); try { @@ -95,7 +95,7 @@ public class ProtobufArrayListTest extends TestCase { // expected } } - + public void testMakeImmutable() { list.add(2); list.add(4); @@ -104,107 +104,213 @@ public class ProtobufArrayListTest extends TestCase { list.makeImmutable(); assertImmutable(list); } - + public void testRemove() { - list.add(2); - list.add(4); - list.add(6); + list.addAll(TERTIARY_LIST); + assertEquals(1, (int) list.remove(0)); + assertEquals(asList(2, 3), list); - list.remove(1); - assertEquals(asList(2, 6), list); + assertTrue(list.remove(Integer.valueOf(3))); + assertEquals(asList(2), list); - list.remove(1); + assertFalse(list.remove(Integer.valueOf(3))); assertEquals(asList(2), list); - list.remove(0); + assertEquals(2, (int) list.remove(0)); assertEquals(asList(), list); + + try { + list.remove(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.remove(0); + } catch (IndexOutOfBoundsException e) { + // expected + } } - + public void testGet() { - list.add(2); - list.add(6); - - assertEquals(2, (int) list.get(0)); - assertEquals(6, (int) list.get(1)); + assertEquals(1, (int) TERTIARY_LIST.get(0)); + assertEquals(2, (int) TERTIARY_LIST.get(1)); + assertEquals(3, (int) TERTIARY_LIST.get(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } } - + public void testSet() { list.add(2); - list.add(6); - - list.set(0, 1); + list.add(4); + + assertEquals(2, (int) list.set(0, 3)); + assertEquals(3, (int) list.get(0)); + + assertEquals(4, (int) list.set(1, 0)); + assertEquals(0, (int) list.get(1)); + + try { + list.set(-1, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.set(2, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAdd() { + assertEquals(0, list.size()); + + assertTrue(list.add(2)); + assertEquals(asList(2), list); + + assertTrue(list.add(3)); + list.add(0, 4); + assertEquals(asList(4, 2, 3), list); + + list.add(0, 1); + list.add(0, 0); + // Force a resize by getting up to 11 elements. + for (int i = 0; i < 6; i++) { + list.add(Integer.valueOf(5 + i)); + } + assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list); + + try { + list.add(-1, 5); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.add(4, 5); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAddAll() { + assertEquals(0, list.size()); + + assertTrue(list.addAll(Collections.singleton(1))); + assertEquals(1, list.size()); assertEquals(1, (int) list.get(0)); - list.set(1, 2); - assertEquals(2, (int) list.get(1)); + + assertTrue(list.addAll(asList(2, 3, 4, 5, 6))); + assertEquals(asList(1, 2, 3, 4, 5, 6), list); + + assertTrue(list.addAll(TERTIARY_LIST)); + assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list); + + assertFalse(list.addAll(Collections.<Integer>emptyList())); + assertFalse(list.addAll(IntArrayList.emptyList())); + } + + public void testSize() { + assertEquals(0, ProtobufArrayList.emptyList().size()); + assertEquals(1, UNARY_LIST.size()); + assertEquals(3, TERTIARY_LIST.size()); + + list.add(3); + list.add(4); + list.add(6); + list.add(8); + assertEquals(4, list.size()); + + list.remove(0); + assertEquals(3, list.size()); + + list.add(17); + assertEquals(4, list.size()); } private void assertImmutable(List<Integer> list) { if (list.contains(1)) { throw new RuntimeException("Cannot test the immutability of lists that contain 1."); } - + try { list.add(1); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.add(0, 1); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(Collections.<Integer>emptyList()); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(Collections.singletonList(1)); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(new ProtobufArrayList<Integer>()); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(UNARY_LIST); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(0, Collections.singleton(1)); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(0, UNARY_LIST); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.addAll(0, Collections.<Integer>emptyList()); fail(); } catch (UnsupportedOperationException e) { // expected - } + } try { list.clear(); @@ -219,56 +325,56 @@ public class ProtobufArrayListTest extends TestCase { } catch (UnsupportedOperationException e) { // expected } - + try { list.remove(new Object()); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.removeAll(Collections.emptyList()); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.removeAll(Collections.singleton(1)); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.removeAll(UNARY_LIST); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.retainAll(Collections.emptyList()); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.retainAll(Collections.singleton(1)); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.retainAll(UNARY_LIST); fail(); } catch (UnsupportedOperationException e) { // expected } - + try { list.set(0, 0); fail(); @@ -276,7 +382,7 @@ public class ProtobufArrayListTest extends TestCase { // expected } } - + private static ProtobufArrayList<Integer> newImmutableProtoArrayList(int... elements) { ProtobufArrayList<Integer> list = new ProtobufArrayList<Integer>(); for (int element : elements) { diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java index b4bc3a3d..8ec22d3f 100644 --- a/java/core/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java @@ -130,8 +130,6 @@ import static protobuf_unittest.UnittestProto.defaultFixed64Extension; import static protobuf_unittest.UnittestProto.defaultFloatExtension; import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension; import static protobuf_unittest.UnittestProto.defaultImportEnumExtension; -// The static imports are to avoid 100+ char lines. The following is roughly equivalent to -// import static protobuf_unittest.UnittestProto.*; import static protobuf_unittest.UnittestProto.defaultInt32Extension; import static protobuf_unittest.UnittestProto.defaultInt64Extension; import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension; @@ -263,12 +261,14 @@ public final class TestUtil { return ByteString.copyFrom(str.getBytes(Internal.UTF_8)); } + // BEGIN FULL-RUNTIME /** * Dirties the message by resetting the momoized serialized size. */ public static void resetMemoizedSize(AbstractMessage message) { message.memoizedSize = -1; } + // END FULL-RUNTIME /** * Get a {@code TestAllTypes} with all fields set as they would be by @@ -1201,17 +1201,29 @@ public final class TestUtil { * Get an unmodifiable {@link ExtensionRegistry} containing all the * extensions of {@code TestAllExtensions}. */ - public static ExtensionRegistry getExtensionRegistry() { + public static ExtensionRegistryLite getExtensionRegistry() { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registerAllExtensions(registry); + return registry.getUnmodifiable(); + } + + // BEGIN FULL-RUNTIME + /** + * Get an unmodifiable {@link ExtensionRegistry} containing all the + * extensions of {@code TestAllExtensions}. + */ + public static ExtensionRegistry getFullExtensionRegistry() { ExtensionRegistry registry = ExtensionRegistry.newInstance(); registerAllExtensions(registry); return registry.getUnmodifiable(); } + // END FULL-RUNTIME /** * Register all of {@code TestAllExtensions}'s extensions with the * given {@link ExtensionRegistry}. */ - public static void registerAllExtensions(ExtensionRegistry registry) { + public static void registerAllExtensions(ExtensionRegistryLite registry) { UnittestProto.registerAllExtensions(registry); TestUtilLite.registerAllExtensionsLite(registry); } @@ -2634,6 +2646,7 @@ public final class TestUtil { } // ================================================================= + // BEGIN FULL-RUNTIME /** * Performs the same things that the methods of {@code TestUtil} do, but @@ -3819,6 +3832,16 @@ public final class TestUtil { "Couldn't read file: " + fullPath.getPath(), e); } } + // END FULL-RUNTIME + + private static ByteString readBytesFromResource(String name) { + try { + return ByteString.copyFrom( + com.google.common.io.ByteStreams.toByteArray(TestUtil.class.getResourceAsStream(name))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } /** * Get the bytes of the "golden message". This is a serialized TestAllTypes @@ -3829,7 +3852,7 @@ public final class TestUtil { */ public static ByteString getGoldenMessage() { if (goldenMessage == null) { - goldenMessage = readBytesFromFile("golden_message_oneof_implemented"); + goldenMessage = readBytesFromResource("/google/protobuf/testdata/golden_message_oneof_implemented"); } return goldenMessage; } @@ -3846,12 +3869,13 @@ public final class TestUtil { public static ByteString getGoldenPackedFieldsMessage() { if (goldenPackedFieldsMessage == null) { goldenPackedFieldsMessage = - readBytesFromFile("golden_packed_fields_message"); + readBytesFromResource("/google/protobuf/testdata/golden_packed_fields_message"); } return goldenPackedFieldsMessage; } private static ByteString goldenPackedFieldsMessage = null; + // BEGIN FULL-RUNTIME /** * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing. * @@ -3871,4 +3895,5 @@ public final class TestUtil { return invalidations; } } + // END FULL-RUNTIME } diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java index 720061d2..24d5589f 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java @@ -382,17 +382,14 @@ public class TextFormatTest extends TestCase { public void testMergeExtensions() throws Exception { TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); - TextFormat.merge(allExtensionsSetText, - TestUtil.getExtensionRegistry(), - builder); + TextFormat.merge(allExtensionsSetText, TestUtil.getFullExtensionRegistry(), builder); TestUtil.assertAllExtensionsSet(builder.build()); } public void testParseExtensions() throws Exception { TestUtil.assertAllExtensionsSet( - TextFormat.parse(allExtensionsSetText, - TestUtil.getExtensionRegistry(), - TestAllExtensions.class)); + TextFormat.parse( + allExtensionsSetText, TestUtil.getFullExtensionRegistry(), TestAllExtensions.class)); } public void testMergeAndParseCompatibility() throws Exception { @@ -523,7 +520,7 @@ public class TextFormatTest extends TestCase { // Test merge(). TestAllTypes.Builder builder = TestAllTypes.newBuilder(); try { - TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder); + TextFormat.merge(text, TestUtil.getFullExtensionRegistry(), builder); fail("Expected parse exception."); } catch (TextFormat.ParseException e) { assertEquals(error, e.getMessage()); @@ -531,8 +528,7 @@ public class TextFormatTest extends TestCase { // Test parse(). try { - TextFormat.parse( - text, TestUtil.getExtensionRegistry(), TestAllTypes.class); + TextFormat.parse(text, TestUtil.getFullExtensionRegistry(), TestAllTypes.class); fail("Expected parse exception."); } catch (TextFormat.ParseException e) { assertEquals(error, e.getMessage()); @@ -544,8 +540,7 @@ public class TextFormatTest extends TestCase { String text) { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); try { - parserWithOverwriteForbidden.merge( - text, TestUtil.getExtensionRegistry(), builder); + parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder); fail("Expected parse exception."); } catch (TextFormat.ParseException e) { assertEquals(error, e.getMessage()); @@ -555,8 +550,7 @@ public class TextFormatTest extends TestCase { private TestAllTypes assertParseSuccessWithOverwriteForbidden( String text) throws TextFormat.ParseException { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); - parserWithOverwriteForbidden.merge( - text, TestUtil.getExtensionRegistry(), builder); + parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder); return builder.build(); } @@ -1118,8 +1112,7 @@ public class TextFormatTest extends TestCase { String input = "foo_string: \"stringvalue\" foo_int: 123"; TestOneof2.Builder builder = TestOneof2.newBuilder(); try { - parserWithOverwriteForbidden.merge( - input, TestUtil.getExtensionRegistry(), builder); + parserWithOverwriteForbidden.merge(input, TestUtil.getFullExtensionRegistry(), builder); fail("Expected parse exception."); } catch (TextFormat.ParseException e) { assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\"" @@ -1131,7 +1124,7 @@ public class TextFormatTest extends TestCase { public void testOneofOverwriteAllowed() throws Exception { String input = "foo_string: \"stringvalue\" foo_int: 123"; TestOneof2.Builder builder = TestOneof2.newBuilder(); - defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder); + defaultParser.merge(input, TestUtil.getFullExtensionRegistry(), builder); // Only the last value sticks. TestOneof2 oneof = builder.build(); assertFalse(oneof.hasFooString()); diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java index 03c33ecf..425b56da 100644 --- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java @@ -132,7 +132,7 @@ public class WireFormatTest extends TestCase { TestAllTypes message = TestUtil.getAllSet(); ByteString rawBytes = message.toByteString(); - ExtensionRegistry registry = TestUtil.getExtensionRegistry(); + ExtensionRegistryLite registry = TestUtil.getExtensionRegistry(); TestAllExtensions message2 = TestAllExtensions.parseFrom(rawBytes, registry); @@ -145,7 +145,7 @@ public class WireFormatTest extends TestCase { TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); ByteString rawBytes = message.toByteString(); - ExtensionRegistry registry = TestUtil.getExtensionRegistry(); + ExtensionRegistryLite registry = TestUtil.getExtensionRegistry(); TestPackedExtensions message2 = TestPackedExtensions.parseFrom(rawBytes, registry); diff --git a/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto b/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto index 5580f72d..736a344f 100644 --- a/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto +++ b/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto @@ -36,8 +36,6 @@ syntax = "proto2"; package protobuf_unittest; -option optimize_for = LITE_RUNTIME; - message LazyMessageLite { optional int32 num = 1; optional int32 num_with_default = 2 [default = 421]; diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto index b18b0d79..20fa03b9 100644 --- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto +++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto @@ -34,7 +34,6 @@ syntax = "proto2"; package protobuf_unittest.lite_equals_and_hash; -option optimize_for = LITE_RUNTIME; message TestOneofEquals { oneof oneof_field { diff --git a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto index c04f5d57..bc2105e5 100644 --- a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto +++ b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto @@ -30,10 +30,9 @@ syntax = "proto3"; -package map_lite_test; +package map_test; -option optimize_for = LITE_RUNTIME; -option java_package = "map_lite_test"; +option java_package = "map_test"; option java_outer_classname = "MapTestProto"; message TestMap { diff --git a/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto index a95c38b2..6793d6b7 100644 --- a/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto +++ b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto @@ -38,7 +38,6 @@ syntax = "proto2"; package protobuf_unittest; -option optimize_for = LITE_RUNTIME; import "com/google/protobuf/non_nested_extension_lite.proto"; diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto index 37c369ed..e42faaa8 100644 --- a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto +++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto @@ -36,7 +36,6 @@ syntax = "proto2"; package protobuf_unittest; -option optimize_for = LITE_RUNTIME; message MessageLiteToBeExtended { extensions 1 to max; diff --git a/java/util/src/main/java/com/google/protobuf/util/Durations.java b/java/util/src/main/java/com/google/protobuf/util/Durations.java index fb7f4343..17b41cbb 100644 --- a/java/util/src/main/java/com/google/protobuf/util/Durations.java +++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java @@ -61,6 +61,9 @@ public final class Durations { public static final Duration MAX_VALUE = Duration.newBuilder().setSeconds(DURATION_SECONDS_MAX).setNanos(999999999).build(); + /** A constant holding the duration of zero. */ + public static final Duration ZERO = Duration.newBuilder().setSeconds(0L).setNanos(0).build(); + private Durations() {} private static final Comparator<Duration> COMPARATOR = diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java index 4a13fb1d..7b4facc1 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java @@ -249,12 +249,9 @@ final class FieldMaskTree { continue; } String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey(); - merge( - entry.getValue(), - childPath, - (Message) source.getField(field), - destination.getFieldBuilder(field), - options); + Message.Builder childBuilder = ((Message) destination.getField(field)).toBuilder(); + merge(entry.getValue(), childPath, (Message) source.getField(field), childBuilder, options); + destination.setField(field, childBuilder.buildPartial()); continue; } if (field.isRepeated()) { @@ -275,7 +272,12 @@ final class FieldMaskTree { } } else { if (source.hasField(field)) { - destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field)); + destination.setField( + field, + ((Message) destination.getField(field)) + .toBuilder() + .mergeFrom((Message) source.getField(field)) + .build()); } } } else { diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java index b2f849c4..aedc5eac 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java @@ -235,7 +235,7 @@ public class FieldMaskUtil { /** * Converts a FieldMask to its canonical form. In the canonical form of a * FieldMask, all field paths are sorted alphabetically and redundant field - * paths are moved. + * paths are removed. */ public static FieldMask normalize(FieldMask mask) { return new FieldMaskTree(mask).toFieldMask(); diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java index 7f69ee68..973f1517 100644 --- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java +++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java @@ -610,7 +610,7 @@ public class JsonFormat { private final CharSequence blankOrNewLine; private static class GsonHolder { - private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create(); + private static final Gson DEFAULT_GSON = new GsonBuilder().create(); } PrinterImpl( diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java index 853b6151..a0d317d4 100644 --- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java @@ -30,9 +30,14 @@ package com.google.protobuf.util; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.Message; +import com.google.protobuf.UninitializedMessageException; import protobuf_unittest.UnittestProto.NestedTestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; +import protobuf_unittest.UnittestProto.TestRequired; +import protobuf_unittest.UnittestProto.TestRequiredMessage; import junit.framework.TestCase; public class FieldMaskTreeTest extends TestCase { @@ -90,8 +95,68 @@ public class FieldMaskTreeTest extends TestCase { tree.intersectFieldPath("bar", result); assertEquals("bar.baz,bar.quz,foo", result.toString()); } - + public void testMerge() throws Exception { + testMergeImpl(true); + testMergeImpl(false); + testMergeRequire(false); + testMergeRequire(true); + } + + private void merge( + FieldMaskTree tree, + Message source, + Message.Builder builder, + FieldMaskUtil.MergeOptions options, + boolean useDynamicMessage) + throws Exception { + if (useDynamicMessage) { + Message.Builder newBuilder = + DynamicMessage.newBuilder(source.getDescriptorForType()) + .mergeFrom(builder.buildPartial().toByteArray()); + tree.merge( + DynamicMessage.newBuilder(source.getDescriptorForType()) + .mergeFrom(source.toByteArray()) + .build(), + newBuilder, + options); + builder.clear(); + builder.mergeFrom(newBuilder.buildPartial()); + } else { + tree.merge(source, builder, options); + } + } + + private void testMergeRequire(boolean useDynamicMessage) throws Exception { + TestRequired value = TestRequired.newBuilder().setA(4321).setB(8765).setC(233333).build(); + TestRequiredMessage source = TestRequiredMessage.newBuilder().setRequiredMessage(value).build(); + + FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions(); + TestRequiredMessage.Builder builder = TestRequiredMessage.newBuilder(); + merge( + new FieldMaskTree().addFieldPath("required_message.a"), + source, + builder, + options, + useDynamicMessage); + assertTrue(builder.hasRequiredMessage()); + assertTrue(builder.getRequiredMessage().hasA()); + assertFalse(builder.getRequiredMessage().hasB()); + assertFalse(builder.getRequiredMessage().hasC()); + merge( + new FieldMaskTree().addFieldPath("required_message.b").addFieldPath("required_message.c"), + source, + builder, + options, + useDynamicMessage); + try { + assertEquals(builder.build(), source); + } catch (UninitializedMessageException e) { + throw new AssertionError("required field isn't set", e); + } + } + + private void testMergeImpl(boolean useDynamicMessage) throws Exception { TestAllTypes value = TestAllTypes.newBuilder() .setOptionalInt32(1234) @@ -119,45 +184,51 @@ public class FieldMaskTreeTest extends TestCase { // Test merging each individual field. NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload.optional_int32").merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.optional_int32"), + source, builder, options, useDynamicMessage); NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder(); expected.getPayloadBuilder().setOptionalInt32(1234); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("payload.optional_nested_message") - .merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.optional_nested_message"), + source, builder, options, useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678)); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"), + source, builder, options, useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected.getPayloadBuilder().addRepeatedInt32(4321); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("payload.repeated_nested_message") - .merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.repeated_nested_message"), + source, builder, options, useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765)); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("child.payload.optional_int32") - .merge(source, builder, options); + merge( + new FieldMaskTree().addFieldPath("child.payload.optional_int32"), + source, + builder, + options, + useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("child.payload.optional_nested_message") - .merge(source, builder, options); + merge( + new FieldMaskTree().addFieldPath("child.payload.optional_nested_message"), + source, + builder, + options, + useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected .getChildBuilder() @@ -166,17 +237,15 @@ public class FieldMaskTreeTest extends TestCase { assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("child.payload.repeated_int32") - .merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("child.payload.repeated_int32"), + source, builder, options, useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("child.payload.repeated_nested_message") - .merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("child.payload.repeated_nested_message"), + source, builder, options, useDynamicMessage); expected = NestedTestAllTypes.newBuilder(); expected .getChildBuilder() @@ -186,23 +255,23 @@ public class FieldMaskTreeTest extends TestCase { // Test merging all fields. builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("child") - .addFieldPath("payload") - .merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("child").addFieldPath("payload"), + source, builder, options, useDynamicMessage); assertEquals(source, builder.build()); // Test repeated options. builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().addRepeatedInt32(1000); - new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"), + source, builder, options, useDynamicMessage); // Default behavior is to append repeated fields. assertEquals(2, builder.getPayload().getRepeatedInt32Count()); assertEquals(1000, builder.getPayload().getRepeatedInt32(0)); assertEquals(4321, builder.getPayload().getRepeatedInt32(1)); // Change to replace repeated fields. options.setReplaceRepeatedFields(true); - new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"), + source, builder, options, useDynamicMessage); assertEquals(1, builder.getPayload().getRepeatedInt32Count()); assertEquals(4321, builder.getPayload().getRepeatedInt32(0)); @@ -210,7 +279,8 @@ public class FieldMaskTreeTest extends TestCase { builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().setOptionalInt32(1000); builder.getPayloadBuilder().setOptionalUint32(2000); - new FieldMaskTree().addFieldPath("payload").merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload"), + source, builder, options, useDynamicMessage); // Default behavior is to merge message fields. assertEquals(1234, builder.getPayload().getOptionalInt32()); assertEquals(2000, builder.getPayload().getOptionalUint32()); @@ -218,14 +288,14 @@ public class FieldMaskTreeTest extends TestCase { // Test merging unset message fields. NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build(); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options); + merge(new FieldMaskTree().addFieldPath("payload"), + clearedSource, builder, options, useDynamicMessage); assertEquals(false, builder.hasPayload()); // Skip a message field if they are unset in both source and target. builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree() - .addFieldPath("payload.optional_int32") - .merge(clearedSource, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.optional_int32"), + clearedSource, builder, options, useDynamicMessage); assertEquals(false, builder.hasPayload()); // Change to replace message fields. @@ -233,7 +303,8 @@ public class FieldMaskTreeTest extends TestCase { builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().setOptionalInt32(1000); builder.getPayloadBuilder().setOptionalUint32(2000); - new FieldMaskTree().addFieldPath("payload").merge(source, builder, options); + merge(new FieldMaskTree().addFieldPath("payload"), + source, builder, options, useDynamicMessage); assertEquals(1234, builder.getPayload().getOptionalInt32()); assertEquals(0, builder.getPayload().getOptionalUint32()); @@ -241,7 +312,8 @@ public class FieldMaskTreeTest extends TestCase { builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().setOptionalInt32(1000); builder.getPayloadBuilder().setOptionalUint32(2000); - new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options); + merge(new FieldMaskTree().addFieldPath("payload"), + clearedSource, builder, options, useDynamicMessage); assertEquals(false, builder.hasPayload()); // Test merging unset primitive fields. @@ -249,18 +321,16 @@ public class FieldMaskTreeTest extends TestCase { builder.getPayloadBuilder().clearOptionalInt32(); NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build(); builder = source.toBuilder(); - new FieldMaskTree() - .addFieldPath("payload.optional_int32") - .merge(sourceWithPayloadInt32Unset, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.optional_int32"), + sourceWithPayloadInt32Unset, builder, options, useDynamicMessage); assertEquals(true, builder.getPayload().hasOptionalInt32()); assertEquals(0, builder.getPayload().getOptionalInt32()); // Change to clear unset primitive fields. options.setReplacePrimitiveFields(true); builder = source.toBuilder(); - new FieldMaskTree() - .addFieldPath("payload.optional_int32") - .merge(sourceWithPayloadInt32Unset, builder, options); + merge(new FieldMaskTree().addFieldPath("payload.optional_int32"), + sourceWithPayloadInt32Unset, builder, options, useDynamicMessage); assertEquals(true, builder.hasPayload()); assertEquals(false, builder.getPayload().hasOptionalInt32()); } diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java index 6ef08508..d9bbe587 100644 --- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java @@ -70,7 +70,6 @@ import java.io.StringReader; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Set; @@ -1188,10 +1187,14 @@ public class JsonFormatTest extends TestCase { assertRoundTripEquals(message); } - public void testDefaultGsonDoesNotHtmlEscape() throws Exception { - TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build(); - assertEquals( - "{\n" + " \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message)); + // Regression test for b/73832901. Make sure html tags are escaped. + public void testHtmlEscape() throws Exception { + TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("</script>").build(); + assertEquals("{\n \"optionalString\": \"\\u003c/script\\u003e\"\n}", toJsonString(message)); + + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + JsonFormat.parser().merge(toJsonString(message), builder); + assertEquals(message.getOptionalString(), builder.getOptionalString()); } public void testIncludingDefaultValueFields() throws Exception { |