Merge from Google internal for 3.4 release

pull/3393/head
Jisi Liu 8 years ago
parent 9053033a50
commit 09354db143
  1. 2
      Makefile.am
  2. 3
      cmake/extract_includes.bat.in
  3. 1
      cmake/libprotoc.cmake
  4. 1
      cmake/tests.cmake
  5. 7
      conformance/conformance_test.cc
  6. 2
      conformance/failure_list_cpp.txt
  7. 601
      conformance/failure_list_python.txt
  8. 589
      conformance/failure_list_python_cpp.txt
  9. 35
      generate_descriptor_proto.sh
  10. 3
      java/core/generate-test-sources-build.xml
  11. 27
      java/core/src/main/java/com/google/protobuf/AbstractMessage.java
  12. 84
      java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
  13. 299
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  14. 82
      java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
  15. 71
      java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
  16. 10
      java/core/src/main/java/com/google/protobuf/DynamicMessage.java
  17. 7
      java/core/src/main/java/com/google/protobuf/Extension.java
  18. 5
      java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
  19. 78
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  20. 93
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  21. 5
      java/core/src/main/java/com/google/protobuf/Internal.java
  22. 4
      java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  23. 24
      java/core/src/main/java/com/google/protobuf/MessageReflection.java
  24. 211
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  25. 2
      java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
  26. 173
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  27. 33
      java/core/src/main/java/com/google/protobuf/Utf8.java
  28. 6
      java/core/src/main/java/com/google/protobuf/WireFormat.java
  29. 123
      java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
  30. 157
      java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
  31. 12
      java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
  32. 78
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  33. 214
      java/core/src/test/java/com/google/protobuf/LiteTest.java
  34. 8
      java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  35. 8
      java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
  36. 8
      java/core/src/test/java/com/google/protobuf/MapTest.java
  37. 12
      java/core/src/test/java/com/google/protobuf/MessageTest.java
  38. 26
      java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
  39. 83
      java/core/src/test/java/com/google/protobuf/TestBadIdentifiersLite.java
  40. 28
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  41. 14
      java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
  42. 17
      java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
  43. 11
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  44. 9
      java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
  45. 6
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  46. 11
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java
  47. 4
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  48. 8
      js/binary/encoder.js
  49. 4
      js/binary/utils.js
  50. 10
      js/binary/writer.js
  51. 355
      js/compatibility_tests/v3.1.0/binary/arith_test.js
  52. 334
      js/compatibility_tests/v3.1.0/binary/decoder_test.js
  53. 628
      js/compatibility_tests/v3.1.0/binary/proto_test.js
  54. 922
      js/compatibility_tests/v3.1.0/binary/reader_test.js
  55. 668
      js/compatibility_tests/v3.1.0/binary/utils_test.js
  56. 122
      js/compatibility_tests/v3.1.0/binary/writer_test.js
  57. 40
      js/compatibility_tests/v3.1.0/commonjs/test6/test6.proto
  58. 42
      js/compatibility_tests/v3.1.0/commonjs/test7/test7.proto
  59. 51
      js/compatibility_tests/v3.1.0/data.proto
  60. 105
      js/compatibility_tests/v3.1.0/debug_test.js
  61. 301
      js/compatibility_tests/v3.1.0/maps_test.js
  62. 1037
      js/compatibility_tests/v3.1.0/message_test.js
  63. 329
      js/compatibility_tests/v3.1.0/proto3_test.js
  64. 89
      js/compatibility_tests/v3.1.0/proto3_test.proto
  65. 262
      js/compatibility_tests/v3.1.0/test.proto
  66. 54
      js/compatibility_tests/v3.1.0/test2.proto
  67. 53
      js/compatibility_tests/v3.1.0/test3.proto
  68. 42
      js/compatibility_tests/v3.1.0/test4.proto
  69. 44
      js/compatibility_tests/v3.1.0/test5.proto
  70. 212
      js/compatibility_tests/v3.1.0/testbinary.proto
  71. 34
      js/compatibility_tests/v3.1.0/testempty.proto
  72. 86
      js/message.js
  73. 18
      js/message_test.js
  74. 1
      js/proto3_test.proto
  75. 8
      js/test.proto
  76. 3
      python/compatibility_tests/v2.5.0/tests/google/protobuf/internal/text_format_test.py
  77. 9
      python/google/protobuf/descriptor.py
  78. 3
      python/google/protobuf/descriptor_database.py
  79. 21
      python/google/protobuf/descriptor_pool.py
  80. 26
      python/google/protobuf/internal/api_implementation.py
  81. 46
      python/google/protobuf/internal/descriptor_pool_test.py
  82. 6
      python/google/protobuf/internal/descriptor_test.py
  83. 107
      python/google/protobuf/internal/encoder.py
  84. 5
      python/google/protobuf/internal/factory_test2.proto
  85. 103
      python/google/protobuf/internal/json_format_test.py
  86. 92
      python/google/protobuf/internal/message_test.py
  87. 1
      python/google/protobuf/internal/more_extensions_dynamic.proto
  88. 18
      python/google/protobuf/internal/python_message.py
  89. 151
      python/google/protobuf/internal/text_format_test.py
  90. 4
      python/google/protobuf/internal/well_known_types.py
  91. 2
      python/google/protobuf/internal/well_known_types_test.py
  92. 54
      python/google/protobuf/json_format.py
  93. 16
      python/google/protobuf/message.py
  94. 14
      python/google/protobuf/message_factory.py
  95. 10
      python/google/protobuf/pyext/descriptor.cc
  96. 24
      python/google/protobuf/pyext/map_container.cc
  97. 62
      python/google/protobuf/pyext/message.cc
  98. 11
      python/google/protobuf/pyext/message_factory.cc
  99. 22
      python/google/protobuf/pyext/repeated_composite_container.cc
  100. 14
      python/google/protobuf/pyext/repeated_scalar_container.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -713,7 +713,6 @@ python_EXTRA_DIST= \
python/google/protobuf/internal/packed_field_test.proto \ python/google/protobuf/internal/packed_field_test.proto \
python/google/protobuf/internal/proto_builder_test.py \ python/google/protobuf/internal/proto_builder_test.py \
python/google/protobuf/internal/python_message.py \ python/google/protobuf/internal/python_message.py \
python/google/protobuf/internal/python_protobuf.cc \
python/google/protobuf/internal/reflection_test.py \ python/google/protobuf/internal/reflection_test.py \
python/google/protobuf/internal/service_reflection_test.py \ python/google/protobuf/internal/service_reflection_test.py \
python/google/protobuf/internal/symbol_database_test.py \ python/google/protobuf/internal/symbol_database_test.py \
@ -762,7 +761,6 @@ python_EXTRA_DIST= \
python/google/protobuf/pyext/repeated_scalar_container.h \ python/google/protobuf/pyext/repeated_scalar_container.h \
python/google/protobuf/pyext/safe_numerics.h \ python/google/protobuf/pyext/safe_numerics.h \
python/google/protobuf/pyext/scoped_pyobject_ptr.h \ python/google/protobuf/pyext/scoped_pyobject_ptr.h \
python/google/protobuf/python_protobuf.h \
python/google/protobuf/reflection.py \ python/google/protobuf/reflection.py \
python/google/protobuf/service.py \ python/google/protobuf/service.py \
python/google/protobuf/service_reflection.py \ python/google/protobuf/service_reflection.py \

@ -36,7 +36,6 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\parser.h" in
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\php\php_generator.h" include\google\protobuf\compiler\php\php_generator.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\php\php_generator.h" include\google\protobuf\compiler\php\php_generator.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\profile.pb.h" include\google\protobuf\compiler\profile.pb.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_generator.h" include\google\protobuf\compiler\python\python_generator.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_generator.h" include\google\protobuf\compiler\python\python_generator.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h
@ -50,6 +49,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_mask.pb.h" incl
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_reflection.h" include\google\protobuf\generated_enum_reflection.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_reflection.h" include\google\protobuf\generated_enum_reflection.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_util.h" include\google\protobuf\generated_enum_util.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_util.h" include\google\protobuf\generated_enum_util.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_reflection.h" include\google\protobuf\generated_message_reflection.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_reflection.h" include\google\protobuf\generated_message_reflection.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_table_driven.h" include\google\protobuf\generated_message_table_driven.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h
@ -70,6 +70,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_type_handler.h" i
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message.h" include\google\protobuf\message.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message.h" include\google\protobuf\message.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message_lite.h" include\google\protobuf\message_lite.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message_lite.h" include\google\protobuf\message_lite.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata.h" include\google\protobuf\metadata.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata.h" include\google\protobuf\metadata.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata_lite.h" include\google\protobuf\metadata_lite.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h

@ -88,7 +88,6 @@ set(libprotoc_files
${protobuf_source_dir}/src/google/protobuf/compiler/php/php_generator.cc ${protobuf_source_dir}/src/google/protobuf/compiler/php/php_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/plugin.cc ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.cc
${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
${protobuf_source_dir}/src/google/protobuf/compiler/profile.pb.cc
${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc

@ -123,6 +123,7 @@ set(tests_files
${protobuf_source_dir}/src/google/protobuf/arenastring_unittest.cc ${protobuf_source_dir}/src/google/protobuf/arenastring_unittest.cc
${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface_unittest.cc
${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc
${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_unittest.cc
${protobuf_source_dir}/src/google/protobuf/compiler/cpp/metadata_test.cc ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/metadata_test.cc

@ -1516,9 +1516,10 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
"BytesField", REQUIRED, "BytesField", REQUIRED,
R"({"optionalBytes": "AQI="})", R"({"optionalBytes": "AQI="})",
R"(optional_bytes: "\x01\x02")"); R"(optional_bytes: "\x01\x02")");
ExpectParseFailureForJson( RunValidJsonTest(
"BytesFieldInvalidBase64Characters", REQUIRED, "BytesFieldBase64Url", RECOMMENDED,
R"({"optionalBytes": "-_=="})"); R"({"optionalBytes": "-_"})",
R"(optional_bytes: "\xfb")");
// Message fields. // Message fields.
RunValidJsonTest( RunValidJsonTest(

@ -12,6 +12,8 @@ Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.FieldMaskTooManyUnderscore.JsonOutput Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.JsonInput.BoolFieldDoubleQuotedFalse Recommended.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.JsonInput.BoolFieldDoubleQuotedTrue Recommended.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.JsonInput.BytesFieldBase64Url.ProtobufOutput
Recommended.JsonInput.FieldMaskInvalidCharacter Recommended.JsonInput.FieldMaskInvalidCharacter
Recommended.JsonInput.FieldNameDuplicate Recommended.JsonInput.FieldNameDuplicate
Recommended.JsonInput.FieldNameDuplicateDifferentCasing1 Recommended.JsonInput.FieldNameDuplicateDifferentCasing1

@ -1,17 +1,616 @@
Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.JsonInput.BoolFieldAllCapitalFalse
Recommended.JsonInput.BoolFieldAllCapitalTrue
Recommended.JsonInput.BoolFieldCamelCaseFalse
Recommended.JsonInput.BoolFieldCamelCaseTrue
Recommended.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.JsonInput.BoolFieldIntegerOne
Recommended.JsonInput.BoolFieldIntegerZero
Recommended.JsonInput.BoolMapFieldKeyNotQuoted
Recommended.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.JsonInput.BytesFieldBase64Url.ProtobufOutput
Recommended.JsonInput.DoubleFieldInfinityNotQuoted Recommended.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.JsonInput.DoubleFieldNanNotQuoted Recommended.JsonInput.DoubleFieldNanNotQuoted
Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.JsonInput.DurationHas3FractionalDigits.Validator
Recommended.JsonInput.DurationHas6FractionalDigits.Validator
Recommended.JsonInput.DurationHas9FractionalDigits.Validator
Recommended.JsonInput.DurationHasZeroFractionalDigit.Validator
Recommended.JsonInput.FieldMaskInvalidCharacter
Recommended.JsonInput.FieldNameDuplicate
Recommended.JsonInput.FieldNameDuplicateDifferentCasing1
Recommended.JsonInput.FieldNameDuplicateDifferentCasing2
Recommended.JsonInput.FieldNameNotQuoted
Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
Recommended.JsonInput.FloatFieldInfinityNotQuoted Recommended.JsonInput.FloatFieldInfinityNotQuoted
Recommended.JsonInput.FloatFieldNanNotQuoted Recommended.JsonInput.FloatFieldNanNotQuoted
Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
Required.JsonInput.BytesFieldInvalidBase64Characters Recommended.JsonInput.Int32MapFieldKeyNotQuoted
Recommended.JsonInput.Int64FieldBeString.Validator
Recommended.JsonInput.Int64MapFieldKeyNotQuoted
Recommended.JsonInput.JsonWithComments
Recommended.JsonInput.MapFieldKeyIsNull
Recommended.JsonInput.MapFieldValueIsNull
Recommended.JsonInput.MissingCommaMultiline
Recommended.JsonInput.MissingCommaOneLine
Recommended.JsonInput.MultilineNoSpaces.JsonOutput
Recommended.JsonInput.MultilineNoSpaces.ProtobufOutput
Recommended.JsonInput.MultilineWithSpaces.JsonOutput
Recommended.JsonInput.MultilineWithSpaces.ProtobufOutput
Recommended.JsonInput.OneLineNoSpaces.JsonOutput
Recommended.JsonInput.OneLineNoSpaces.ProtobufOutput
Recommended.JsonInput.OneLineWithSpaces.JsonOutput
Recommended.JsonInput.OneLineWithSpaces.ProtobufOutput
Recommended.JsonInput.OneofZeroBool.JsonOutput
Recommended.JsonInput.OneofZeroBool.ProtobufOutput
Recommended.JsonInput.OneofZeroBytes.JsonOutput
Recommended.JsonInput.OneofZeroBytes.ProtobufOutput
Recommended.JsonInput.OneofZeroDouble.JsonOutput
Recommended.JsonInput.OneofZeroDouble.ProtobufOutput
Recommended.JsonInput.OneofZeroEnum.JsonOutput
Recommended.JsonInput.OneofZeroEnum.ProtobufOutput
Recommended.JsonInput.OneofZeroFloat.JsonOutput
Recommended.JsonInput.OneofZeroFloat.ProtobufOutput
Recommended.JsonInput.OneofZeroMessage.JsonOutput
Recommended.JsonInput.OneofZeroMessage.ProtobufOutput
Recommended.JsonInput.OneofZeroString.JsonOutput
Recommended.JsonInput.OneofZeroString.ProtobufOutput
Recommended.JsonInput.OneofZeroUint32.JsonOutput
Recommended.JsonInput.OneofZeroUint32.ProtobufOutput
Recommended.JsonInput.OneofZeroUint64.JsonOutput
Recommended.JsonInput.OneofZeroUint64.ProtobufOutput
Recommended.JsonInput.RepeatedFieldMessageElementIsNull
Recommended.JsonInput.RepeatedFieldPrimitiveElementIsNull
Recommended.JsonInput.RepeatedFieldTrailingComma
Recommended.JsonInput.RepeatedFieldTrailingCommaWithNewlines
Recommended.JsonInput.RepeatedFieldTrailingCommaWithSpace
Recommended.JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
Recommended.JsonInput.StringEndsWithEscapeChar
Recommended.JsonInput.StringFieldInvalidEscape
Recommended.JsonInput.StringFieldSingleQuoteBoth
Recommended.JsonInput.StringFieldSingleQuoteKey
Recommended.JsonInput.StringFieldSingleQuoteValue
Recommended.JsonInput.StringFieldSurrogateInWrongOrder
Recommended.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.JsonInput.StringFieldUnterminatedEscape
Recommended.JsonInput.StringFieldUppercaseEscapeLetter
Recommended.JsonInput.TimestampHas3FractionalDigits.Validator
Recommended.JsonInput.TimestampHas6FractionalDigits.Validator
Recommended.JsonInput.TimestampHas9FractionalDigits.Validator
Recommended.JsonInput.TimestampHasZeroFractionalDigit.Validator
Recommended.JsonInput.TimestampZeroNormalized.Validator
Recommended.JsonInput.TrailingCommaInAnObject
Recommended.JsonInput.TrailingCommaInAnObjectWithNewlines
Recommended.JsonInput.TrailingCommaInAnObjectWithSpace
Recommended.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
Recommended.JsonInput.Uint32MapFieldKeyNotQuoted
Recommended.JsonInput.Uint64FieldBeString.Validator
Recommended.JsonInput.Uint64MapFieldKeyNotQuoted
Recommended.ProtobufInput.OneofZeroBool.JsonOutput
Recommended.ProtobufInput.OneofZeroBool.ProtobufOutput
Recommended.ProtobufInput.OneofZeroBytes.JsonOutput
Recommended.ProtobufInput.OneofZeroBytes.ProtobufOutput
Recommended.ProtobufInput.OneofZeroDouble.JsonOutput
Recommended.ProtobufInput.OneofZeroDouble.ProtobufOutput
Recommended.ProtobufInput.OneofZeroEnum.JsonOutput
Recommended.ProtobufInput.OneofZeroEnum.ProtobufOutput
Recommended.ProtobufInput.OneofZeroFloat.JsonOutput
Recommended.ProtobufInput.OneofZeroFloat.ProtobufOutput
Recommended.ProtobufInput.OneofZeroMessage.JsonOutput
Recommended.ProtobufInput.OneofZeroMessage.ProtobufOutput
Recommended.ProtobufInput.OneofZeroString.JsonOutput
Recommended.ProtobufInput.OneofZeroString.ProtobufOutput
Recommended.ProtobufInput.OneofZeroUint32.JsonOutput
Recommended.ProtobufInput.OneofZeroUint32.ProtobufOutput
Recommended.ProtobufInput.OneofZeroUint64.JsonOutput
Recommended.ProtobufInput.OneofZeroUint64.ProtobufOutput
Required.DurationProtoInputTooLarge.JsonOutput
Required.DurationProtoInputTooSmall.JsonOutput
Required.JsonInput.AllFieldAcceptNull.JsonOutput
Required.JsonInput.AllFieldAcceptNull.ProtobufOutput
Required.JsonInput.Any.JsonOutput
Required.JsonInput.Any.ProtobufOutput
Required.JsonInput.AnyNested.JsonOutput
Required.JsonInput.AnyNested.ProtobufOutput
Required.JsonInput.AnyUnorderedTypeTag.JsonOutput
Required.JsonInput.AnyUnorderedTypeTag.ProtobufOutput
Required.JsonInput.AnyWithDuration.JsonOutput
Required.JsonInput.AnyWithDuration.ProtobufOutput
Required.JsonInput.AnyWithFieldMask.JsonOutput
Required.JsonInput.AnyWithFieldMask.ProtobufOutput
Required.JsonInput.AnyWithInt32ValueWrapper.JsonOutput
Required.JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
Required.JsonInput.AnyWithStruct.JsonOutput
Required.JsonInput.AnyWithStruct.ProtobufOutput
Required.JsonInput.AnyWithTimestamp.JsonOutput
Required.JsonInput.AnyWithTimestamp.ProtobufOutput
Required.JsonInput.AnyWithValueForInteger.JsonOutput
Required.JsonInput.AnyWithValueForInteger.ProtobufOutput
Required.JsonInput.AnyWithValueForJsonObject.JsonOutput
Required.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
Required.JsonInput.BoolFieldFalse.JsonOutput
Required.JsonInput.BoolFieldFalse.ProtobufOutput
Required.JsonInput.BoolFieldTrue.JsonOutput
Required.JsonInput.BoolFieldTrue.ProtobufOutput
Required.JsonInput.BoolMapEscapedKey.JsonOutput
Required.JsonInput.BoolMapEscapedKey.ProtobufOutput
Required.JsonInput.BoolMapField.JsonOutput
Required.JsonInput.BoolMapField.ProtobufOutput
Required.JsonInput.BytesField.JsonOutput
Required.JsonInput.BytesField.ProtobufOutput
Required.JsonInput.BytesRepeatedField.JsonOutput
Required.JsonInput.BytesRepeatedField.ProtobufOutput
Required.JsonInput.DoubleFieldInfinity.JsonOutput
Required.JsonInput.DoubleFieldInfinity.ProtobufOutput
Required.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
Required.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
Required.JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
Required.JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
Required.JsonInput.DoubleFieldMinNegativeValue.JsonOutput
Required.JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
Required.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
Required.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
Required.JsonInput.DoubleFieldNan.JsonOutput
Required.JsonInput.DoubleFieldNan.ProtobufOutput
Required.JsonInput.DoubleFieldNegativeInfinity.JsonOutput
Required.JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
Required.JsonInput.DoubleFieldQuotedValue.JsonOutput
Required.JsonInput.DoubleFieldQuotedValue.ProtobufOutput
Required.JsonInput.DoubleFieldTooLarge
Required.JsonInput.DoubleFieldTooSmall Required.JsonInput.DoubleFieldTooSmall
Required.JsonInput.DurationJsonInputTooLarge
Required.JsonInput.DurationJsonInputTooSmall
Required.JsonInput.DurationMaxValue.JsonOutput
Required.JsonInput.DurationMaxValue.ProtobufOutput
Required.JsonInput.DurationMinValue.JsonOutput
Required.JsonInput.DurationMinValue.ProtobufOutput
Required.JsonInput.DurationMissingS
Required.JsonInput.DurationRepeatedValue.JsonOutput
Required.JsonInput.DurationRepeatedValue.ProtobufOutput
Required.JsonInput.EnumField.JsonOutput
Required.JsonInput.EnumField.ProtobufOutput
Required.JsonInput.EnumFieldNotQuoted
Required.JsonInput.EnumFieldNumericValueNonZero.JsonOutput
Required.JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
Required.JsonInput.EnumFieldNumericValueZero.JsonOutput
Required.JsonInput.EnumFieldNumericValueZero.ProtobufOutput
Required.JsonInput.EnumFieldUnknownValue.Validator Required.JsonInput.EnumFieldUnknownValue.Validator
Required.JsonInput.EnumRepeatedField.JsonOutput
Required.JsonInput.EnumRepeatedField.ProtobufOutput
Required.JsonInput.FieldMask.JsonOutput
Required.JsonInput.FieldMask.ProtobufOutput
Required.JsonInput.FieldNameEscaped.JsonOutput
Required.JsonInput.FieldNameEscaped.ProtobufOutput
Required.JsonInput.FieldNameInLowerCamelCase.Validator
Required.JsonInput.FieldNameInSnakeCase.JsonOutput
Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
Required.JsonInput.FieldNameWithMixedCases.JsonOutput
Required.JsonInput.FieldNameWithMixedCases.ProtobufOutput
Required.JsonInput.FieldNameWithMixedCases.Validator
Required.JsonInput.FieldNameWithNumbers.JsonOutput
Required.JsonInput.FieldNameWithNumbers.ProtobufOutput
Required.JsonInput.FieldNameWithNumbers.Validator
Required.JsonInput.FloatFieldInfinity.JsonOutput
Required.JsonInput.FloatFieldInfinity.ProtobufOutput
Required.JsonInput.FloatFieldMaxNegativeValue.JsonOutput
Required.JsonInput.FloatFieldMaxNegativeValue.ProtobufOutput
Required.JsonInput.FloatFieldMaxPositiveValue.JsonOutput
Required.JsonInput.FloatFieldMaxPositiveValue.ProtobufOutput
Required.JsonInput.FloatFieldMinNegativeValue.JsonOutput
Required.JsonInput.FloatFieldMinNegativeValue.ProtobufOutput
Required.JsonInput.FloatFieldMinPositiveValue.JsonOutput
Required.JsonInput.FloatFieldMinPositiveValue.ProtobufOutput
Required.JsonInput.FloatFieldNan.JsonOutput
Required.JsonInput.FloatFieldNan.ProtobufOutput
Required.JsonInput.FloatFieldNegativeInfinity.JsonOutput
Required.JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
Required.JsonInput.FloatFieldQuotedValue.JsonOutput
Required.JsonInput.FloatFieldQuotedValue.ProtobufOutput
Required.JsonInput.FloatFieldTooLarge Required.JsonInput.FloatFieldTooLarge
Required.JsonInput.FloatFieldTooSmall Required.JsonInput.FloatFieldTooSmall
Required.JsonInput.HelloWorld.JsonOutput
Required.JsonInput.HelloWorld.ProtobufOutput
Required.JsonInput.Int32FieldExponentialFormat.JsonOutput
Required.JsonInput.Int32FieldExponentialFormat.ProtobufOutput
Required.JsonInput.Int32FieldFloatTrailingZero.JsonOutput
Required.JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
Required.JsonInput.Int32FieldLeadingSpace
Required.JsonInput.Int32FieldLeadingZero
Required.JsonInput.Int32FieldMaxFloatValue.JsonOutput
Required.JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
Required.JsonInput.Int32FieldMaxValue.JsonOutput
Required.JsonInput.Int32FieldMaxValue.ProtobufOutput
Required.JsonInput.Int32FieldMinFloatValue.JsonOutput
Required.JsonInput.Int32FieldMinFloatValue.ProtobufOutput
Required.JsonInput.Int32FieldMinValue.JsonOutput
Required.JsonInput.Int32FieldMinValue.ProtobufOutput
Required.JsonInput.Int32FieldNegativeWithLeadingZero
Required.JsonInput.Int32FieldNotInteger
Required.JsonInput.Int32FieldNotNumber
Required.JsonInput.Int32FieldPlusSign
Required.JsonInput.Int32FieldStringValue.JsonOutput
Required.JsonInput.Int32FieldStringValue.ProtobufOutput
Required.JsonInput.Int32FieldStringValueEscaped.JsonOutput
Required.JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
Required.JsonInput.Int32FieldTooLarge
Required.JsonInput.Int32FieldTooSmall
Required.JsonInput.Int32FieldTrailingSpace
Required.JsonInput.Int32MapEscapedKey.JsonOutput
Required.JsonInput.Int32MapEscapedKey.ProtobufOutput
Required.JsonInput.Int32MapField.JsonOutput
Required.JsonInput.Int32MapField.ProtobufOutput
Required.JsonInput.Int64FieldMaxValue.JsonOutput
Required.JsonInput.Int64FieldMaxValue.ProtobufOutput
Required.JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
Required.JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
Required.JsonInput.Int64FieldMinValue.JsonOutput
Required.JsonInput.Int64FieldMinValue.ProtobufOutput
Required.JsonInput.Int64FieldMinValueNotQuoted.JsonOutput
Required.JsonInput.Int64FieldMinValueNotQuoted.ProtobufOutput
Required.JsonInput.Int64FieldNotInteger
Required.JsonInput.Int64FieldNotNumber
Required.JsonInput.Int64FieldTooLarge
Required.JsonInput.Int64FieldTooSmall
Required.JsonInput.Int64MapEscapedKey.JsonOutput
Required.JsonInput.Int64MapEscapedKey.ProtobufOutput
Required.JsonInput.Int64MapField.JsonOutput
Required.JsonInput.Int64MapField.ProtobufOutput
Required.JsonInput.MessageField.JsonOutput
Required.JsonInput.MessageField.ProtobufOutput
Required.JsonInput.MessageMapField.JsonOutput
Required.JsonInput.MessageMapField.ProtobufOutput
Required.JsonInput.MessageRepeatedField.JsonOutput
Required.JsonInput.MessageRepeatedField.ProtobufOutput
Required.JsonInput.OneofFieldDuplicate
Required.JsonInput.OptionalBoolWrapper.JsonOutput
Required.JsonInput.OptionalBoolWrapper.ProtobufOutput
Required.JsonInput.OptionalBytesWrapper.JsonOutput
Required.JsonInput.OptionalBytesWrapper.ProtobufOutput
Required.JsonInput.OptionalDoubleWrapper.JsonOutput
Required.JsonInput.OptionalDoubleWrapper.ProtobufOutput
Required.JsonInput.OptionalFloatWrapper.JsonOutput
Required.JsonInput.OptionalFloatWrapper.ProtobufOutput
Required.JsonInput.OptionalInt32Wrapper.JsonOutput
Required.JsonInput.OptionalInt32Wrapper.ProtobufOutput
Required.JsonInput.OptionalInt64Wrapper.JsonOutput
Required.JsonInput.OptionalInt64Wrapper.ProtobufOutput
Required.JsonInput.OptionalStringWrapper.JsonOutput
Required.JsonInput.OptionalStringWrapper.ProtobufOutput
Required.JsonInput.OptionalUint32Wrapper.JsonOutput
Required.JsonInput.OptionalUint32Wrapper.ProtobufOutput
Required.JsonInput.OptionalUint64Wrapper.JsonOutput
Required.JsonInput.OptionalUint64Wrapper.ProtobufOutput
Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
Required.JsonInput.OriginalProtoFieldName.JsonOutput
Required.JsonInput.OriginalProtoFieldName.ProtobufOutput
Required.JsonInput.PrimitiveRepeatedField.JsonOutput
Required.JsonInput.PrimitiveRepeatedField.ProtobufOutput
Required.JsonInput.RepeatedBoolWrapper.JsonOutput
Required.JsonInput.RepeatedBoolWrapper.ProtobufOutput
Required.JsonInput.RepeatedBytesWrapper.JsonOutput
Required.JsonInput.RepeatedBytesWrapper.ProtobufOutput
Required.JsonInput.RepeatedDoubleWrapper.JsonOutput
Required.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotMessage
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotString
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotString
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotMessage
Required.JsonInput.RepeatedFloatWrapper.JsonOutput
Required.JsonInput.RepeatedFloatWrapper.ProtobufOutput
Required.JsonInput.RepeatedInt32Wrapper.JsonOutput
Required.JsonInput.RepeatedInt32Wrapper.ProtobufOutput
Required.JsonInput.RepeatedInt64Wrapper.JsonOutput
Required.JsonInput.RepeatedInt64Wrapper.ProtobufOutput
Required.JsonInput.RepeatedStringWrapper.JsonOutput
Required.JsonInput.RepeatedStringWrapper.ProtobufOutput
Required.JsonInput.RepeatedUint32Wrapper.JsonOutput
Required.JsonInput.RepeatedUint32Wrapper.ProtobufOutput
Required.JsonInput.RepeatedUint64Wrapper.JsonOutput
Required.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
Required.JsonInput.StringField.JsonOutput
Required.JsonInput.StringField.ProtobufOutput
Required.JsonInput.StringFieldEscape.JsonOutput
Required.JsonInput.StringFieldEscape.ProtobufOutput
Required.JsonInput.StringFieldNotAString
Required.JsonInput.StringFieldSurrogatePair.JsonOutput
Required.JsonInput.StringFieldSurrogatePair.ProtobufOutput
Required.JsonInput.StringFieldUnicode.JsonOutput
Required.JsonInput.StringFieldUnicode.ProtobufOutput
Required.JsonInput.StringFieldUnicodeEscape.JsonOutput
Required.JsonInput.StringFieldUnicodeEscape.ProtobufOutput
Required.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
Required.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
Required.JsonInput.StringRepeatedField.JsonOutput
Required.JsonInput.StringRepeatedField.ProtobufOutput
Required.JsonInput.Struct.JsonOutput
Required.JsonInput.Struct.ProtobufOutput
Required.JsonInput.TimestampJsonInputLowercaseT Required.JsonInput.TimestampJsonInputLowercaseT
Required.JsonInput.TimestampJsonInputLowercaseZ
Required.JsonInput.TimestampJsonInputMissingT
Required.JsonInput.TimestampJsonInputMissingZ
Required.JsonInput.TimestampJsonInputTooLarge
Required.JsonInput.TimestampJsonInputTooSmall
Required.JsonInput.TimestampMaxValue.JsonOutput
Required.JsonInput.TimestampMaxValue.ProtobufOutput
Required.JsonInput.TimestampMinValue.JsonOutput
Required.JsonInput.TimestampMinValue.ProtobufOutput
Required.JsonInput.TimestampRepeatedValue.JsonOutput
Required.JsonInput.TimestampRepeatedValue.ProtobufOutput
Required.JsonInput.TimestampWithNegativeOffset.JsonOutput
Required.JsonInput.TimestampWithNegativeOffset.ProtobufOutput
Required.JsonInput.TimestampWithPositiveOffset.JsonOutput
Required.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
Required.JsonInput.Uint32FieldMaxFloatValue.JsonOutput
Required.JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
Required.JsonInput.Uint32FieldMaxValue.JsonOutput
Required.JsonInput.Uint32FieldMaxValue.ProtobufOutput
Required.JsonInput.Uint32FieldNotInteger
Required.JsonInput.Uint32FieldNotNumber
Required.JsonInput.Uint32FieldTooLarge
Required.JsonInput.Uint32MapField.JsonOutput
Required.JsonInput.Uint32MapField.ProtobufOutput
Required.JsonInput.Uint64FieldMaxValue.JsonOutput
Required.JsonInput.Uint64FieldMaxValue.ProtobufOutput
Required.JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
Required.JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
Required.JsonInput.Uint64FieldNotInteger
Required.JsonInput.Uint64FieldNotNumber
Required.JsonInput.Uint64FieldTooLarge
Required.JsonInput.Uint64MapField.JsonOutput
Required.JsonInput.Uint64MapField.ProtobufOutput
Required.JsonInput.ValueAcceptBool.JsonOutput
Required.JsonInput.ValueAcceptBool.ProtobufOutput
Required.JsonInput.ValueAcceptFloat.JsonOutput
Required.JsonInput.ValueAcceptFloat.ProtobufOutput
Required.JsonInput.ValueAcceptInteger.JsonOutput
Required.JsonInput.ValueAcceptInteger.ProtobufOutput
Required.JsonInput.ValueAcceptList.JsonOutput
Required.JsonInput.ValueAcceptList.ProtobufOutput
Required.JsonInput.ValueAcceptNull.JsonOutput
Required.JsonInput.ValueAcceptNull.ProtobufOutput
Required.JsonInput.ValueAcceptObject.JsonOutput
Required.JsonInput.ValueAcceptObject.ProtobufOutput
Required.JsonInput.ValueAcceptString.JsonOutput
Required.JsonInput.ValueAcceptString.ProtobufOutput
Required.JsonInput.WrapperTypesWithNullValue.JsonOutput
Required.JsonInput.WrapperTypesWithNullValue.ProtobufOutput
Required.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
Required.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
Required.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
Required.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
Required.ProtobufInput.IllegalZeroFieldNum_Case_0 Required.ProtobufInput.IllegalZeroFieldNum_Case_0
Required.ProtobufInput.IllegalZeroFieldNum_Case_1 Required.ProtobufInput.IllegalZeroFieldNum_Case_1
Required.ProtobufInput.IllegalZeroFieldNum_Case_2 Required.ProtobufInput.IllegalZeroFieldNum_Case_2
Required.ProtobufInput.IllegalZeroFieldNum_Case_3 Required.ProtobufInput.IllegalZeroFieldNum_Case_3
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.INT32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.INT64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.STRING
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.INT32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.INT64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.STRING
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.BOOL
Required.ProtobufInput.PrematureEofBeforeUnknownValue.BYTES
Required.ProtobufInput.PrematureEofBeforeUnknownValue.DOUBLE
Required.ProtobufInput.PrematureEofBeforeUnknownValue.ENUM
Required.ProtobufInput.PrematureEofBeforeUnknownValue.FIXED32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.FIXED64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.FLOAT
Required.ProtobufInput.PrematureEofBeforeUnknownValue.INT32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.INT64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.MESSAGE
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SINT32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SINT64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.STRING
Required.ProtobufInput.PrematureEofBeforeUnknownValue.UINT32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.UINT64
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.BYTES
Required.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.STRING
Required.ProtobufInput.PrematureEofInPackedField.BOOL
Required.ProtobufInput.PrematureEofInPackedField.DOUBLE
Required.ProtobufInput.PrematureEofInPackedField.ENUM
Required.ProtobufInput.PrematureEofInPackedField.FIXED32
Required.ProtobufInput.PrematureEofInPackedField.FIXED64
Required.ProtobufInput.PrematureEofInPackedField.FLOAT
Required.ProtobufInput.PrematureEofInPackedField.INT32
Required.ProtobufInput.PrematureEofInPackedField.INT64
Required.ProtobufInput.PrematureEofInPackedField.SFIXED32
Required.ProtobufInput.PrematureEofInPackedField.SFIXED64
Required.ProtobufInput.PrematureEofInPackedField.SINT32
Required.ProtobufInput.PrematureEofInPackedField.SINT64
Required.ProtobufInput.PrematureEofInPackedField.UINT32
Required.ProtobufInput.PrematureEofInPackedField.UINT64
Required.ProtobufInput.PrematureEofInPackedFieldValue.BOOL
Required.ProtobufInput.PrematureEofInPackedFieldValue.DOUBLE
Required.ProtobufInput.PrematureEofInPackedFieldValue.ENUM
Required.ProtobufInput.PrematureEofInPackedFieldValue.FIXED32
Required.ProtobufInput.PrematureEofInPackedFieldValue.FIXED64
Required.ProtobufInput.PrematureEofInPackedFieldValue.FLOAT
Required.ProtobufInput.PrematureEofInPackedFieldValue.INT32
Required.ProtobufInput.PrematureEofInPackedFieldValue.INT64
Required.ProtobufInput.PrematureEofInPackedFieldValue.SFIXED32
Required.ProtobufInput.PrematureEofInPackedFieldValue.SFIXED64
Required.ProtobufInput.PrematureEofInPackedFieldValue.SINT32
Required.ProtobufInput.PrematureEofInPackedFieldValue.SINT64
Required.ProtobufInput.PrematureEofInPackedFieldValue.UINT32
Required.ProtobufInput.PrematureEofInPackedFieldValue.UINT64
Required.ProtobufInput.PrematureEofInSubmessageValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.INT32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.INT64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.INT32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.INT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofInsideUnknownValue.BOOL
Required.ProtobufInput.PrematureEofInsideUnknownValue.BYTES
Required.ProtobufInput.PrematureEofInsideUnknownValue.DOUBLE
Required.ProtobufInput.PrematureEofInsideUnknownValue.ENUM
Required.ProtobufInput.PrematureEofInsideUnknownValue.FIXED32
Required.ProtobufInput.PrematureEofInsideUnknownValue.FIXED64
Required.ProtobufInput.PrematureEofInsideUnknownValue.FLOAT
Required.ProtobufInput.PrematureEofInsideUnknownValue.INT32
Required.ProtobufInput.PrematureEofInsideUnknownValue.INT64
Required.ProtobufInput.PrematureEofInsideUnknownValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideUnknownValue.SFIXED32
Required.ProtobufInput.PrematureEofInsideUnknownValue.SFIXED64
Required.ProtobufInput.PrematureEofInsideUnknownValue.SINT32
Required.ProtobufInput.PrematureEofInsideUnknownValue.SINT64
Required.ProtobufInput.PrematureEofInsideUnknownValue.STRING
Required.ProtobufInput.PrematureEofInsideUnknownValue.UINT32
Required.ProtobufInput.PrematureEofInsideUnknownValue.UINT64
Required.ProtobufInput.RepeatedScalarSelectsLast.BOOL.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.BOOL.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.DOUBLE.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.DOUBLE.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FLOAT.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FLOAT.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.BOOL.JsonOutput
Required.ProtobufInput.ValidDataRepeated.BOOL.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.DOUBLE.JsonOutput
Required.ProtobufInput.ValidDataRepeated.DOUBLE.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.FIXED32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.FIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.FIXED64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.FIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
Required.ProtobufInput.ValidDataRepeated.FLOAT.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.INT32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.INT32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.INT64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.INT64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SINT32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SINT32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SINT64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SINT64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.UINT32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.UINT32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.UINT64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.UINT64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.BOOL.JsonOutput
Required.ProtobufInput.ValidDataScalar.BOOL.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.DOUBLE.JsonOutput
Required.ProtobufInput.ValidDataScalar.DOUBLE.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.FIXED32.JsonOutput
Required.ProtobufInput.ValidDataScalar.FIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.FIXED64.JsonOutput
Required.ProtobufInput.ValidDataScalar.FIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.FLOAT.JsonOutput
Required.ProtobufInput.ValidDataScalar.FLOAT.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.INT32.JsonOutput
Required.ProtobufInput.ValidDataScalar.INT32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.INT64.JsonOutput
Required.ProtobufInput.ValidDataScalar.INT64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SFIXED32.JsonOutput
Required.ProtobufInput.ValidDataScalar.SFIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SFIXED64.JsonOutput
Required.ProtobufInput.ValidDataScalar.SFIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SINT32.JsonOutput
Required.ProtobufInput.ValidDataScalar.SINT32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SINT64.JsonOutput
Required.ProtobufInput.ValidDataScalar.SINT64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.UINT32.JsonOutput
Required.ProtobufInput.ValidDataScalar.UINT32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.UINT64.JsonOutput
Required.ProtobufInput.ValidDataScalar.UINT64.ProtobufOutput
Required.TimestampProtoInputTooLarge.JsonOutput
Required.TimestampProtoInputTooSmall.JsonOutput

@ -7,21 +7,462 @@
# TODO(haberman): insert links to corresponding bugs tracking the issue. # TODO(haberman): insert links to corresponding bugs tracking the issue.
# Should we use GitHub issues or the Google-internal bug tracker? # Should we use GitHub issues or the Google-internal bug tracker?
Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.JsonInput.BoolFieldAllCapitalFalse
Recommended.JsonInput.BoolFieldAllCapitalTrue
Recommended.JsonInput.BoolFieldCamelCaseFalse
Recommended.JsonInput.BoolFieldCamelCaseTrue
Recommended.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.JsonInput.BoolFieldIntegerOne
Recommended.JsonInput.BoolFieldIntegerZero
Recommended.JsonInput.BoolMapFieldKeyNotQuoted
Recommended.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.JsonInput.BytesFieldBase64Url.ProtobufOutput
Recommended.JsonInput.DoubleFieldInfinityNotQuoted Recommended.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.JsonInput.DoubleFieldNanNotQuoted Recommended.JsonInput.DoubleFieldNanNotQuoted
Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted Recommended.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.JsonInput.DurationHas3FractionalDigits.Validator
Recommended.JsonInput.DurationHas6FractionalDigits.Validator
Recommended.JsonInput.DurationHas9FractionalDigits.Validator
Recommended.JsonInput.DurationHasZeroFractionalDigit.Validator
Recommended.JsonInput.FieldMaskInvalidCharacter
Recommended.JsonInput.FieldNameDuplicate
Recommended.JsonInput.FieldNameDuplicateDifferentCasing1
Recommended.JsonInput.FieldNameDuplicateDifferentCasing2
Recommended.JsonInput.FieldNameNotQuoted
Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
Recommended.JsonInput.FloatFieldInfinityNotQuoted Recommended.JsonInput.FloatFieldInfinityNotQuoted
Recommended.JsonInput.FloatFieldNanNotQuoted Recommended.JsonInput.FloatFieldNanNotQuoted
Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted Recommended.JsonInput.FloatFieldNegativeInfinityNotQuoted
Required.JsonInput.BytesFieldInvalidBase64Characters Recommended.JsonInput.Int32MapFieldKeyNotQuoted
Recommended.JsonInput.Int64FieldBeString.Validator
Recommended.JsonInput.Int64MapFieldKeyNotQuoted
Recommended.JsonInput.JsonWithComments
Recommended.JsonInput.MapFieldKeyIsNull
Recommended.JsonInput.MapFieldValueIsNull
Recommended.JsonInput.MissingCommaMultiline
Recommended.JsonInput.MissingCommaOneLine
Recommended.JsonInput.MultilineNoSpaces.JsonOutput
Recommended.JsonInput.MultilineNoSpaces.ProtobufOutput
Recommended.JsonInput.MultilineWithSpaces.JsonOutput
Recommended.JsonInput.MultilineWithSpaces.ProtobufOutput
Recommended.JsonInput.OneLineNoSpaces.JsonOutput
Recommended.JsonInput.OneLineNoSpaces.ProtobufOutput
Recommended.JsonInput.OneLineWithSpaces.JsonOutput
Recommended.JsonInput.OneLineWithSpaces.ProtobufOutput
Recommended.JsonInput.OneofZeroBool.JsonOutput
Recommended.JsonInput.OneofZeroBool.ProtobufOutput
Recommended.JsonInput.OneofZeroBytes.JsonOutput
Recommended.JsonInput.OneofZeroBytes.ProtobufOutput
Recommended.JsonInput.OneofZeroDouble.JsonOutput
Recommended.JsonInput.OneofZeroDouble.ProtobufOutput
Recommended.JsonInput.OneofZeroEnum.JsonOutput
Recommended.JsonInput.OneofZeroEnum.ProtobufOutput
Recommended.JsonInput.OneofZeroFloat.JsonOutput
Recommended.JsonInput.OneofZeroFloat.ProtobufOutput
Recommended.JsonInput.OneofZeroMessage.JsonOutput
Recommended.JsonInput.OneofZeroMessage.ProtobufOutput
Recommended.JsonInput.OneofZeroString.JsonOutput
Recommended.JsonInput.OneofZeroString.ProtobufOutput
Recommended.JsonInput.OneofZeroUint32.JsonOutput
Recommended.JsonInput.OneofZeroUint32.ProtobufOutput
Recommended.JsonInput.OneofZeroUint64.JsonOutput
Recommended.JsonInput.OneofZeroUint64.ProtobufOutput
Recommended.JsonInput.RepeatedFieldMessageElementIsNull
Recommended.JsonInput.RepeatedFieldPrimitiveElementIsNull
Recommended.JsonInput.RepeatedFieldTrailingComma
Recommended.JsonInput.RepeatedFieldTrailingCommaWithNewlines
Recommended.JsonInput.RepeatedFieldTrailingCommaWithSpace
Recommended.JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
Recommended.JsonInput.StringEndsWithEscapeChar
Recommended.JsonInput.StringFieldInvalidEscape
Recommended.JsonInput.StringFieldSingleQuoteBoth
Recommended.JsonInput.StringFieldSingleQuoteKey
Recommended.JsonInput.StringFieldSingleQuoteValue
Recommended.JsonInput.StringFieldSurrogateInWrongOrder
Recommended.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.JsonInput.StringFieldUnterminatedEscape
Recommended.JsonInput.StringFieldUppercaseEscapeLetter
Recommended.JsonInput.TimestampHas3FractionalDigits.Validator
Recommended.JsonInput.TimestampHas6FractionalDigits.Validator
Recommended.JsonInput.TimestampHas9FractionalDigits.Validator
Recommended.JsonInput.TimestampHasZeroFractionalDigit.Validator
Recommended.JsonInput.TimestampZeroNormalized.Validator
Recommended.JsonInput.TrailingCommaInAnObject
Recommended.JsonInput.TrailingCommaInAnObjectWithNewlines
Recommended.JsonInput.TrailingCommaInAnObjectWithSpace
Recommended.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
Recommended.JsonInput.Uint32MapFieldKeyNotQuoted
Recommended.JsonInput.Uint64FieldBeString.Validator
Recommended.JsonInput.Uint64MapFieldKeyNotQuoted
Recommended.ProtobufInput.OneofZeroBool.JsonOutput
Recommended.ProtobufInput.OneofZeroBool.ProtobufOutput
Recommended.ProtobufInput.OneofZeroBytes.JsonOutput
Recommended.ProtobufInput.OneofZeroBytes.ProtobufOutput
Recommended.ProtobufInput.OneofZeroDouble.JsonOutput
Recommended.ProtobufInput.OneofZeroDouble.ProtobufOutput
Recommended.ProtobufInput.OneofZeroEnum.JsonOutput
Recommended.ProtobufInput.OneofZeroEnum.ProtobufOutput
Recommended.ProtobufInput.OneofZeroFloat.JsonOutput
Recommended.ProtobufInput.OneofZeroFloat.ProtobufOutput
Recommended.ProtobufInput.OneofZeroMessage.JsonOutput
Recommended.ProtobufInput.OneofZeroMessage.ProtobufOutput
Recommended.ProtobufInput.OneofZeroString.JsonOutput
Recommended.ProtobufInput.OneofZeroString.ProtobufOutput
Recommended.ProtobufInput.OneofZeroUint32.JsonOutput
Recommended.ProtobufInput.OneofZeroUint32.ProtobufOutput
Recommended.ProtobufInput.OneofZeroUint64.JsonOutput
Recommended.ProtobufInput.OneofZeroUint64.ProtobufOutput
Required.DurationProtoInputTooLarge.JsonOutput
Required.DurationProtoInputTooSmall.JsonOutput
Required.JsonInput.AllFieldAcceptNull.JsonOutput
Required.JsonInput.AllFieldAcceptNull.ProtobufOutput
Required.JsonInput.Any.JsonOutput
Required.JsonInput.Any.ProtobufOutput
Required.JsonInput.AnyNested.JsonOutput
Required.JsonInput.AnyNested.ProtobufOutput
Required.JsonInput.AnyUnorderedTypeTag.JsonOutput
Required.JsonInput.AnyUnorderedTypeTag.ProtobufOutput
Required.JsonInput.AnyWithDuration.JsonOutput
Required.JsonInput.AnyWithDuration.ProtobufOutput
Required.JsonInput.AnyWithFieldMask.JsonOutput
Required.JsonInput.AnyWithFieldMask.ProtobufOutput
Required.JsonInput.AnyWithInt32ValueWrapper.JsonOutput
Required.JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
Required.JsonInput.AnyWithStruct.JsonOutput
Required.JsonInput.AnyWithStruct.ProtobufOutput
Required.JsonInput.AnyWithTimestamp.JsonOutput
Required.JsonInput.AnyWithTimestamp.ProtobufOutput
Required.JsonInput.AnyWithValueForInteger.JsonOutput
Required.JsonInput.AnyWithValueForInteger.ProtobufOutput
Required.JsonInput.AnyWithValueForJsonObject.JsonOutput
Required.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
Required.JsonInput.BoolFieldFalse.JsonOutput
Required.JsonInput.BoolFieldFalse.ProtobufOutput
Required.JsonInput.BoolFieldTrue.JsonOutput
Required.JsonInput.BoolFieldTrue.ProtobufOutput
Required.JsonInput.BoolMapEscapedKey.JsonOutput
Required.JsonInput.BoolMapEscapedKey.ProtobufOutput
Required.JsonInput.BoolMapField.JsonOutput
Required.JsonInput.BoolMapField.ProtobufOutput
Required.JsonInput.BytesField.JsonOutput
Required.JsonInput.BytesField.ProtobufOutput
Required.JsonInput.BytesRepeatedField.JsonOutput
Required.JsonInput.BytesRepeatedField.ProtobufOutput
Required.JsonInput.DoubleFieldInfinity.JsonOutput
Required.JsonInput.DoubleFieldInfinity.ProtobufOutput
Required.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
Required.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
Required.JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
Required.JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
Required.JsonInput.DoubleFieldMinNegativeValue.JsonOutput
Required.JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
Required.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
Required.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
Required.JsonInput.DoubleFieldNan.JsonOutput
Required.JsonInput.DoubleFieldNan.ProtobufOutput
Required.JsonInput.DoubleFieldNegativeInfinity.JsonOutput
Required.JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
Required.JsonInput.DoubleFieldQuotedValue.JsonOutput
Required.JsonInput.DoubleFieldQuotedValue.ProtobufOutput
Required.JsonInput.DoubleFieldTooLarge
Required.JsonInput.DoubleFieldTooSmall Required.JsonInput.DoubleFieldTooSmall
Required.JsonInput.DurationJsonInputTooLarge
Required.JsonInput.DurationJsonInputTooSmall
Required.JsonInput.DurationMaxValue.JsonOutput
Required.JsonInput.DurationMaxValue.ProtobufOutput
Required.JsonInput.DurationMinValue.JsonOutput
Required.JsonInput.DurationMinValue.ProtobufOutput
Required.JsonInput.DurationMissingS
Required.JsonInput.DurationRepeatedValue.JsonOutput
Required.JsonInput.DurationRepeatedValue.ProtobufOutput
Required.JsonInput.EnumField.JsonOutput
Required.JsonInput.EnumField.ProtobufOutput
Required.JsonInput.EnumFieldNotQuoted
Required.JsonInput.EnumFieldNumericValueNonZero.JsonOutput
Required.JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
Required.JsonInput.EnumFieldNumericValueZero.JsonOutput
Required.JsonInput.EnumFieldNumericValueZero.ProtobufOutput
Required.JsonInput.EnumFieldUnknownValue.Validator Required.JsonInput.EnumFieldUnknownValue.Validator
Required.JsonInput.EnumRepeatedField.JsonOutput
Required.JsonInput.EnumRepeatedField.ProtobufOutput
Required.JsonInput.FieldMask.JsonOutput
Required.JsonInput.FieldMask.ProtobufOutput
Required.JsonInput.FieldNameEscaped.JsonOutput
Required.JsonInput.FieldNameEscaped.ProtobufOutput
Required.JsonInput.FieldNameInLowerCamelCase.Validator
Required.JsonInput.FieldNameInSnakeCase.JsonOutput
Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput
Required.JsonInput.FieldNameWithMixedCases.JsonOutput
Required.JsonInput.FieldNameWithMixedCases.ProtobufOutput
Required.JsonInput.FieldNameWithMixedCases.Validator
Required.JsonInput.FieldNameWithNumbers.JsonOutput
Required.JsonInput.FieldNameWithNumbers.ProtobufOutput
Required.JsonInput.FieldNameWithNumbers.Validator
Required.JsonInput.FloatFieldInfinity.JsonOutput
Required.JsonInput.FloatFieldInfinity.ProtobufOutput
Required.JsonInput.FloatFieldMaxNegativeValue.JsonOutput
Required.JsonInput.FloatFieldMaxNegativeValue.ProtobufOutput
Required.JsonInput.FloatFieldMaxPositiveValue.JsonOutput
Required.JsonInput.FloatFieldMaxPositiveValue.ProtobufOutput
Required.JsonInput.FloatFieldMinNegativeValue.JsonOutput
Required.JsonInput.FloatFieldMinNegativeValue.ProtobufOutput
Required.JsonInput.FloatFieldMinPositiveValue.JsonOutput
Required.JsonInput.FloatFieldMinPositiveValue.ProtobufOutput
Required.JsonInput.FloatFieldNan.JsonOutput
Required.JsonInput.FloatFieldNan.ProtobufOutput
Required.JsonInput.FloatFieldNegativeInfinity.JsonOutput
Required.JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
Required.JsonInput.FloatFieldQuotedValue.JsonOutput
Required.JsonInput.FloatFieldQuotedValue.ProtobufOutput
Required.JsonInput.FloatFieldTooLarge Required.JsonInput.FloatFieldTooLarge
Required.JsonInput.FloatFieldTooSmall Required.JsonInput.FloatFieldTooSmall
Required.JsonInput.HelloWorld.JsonOutput
Required.JsonInput.HelloWorld.ProtobufOutput
Required.JsonInput.Int32FieldExponentialFormat.JsonOutput
Required.JsonInput.Int32FieldExponentialFormat.ProtobufOutput
Required.JsonInput.Int32FieldFloatTrailingZero.JsonOutput
Required.JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
Required.JsonInput.Int32FieldLeadingSpace
Required.JsonInput.Int32FieldLeadingZero
Required.JsonInput.Int32FieldMaxFloatValue.JsonOutput
Required.JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
Required.JsonInput.Int32FieldMaxValue.JsonOutput
Required.JsonInput.Int32FieldMaxValue.ProtobufOutput
Required.JsonInput.Int32FieldMinFloatValue.JsonOutput
Required.JsonInput.Int32FieldMinFloatValue.ProtobufOutput
Required.JsonInput.Int32FieldMinValue.JsonOutput
Required.JsonInput.Int32FieldMinValue.ProtobufOutput
Required.JsonInput.Int32FieldNegativeWithLeadingZero
Required.JsonInput.Int32FieldNotInteger
Required.JsonInput.Int32FieldNotNumber
Required.JsonInput.Int32FieldPlusSign
Required.JsonInput.Int32FieldStringValue.JsonOutput
Required.JsonInput.Int32FieldStringValue.ProtobufOutput
Required.JsonInput.Int32FieldStringValueEscaped.JsonOutput
Required.JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
Required.JsonInput.Int32FieldTooLarge
Required.JsonInput.Int32FieldTooSmall
Required.JsonInput.Int32FieldTrailingSpace
Required.JsonInput.Int32MapEscapedKey.JsonOutput
Required.JsonInput.Int32MapEscapedKey.ProtobufOutput
Required.JsonInput.Int32MapField.JsonOutput
Required.JsonInput.Int32MapField.ProtobufOutput
Required.JsonInput.Int64FieldMaxValue.JsonOutput
Required.JsonInput.Int64FieldMaxValue.ProtobufOutput
Required.JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
Required.JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
Required.JsonInput.Int64FieldMinValue.JsonOutput
Required.JsonInput.Int64FieldMinValue.ProtobufOutput
Required.JsonInput.Int64FieldMinValueNotQuoted.JsonOutput
Required.JsonInput.Int64FieldMinValueNotQuoted.ProtobufOutput
Required.JsonInput.Int64FieldNotInteger
Required.JsonInput.Int64FieldNotNumber
Required.JsonInput.Int64FieldTooLarge
Required.JsonInput.Int64FieldTooSmall
Required.JsonInput.Int64MapEscapedKey.JsonOutput
Required.JsonInput.Int64MapEscapedKey.ProtobufOutput
Required.JsonInput.Int64MapField.JsonOutput
Required.JsonInput.Int64MapField.ProtobufOutput
Required.JsonInput.MessageField.JsonOutput
Required.JsonInput.MessageField.ProtobufOutput
Required.JsonInput.MessageMapField.JsonOutput
Required.JsonInput.MessageMapField.ProtobufOutput
Required.JsonInput.MessageRepeatedField.JsonOutput
Required.JsonInput.MessageRepeatedField.ProtobufOutput
Required.JsonInput.OneofFieldDuplicate
Required.JsonInput.OptionalBoolWrapper.JsonOutput
Required.JsonInput.OptionalBoolWrapper.ProtobufOutput
Required.JsonInput.OptionalBytesWrapper.JsonOutput
Required.JsonInput.OptionalBytesWrapper.ProtobufOutput
Required.JsonInput.OptionalDoubleWrapper.JsonOutput
Required.JsonInput.OptionalDoubleWrapper.ProtobufOutput
Required.JsonInput.OptionalFloatWrapper.JsonOutput
Required.JsonInput.OptionalFloatWrapper.ProtobufOutput
Required.JsonInput.OptionalInt32Wrapper.JsonOutput
Required.JsonInput.OptionalInt32Wrapper.ProtobufOutput
Required.JsonInput.OptionalInt64Wrapper.JsonOutput
Required.JsonInput.OptionalInt64Wrapper.ProtobufOutput
Required.JsonInput.OptionalStringWrapper.JsonOutput
Required.JsonInput.OptionalStringWrapper.ProtobufOutput
Required.JsonInput.OptionalUint32Wrapper.JsonOutput
Required.JsonInput.OptionalUint32Wrapper.ProtobufOutput
Required.JsonInput.OptionalUint64Wrapper.JsonOutput
Required.JsonInput.OptionalUint64Wrapper.ProtobufOutput
Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
Required.JsonInput.OriginalProtoFieldName.JsonOutput
Required.JsonInput.OriginalProtoFieldName.ProtobufOutput
Required.JsonInput.PrimitiveRepeatedField.JsonOutput
Required.JsonInput.PrimitiveRepeatedField.ProtobufOutput
Required.JsonInput.RepeatedBoolWrapper.JsonOutput
Required.JsonInput.RepeatedBoolWrapper.ProtobufOutput
Required.JsonInput.RepeatedBytesWrapper.JsonOutput
Required.JsonInput.RepeatedBytesWrapper.ProtobufOutput
Required.JsonInput.RepeatedDoubleWrapper.JsonOutput
Required.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotMessage
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotString
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotString
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotMessage
Required.JsonInput.RepeatedFloatWrapper.JsonOutput
Required.JsonInput.RepeatedFloatWrapper.ProtobufOutput
Required.JsonInput.RepeatedInt32Wrapper.JsonOutput
Required.JsonInput.RepeatedInt32Wrapper.ProtobufOutput
Required.JsonInput.RepeatedInt64Wrapper.JsonOutput
Required.JsonInput.RepeatedInt64Wrapper.ProtobufOutput
Required.JsonInput.RepeatedStringWrapper.JsonOutput
Required.JsonInput.RepeatedStringWrapper.ProtobufOutput
Required.JsonInput.RepeatedUint32Wrapper.JsonOutput
Required.JsonInput.RepeatedUint32Wrapper.ProtobufOutput
Required.JsonInput.RepeatedUint64Wrapper.JsonOutput
Required.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
Required.JsonInput.StringField.JsonOutput
Required.JsonInput.StringField.ProtobufOutput
Required.JsonInput.StringFieldEscape.JsonOutput
Required.JsonInput.StringFieldEscape.ProtobufOutput
Required.JsonInput.StringFieldNotAString
Required.JsonInput.StringFieldSurrogatePair.JsonOutput
Required.JsonInput.StringFieldSurrogatePair.ProtobufOutput
Required.JsonInput.StringFieldUnicode.JsonOutput
Required.JsonInput.StringFieldUnicode.ProtobufOutput
Required.JsonInput.StringFieldUnicodeEscape.JsonOutput
Required.JsonInput.StringFieldUnicodeEscape.ProtobufOutput
Required.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
Required.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
Required.JsonInput.StringRepeatedField.JsonOutput
Required.JsonInput.StringRepeatedField.ProtobufOutput
Required.JsonInput.Struct.JsonOutput
Required.JsonInput.Struct.ProtobufOutput
Required.JsonInput.TimestampJsonInputLowercaseT Required.JsonInput.TimestampJsonInputLowercaseT
Required.JsonInput.TimestampJsonInputLowercaseZ
Required.JsonInput.TimestampJsonInputMissingT
Required.JsonInput.TimestampJsonInputMissingZ
Required.JsonInput.TimestampJsonInputTooLarge
Required.JsonInput.TimestampJsonInputTooSmall
Required.JsonInput.TimestampMaxValue.JsonOutput
Required.JsonInput.TimestampMaxValue.ProtobufOutput
Required.JsonInput.TimestampMinValue.JsonOutput
Required.JsonInput.TimestampMinValue.ProtobufOutput
Required.JsonInput.TimestampRepeatedValue.JsonOutput
Required.JsonInput.TimestampRepeatedValue.ProtobufOutput
Required.JsonInput.TimestampWithNegativeOffset.JsonOutput
Required.JsonInput.TimestampWithNegativeOffset.ProtobufOutput
Required.JsonInput.TimestampWithPositiveOffset.JsonOutput
Required.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
Required.JsonInput.Uint32FieldMaxFloatValue.JsonOutput
Required.JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
Required.JsonInput.Uint32FieldMaxValue.JsonOutput
Required.JsonInput.Uint32FieldMaxValue.ProtobufOutput
Required.JsonInput.Uint32FieldNotInteger
Required.JsonInput.Uint32FieldNotNumber
Required.JsonInput.Uint32FieldTooLarge
Required.JsonInput.Uint32MapField.JsonOutput
Required.JsonInput.Uint32MapField.ProtobufOutput
Required.JsonInput.Uint64FieldMaxValue.JsonOutput
Required.JsonInput.Uint64FieldMaxValue.ProtobufOutput
Required.JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
Required.JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
Required.JsonInput.Uint64FieldNotInteger
Required.JsonInput.Uint64FieldNotNumber
Required.JsonInput.Uint64FieldTooLarge
Required.JsonInput.Uint64MapField.JsonOutput
Required.JsonInput.Uint64MapField.ProtobufOutput
Required.JsonInput.ValueAcceptBool.JsonOutput
Required.JsonInput.ValueAcceptBool.ProtobufOutput
Required.JsonInput.ValueAcceptFloat.JsonOutput
Required.JsonInput.ValueAcceptFloat.ProtobufOutput
Required.JsonInput.ValueAcceptInteger.JsonOutput
Required.JsonInput.ValueAcceptInteger.ProtobufOutput
Required.JsonInput.ValueAcceptList.JsonOutput
Required.JsonInput.ValueAcceptList.ProtobufOutput
Required.JsonInput.ValueAcceptNull.JsonOutput
Required.JsonInput.ValueAcceptNull.ProtobufOutput
Required.JsonInput.ValueAcceptObject.JsonOutput
Required.JsonInput.ValueAcceptObject.ProtobufOutput
Required.JsonInput.ValueAcceptString.JsonOutput
Required.JsonInput.ValueAcceptString.ProtobufOutput
Required.JsonInput.WrapperTypesWithNullValue.JsonOutput
Required.JsonInput.WrapperTypesWithNullValue.ProtobufOutput
Required.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
Required.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
Required.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
Required.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
Required.ProtobufInput.IllegalZeroFieldNum_Case_0
Required.ProtobufInput.IllegalZeroFieldNum_Case_1
Required.ProtobufInput.IllegalZeroFieldNum_Case_2
Required.ProtobufInput.IllegalZeroFieldNum_Case_3
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.INT32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.INT64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.STRING
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofBeforeKnownNonRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.INT32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.INT64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.STRING
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.BOOL
Required.ProtobufInput.PrematureEofBeforeUnknownValue.BYTES
Required.ProtobufInput.PrematureEofBeforeUnknownValue.DOUBLE
Required.ProtobufInput.PrematureEofBeforeUnknownValue.ENUM
Required.ProtobufInput.PrematureEofBeforeUnknownValue.FIXED32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.FIXED64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.FLOAT
Required.ProtobufInput.PrematureEofBeforeUnknownValue.INT32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.INT64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.MESSAGE
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SINT32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.SINT64
Required.ProtobufInput.PrematureEofBeforeUnknownValue.STRING
Required.ProtobufInput.PrematureEofBeforeUnknownValue.UINT32
Required.ProtobufInput.PrematureEofBeforeUnknownValue.UINT64
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.BYTES
Required.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.MESSAGE
Required.ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.STRING
Required.ProtobufInput.PrematureEofInPackedField.BOOL Required.ProtobufInput.PrematureEofInPackedField.BOOL
Required.ProtobufInput.PrematureEofInPackedField.DOUBLE Required.ProtobufInput.PrematureEofInPackedField.DOUBLE
Required.ProtobufInput.PrematureEofInPackedField.ENUM Required.ProtobufInput.PrematureEofInPackedField.ENUM
@ -36,3 +477,149 @@ Required.ProtobufInput.PrematureEofInPackedField.SINT32
Required.ProtobufInput.PrematureEofInPackedField.SINT64 Required.ProtobufInput.PrematureEofInPackedField.SINT64
Required.ProtobufInput.PrematureEofInPackedField.UINT32 Required.ProtobufInput.PrematureEofInPackedField.UINT32
Required.ProtobufInput.PrematureEofInPackedField.UINT64 Required.ProtobufInput.PrematureEofInPackedField.UINT64
Required.ProtobufInput.PrematureEofInPackedFieldValue.BOOL
Required.ProtobufInput.PrematureEofInPackedFieldValue.DOUBLE
Required.ProtobufInput.PrematureEofInPackedFieldValue.ENUM
Required.ProtobufInput.PrematureEofInPackedFieldValue.FIXED32
Required.ProtobufInput.PrematureEofInPackedFieldValue.FIXED64
Required.ProtobufInput.PrematureEofInPackedFieldValue.FLOAT
Required.ProtobufInput.PrematureEofInPackedFieldValue.INT32
Required.ProtobufInput.PrematureEofInPackedFieldValue.INT64
Required.ProtobufInput.PrematureEofInPackedFieldValue.SFIXED32
Required.ProtobufInput.PrematureEofInPackedFieldValue.SFIXED64
Required.ProtobufInput.PrematureEofInPackedFieldValue.SINT32
Required.ProtobufInput.PrematureEofInPackedFieldValue.SINT64
Required.ProtobufInput.PrematureEofInPackedFieldValue.UINT32
Required.ProtobufInput.PrematureEofInPackedFieldValue.UINT64
Required.ProtobufInput.PrematureEofInSubmessageValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.INT32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.INT64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofInsideKnownNonRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.BOOL
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.BYTES
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.DOUBLE
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.ENUM
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.FIXED32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.FIXED64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.FLOAT
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.INT32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.INT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SFIXED32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SFIXED64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SINT32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.SINT64
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.STRING
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.UINT32
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.UINT64
Required.ProtobufInput.PrematureEofInsideUnknownValue.BOOL
Required.ProtobufInput.PrematureEofInsideUnknownValue.BYTES
Required.ProtobufInput.PrematureEofInsideUnknownValue.DOUBLE
Required.ProtobufInput.PrematureEofInsideUnknownValue.ENUM
Required.ProtobufInput.PrematureEofInsideUnknownValue.FIXED32
Required.ProtobufInput.PrematureEofInsideUnknownValue.FIXED64
Required.ProtobufInput.PrematureEofInsideUnknownValue.FLOAT
Required.ProtobufInput.PrematureEofInsideUnknownValue.INT32
Required.ProtobufInput.PrematureEofInsideUnknownValue.INT64
Required.ProtobufInput.PrematureEofInsideUnknownValue.MESSAGE
Required.ProtobufInput.PrematureEofInsideUnknownValue.SFIXED32
Required.ProtobufInput.PrematureEofInsideUnknownValue.SFIXED64
Required.ProtobufInput.PrematureEofInsideUnknownValue.SINT32
Required.ProtobufInput.PrematureEofInsideUnknownValue.SINT64
Required.ProtobufInput.PrematureEofInsideUnknownValue.STRING
Required.ProtobufInput.PrematureEofInsideUnknownValue.UINT32
Required.ProtobufInput.PrematureEofInsideUnknownValue.UINT64
Required.ProtobufInput.RepeatedScalarSelectsLast.BOOL.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.BOOL.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.DOUBLE.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.DOUBLE.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FIXED64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FLOAT.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.FLOAT.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.INT64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SFIXED64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.SINT64.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT32.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT32.ProtobufOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT64.JsonOutput
Required.ProtobufInput.RepeatedScalarSelectsLast.UINT64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.BOOL.JsonOutput
Required.ProtobufInput.ValidDataRepeated.BOOL.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.DOUBLE.JsonOutput
Required.ProtobufInput.ValidDataRepeated.DOUBLE.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.FIXED32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.FIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.FIXED64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.FIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
Required.ProtobufInput.ValidDataRepeated.FLOAT.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.INT32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.INT32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.INT64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.INT64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SFIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SINT32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SINT32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.SINT64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.SINT64.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.UINT32.JsonOutput
Required.ProtobufInput.ValidDataRepeated.UINT32.ProtobufOutput
Required.ProtobufInput.ValidDataRepeated.UINT64.JsonOutput
Required.ProtobufInput.ValidDataRepeated.UINT64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.BOOL.JsonOutput
Required.ProtobufInput.ValidDataScalar.BOOL.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.DOUBLE.JsonOutput
Required.ProtobufInput.ValidDataScalar.DOUBLE.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.FIXED32.JsonOutput
Required.ProtobufInput.ValidDataScalar.FIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.FIXED64.JsonOutput
Required.ProtobufInput.ValidDataScalar.FIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.FLOAT.JsonOutput
Required.ProtobufInput.ValidDataScalar.FLOAT.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.INT32.JsonOutput
Required.ProtobufInput.ValidDataScalar.INT32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.INT64.JsonOutput
Required.ProtobufInput.ValidDataScalar.INT64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SFIXED32.JsonOutput
Required.ProtobufInput.ValidDataScalar.SFIXED32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SFIXED64.JsonOutput
Required.ProtobufInput.ValidDataScalar.SFIXED64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SINT32.JsonOutput
Required.ProtobufInput.ValidDataScalar.SINT32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.SINT64.JsonOutput
Required.ProtobufInput.ValidDataScalar.SINT64.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.UINT32.JsonOutput
Required.ProtobufInput.ValidDataScalar.UINT32.ProtobufOutput
Required.ProtobufInput.ValidDataScalar.UINT64.JsonOutput
Required.ProtobufInput.ValidDataScalar.UINT64.ProtobufOutput
Required.TimestampProtoInputTooLarge.JsonOutput
Required.TimestampProtoInputTooSmall.JsonOutput

@ -42,12 +42,23 @@ declare -a RUNTIME_PROTO_FILES=(\
google/protobuf/wrappers.proto) google/protobuf/wrappers.proto)
declare -a COMPILER_PROTO_FILES=(\ declare -a COMPILER_PROTO_FILES=(\
google/protobuf/compiler/plugin.proto \ google/protobuf/compiler/plugin.proto)
google/protobuf/compiler/profile.proto \
)
CORE_PROTO_IS_CORRECT=0 CORE_PROTO_IS_CORRECT=0
PROCESS_ROUND=1 PROCESS_ROUND=1
BOOTSTRAP_PROTOC=""
while [ $# -gt 0 ]; do
case $1 in
--bootstrap_protoc)
BOOTSTRAP_PROTOC=$2
shift
;;
*)
break
;;
esac
shift
done
TMP=$(mktemp -d) TMP=$(mktemp -d)
echo "Updating descriptor protos..." echo "Updating descriptor protos..."
while [ $CORE_PROTO_IS_CORRECT -ne 1 ] while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
@ -55,14 +66,20 @@ do
echo "Round $PROCESS_ROUND" echo "Round $PROCESS_ROUND"
CORE_PROTO_IS_CORRECT=1 CORE_PROTO_IS_CORRECT=1
make $@ protoc if [ "$BOOTSTRAP_PROTOC" != "" ]; then
if test $? -ne 0; then PROTOC=$BOOTSTRAP_PROTOC
echo "Failed to build protoc." BOOTSTRAP_PROTOC=""
exit 1 else
make $@ protoc
if test $? -ne 0; then
echo "Failed to build protoc."
exit 1
fi
PROTOC="./protoc"
fi fi
./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \ $PROTOC --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP ${COMPILER_PROTO_FILES[@]} $PROTOC --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP ${COMPILER_PROTO_FILES[@]}
for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]} ${COMPILER_PROTO_FILES[@]}; do for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]} ${COMPILER_PROTO_FILES[@]}; do
BASE_NAME=${PROTO_FILE%.*} BASE_NAME=${PROTO_FILE%.*}

@ -5,6 +5,7 @@
<arg value="--proto_path=${protobuf.source.dir}"/> <arg value="--proto_path=${protobuf.source.dir}"/>
<arg value="--proto_path=${test.proto.dir}"/> <arg value="--proto_path=${test.proto.dir}"/>
<arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/> <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/> <arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/> <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/> <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
@ -40,4 +41,4 @@
<arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/> <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
<arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/> <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
</exec> </exec>
</project> </project>

@ -32,6 +32,7 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Internal.EnumLite; import com.google.protobuf.Internal.EnumLite;
import java.io.IOException; import java.io.IOException;
@ -162,7 +163,7 @@ public abstract class AbstractMessage
} }
return hash; return hash;
} }
private static ByteString toByteString(Object value) { private static ByteString toByteString(Object value) {
if (value instanceof byte[]) { if (value instanceof byte[]) {
return ByteString.copyFrom((byte[]) value); return ByteString.copyFrom((byte[]) value);
@ -170,7 +171,7 @@ public abstract class AbstractMessage
return (ByteString) value; return (ByteString) value;
} }
} }
/** /**
* Compares two bytes fields. The parameters must be either a byte array or a * Compares two bytes fields. The parameters must be either a byte array or a
* ByteString object. They can be of different type though. * ByteString object. They can be of different type though.
@ -181,7 +182,7 @@ public abstract class AbstractMessage
} }
return toByteString(a).equals(toByteString(b)); return toByteString(a).equals(toByteString(b));
} }
/** /**
* Converts a list of MapEntry messages into a Map used for equals() and * Converts a list of MapEntry messages into a Map used for equals() and
* hashCode(). * hashCode().
@ -212,7 +213,7 @@ public abstract class AbstractMessage
} }
return result; return result;
} }
/** /**
* Compares two map fields. The parameters must be a list of MapEntry * Compares two map fields. The parameters must be a list of MapEntry
* messages. * messages.
@ -223,13 +224,13 @@ public abstract class AbstractMessage
Map mb = convertMapEntryListToMap((List) b); Map mb = convertMapEntryListToMap((List) b);
return MapFieldLite.equals(ma, mb); return MapFieldLite.equals(ma, mb);
} }
/** /**
* Compares two set of fields. * Compares two set of fields.
* This method is used to implement {@link AbstractMessage#equals(Object)} * This method is used to implement {@link AbstractMessage#equals(Object)}
* and {@link AbstractMutableMessage#equals(Object)}. It takes special care * and {@link AbstractMutableMessage#equals(Object)}. It takes special care
* of bytes fields because immutable messages and mutable messages use * of bytes fields because immutable messages and mutable messages use
* different Java type to reprensent a bytes field and this method should be * different Java type to represent a bytes field and this method should be
* able to compare immutable messages, mutable messages and also an immutable * able to compare immutable messages, mutable messages and also an immutable
* message to a mutable message. * message to a mutable message.
*/ */
@ -275,7 +276,7 @@ public abstract class AbstractMessage
} }
return true; return true;
} }
/** /**
* Calculates the hash code of a map field. {@code value} must be a list of * Calculates the hash code of a map field. {@code value} must be a list of
* MapEntry messages. * MapEntry messages.
@ -371,7 +372,7 @@ public abstract class AbstractMessage
public String getInitializationErrorString() { public String getInitializationErrorString() {
return MessageReflection.delimitWithCommas(findInitializationErrors()); return MessageReflection.delimitWithCommas(findInitializationErrors());
} }
@Override @Override
protected BuilderType internalMergeFrom(AbstractMessageLite other) { protected BuilderType internalMergeFrom(AbstractMessageLite other) {
return mergeFrom((Message) other); return mergeFrom((Message) other);
@ -432,8 +433,12 @@ public abstract class AbstractMessage
final CodedInputStream input, final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry) final ExtensionRegistryLite extensionRegistry)
throws IOException { throws IOException {
boolean discardUnknown =
getDescriptorForType().getFile().getSyntax() == Syntax.PROTO3
? input.shouldDiscardUnknownFieldsProto3()
: input.shouldDiscardUnknownFields();
final UnknownFieldSet.Builder unknownFields = final UnknownFieldSet.Builder unknownFields =
UnknownFieldSet.newBuilder(getUnknownFields()); discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields());
while (true) { while (true) {
final int tag = input.readTag(); final int tag = input.readTag();
if (tag == 0) { if (tag == 0) {
@ -451,7 +456,9 @@ public abstract class AbstractMessage
break; break;
} }
} }
setUnknownFields(unknownFields.build()); if (unknownFields != null) {
setUnknownFields(unknownFields.build());
}
return (BuilderType) this; return (BuilderType) this;
} }

@ -36,7 +36,9 @@ import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* A partial implementation of the {@link MessageLite} interface which * A partial implementation of the {@link MessageLite} interface which
@ -118,8 +120,13 @@ public abstract class AbstractMessageLite<
} }
} }
protected static <T> void addAll(final Iterable<T> values, // For binary compatibility
final Collection<? super T> list) { @Deprecated
protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
Builder.addAll(values, (List) list);
}
protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
Builder.addAll(values, list); Builder.addAll(values, list);
} }
@ -334,6 +341,25 @@ public abstract class AbstractMessageLite<
+ " threw an IOException (should never happen)."; + " threw an IOException (should never happen).";
} }
// We check nulls as we iterate to avoid iterating over values twice.
private static <T> void addAllCheckingNulls(Iterable<T> values, List<? super T> list) {
if (list instanceof ArrayList && values instanceof Collection) {
((ArrayList<T>) list).ensureCapacity(list.size() + ((Collection<T>) values).size());
}
int begin = list.size();
for (T value : values) {
if (value == null) {
// encountered a null value so we must undo our modifications prior to throwing
String message = "Element at index " + (list.size() - begin) + " is null.";
for (int i = list.size() - 1; i >= begin; i--) {
list.remove(i);
}
throw new NullPointerException(message);
}
list.add(value);
}
}
/** /**
* Construct an UninitializedMessageException reporting missing fields in * Construct an UninitializedMessageException reporting missing fields in
* the given message. * the given message.
@ -343,16 +369,20 @@ public abstract class AbstractMessageLite<
return new UninitializedMessageException(message); return new UninitializedMessageException(message);
} }
// For binary compatibility.
@Deprecated
protected static <T> void addAll(final Iterable<T> values, final Collection<? super T> list) {
addAll(values, (List<T>) list);
}
/** /**
* Adds the {@code values} to the {@code list}. This is a helper method * Adds the {@code values} to the {@code list}. This is a helper method used by generated code.
* used by generated code. Users should ignore it. * Users should ignore it.
* *
* @throws NullPointerException if {@code values} or any of the elements of * @throws NullPointerException if {@code values} or any of the elements of {@code values} is
* {@code values} is null. When that happens, some elements of * null.
* {@code values} may have already been added to the result {@code list}.
*/ */
protected static <T> void addAll(final Iterable<T> values, protected static <T> void addAll(final Iterable<T> values, final List<? super T> list) {
final Collection<? super T> list) {
checkNotNull(values); checkNotNull(values);
if (values instanceof LazyStringList) { if (values instanceof LazyStringList) {
// For StringOrByteStringLists, check the underlying elements to avoid // For StringOrByteStringLists, check the underlying elements to avoid
@ -360,25 +390,31 @@ public abstract class AbstractMessageLite<
// TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is // TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
// if even possible to hit this condition as all protobuf methods check for null first, // if even possible to hit this condition as all protobuf methods check for null first,
// right? // right?
checkForNullValues(((LazyStringList) values).getUnderlyingElements()); List<?> lazyValues = ((LazyStringList) values).getUnderlyingElements();
list.addAll((Collection<T>) values); LazyStringList lazyList = (LazyStringList) list;
} else if (values instanceof Collection) { int begin = list.size();
if (!(values instanceof PrimitiveNonBoxingCollection)) { for (Object value : lazyValues) {
checkForNullValues(values); if (value == null) {
// encountered a null value so we must undo our modifications prior to throwing
String message = "Element at index " + (lazyList.size() - begin) + " is null.";
for (int i = lazyList.size() - 1; i >= begin; i--) {
lazyList.remove(i);
}
throw new NullPointerException(message);
}
if (value instanceof ByteString) {
lazyList.add((ByteString) value);
} else {
lazyList.add((String) value);
}
} }
list.addAll((Collection<T>) values);
} else { } else {
for (final T value : values) { if (values instanceof PrimitiveNonBoxingCollection) {
checkNotNull(value); list.addAll((Collection<T>) values);
list.add(value); } else {
addAllCheckingNulls(values, list);
} }
} }
} }
private static void checkForNullValues(final Iterable<?> values) {
for (final Object value : values) {
checkNotNull(value);
}
}
} }
} }

@ -34,8 +34,8 @@ import static com.google.protobuf.Internal.EMPTY_BYTE_ARRAY;
import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER; import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER;
import static com.google.protobuf.Internal.UTF_8; import static com.google.protobuf.Internal.UTF_8;
import static com.google.protobuf.Internal.checkNotNull; import static com.google.protobuf.Internal.checkNotNull;
import static com.google.protobuf.WireFormat.FIXED_32_SIZE; import static com.google.protobuf.WireFormat.FIXED32_SIZE;
import static com.google.protobuf.WireFormat.FIXED_64_SIZE; import static com.google.protobuf.WireFormat.FIXED64_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE; import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -372,6 +372,64 @@ public abstract class CodedInputStream {
return oldLimit; return oldLimit;
} }
private boolean explicitDiscardUnknownFields = false;
/** TODO(liujisi): flip the default.*/
private static volatile boolean proto3DiscardUnknownFieldsDefault = true;
static void setProto3DiscardUnknownsByDefaultForTest() {
proto3DiscardUnknownFieldsDefault = true;
}
static void setProto3KeepUnknownsByDefaultForTest() {
proto3DiscardUnknownFieldsDefault = false;
}
static boolean getProto3DiscardUnknownFieldsDefault() {
return proto3DiscardUnknownFieldsDefault;
}
/**
* Sets this {@code CodedInputStream} to discard unknown fields. Only applies to full runtime
* messages; lite messages will always preserve unknowns.
*
* <p>Note calling this function alone will have NO immediate effect on the underlying input data.
* The unknown fields will be discarded during parsing. This affects both Proto2 and Proto3 full
* runtime.
*/
final void discardUnknownFields() {
explicitDiscardUnknownFields = true;
}
/**
* Reverts the unknown fields preservation behavior for Proto2 and Proto3 full runtime to their
* default.
*/
final void unsetDiscardUnknownFields() {
explicitDiscardUnknownFields = false;
}
/**
* Whether unknown fields in this input stream should be discarded during parsing into full
* 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;
}
/** /**
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}). Only valid for {@link * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). Only valid for {@link
* InputStream}-backed streams. * InputStream}-backed streams.
@ -572,7 +630,7 @@ public abstract class CodedInputStream {
skipRawVarint(); skipRawVarint();
return true; return true;
case WireFormat.WIRETYPE_FIXED64: case WireFormat.WIRETYPE_FIXED64:
skipRawBytes(FIXED_64_SIZE); skipRawBytes(FIXED64_SIZE);
return true; return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED: case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32()); skipRawBytes(readRawVarint32());
@ -585,7 +643,7 @@ public abstract class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP: case WireFormat.WIRETYPE_END_GROUP:
return false; return false;
case WireFormat.WIRETYPE_FIXED32: case WireFormat.WIRETYPE_FIXED32:
skipRawBytes(FIXED_32_SIZE); skipRawBytes(FIXED32_SIZE);
return true; return true;
default: default:
throw InvalidProtocolBufferException.invalidWireType(); throw InvalidProtocolBufferException.invalidWireType();
@ -1064,12 +1122,12 @@ public abstract class CodedInputStream {
public int readRawLittleEndian32() throws IOException { public int readRawLittleEndian32() throws IOException {
int tempPos = pos; int tempPos = pos;
if (limit - tempPos < FIXED_32_SIZE) { if (limit - tempPos < FIXED32_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage(); throw InvalidProtocolBufferException.truncatedMessage();
} }
final byte[] buffer = this.buffer; final byte[] buffer = this.buffer;
pos = tempPos + FIXED_32_SIZE; pos = tempPos + FIXED32_SIZE;
return (((buffer[tempPos] & 0xff)) return (((buffer[tempPos] & 0xff))
| ((buffer[tempPos + 1] & 0xff) << 8) | ((buffer[tempPos + 1] & 0xff) << 8)
| ((buffer[tempPos + 2] & 0xff) << 16) | ((buffer[tempPos + 2] & 0xff) << 16)
@ -1080,12 +1138,12 @@ public abstract class CodedInputStream {
public long readRawLittleEndian64() throws IOException { public long readRawLittleEndian64() throws IOException {
int tempPos = pos; int tempPos = pos;
if (limit - tempPos < FIXED_64_SIZE) { if (limit - tempPos < FIXED64_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage(); throw InvalidProtocolBufferException.truncatedMessage();
} }
final byte[] buffer = this.buffer; final byte[] buffer = this.buffer;
pos = tempPos + FIXED_64_SIZE; pos = tempPos + FIXED64_SIZE;
return (((buffer[tempPos] & 0xffL)) return (((buffer[tempPos] & 0xffL))
| ((buffer[tempPos + 1] & 0xffL) << 8) | ((buffer[tempPos + 1] & 0xffL) << 8)
| ((buffer[tempPos + 2] & 0xffL) << 16) | ((buffer[tempPos + 2] & 0xffL) << 16)
@ -1290,7 +1348,7 @@ public abstract class CodedInputStream {
skipRawVarint(); skipRawVarint();
return true; return true;
case WireFormat.WIRETYPE_FIXED64: case WireFormat.WIRETYPE_FIXED64:
skipRawBytes(FIXED_64_SIZE); skipRawBytes(FIXED64_SIZE);
return true; return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED: case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32()); skipRawBytes(readRawVarint32());
@ -1303,7 +1361,7 @@ public abstract class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP: case WireFormat.WIRETYPE_END_GROUP:
return false; return false;
case WireFormat.WIRETYPE_FIXED32: case WireFormat.WIRETYPE_FIXED32:
skipRawBytes(FIXED_32_SIZE); skipRawBytes(FIXED32_SIZE);
return true; return true;
default: default:
throw InvalidProtocolBufferException.invalidWireType(); throw InvalidProtocolBufferException.invalidWireType();
@ -1429,7 +1487,9 @@ public abstract class CodedInputStream {
final int size = readRawVarint32(); final int size = readRawVarint32();
if (size > 0 && size <= remaining()) { if (size > 0 && size <= remaining()) {
// TODO(nathanmittler): Is there a way to avoid this copy? // TODO(nathanmittler): Is there a way to avoid this copy?
byte[] bytes = copyToArray(pos, pos + size); // The same as readBytes' logic
byte[] bytes = new byte[size];
UnsafeUtil.copyMemory(pos, bytes, 0, size);
String result = new String(bytes, UTF_8); String result = new String(bytes, UTF_8);
pos += size; pos += size;
return result; return result;
@ -1449,7 +1509,9 @@ public abstract class CodedInputStream {
final int size = readRawVarint32(); final int size = readRawVarint32();
if (size >= 0 && size <= remaining()) { if (size >= 0 && size <= remaining()) {
// TODO(nathanmittler): Is there a way to avoid this copy? // TODO(nathanmittler): Is there a way to avoid this copy?
byte[] bytes = copyToArray(pos, pos + size); // 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. // TODO(martinrb): We could save a pass by validating while decoding.
if (!Utf8.isValidUtf8(bytes)) { if (!Utf8.isValidUtf8(bytes)) {
throw InvalidProtocolBufferException.invalidUtf8(); throw InvalidProtocolBufferException.invalidUtf8();
@ -1545,14 +1607,17 @@ public abstract class CodedInputStream {
public ByteString readBytes() throws IOException { public ByteString readBytes() throws IOException {
final int size = readRawVarint32(); final int size = readRawVarint32();
if (size > 0 && size <= remaining()) { if (size > 0 && size <= remaining()) {
ByteBuffer result;
if (immutable && enableAliasing) { if (immutable && enableAliasing) {
result = slice(pos, pos + size); final ByteBuffer result = slice(pos, pos + size);
pos += size;
return ByteString.wrap(result);
} else { } else {
result = copy(pos, pos + size); // Use UnsafeUtil to copy the memory to bytes instead of using ByteBuffer ways.
byte[] bytes = new byte[size];
UnsafeUtil.copyMemory(pos, bytes, 0, size);
pos += size;
return ByteString.wrap(bytes);
} }
pos += size;
return ByteString.wrap(result);
} }
if (size == 0) { if (size == 0) {
@ -1573,18 +1638,21 @@ public abstract class CodedInputStream {
public ByteBuffer readByteBuffer() throws IOException { public ByteBuffer readByteBuffer() throws IOException {
final int size = readRawVarint32(); final int size = readRawVarint32();
if (size > 0 && size <= remaining()) { if (size > 0 && size <= remaining()) {
ByteBuffer result;
// "Immutable" implies that buffer is backing a ByteString. // "Immutable" implies that buffer is backing a ByteString.
// Disallow slicing in this case to prevent the caller from modifying the contents // Disallow slicing in this case to prevent the caller from modifying the contents
// of the ByteString. // of the ByteString.
if (!immutable && enableAliasing) { if (!immutable && enableAliasing) {
result = slice(pos, pos + size); final ByteBuffer result = slice(pos, pos + size);
pos += size;
return result;
} else { } else {
result = copy(pos, pos + size); // The same as readBytes' logic
byte[] bytes = new byte[size];
UnsafeUtil.copyMemory(pos, bytes, 0, size);
pos += size;
return ByteBuffer.wrap(bytes);
} }
pos += size;
// TODO(nathanmittler): Investigate making the ByteBuffer be made read-only // TODO(nathanmittler): Investigate making the ByteBuffer be made read-only
return result;
} }
if (size == 0) { if (size == 0) {
@ -1785,11 +1853,11 @@ public abstract class CodedInputStream {
public int readRawLittleEndian32() throws IOException { public int readRawLittleEndian32() throws IOException {
long tempPos = pos; long tempPos = pos;
if (limit - tempPos < FIXED_32_SIZE) { if (limit - tempPos < FIXED32_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage(); throw InvalidProtocolBufferException.truncatedMessage();
} }
pos = tempPos + FIXED_32_SIZE; pos = tempPos + FIXED32_SIZE;
return (((UnsafeUtil.getByte(tempPos) & 0xff)) return (((UnsafeUtil.getByte(tempPos) & 0xff))
| ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8) | ((UnsafeUtil.getByte(tempPos + 1) & 0xff) << 8)
| ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16) | ((UnsafeUtil.getByte(tempPos + 2) & 0xff) << 16)
@ -1800,11 +1868,11 @@ public abstract class CodedInputStream {
public long readRawLittleEndian64() throws IOException { public long readRawLittleEndian64() throws IOException {
long tempPos = pos; long tempPos = pos;
if (limit - tempPos < FIXED_64_SIZE) { if (limit - tempPos < FIXED64_SIZE) {
throw InvalidProtocolBufferException.truncatedMessage(); throw InvalidProtocolBufferException.truncatedMessage();
} }
pos = tempPos + FIXED_64_SIZE; pos = tempPos + FIXED64_SIZE;
return (((UnsafeUtil.getByte(tempPos) & 0xffL)) return (((UnsafeUtil.getByte(tempPos) & 0xffL))
| ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8) | ((UnsafeUtil.getByte(tempPos + 1) & 0xffL) << 8)
| ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16) | ((UnsafeUtil.getByte(tempPos + 2) & 0xffL) << 16)
@ -1943,27 +2011,6 @@ public abstract class CodedInputStream {
buffer.limit(prevLimit); buffer.limit(prevLimit);
} }
} }
private ByteBuffer copy(long begin, long end) throws IOException {
return ByteBuffer.wrap(copyToArray(begin, end));
}
private byte[] copyToArray(long begin, long end) throws IOException {
int prevPos = buffer.position();
int prevLimit = buffer.limit();
try {
buffer.position(bufferPos(begin));
buffer.limit(bufferPos(end));
byte[] bytes = new byte[(int) (end - begin)];
buffer.get(bytes);
return bytes;
} catch (IllegalArgumentException e) {
throw InvalidProtocolBufferException.truncatedMessage();
} finally {
buffer.position(prevPos);
buffer.limit(prevLimit);
}
}
} }
/** /**
@ -2034,7 +2081,7 @@ public abstract class CodedInputStream {
skipRawVarint(); skipRawVarint();
return true; return true;
case WireFormat.WIRETYPE_FIXED64: case WireFormat.WIRETYPE_FIXED64:
skipRawBytes(FIXED_64_SIZE); skipRawBytes(FIXED64_SIZE);
return true; return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED: case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32()); skipRawBytes(readRawVarint32());
@ -2047,7 +2094,7 @@ public abstract class CodedInputStream {
case WireFormat.WIRETYPE_END_GROUP: case WireFormat.WIRETYPE_END_GROUP:
return false; return false;
case WireFormat.WIRETYPE_FIXED32: case WireFormat.WIRETYPE_FIXED32:
skipRawBytes(FIXED_32_SIZE); skipRawBytes(FIXED32_SIZE);
return true; return true;
default: default:
throw InvalidProtocolBufferException.invalidWireType(); throw InvalidProtocolBufferException.invalidWireType();
@ -2332,8 +2379,7 @@ public abstract class CodedInputStream {
if (size == 0) { if (size == 0) {
return ByteString.EMPTY; return ByteString.EMPTY;
} }
// Slow path: Build a byte array first then copy it. return readBytesSlowPath(size);
return ByteString.wrap(readRawBytesSlowPath(size));
} }
@Override @Override
@ -2558,13 +2604,13 @@ public abstract class CodedInputStream {
public int readRawLittleEndian32() throws IOException { public int readRawLittleEndian32() throws IOException {
int tempPos = pos; int tempPos = pos;
if (bufferSize - tempPos < FIXED_32_SIZE) { if (bufferSize - tempPos < FIXED32_SIZE) {
refillBuffer(FIXED_32_SIZE); refillBuffer(FIXED32_SIZE);
tempPos = pos; tempPos = pos;
} }
final byte[] buffer = this.buffer; final byte[] buffer = this.buffer;
pos = tempPos + FIXED_32_SIZE; pos = tempPos + FIXED32_SIZE;
return (((buffer[tempPos] & 0xff)) return (((buffer[tempPos] & 0xff))
| ((buffer[tempPos + 1] & 0xff) << 8) | ((buffer[tempPos + 1] & 0xff) << 8)
| ((buffer[tempPos + 2] & 0xff) << 16) | ((buffer[tempPos + 2] & 0xff) << 16)
@ -2575,13 +2621,13 @@ public abstract class CodedInputStream {
public long readRawLittleEndian64() throws IOException { public long readRawLittleEndian64() throws IOException {
int tempPos = pos; int tempPos = pos;
if (bufferSize - tempPos < FIXED_64_SIZE) { if (bufferSize - tempPos < FIXED64_SIZE) {
refillBuffer(FIXED_64_SIZE); refillBuffer(FIXED64_SIZE);
tempPos = pos; tempPos = pos;
} }
final byte[] buffer = this.buffer; final byte[] buffer = this.buffer;
pos = tempPos + FIXED_64_SIZE; pos = tempPos + FIXED64_SIZE;
return (((buffer[tempPos] & 0xffL)) return (((buffer[tempPos] & 0xffL))
| ((buffer[tempPos + 1] & 0xffL) << 8) | ((buffer[tempPos + 1] & 0xffL) << 8)
| ((buffer[tempPos + 2] & 0xffL) << 16) | ((buffer[tempPos + 2] & 0xffL) << 16)
@ -2675,7 +2721,13 @@ public abstract class CodedInputStream {
*/ */
private void refillBuffer(int n) throws IOException { private void refillBuffer(int n) throws IOException {
if (!tryRefillBuffer(n)) { if (!tryRefillBuffer(n)) {
throw InvalidProtocolBufferException.truncatedMessage(); // We have to distinguish the exception between sizeLimitExceeded and truncatedMessage. So
// we just throw an sizeLimitExceeded exception here if it exceeds the sizeLimit
if (n > sizeLimit - totalBytesRetired - pos) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
} else {
throw InvalidProtocolBufferException.truncatedMessage();
}
} }
} }
@ -2684,8 +2736,8 @@ public abstract class CodedInputStream {
* buffer. Caller must ensure that the requested space is not yet available, and that the * buffer. Caller must ensure that the requested space is not yet available, and that the
* requested space is less than BUFFER_SIZE. * requested space is less than BUFFER_SIZE.
* *
* @return {@code true} if the bytes could be made available; {@code false} if the end of the * @return {@code true} If the bytes could be made available; {@code false} 1. Current at the
* stream or the current limit was reached. * end of the stream 2. The current limit was reached 3. The total size limit was reached
*/ */
private boolean tryRefillBuffer(int n) throws IOException { private boolean tryRefillBuffer(int n) throws IOException {
if (pos + n <= bufferSize) { if (pos + n <= bufferSize) {
@ -2693,6 +2745,14 @@ public abstract class CodedInputStream {
"refillBuffer() called when " + n + " bytes were already available in buffer"); "refillBuffer() called when " + n + " bytes were already available in buffer");
} }
// Check whether the size of total message needs to read is bigger than the size limit.
// We shouldn't throw an exception here as isAtEnd() function needs to get this function's
// return as the result.
if (n > sizeLimit - totalBytesRetired - pos) {
return false;
}
// Shouldn't throw the exception here either.
if (totalBytesRetired + pos + n > currentLimit) { if (totalBytesRetired + pos + n > currentLimit) {
// Oops, we hit a limit. // Oops, we hit a limit.
return false; return false;
@ -2712,7 +2772,16 @@ public abstract class CodedInputStream {
pos = 0; pos = 0;
} }
int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize); // Here we should refill the buffer as many bytes as possible.
int bytesRead =
input.read(
buffer,
bufferSize,
Math.min(
// the size of allocated but unused bytes in the buffer
buffer.length - bufferSize,
// do not exceed the total bytes limit
sizeLimit - totalBytesRetired - bufferSize));
if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) { if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
throw new IllegalStateException( throw new IllegalStateException(
"InputStream#read(byte[]) returned invalid result: " "InputStream#read(byte[]) returned invalid result: "
@ -2721,10 +2790,6 @@ public abstract class CodedInputStream {
} }
if (bytesRead > 0) { if (bytesRead > 0) {
bufferSize += bytesRead; bufferSize += bytesRead;
// Integer-overflow-conscious check against sizeLimit
if (totalBytesRetired + n - sizeLimit > 0) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
}
recomputeBufferSizeAfterLimit(); recomputeBufferSizeAfterLimit();
return (bufferSize >= n) ? true : tryRefillBuffer(n); return (bufferSize >= n) ? true : tryRefillBuffer(n);
} }
@ -2756,6 +2821,49 @@ public abstract class CodedInputStream {
* (bufferSize - pos) && size > 0) * (bufferSize - pos) && size > 0)
*/ */
private byte[] readRawBytesSlowPath(final int size) throws IOException { private byte[] readRawBytesSlowPath(final int size) throws IOException {
// Attempt to read the data in one byte array when it's safe to do.
byte[] result = readRawBytesSlowPathOneChunk(size);
if (result != null) {
return result;
}
final int originalBufferPos = pos;
final int bufferedBytes = bufferSize - pos;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
pos = 0;
bufferSize = 0;
// Determine the number of bytes we need to read from the input stream.
int sizeLeft = size - bufferedBytes;
// The size is very large. For security reasons we read them in small
// chunks.
List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
// OK, got everything. Now concatenate it all into one buffer.
final byte[] bytes = new byte[size];
// Start by copying the leftover bytes from this.buffer.
System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
// And now all the chunks.
int tempPos = bufferedBytes;
for (final byte[] chunk : chunks) {
System.arraycopy(chunk, 0, bytes, tempPos, chunk.length);
tempPos += chunk.length;
}
// Done.
return bytes;
}
/**
* Attempts to read the data in one byte array when it's safe to do. Returns null if the size to
* read is too large and needs to be allocated in smaller chunks for security reasons.
*/
private byte[] readRawBytesSlowPathOneChunk(final int size) throws IOException {
if (size == 0) { if (size == 0) {
return Internal.EMPTY_BYTE_ARRAY; return Internal.EMPTY_BYTE_ARRAY;
} }
@ -2776,14 +2884,7 @@ public abstract class CodedInputStream {
throw InvalidProtocolBufferException.truncatedMessage(); throw InvalidProtocolBufferException.truncatedMessage();
} }
final int originalBufferPos = pos;
final int bufferedBytes = bufferSize - pos; final int bufferedBytes = bufferSize - pos;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
pos = 0;
bufferSize = 0;
// Determine the number of bytes we need to read from the input stream. // Determine the number of bytes we need to read from the input stream.
int sizeLeft = size - bufferedBytes; int sizeLeft = size - bufferedBytes;
// TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_SIZE. // TODO(nathanmittler): Consider using a value larger than DEFAULT_BUFFER_SIZE.
@ -2793,7 +2894,10 @@ public abstract class CodedInputStream {
final byte[] bytes = new byte[size]; final byte[] bytes = new byte[size];
// Copy all of the buffered bytes to the result buffer. // Copy all of the buffered bytes to the result buffer.
System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes); System.arraycopy(buffer, pos, bytes, 0, bufferedBytes);
totalBytesRetired += bufferSize;
pos = 0;
bufferSize = 0;
// Fill the remaining bytes from the input stream. // Fill the remaining bytes from the input stream.
int tempPos = bufferedBytes; int tempPos = bufferedBytes;
@ -2809,6 +2913,11 @@ public abstract class CodedInputStream {
return bytes; return bytes;
} }
return null;
}
/** Reads the remaining data in small chunks from the input stream. */
private List<byte[]> readRawBytesSlowPathRemainingChunks(int sizeLeft) throws IOException {
// The size is very large. For security reasons, we can't allocate the // The size is very large. For security reasons, we can't allocate the
// entire byte array yet. The size comes directly from the input, so a // entire byte array yet. The size comes directly from the input, so a
// maliciously-crafted message could provide a bogus very large size in // maliciously-crafted message could provide a bogus very large size in
@ -2834,21 +2943,41 @@ public abstract class CodedInputStream {
chunks.add(chunk); chunks.add(chunk);
} }
// OK, got everything. Now concatenate it all into one buffer. return chunks;
final byte[] bytes = new byte[size]; }
// Start by copying the leftover bytes from this.buffer.
System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
// And now all the chunks. /**
int tempPos = bufferedBytes; * Like readBytes, but caller must have already checked the fast path: (size <= (bufferSize -
for (final byte[] chunk : chunks) { * pos) && size > 0 || size == 0)
System.arraycopy(chunk, 0, bytes, tempPos, chunk.length); */
tempPos += chunk.length; private ByteString readBytesSlowPath(final int size) throws IOException {
final byte[] result = readRawBytesSlowPathOneChunk(size);
if (result != null) {
return ByteString.wrap(result);
} }
// Done. final int originalBufferPos = pos;
return bytes; final int bufferedBytes = bufferSize - pos;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
pos = 0;
bufferSize = 0;
// Determine the number of bytes we need to read from the input stream.
int sizeLeft = size - bufferedBytes;
// The size is very large. For security reasons we read them in small
// chunks.
List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
// Wrap the byte arrays into a single ByteString.
List<ByteString> byteStrings = new ArrayList<ByteString>(1 + chunks.size());
byteStrings.add(ByteString.copyFrom(buffer, originalBufferPos, bufferedBytes));
for (byte[] chunk : chunks) {
byteStrings.add(ByteString.wrap(chunk));
}
return ByteString.copyFrom(byteStrings);
} }
@Override @Override

@ -30,8 +30,8 @@
package com.google.protobuf; package com.google.protobuf;
import static com.google.protobuf.WireFormat.FIXED_32_SIZE; import static com.google.protobuf.WireFormat.FIXED32_SIZE;
import static com.google.protobuf.WireFormat.FIXED_64_SIZE; import static com.google.protobuf.WireFormat.FIXED64_SIZE;
import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE; import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
import static java.lang.Math.max; import static java.lang.Math.max;
@ -59,13 +59,12 @@ import java.util.logging.Logger;
public abstract class CodedOutputStream extends ByteOutput { public abstract class CodedOutputStream extends ByteOutput {
private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName()); private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations(); private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset();
/** /**
* @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
*/ */
@Deprecated @Deprecated
public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE; public static final int LITTLE_ENDIAN_32_SIZE = FIXED32_SIZE;
/** /**
* The buffer size used in {@link #newInstance(OutputStream)}. * The buffer size used in {@link #newInstance(OutputStream)}.
@ -755,7 +754,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code fixed32} field. * {@code fixed32} field.
*/ */
public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
return FIXED_32_SIZE; return FIXED32_SIZE;
} }
/** /**
@ -763,7 +762,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code sfixed32} field. * {@code sfixed32} field.
*/ */
public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) {
return FIXED_32_SIZE; return FIXED32_SIZE;
} }
/** /**
@ -813,7 +812,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code fixed64} field. * {@code fixed64} field.
*/ */
public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
return FIXED_64_SIZE; return FIXED64_SIZE;
} }
/** /**
@ -821,7 +820,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code sfixed64} field. * {@code sfixed64} field.
*/ */
public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) {
return FIXED_64_SIZE; return FIXED64_SIZE;
} }
/** /**
@ -829,7 +828,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code float} field, including tag. * {@code float} field, including tag.
*/ */
public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) { public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) {
return FIXED_32_SIZE; return FIXED32_SIZE;
} }
/** /**
@ -837,7 +836,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* {@code double} field, including tag. * {@code double} field, including tag.
*/ */
public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) { public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) {
return FIXED_64_SIZE; return FIXED64_SIZE;
} }
/** /**
@ -1321,15 +1320,12 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public final void writeUInt32NoTag(int value) throws IOException { public final void writeUInt32NoTag(int value) throws IOException {
if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
long pos = ARRAY_BASE_OFFSET + position;
while (true) { while (true) {
if ((value & ~0x7F) == 0) { if ((value & ~0x7F) == 0) {
UnsafeUtil.putByte(buffer, pos++, (byte) value); UnsafeUtil.putByte(buffer, position++, (byte) value);
position++;
return; return;
} else { } else {
UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
position++;
value >>>= 7; value >>>= 7;
} }
} }
@ -1367,15 +1363,12 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public final void writeUInt64NoTag(long value) throws IOException { public final void writeUInt64NoTag(long value) throws IOException {
if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) {
long pos = ARRAY_BASE_OFFSET + position;
while (true) { while (true) {
if ((value & ~0x7FL) == 0) { if ((value & ~0x7FL) == 0) {
UnsafeUtil.putByte(buffer, pos++, (byte) value); UnsafeUtil.putByte(buffer, position++, (byte) value);
position++;
return; return;
} else { } else {
UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
position++;
value >>>= 7; value >>>= 7;
} }
} }
@ -1854,7 +1847,7 @@ public abstract class CodedOutputStream extends ByteOutput {
} }
static boolean isSupported() { static boolean isSupported() {
return UnsafeUtil.hasUnsafeByteBufferOperations() && UnsafeUtil.hasUnsafeCopyMemory(); return UnsafeUtil.hasUnsafeByteBufferOperations();
} }
@Override @Override
@ -2030,7 +2023,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed32NoTag(int value) throws IOException { public void writeFixed32NoTag(int value) throws IOException {
buffer.putInt(bufferPos(position), value); buffer.putInt(bufferPos(position), value);
position += FIXED_32_SIZE; position += FIXED32_SIZE;
} }
@Override @Override
@ -2064,7 +2057,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed64NoTag(long value) throws IOException { public void writeFixed64NoTag(long value) throws IOException {
buffer.putLong(bufferPos(position), value); buffer.putLong(bufferPos(position), value);
position += FIXED_64_SIZE; position += FIXED64_SIZE;
} }
@Override @Override
@ -2081,8 +2074,7 @@ public abstract class CodedOutputStream extends ByteOutput {
String.format("Pos: %d, limit: %d, len: %d", position, limit, length)); String.format("Pos: %d, limit: %d, len: %d", position, limit, length));
} }
UnsafeUtil.copyMemory( UnsafeUtil.copyMemory(value, offset, position, length);
value, UnsafeUtil.getArrayBaseOffset() + offset, null, position, length);
position += length; position += length;
} }
@ -2249,19 +2241,17 @@ public abstract class CodedOutputStream extends ByteOutput {
*/ */
final void bufferUInt32NoTag(int value) { final void bufferUInt32NoTag(int value) {
if (HAS_UNSAFE_ARRAY_OPERATIONS) { if (HAS_UNSAFE_ARRAY_OPERATIONS) {
final long originalPos = ARRAY_BASE_OFFSET + position; final long originalPos = position;
long pos = originalPos;
while (true) { while (true) {
if ((value & ~0x7F) == 0) { if ((value & ~0x7F) == 0) {
UnsafeUtil.putByte(buffer, pos++, (byte) value); UnsafeUtil.putByte(buffer, position++, (byte) value);
break; break;
} else { } else {
UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
value >>>= 7; value >>>= 7;
} }
} }
int delta = (int) (pos - originalPos); int delta = (int) (position - originalPos);
position += delta;
totalBytesWritten += delta; totalBytesWritten += delta;
} else { } else {
while (true) { while (true) {
@ -2284,19 +2274,17 @@ public abstract class CodedOutputStream extends ByteOutput {
*/ */
final void bufferUInt64NoTag(long value) { final void bufferUInt64NoTag(long value) {
if (HAS_UNSAFE_ARRAY_OPERATIONS) { if (HAS_UNSAFE_ARRAY_OPERATIONS) {
final long originalPos = ARRAY_BASE_OFFSET + position; final long originalPos = position;
long pos = originalPos;
while (true) { while (true) {
if ((value & ~0x7FL) == 0) { if ((value & ~0x7FL) == 0) {
UnsafeUtil.putByte(buffer, pos++, (byte) value); UnsafeUtil.putByte(buffer, position++, (byte) value);
break; break;
} else { } else {
UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); UnsafeUtil.putByte(buffer, position++, (byte) (((int) value & 0x7F) | 0x80));
value >>>= 7; value >>>= 7;
} }
} }
int delta = (int) (pos - originalPos); int delta = (int) (position - originalPos);
position += delta;
totalBytesWritten += delta; totalBytesWritten += delta;
} else { } else {
while (true) { while (true) {
@ -2322,7 +2310,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) ((value >> 8) & 0xFF); buffer[position++] = (byte) ((value >> 8) & 0xFF);
buffer[position++] = (byte) ((value >> 16) & 0xFF); buffer[position++] = (byte) ((value >> 16) & 0xFF);
buffer[position++] = (byte) ((value >> 24) & 0xFF); buffer[position++] = (byte) ((value >> 24) & 0xFF);
totalBytesWritten += FIXED_32_SIZE; totalBytesWritten += FIXED32_SIZE;
} }
/** /**
@ -2338,7 +2326,7 @@ public abstract class CodedOutputStream extends ByteOutput {
buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); buffer[position++] = (byte) ((int) (value >> 40) & 0xFF);
buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); buffer[position++] = (byte) ((int) (value >> 48) & 0xFF);
buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
totalBytesWritten += FIXED_64_SIZE; totalBytesWritten += FIXED64_SIZE;
} }
} }
@ -2379,7 +2367,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed32(final int fieldNumber, final int value) throws IOException { public void writeFixed32(final int fieldNumber, final int value) throws IOException {
flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE); flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
bufferFixed32NoTag(value); bufferFixed32NoTag(value);
} }
@ -2393,7 +2381,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed64(final int fieldNumber, final long value) throws IOException { public void writeFixed64(final int fieldNumber, final long value) throws IOException {
flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE); flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
bufferFixed64NoTag(value); bufferFixed64NoTag(value);
} }
@ -2519,7 +2507,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed32NoTag(final int value) throws IOException { public void writeFixed32NoTag(final int value) throws IOException {
flushIfNotAvailable(FIXED_32_SIZE); flushIfNotAvailable(FIXED32_SIZE);
bufferFixed32NoTag(value); bufferFixed32NoTag(value);
} }
@ -2531,7 +2519,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed64NoTag(final long value) throws IOException { public void writeFixed64NoTag(final long value) throws IOException {
flushIfNotAvailable(FIXED_64_SIZE); flushIfNotAvailable(FIXED64_SIZE);
bufferFixed64NoTag(value); bufferFixed64NoTag(value);
} }
@ -2682,7 +2670,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed32(final int fieldNumber, final int value) throws IOException { public void writeFixed32(final int fieldNumber, final int value) throws IOException {
flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE); flushIfNotAvailable(MAX_VARINT_SIZE + FIXED32_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
bufferFixed32NoTag(value); bufferFixed32NoTag(value);
} }
@ -2696,7 +2684,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed64(final int fieldNumber, final long value) throws IOException { public void writeFixed64(final int fieldNumber, final long value) throws IOException {
flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE); flushIfNotAvailable(MAX_VARINT_SIZE + FIXED64_SIZE);
bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
bufferFixed64NoTag(value); bufferFixed64NoTag(value);
} }
@ -2822,7 +2810,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed32NoTag(final int value) throws IOException { public void writeFixed32NoTag(final int value) throws IOException {
flushIfNotAvailable(FIXED_32_SIZE); flushIfNotAvailable(FIXED32_SIZE);
bufferFixed32NoTag(value); bufferFixed32NoTag(value);
} }
@ -2834,7 +2822,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override @Override
public void writeFixed64NoTag(final long value) throws IOException { public void writeFixed64NoTag(final long value) throws IOException {
flushIfNotAvailable(FIXED_64_SIZE); flushIfNotAvailable(FIXED64_SIZE);
bufferFixed64NoTag(value); bufferFixed64NoTag(value);
} }

@ -0,0 +1,71 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Parsers to discard unknown fields during parsing.
*/
public final class DiscardUnknownFieldsParser {
/**
* Warps a given {@link Parser} into a new {@link Parser} that discards unknown fields during
* parsing.
*
* <p>Usage example:
* <pre>{@code
* private final static Parser<Foo> FOO_PARSER = DiscardUnknownFieldsParser.wrap(Foo.parser());
* Foo parseFooDiscardUnknown(ByteBuffer input) throws IOException {
* return FOO_PARSER.parseFrom(input);
* }
* }</pre>
*
* <p>Like all other implementations of {@code Parser}, this parser is stateless and thread-safe.
*
* @param parser The delegated parser that parses messages.
* @return a {@link Parser} that will discard unknown fields during parsing.
*/
public static final <T extends Message> Parser<T> wrap(final Parser<T> parser) {
return new AbstractParser<T>() {
@Override
public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
input.discardUnknownFields();
return parser.parsePartialFrom(input, extensionRegistry);
} finally {
input.unsetDiscardUnknownFields();
}
}
};
}
private DiscardUnknownFieldsParser() {}
}

@ -590,9 +590,8 @@ public final class DynamicMessage extends AbstractMessage {
@Override @Override
public Builder setUnknownFields(UnknownFieldSet unknownFields) { public Builder setUnknownFields(UnknownFieldSet unknownFields) {
if (getDescriptorForType().getFile().getSyntax() if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
== Descriptors.FileDescriptor.Syntax.PROTO3) { && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
// Proto3 discards unknown fields.
return this; return this;
} }
this.unknownFields = unknownFields; this.unknownFields = unknownFields;
@ -601,9 +600,8 @@ public final class DynamicMessage extends AbstractMessage {
@Override @Override
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) { public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
if (getDescriptorForType().getFile().getSyntax() if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
== Descriptors.FileDescriptor.Syntax.PROTO3) { && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
// Proto3 discards unknown fields.
return this; return this;
} }
this.unknownFields = this.unknownFields =

@ -58,10 +58,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
PROTO1, PROTO1,
} }
protected ExtensionType getExtensionType() { protected abstract ExtensionType getExtensionType();
// TODO(liujisi): make this abstract after we fix proto1.
return ExtensionType.IMMUTABLE;
}
/** /**
* Type of a message extension. * Type of a message extension.
@ -70,7 +67,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
PROTO1, PROTO1,
PROTO2, PROTO2,
} }
/** /**
* If the extension is a message extension (i.e., getLiteType() == MESSAGE), * If the extension is a message extension (i.e., getLiteType() == MESSAGE),
* returns the type of the message, otherwise undefined. * returns the type of the message, otherwise undefined.

@ -34,7 +34,7 @@ import static com.google.protobuf.ExtensionRegistryLite.EMPTY_REGISTRY_LITE;
/** /**
* A factory object to create instances of {@link ExtensionRegistryLite}. * A factory object to create instances of {@link ExtensionRegistryLite}.
* *
* <p> * <p>
* This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries * This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries
* are available, and if so, the instances returned are actually {@link ExtensionRegistry}. * are available, and if so, the instances returned are actually {@link ExtensionRegistry}.
@ -82,6 +82,7 @@ final class ExtensionRegistryFactory {
return EMPTY_REGISTRY_LITE; return EMPTY_REGISTRY_LITE;
} }
static boolean isFullRegistry(ExtensionRegistryLite registry) { static boolean isFullRegistry(ExtensionRegistryLite registry) {
return EXTENSION_REGISTRY_CLASS != null return EXTENSION_REGISTRY_CLASS != null
&& EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass()); && EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass());
@ -90,6 +91,6 @@ final class ExtensionRegistryFactory {
private static final ExtensionRegistryLite invokeSubclassFactory(String methodName) private static final ExtensionRegistryLite invokeSubclassFactory(String methodName)
throws Exception { throws Exception {
return (ExtensionRegistryLite) EXTENSION_REGISTRY_CLASS return (ExtensionRegistryLite) EXTENSION_REGISTRY_CLASS
.getMethod(methodName).invoke(null); .getDeclaredMethod(methodName).invoke(null);
} }
} }

@ -107,11 +107,12 @@ public abstract class GeneratedMessageLite<
@SuppressWarnings("unchecked") // Guaranteed by runtime @SuppressWarnings("unchecked") // Guaranteed by runtime
@Override @Override
public int hashCode() { public int hashCode() {
if (memoizedHashCode == 0) { if (memoizedHashCode != 0) {
HashCodeVisitor visitor = new HashCodeVisitor(); return memoizedHashCode;
visit(visitor, (MessageType) this);
memoizedHashCode = visitor.hashCode;
} }
HashCodeVisitor visitor = new HashCodeVisitor();
visit(visitor, (MessageType) this);
memoizedHashCode = visitor.hashCode;
return memoizedHashCode; return memoizedHashCode;
} }
@ -331,7 +332,7 @@ public abstract class GeneratedMessageLite<
if (isBuilt) { if (isBuilt) {
MessageType newInstance = MessageType newInstance =
(MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
newInstance.visit(MergeFromVisitor.INSTANCE, instance); mergeFromInstance(newInstance, instance);
instance = newInstance; instance = newInstance;
isBuilt = false; isBuilt = false;
} }
@ -386,10 +387,14 @@ public abstract class GeneratedMessageLite<
/** All subclasses implement this. */ /** All subclasses implement this. */
public BuilderType mergeFrom(MessageType message) { public BuilderType mergeFrom(MessageType message) {
copyOnWrite(); copyOnWrite();
instance.visit(MergeFromVisitor.INSTANCE, message); mergeFromInstance(instance, message);
return (BuilderType) this; return (BuilderType) this;
} }
private void mergeFromInstance(MessageType dest, MessageType src) {
dest.visit(MergeFromVisitor.INSTANCE, src);
}
@Override @Override
public MessageType getDefaultInstanceForType() { public MessageType getDefaultInstanceForType() {
return defaultInstance; return defaultInstance;
@ -1713,7 +1718,6 @@ public abstract class GeneratedMessageLite<
Object visitOneofLong(boolean minePresent, Object mine, Object other); Object visitOneofLong(boolean minePresent, Object mine, Object other);
Object visitOneofString(boolean minePresent, Object mine, Object other); Object visitOneofString(boolean minePresent, Object mine, Object other);
Object visitOneofByteString(boolean minePresent, Object mine, Object other); Object visitOneofByteString(boolean minePresent, Object mine, Object other);
Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other);
Object visitOneofMessage(boolean minePresent, Object mine, Object other); Object visitOneofMessage(boolean minePresent, Object mine, Object other);
void visitOneofNotSet(boolean minePresent); void visitOneofNotSet(boolean minePresent);
@ -1721,7 +1725,6 @@ public abstract class GeneratedMessageLite<
* Message fields use null sentinals. * Message fields use null sentinals.
*/ */
<T extends MessageLite> T visitMessage(T mine, T other); <T extends MessageLite> T visitMessage(T mine, T other);
LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other);
<T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other); <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
BooleanList visitBooleanList(BooleanList mine, BooleanList other); BooleanList visitBooleanList(BooleanList mine, BooleanList other);
@ -1864,14 +1867,6 @@ public abstract class GeneratedMessageLite<
throw NOT_EQUALS; throw NOT_EQUALS;
} }
@Override
public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
if (minePresent && mine.equals(other)) {
return mine;
}
throw NOT_EQUALS;
}
@Override @Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) { if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) {
@ -1902,21 +1897,6 @@ public abstract class GeneratedMessageLite<
return mine; return mine;
} }
@Override
public LazyFieldLite visitLazyMessage(
LazyFieldLite mine, LazyFieldLite other) {
if (mine == null && other == null) {
return null;
}
if (mine == null || other == null) {
throw NOT_EQUALS;
}
if (mine.equals(other)) {
return mine;
}
throw NOT_EQUALS;
}
@Override @Override
public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) { public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
if (!mine.equals(other)) { if (!mine.equals(other)) {
@ -2093,12 +2073,6 @@ public abstract class GeneratedMessageLite<
return mine; return mine;
} }
@Override
public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
hashCode = (53 * hashCode) + mine.hashCode();
return mine;
}
@Override @Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
return visitMessage((MessageLite) mine, (MessageLite) other); return visitMessage((MessageLite) mine, (MessageLite) other);
@ -2127,18 +2101,6 @@ public abstract class GeneratedMessageLite<
return mine; return mine;
} }
@Override
public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
final int protoHash;
if (mine != null) {
protoHash = mine.hashCode();
} else {
protoHash = 37;
}
hashCode = (53 * hashCode) + protoHash;
return mine;
}
@Override @Override
public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) { public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
hashCode = (53 * hashCode) + mine.hashCode(); hashCode = (53 * hashCode) + mine.hashCode();
@ -2281,13 +2243,6 @@ public abstract class GeneratedMessageLite<
return other; return other;
} }
@Override
public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
LazyFieldLite lazy = minePresent ? (LazyFieldLite) mine : new LazyFieldLite();
lazy.merge((LazyFieldLite) other);
return lazy;
}
@Override @Override
public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
if (minePresent) { if (minePresent) {
@ -2311,17 +2266,6 @@ public abstract class GeneratedMessageLite<
return mine != null ? mine : other; return mine != null ? mine : other;
} }
@Override
public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
if (other != null) {
if (mine == null) {
mine = new LazyFieldLite();
}
mine.merge(other);
}
return mine;
}
@Override @Override
public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) { public <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other) {
int size = mine.size(); int size = mine.size();

@ -30,6 +30,8 @@
package com.google.protobuf; package com.google.protobuf;
import static com.google.protobuf.Internal.checkNotNull;
import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumDescriptor; import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.EnumValueDescriptor;
@ -47,7 +49,6 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
// to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in // to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in
// this file is also excluded from opensource to avoid conflict. // this file is also excluded from opensource to avoid conflict.
import com.google.protobuf.GeneratedMessage.GeneratedExtension; import com.google.protobuf.GeneratedMessage.GeneratedExtension;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectStreamException; import java.io.ObjectStreamException;
@ -277,13 +278,30 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
/** /**
* Called by subclasses to parse an unknown field. * Called by subclasses to parse an unknown field.
*
* @return {@code true} unless the tag is an end-group tag. * @return {@code true} unless the tag is an end-group tag.
*/ */
protected boolean parseUnknownField( protected boolean parseUnknownField(
CodedInputStream input, CodedInputStream input,
UnknownFieldSet.Builder unknownFields, UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry, ExtensionRegistryLite extensionRegistry,
int tag) throws IOException { int tag)
throws IOException {
if (input.shouldDiscardUnknownFields()) {
return input.skipField(tag);
}
return unknownFields.mergeFieldFrom(tag, input);
}
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 unknownFields.mergeFieldFrom(tag, input);
} }
@ -619,15 +637,22 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return (BuilderType) this; return (BuilderType) this;
} }
protected BuilderType setUnknownFieldsProto3(final UnknownFieldSet unknownFields) {
if (CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
return (BuilderType) this;
}
this.unknownFields = unknownFields;
onChanged();
return (BuilderType) this;
}
@Override @Override
public BuilderType mergeUnknownFields( public BuilderType mergeUnknownFields(
final UnknownFieldSet unknownFields) { final UnknownFieldSet unknownFields) {
this.unknownFields = return setUnknownFields(
UnknownFieldSet.newBuilder(this.unknownFields) UnknownFieldSet.newBuilder(this.unknownFields)
.mergeFrom(unknownFields) .mergeFrom(unknownFields)
.build(); .build());
onChanged();
return (BuilderType) this;
} }
@Override @Override
@ -665,18 +690,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return unknownFields; return unknownFields;
} }
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
final CodedInputStream input,
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
return unknownFields.mergeFieldFrom(tag, input);
}
/** /**
* Implementation of {@link BuilderParent} for giving to our children. This * Implementation of {@link BuilderParent} for giving to our children. This
* small inner class makes it so we don't publicly expose the BuilderParent * small inner class makes it so we don't publicly expose the BuilderParent
@ -987,8 +1000,23 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
ExtensionRegistryLite extensionRegistry, ExtensionRegistryLite extensionRegistry,
int tag) throws IOException { int tag) throws IOException {
return MessageReflection.mergeFieldFrom( return MessageReflection.mergeFieldFrom(
input, unknownFields, extensionRegistry, getDescriptorForType(), input, input.shouldDiscardUnknownFields() ? null : unknownFields, extensionRegistry,
new MessageReflection.ExtensionAdapter(extensions), tag); getDescriptorForType(), new MessageReflection.ExtensionAdapter(extensions), tag);
}
@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);
} }
@ -1458,21 +1486,6 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return super.isInitialized() && extensionsAreInitialized(); return super.isInitialized() && extensionsAreInitialized();
} }
/**
* Called by subclasses to parse an unknown field or an extension.
* @return {@code true} unless the tag is an end-group tag.
*/
@Override
protected boolean parseUnknownField(
final CodedInputStream input,
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
return MessageReflection.mergeFieldFrom(
input, unknownFields, extensionRegistry, getDescriptorForType(),
new MessageReflection.BuilderAdapter(this), tag);
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Reflection // Reflection
@ -2277,7 +2290,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
public Object getRepeatedRaw(Builder builder, int index) { public Object getRepeatedRaw(Builder builder, int index) {
return getRepeated(builder, index); return getRepeated(builder, index);
} }
@Override @Override
public void setRepeated(Builder builder, int index, Object value) { public void setRepeated(Builder builder, int index, Object value) {
getMutableMapField(builder).getMutableList().set(index, coerceType((Message) value)); getMutableMapField(builder).getMutableList().set(index, coerceType((Message) value));
@ -2678,7 +2691,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return (Extension<MessageType, T>) extension; return (Extension<MessageType, T>) extension;
} }
protected static int computeStringSize(final int fieldNumber, final Object value) { protected static int computeStringSize(final int fieldNumber, final Object value) {
if (value instanceof String) { if (value instanceof String) {
return CodedOutputStream.computeStringSize(fieldNumber, (String) value); return CodedOutputStream.computeStringSize(fieldNumber, (String) value);
@ -2686,7 +2699,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value); return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value);
} }
} }
protected static int computeStringSizeNoTag(final Object value) { protected static int computeStringSizeNoTag(final Object value) {
if (value instanceof String) { if (value instanceof String) {
return CodedOutputStream.computeStringSizeNoTag((String) value); return CodedOutputStream.computeStringSizeNoTag((String) value);
@ -2694,7 +2707,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
return CodedOutputStream.computeBytesSizeNoTag((ByteString) value); return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
} }
} }
protected static void writeString( protected static void writeString(
CodedOutputStream output, final int fieldNumber, final Object value) throws IOException { CodedOutputStream output, final int fieldNumber, final Object value) throws IOException {
if (value instanceof String) { if (value instanceof String) {
@ -2703,7 +2716,7 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
output.writeBytes(fieldNumber, (ByteString) value); output.writeBytes(fieldNumber, (ByteString) value);
} }
} }
protected static void writeStringNoTag( protected static void writeStringNoTag(
CodedOutputStream output, final Object value) throws IOException { CodedOutputStream output, final Object value) throws IOException {
if (value instanceof String) { if (value instanceof String) {

@ -414,9 +414,8 @@ public final class Internal {
} }
} }
/**
* An empty byte array constant used in generated code. /** An empty byte array constant used in generated code. */
*/
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/** /**

@ -50,6 +50,10 @@ public class InvalidProtocolBufferException extends IOException {
super(e.getMessage(), e); super(e.getMessage(), e);
} }
public InvalidProtocolBufferException(final String description, IOException e) {
super(description, e);
}
/** /**
* Attaches an unfinished message to the exception to support best-effort * Attaches an unfinished message to the exception to support best-effort
* parsing in {@code Parser} interface. * parsing in {@code Parser} interface.

@ -31,7 +31,6 @@
package com.google.protobuf; package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -714,12 +713,14 @@ class MessageReflection {
} }
/** /**
* Parses a single field into MergeTarget. The target can be Message.Builder, * Parses a single field into MergeTarget. The target can be Message.Builder, FieldSet or
* FieldSet or MutableMessage. * MutableMessage.
* *
* Package-private because it is used by GeneratedMessage.ExtendableMessage. * <p>Package-private because it is used by GeneratedMessage.ExtendableMessage.
* *
* @param tag The tag, which should have already been read. * @param tag The tag, which should have already been read.
* @param unknownFields If not null, unknown fields will be merged to this {@link
* UnknownFieldSet}, otherwise unknown fields will be discarded.
* @return {@code true} unless the tag is an end-group tag. * @return {@code true} unless the tag is an end-group tag.
*/ */
static boolean mergeFieldFrom( static boolean mergeFieldFrom(
@ -728,7 +729,8 @@ class MessageReflection {
ExtensionRegistryLite extensionRegistry, ExtensionRegistryLite extensionRegistry,
Descriptors.Descriptor type, Descriptors.Descriptor type,
MergeTarget target, MergeTarget target,
int tag) throws IOException { int tag)
throws IOException {
if (type.getOptions().getMessageSetWireFormat() && if (type.getOptions().getMessageSetWireFormat() &&
tag == WireFormat.MESSAGE_SET_ITEM_TAG) { tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream( mergeMessageSetExtensionFromCodedStream(
@ -792,7 +794,11 @@ class MessageReflection {
} }
if (unknown) { // Unknown field or wrong wire type. Skip. if (unknown) { // Unknown field or wrong wire type. Skip.
return unknownFields.mergeFieldFrom(tag, input); if (unknownFields != null) {
return unknownFields.mergeFieldFrom(tag, input);
} else {
return input.skipField(tag);
}
} }
if (packed) { if (packed) {
@ -844,7 +850,9 @@ class MessageReflection {
// If the number isn't recognized as a valid value for this enum, // If the number isn't recognized as a valid value for this enum,
// drop it. // drop it.
if (value == null) { if (value == null) {
unknownFields.mergeVarintField(fieldNumber, rawValue); if (unknownFields != null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
}
return true; return true;
} }
} }
@ -947,7 +955,7 @@ class MessageReflection {
mergeMessageSetExtensionFromBytes( mergeMessageSetExtensionFromBytes(
rawBytes, extension, extensionRegistry, target); rawBytes, extension, extensionRegistry, target);
} else { // We don't know how to parse this. Ignore it. } else { // We don't know how to parse this. Ignore it.
if (rawBytes != null) { if (rawBytes != null && unknownFields != null) {
unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder() unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(rawBytes).build()); .addLengthDelimited(rawBytes).build());
} }

@ -34,7 +34,6 @@ import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumDescriptor; import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.CharBuffer; import java.nio.CharBuffer;
@ -56,14 +55,7 @@ import java.util.regex.Pattern;
public final class TextFormat { public final class TextFormat {
private TextFormat() {} private TextFormat() {}
private static final Logger logger = private static final Logger logger = Logger.getLogger(TextFormat.class.getName());
Logger.getLogger(TextFormat.class.getName());
private static final Printer DEFAULT_PRINTER = new Printer();
private static final Printer SINGLE_LINE_PRINTER =
(new Printer()).setSingleLineMode(true);
private static final Printer UNICODE_PRINTER =
(new Printer()).setEscapeNonAscii(false);
/** /**
* Outputs a textual representation of the Protocol Message supplied into * Outputs a textual representation of the Protocol Message supplied into
@ -73,14 +65,14 @@ public final class TextFormat {
public static void print( public static void print(
final MessageOrBuilder message, final Appendable output) final MessageOrBuilder message, final Appendable output)
throws IOException { throws IOException {
DEFAULT_PRINTER.print(message, new TextGenerator(output)); Printer.DEFAULT.print(message, multiLineOutput(output));
} }
/** Outputs a textual representation of {@code fields} to {@code output}. */ /** Outputs a textual representation of {@code fields} to {@code output}. */
public static void print(final UnknownFieldSet fields, public static void print(final UnknownFieldSet fields,
final Appendable output) final Appendable output)
throws IOException { throws IOException {
DEFAULT_PRINTER.printUnknownFields(fields, new TextGenerator(output)); Printer.DEFAULT.printUnknownFields(fields, multiLineOutput(output));
} }
/** /**
@ -90,7 +82,7 @@ public final class TextFormat {
public static void printUnicode( public static void printUnicode(
final MessageOrBuilder message, final Appendable output) final MessageOrBuilder message, final Appendable output)
throws IOException { throws IOException {
UNICODE_PRINTER.print(message, new TextGenerator(output)); Printer.UNICODE.print(message, multiLineOutput(output));
} }
/** /**
@ -100,7 +92,7 @@ public final class TextFormat {
public static void printUnicode(final UnknownFieldSet fields, public static void printUnicode(final UnknownFieldSet fields,
final Appendable output) final Appendable output)
throws IOException { throws IOException {
UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output)); Printer.UNICODE.printUnknownFields(fields, multiLineOutput(output));
} }
/** /**
@ -109,10 +101,9 @@ public final class TextFormat {
*/ */
public static String shortDebugString(final MessageOrBuilder message) { public static String shortDebugString(final MessageOrBuilder message) {
try { try {
final StringBuilder sb = new StringBuilder(); final StringBuilder text = new StringBuilder();
SINGLE_LINE_PRINTER.print(message, new TextGenerator(sb)); Printer.DEFAULT.print(message, singleLineOutput(text));
// Single line mode currently might have an extra space at the end. return text.toString();
return sb.toString().trim();
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
@ -125,11 +116,11 @@ public final class TextFormat {
public static String shortDebugString(final FieldDescriptor field, public static String shortDebugString(final FieldDescriptor field,
final Object value) { final Object value) {
try { try {
final StringBuilder sb = new StringBuilder(); final StringBuilder text = new StringBuilder();
SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb)); Printer.DEFAULT.printField(field, value, singleLineOutput(text));
return sb.toString().trim(); return text.toString();
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
} }
@ -139,10 +130,9 @@ public final class TextFormat {
*/ */
public static String shortDebugString(final UnknownFieldSet fields) { public static String shortDebugString(final UnknownFieldSet fields) {
try { try {
final StringBuilder sb = new StringBuilder(); final StringBuilder text = new StringBuilder();
SINGLE_LINE_PRINTER.printUnknownFields(fields, new TextGenerator(sb)); Printer.DEFAULT.printUnknownFields(fields, singleLineOutput(text));
// Single line mode currently might have an extra space at the end. return text.toString();
return sb.toString().trim();
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
@ -183,7 +173,7 @@ public final class TextFormat {
public static String printToUnicodeString(final MessageOrBuilder message) { public static String printToUnicodeString(final MessageOrBuilder message) {
try { try {
final StringBuilder text = new StringBuilder(); final StringBuilder text = new StringBuilder();
UNICODE_PRINTER.print(message, new TextGenerator(text)); Printer.UNICODE.print(message, multiLineOutput(text));
return text.toString(); return text.toString();
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
@ -197,7 +187,7 @@ public final class TextFormat {
public static String printToUnicodeString(final UnknownFieldSet fields) { public static String printToUnicodeString(final UnknownFieldSet fields) {
try { try {
final StringBuilder text = new StringBuilder(); final StringBuilder text = new StringBuilder();
UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(text)); Printer.UNICODE.printUnknownFields(fields, multiLineOutput(text));
return text.toString(); return text.toString();
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
@ -208,7 +198,7 @@ public final class TextFormat {
final Object value, final Object value,
final Appendable output) final Appendable output)
throws IOException { throws IOException {
DEFAULT_PRINTER.printField(field, value, new TextGenerator(output)); Printer.DEFAULT.printField(field, value, multiLineOutput(output));
} }
public static String printFieldToString(final FieldDescriptor field, public static String printFieldToString(final FieldDescriptor field,
@ -222,6 +212,23 @@ public final class TextFormat {
} }
} }
/**
* Outputs a unicode textual representation of the value of given field value.
*
* <p>Same as {@code printFieldValue()}, except that non-ASCII characters in string type fields
* are not escaped in backslash+octals.
*
* @param field the descriptor of the field
* @param value the value of the field
* @param output the output to which to append the formatted value
* @throws ClassCastException if the value is not appropriate for the given field descriptor
* @throws IOException if there is an exception writing to the output
*/
public static void printUnicodeFieldValue(
final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
Printer.UNICODE.printFieldValue(field, value, multiLineOutput(output));
}
/** /**
* Outputs a textual representation of the value of given field value. * Outputs a textual representation of the value of given field value.
* *
@ -236,7 +243,7 @@ public final class TextFormat {
final Object value, final Object value,
final Appendable output) final Appendable output)
throws IOException { throws IOException {
DEFAULT_PRINTER.printFieldValue(field, value, new TextGenerator(output)); Printer.DEFAULT.printFieldValue(field, value, multiLineOutput(output));
} }
/** /**
@ -253,7 +260,7 @@ public final class TextFormat {
final Object value, final Object value,
final Appendable output) final Appendable output)
throws IOException { throws IOException {
printUnknownFieldValue(tag, value, new TextGenerator(output)); printUnknownFieldValue(tag, value, multiLineOutput(output));
} }
private static void printUnknownFieldValue(final int tag, private static void printUnknownFieldValue(final int tag,
@ -277,7 +284,7 @@ public final class TextFormat {
generator.print("\""); generator.print("\"");
break; break;
case WireFormat.WIRETYPE_START_GROUP: case WireFormat.WIRETYPE_START_GROUP:
DEFAULT_PRINTER.printUnknownFields((UnknownFieldSet) value, generator); Printer.DEFAULT.printUnknownFields((UnknownFieldSet) value, generator);
break; break;
default: default:
throw new IllegalArgumentException("Bad tag: " + tag); throw new IllegalArgumentException("Bad tag: " + tag);
@ -286,24 +293,16 @@ public final class TextFormat {
/** Helper class for converting protobufs to text. */ /** Helper class for converting protobufs to text. */
private static final class Printer { private static final class Printer {
/** Whether to omit newlines from the output. */ // Printer instance which escapes non-ASCII characters.
boolean singleLineMode = false; static final Printer DEFAULT = new Printer(true);
// Printer instance which emits Unicode (it still escapes newlines and quotes in strings).
static final Printer UNICODE = new Printer(false);
/** Whether to escape non ASCII characters with backslash and octal. */ /** Whether to escape non ASCII characters with backslash and octal. */
boolean escapeNonAscii = true; private final boolean escapeNonAscii;
private Printer() {}
/** Setter of singleLineMode */ private Printer(boolean escapeNonAscii) {
private Printer setSingleLineMode(boolean singleLineMode) {
this.singleLineMode = singleLineMode;
return this;
}
/** Setter of escapeNonAscii */
private Printer setEscapeNonAscii(boolean escapeNonAscii) {
this.escapeNonAscii = escapeNonAscii; this.escapeNonAscii = escapeNonAscii;
return this;
} }
private void print( private void print(
@ -355,12 +354,9 @@ public final class TextFormat {
} }
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (singleLineMode) { generator.print(" {");
generator.print(" { "); generator.eol();
} else { generator.indent();
generator.print(" {\n");
generator.indent();
}
} else { } else {
generator.print(": "); generator.print(": ");
} }
@ -368,19 +364,10 @@ public final class TextFormat {
printFieldValue(field, value, generator); printFieldValue(field, value, generator);
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (singleLineMode) { generator.outdent();
generator.print("} "); generator.print("}");
} else {
generator.outdent();
generator.print("}\n");
}
} else {
if (singleLineMode) {
generator.print(" ");
} else {
generator.print("\n");
}
} }
generator.eol();
} }
private void printFieldValue(final FieldDescriptor field, private void printFieldValue(final FieldDescriptor field,
@ -469,19 +456,13 @@ public final class TextFormat {
field.getLengthDelimitedList(), generator); field.getLengthDelimitedList(), generator);
for (final UnknownFieldSet value : field.getGroupList()) { for (final UnknownFieldSet value : field.getGroupList()) {
generator.print(entry.getKey().toString()); generator.print(entry.getKey().toString());
if (singleLineMode) { generator.print(" {");
generator.print(" { "); generator.eol();
} else { generator.indent();
generator.print(" {\n");
generator.indent();
}
printUnknownFields(value, generator); printUnknownFields(value, generator);
if (singleLineMode) { generator.outdent();
generator.print("} "); generator.print("}");
} else { generator.eol();
generator.outdent();
generator.print("}\n");
}
} }
} }
} }
@ -495,7 +476,7 @@ public final class TextFormat {
generator.print(String.valueOf(number)); generator.print(String.valueOf(number));
generator.print(": "); generator.print(": ");
printUnknownFieldValue(wireType, value, generator); printUnknownFieldValue(wireType, value, generator);
generator.print(singleLineMode ? " " : "\n"); generator.eol();
} }
} }
} }
@ -521,16 +502,29 @@ public final class TextFormat {
} }
} }
/** private static TextGenerator multiLineOutput(Appendable output) {
return new TextGenerator(output, false);
}
private static TextGenerator singleLineOutput(Appendable output) {
return new TextGenerator(output, true);
}
/**
* An inner class for writing text to the output stream. * An inner class for writing text to the output stream.
*/ */
private static final class TextGenerator { private static final class TextGenerator {
private final Appendable output; private final Appendable output;
private final StringBuilder indent = new StringBuilder(); private final StringBuilder indent = new StringBuilder();
private boolean atStartOfLine = true; private final boolean singleLineMode;
// While technically we are "at the start of a line" at the very beginning of the output, all
// we would do in response to this is emit the (zero length) indentation, so it has no effect.
// Setting it false here does however suppress an unwanted leading space in single-line mode.
private boolean atStartOfLine = false;
private TextGenerator(final Appendable output) { private TextGenerator(final Appendable output, boolean singleLineMode) {
this.output = output; this.output = output;
this.singleLineMode = singleLineMode;
} }
/** /**
@ -552,35 +546,31 @@ public final class TextFormat {
throw new IllegalArgumentException( throw new IllegalArgumentException(
" Outdent() without matching Indent()."); " Outdent() without matching Indent().");
} }
indent.delete(length - 2, length); indent.setLength(length - 2);
} }
/** /**
* Print text to the output stream. * Print text to the output stream. Bare newlines are never expected to be passed to this
* method; to indicate the end of a line, call "eol()".
*/ */
public void print(final CharSequence text) throws IOException { public void print(final CharSequence text) throws IOException {
final int size = text.length(); if (atStartOfLine) {
int pos = 0; atStartOfLine = false;
output.append(singleLineMode ? " " : indent);
for (int i = 0; i < size; i++) {
if (text.charAt(i) == '\n') {
write(text.subSequence(pos, i + 1));
pos = i + 1;
atStartOfLine = true;
}
} }
write(text.subSequence(pos, size)); output.append(text);
} }
private void write(final CharSequence data) throws IOException { /**
if (data.length() == 0) { * Signifies reaching the "end of the current line" in the output. In single-line mode, this
return; * does not result in a newline being emitted, but ensures that a separating space is written
} * before the next output.
if (atStartOfLine) { */
atStartOfLine = false; public void eol() throws IOException {
output.append(indent); if (!singleLineMode) {
output.append("\n");
} }
output.append(data); atStartOfLine = true;
} }
} }
@ -1469,9 +1459,15 @@ public final class TextFormat {
extensionRegistry, name.toString()); extensionRegistry, name.toString());
if (extension == null) { if (extension == null) {
unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + unknownFields.add(
(tokenizer.getPreviousColumn() + 1) + ":\t" + (tokenizer.getPreviousLine() + 1)
type.getFullName() + ".[" + name + "]"); + ":"
+ (tokenizer.getPreviousColumn() + 1)
+ ":\t"
+ type.getFullName()
+ ".["
+ name
+ "]");
} else { } else {
if (extension.descriptor.getContainingType() != type) { if (extension.descriptor.getContainingType() != type) {
throw tokenizer.parseExceptionPreviousToken( throw tokenizer.parseExceptionPreviousToken(
@ -1506,9 +1502,14 @@ public final class TextFormat {
} }
if (field == null) { if (field == null) {
unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + unknownFields.add(
(tokenizer.getPreviousColumn() + 1) + ":\t" + (tokenizer.getPreviousLine() + 1)
type.getFullName() + "." + name); + ":"
+ (tokenizer.getPreviousColumn() + 1)
+ ":\t"
+ type.getFullName()
+ "."
+ name);
} }
} }

@ -715,7 +715,7 @@ public final class UnknownFieldSet implements MessageLite {
* @see UnknownFieldSet * @see UnknownFieldSet
*/ */
public static final class Field { public static final class Field {
Field() {} private Field() {}
/** Construct a new {@link Builder}. */ /** Construct a new {@link Builder}. */
public static Builder newBuilder() { public static Builder newBuilder() {

@ -47,8 +47,29 @@ final class UnsafeUtil {
private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS = private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
supportsUnsafeByteBufferOperations(); supportsUnsafeByteBufferOperations();
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations(); private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
private static final boolean HAS_UNSAFE_COPY_MEMORY = supportsUnsafeCopyMemory();
private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset(); private static final long BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(byte[].class);
// Micro-optimization: we can assume a scale of 1 and skip the multiply
// private static final long BYTE_ARRAY_INDEX_SCALE = 1;
private static final long BOOLEAN_ARRAY_BASE_OFFSET = arrayBaseOffset(boolean[].class);
private static final long BOOLEAN_ARRAY_INDEX_SCALE = arrayIndexScale(boolean[].class);
private static final long INT_ARRAY_BASE_OFFSET = arrayBaseOffset(int[].class);
private static final long INT_ARRAY_INDEX_SCALE = arrayIndexScale(int[].class);
private static final long LONG_ARRAY_BASE_OFFSET = arrayBaseOffset(long[].class);
private static final long LONG_ARRAY_INDEX_SCALE = arrayIndexScale(long[].class);
private static final long FLOAT_ARRAY_BASE_OFFSET = arrayBaseOffset(float[].class);
private static final long FLOAT_ARRAY_INDEX_SCALE = arrayIndexScale(float[].class);
private static final long DOUBLE_ARRAY_BASE_OFFSET = arrayBaseOffset(double[].class);
private static final long DOUBLE_ARRAY_INDEX_SCALE = arrayIndexScale(double[].class);
private static final long OBJECT_ARRAY_BASE_OFFSET = arrayBaseOffset(Object[].class);
private static final long OBJECT_ARRAY_INDEX_SCALE = arrayIndexScale(Object[].class);
private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField()); private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
private UnsafeUtil() {} private UnsafeUtil() {}
@ -57,10 +78,6 @@ final class UnsafeUtil {
return HAS_UNSAFE_ARRAY_OPERATIONS; return HAS_UNSAFE_ARRAY_OPERATIONS;
} }
static boolean hasUnsafeCopyMemory() {
return HAS_UNSAFE_COPY_MEMORY;
}
static boolean hasUnsafeByteBufferOperations() { static boolean hasUnsafeByteBufferOperations() {
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS; return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
} }
@ -69,8 +86,12 @@ final class UnsafeUtil {
return MEMORY_ACCESSOR.objectFieldOffset(field); return MEMORY_ACCESSOR.objectFieldOffset(field);
} }
static long getArrayBaseOffset() { private static int arrayBaseOffset(Class<?> clazz) {
return ARRAY_BASE_OFFSET; return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(clazz) : -1;
}
private static int arrayIndexScale(Class<?> clazz) {
return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayIndexScale(clazz) : -1;
} }
static byte getByte(Object target, long offset) { static byte getByte(Object target, long offset) {
@ -129,9 +150,82 @@ final class UnsafeUtil {
MEMORY_ACCESSOR.putObject(target, offset, value); MEMORY_ACCESSOR.putObject(target, offset, value);
} }
static void copyMemory( static byte getByte(byte[] target, long index) {
Object src, long srcOffset, Object target, long targetOffset, long length) { return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index);
MEMORY_ACCESSOR.copyMemory(src, srcOffset, target, targetOffset, length); }
static void putByte(byte[] target, long index, byte value) {
MEMORY_ACCESSOR.putByte(target, BYTE_ARRAY_BASE_OFFSET + index, value);
}
static int getInt(int[] target, long index) {
return MEMORY_ACCESSOR.getInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE));
}
static void putInt(int[] target, long index, int value) {
MEMORY_ACCESSOR.putInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE), value);
}
static long getLong(long[] target, long index) {
return MEMORY_ACCESSOR.getLong(
target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE));
}
static void putLong(long[] target, long index, long value) {
MEMORY_ACCESSOR.putLong(
target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE), value);
}
static boolean getBoolean(boolean[] target, long index) {
return MEMORY_ACCESSOR.getBoolean(
target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE));
}
static void putBoolean(boolean[] target, long index, boolean value) {
MEMORY_ACCESSOR.putBoolean(
target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE), value);
}
static float getFloat(float[] target, long index) {
return MEMORY_ACCESSOR.getFloat(
target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE));
}
static void putFloat(float[] target, long index, float value) {
MEMORY_ACCESSOR.putFloat(
target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE), value);
}
static double getDouble(double[] target, long index) {
return MEMORY_ACCESSOR.getDouble(
target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE));
}
static void putDouble(double[] target, long index, double value) {
MEMORY_ACCESSOR.putDouble(
target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE), value);
}
static Object getObject(Object[] target, long index) {
return MEMORY_ACCESSOR.getObject(
target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE));
}
static void putObject(Object[] target, long index, Object value) {
MEMORY_ACCESSOR.putObject(
target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE), value);
}
static void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
MEMORY_ACCESSOR.copyMemory(src, srcIndex, targetOffset, length);
}
static void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
MEMORY_ACCESSOR.copyMemory(srcOffset, target, targetIndex, length);
}
static void copyMemory(byte[] src, long srcIndex, byte[] target, long targetIndex, long length) {
System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length);
} }
static byte getByte(long address) { static byte getByte(long address) {
@ -221,6 +315,7 @@ final class UnsafeUtil {
Class<?> clazz = UNSAFE.getClass(); Class<?> clazz = UNSAFE.getClass();
clazz.getMethod("objectFieldOffset", Field.class); clazz.getMethod("objectFieldOffset", Field.class);
clazz.getMethod("arrayBaseOffset", Class.class); clazz.getMethod("arrayBaseOffset", Class.class);
clazz.getMethod("arrayIndexScale", Class.class);
clazz.getMethod("getInt", Object.class, long.class); clazz.getMethod("getInt", Object.class, long.class);
clazz.getMethod("putInt", Object.class, long.class, int.class); clazz.getMethod("putInt", Object.class, long.class, int.class);
clazz.getMethod("getLong", Object.class, long.class); clazz.getMethod("getLong", Object.class, long.class);
@ -245,27 +340,6 @@ final class UnsafeUtil {
return false; return false;
} }
/**
* Indicates whether or not unsafe copyMemory(object, long, object, long, long) operations are
* supported on this platform.
*/
private static boolean supportsUnsafeCopyMemory() {
if (UNSAFE == null) {
return false;
}
try {
Class<?> clazz = UNSAFE.getClass();
clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
return true;
} catch (Throwable e) {
logger.log(
Level.WARNING,
"copyMemory is missing from platform - proto runtime falling back to safer methods.");
}
return false;
}
private static boolean supportsUnsafeByteBufferOperations() { private static boolean supportsUnsafeByteBufferOperations() {
if (UNSAFE == null) { if (UNSAFE == null) {
return false; return false;
@ -283,6 +357,7 @@ final class UnsafeUtil {
clazz.getMethod("getLong", long.class); clazz.getMethod("getLong", long.class);
clazz.getMethod("putLong", long.class, long.class); clazz.getMethod("putLong", long.class, long.class);
clazz.getMethod("copyMemory", long.class, long.class, long.class); clazz.getMethod("copyMemory", long.class, long.class, long.class);
clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
return true; return true;
} catch (Throwable e) { } catch (Throwable e) {
logger.log( logger.log(
@ -307,13 +382,6 @@ final class UnsafeUtil {
return field(Buffer.class, "address"); return field(Buffer.class, "address");
} }
/**
* Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
*/
private static int byteArrayBaseOffset() {
return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(byte[].class) : -1;
}
/** /**
* Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
* available. * available.
@ -394,6 +462,10 @@ final class UnsafeUtil {
return unsafe.arrayBaseOffset(clazz); return unsafe.arrayBaseOffset(clazz);
} }
public final int arrayIndexScale(Class<?> clazz) {
return unsafe.arrayIndexScale(clazz);
}
public abstract byte getByte(long address); public abstract byte getByte(long address);
public abstract void putByte(long address, byte value); public abstract void putByte(long address, byte value);
@ -408,10 +480,11 @@ final class UnsafeUtil {
public abstract void copyMemory(long srcAddress, long targetAddress, long length); public abstract void copyMemory(long srcAddress, long targetAddress, long length);
public abstract void copyMemory(
Object src, long srcOffset, Object target, long targetOffset, long length);
public abstract Object getStaticObject(Field field); public abstract Object getStaticObject(Field field);
public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);
public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);
} }
private static final class JvmMemoryAccessor extends MemoryAccessor { private static final class JvmMemoryAccessor extends MemoryAccessor {
@ -490,16 +563,20 @@ final class UnsafeUtil {
unsafe.putDouble(target, offset, value); unsafe.putDouble(target, offset, value);
} }
@Override
public void copyMemory(
Object src, long srcOffset, Object target, long targetOffset, long length) {
unsafe.copyMemory(src, srcOffset, target, targetOffset, length);
}
@Override @Override
public void copyMemory(long srcAddress, long targetAddress, long length) { public void copyMemory(long srcAddress, long targetAddress, long length) {
unsafe.copyMemory(srcAddress, targetAddress, length); unsafe.copyMemory(srcAddress, targetAddress, length);
} }
@Override
public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
}
@Override
public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
}
@Override @Override
public Object getStaticObject(Field field) { public Object getStaticObject(Field field) {

@ -31,7 +31,6 @@
package com.google.protobuf; package com.google.protobuf;
import static com.google.protobuf.UnsafeUtil.addressOffset; import static com.google.protobuf.UnsafeUtil.addressOffset;
import static com.google.protobuf.UnsafeUtil.getArrayBaseOffset;
import static com.google.protobuf.UnsafeUtil.hasUnsafeArrayOperations; import static com.google.protobuf.UnsafeUtil.hasUnsafeArrayOperations;
import static com.google.protobuf.UnsafeUtil.hasUnsafeByteBufferOperations; import static com.google.protobuf.UnsafeUtil.hasUnsafeByteBufferOperations;
import static java.lang.Character.MAX_SURROGATE; import static java.lang.Character.MAX_SURROGATE;
@ -1001,8 +1000,8 @@ final class Utf8 {
throw new ArrayIndexOutOfBoundsException( throw new ArrayIndexOutOfBoundsException(
String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit)); String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit));
} }
long offset = getArrayBaseOffset() + index; long offset = index;
final long offsetLimit = getArrayBaseOffset() + limit; final long offsetLimit = limit;
if (state != COMPLETE) { if (state != COMPLETE) {
// The previous decoding operation was incomplete (or malformed). // The previous decoding operation was incomplete (or malformed).
// We look for a well-formed sequence consisting of bytes from // We look for a well-formed sequence consisting of bytes from
@ -1187,7 +1186,7 @@ final class Utf8 {
@Override @Override
int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) { int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
long outIx = getArrayBaseOffset() + offset; long outIx = offset;
final long outLimit = outIx + length; final long outLimit = outIx + length;
final int inLimit = in.length(); final int inLimit = in.length();
if (inLimit > length || out.length - length < offset) { if (inLimit > length || out.length - length < offset) {
@ -1204,7 +1203,7 @@ final class Utf8 {
} }
if (inIx == inLimit) { if (inIx == inLimit) {
// We're done, it was ASCII encoded. // We're done, it was ASCII encoded.
return (int) (outIx - getArrayBaseOffset()); return (int) outIx;
} }
for (char c; inIx < inLimit; ++inIx) { for (char c; inIx < inLimit; ++inIx) {
@ -1243,7 +1242,7 @@ final class Utf8 {
} }
// All bytes have been encoded. // All bytes have been encoded.
return (int) (outIx - getArrayBaseOffset()); return (int) outIx;
} }
@Override @Override
@ -1321,31 +1320,17 @@ final class Utf8 {
*/ */
private static int unsafeEstimateConsecutiveAscii( private static int unsafeEstimateConsecutiveAscii(
byte[] bytes, long offset, final int maxChars) { byte[] bytes, long offset, final int maxChars) {
int remaining = maxChars; if (maxChars < UNSAFE_COUNT_ASCII_THRESHOLD) {
if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) {
// Don't bother with small strings. // Don't bother with small strings.
return 0; return 0;
} }
// Read bytes until 8-byte aligned so that we can read longs in the loop below. for (int i = 0; i < maxChars; i++) {
// Byte arrays are already either 8 or 16-byte aligned, so we just need to make sure that
// the index (relative to the start of the array) is also 8-byte aligned. We do this by
// ANDing the index with 7 to determine the number of bytes that need to be read before
// we're 8-byte aligned.
final int unaligned = 8 - ((int) offset & 7);
for (int j = unaligned; j > 0; j--) {
if (UnsafeUtil.getByte(bytes, offset++) < 0) { if (UnsafeUtil.getByte(bytes, offset++) < 0) {
return unaligned - j; return i;
} }
} }
return maxChars;
// This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
// To speed things up further, we're reading longs instead of bytes so we use a mask to
// determine if any byte in the current long is non-ASCII.
remaining -= unaligned;
for (; remaining >= 8 && (UnsafeUtil.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
offset += 8, remaining -= 8) {}
return maxChars - remaining;
} }
/** /**

@ -47,8 +47,10 @@ public final class WireFormat {
// Do not allow instantiation. // Do not allow instantiation.
private WireFormat() {} private WireFormat() {}
static final int FIXED_32_SIZE = 4; static final int FIXED32_SIZE = 4;
static final int FIXED_64_SIZE = 8; static final int FIXED64_SIZE = 8;
static final int MAX_VARINT32_SIZE = 5;
static final int MAX_VARINT64_SIZE = 10;
static final int MAX_VARINT_SIZE = 10; static final int MAX_VARINT_SIZE = 10;
public static final int WIRETYPE_VARINT = 0; public static final int WIRETYPE_VARINT = 0;

@ -41,6 +41,7 @@ import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -613,6 +614,82 @@ public class CodedInputStreamTest extends TestCase {
checkSizeLimitExceeded(expected); checkSizeLimitExceeded(expected);
} }
} }
public void testRefillBufferWithCorrectSize() throws Exception {
// NOTE: refillBuffer only applies to the stream-backed CIS.
byte[] bytes = "123456789".getBytes("UTF-8");
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
output.writeRawVarint32(tag);
output.writeRawVarint32(bytes.length);
output.writeRawBytes(bytes);
output.writeRawVarint32(tag);
output.writeRawVarint32(bytes.length);
output.writeRawBytes(bytes);
output.writeRawByte(4);
output.flush();
// Input is two string with length 9 and one raw byte.
byte[] rawInput = rawOutput.toByteArray();
for (int inputStreamBufferLength = 8;
inputStreamBufferLength <= rawInput.length + 1; inputStreamBufferLength++) {
CodedInputStream input = CodedInputStream.newInstance(
new ByteArrayInputStream(rawInput), inputStreamBufferLength);
input.setSizeLimit(rawInput.length - 1);
input.readString();
input.readString();
try {
input.readRawByte(); // Hits limit.
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException expected) {
checkSizeLimitExceeded(expected);
}
}
}
public void testIsAtEnd() throws Exception {
CodedInputStream input = CodedInputStream.newInstance(
new ByteArrayInputStream(new byte[5]));
try {
for (int i = 0; i < 5; i++) {
assertEquals(false, input.isAtEnd());
input.readRawByte();
}
assertEquals(true, input.isAtEnd());
} catch (Exception e) {
fail("Catch exception in the testIsAtEnd");
}
}
public void testCurrentLimitExceeded() throws Exception {
byte[] bytes = "123456789".getBytes("UTF-8");
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
output.writeRawVarint32(tag);
output.writeRawVarint32(bytes.length);
output.writeRawBytes(bytes);
output.flush();
byte[] rawInput = rawOutput.toByteArray();
CodedInputStream input = CodedInputStream.newInstance(
new ByteArrayInputStream(rawInput));
// The length of the whole rawInput
input.setSizeLimit(11);
// Some number that is smaller than the rawInput's length
// but larger than 2
input.pushLimit(5);
try {
input.readString();
fail("Should have thrown an exception");
} catch (InvalidProtocolBufferException expected) {
assertEquals(expected.getMessage(),
InvalidProtocolBufferException.truncatedMessage().getMessage());
}
}
public void testSizeLimitMultipleMessages() throws Exception { public void testSizeLimitMultipleMessages() throws Exception {
// NOTE: Size limit only applies to the stream-backed CIS. // NOTE: Size limit only applies to the stream-backed CIS.
@ -807,6 +884,52 @@ public class CodedInputStreamTest extends TestCase {
} }
} }
public void testReadLargeByteStringFromInputStream() throws Exception {
byte[] bytes = new byte[1024 * 1024];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) (i & 0xFF);
}
ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
output.writeRawVarint32(bytes.length);
output.writeRawBytes(bytes);
output.flush();
byte[] data = rawOutput.toByteString().toByteArray();
CodedInputStream input = CodedInputStream.newInstance(
new ByteArrayInputStream(data) {
@Override
public synchronized int available() {
return 0;
}
});
ByteString result = input.readBytes();
assertEquals(ByteString.copyFrom(bytes), result);
}
public void testReadLargeByteArrayFromInputStream() throws Exception {
byte[] bytes = new byte[1024 * 1024];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) (i & 0xFF);
}
ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
output.writeRawVarint32(bytes.length);
output.writeRawBytes(bytes);
output.flush();
byte[] data = rawOutput.toByteString().toByteArray();
CodedInputStream input = CodedInputStream.newInstance(
new ByteArrayInputStream(data) {
@Override
public synchronized int available() {
return 0;
}
});
byte[] result = input.readByteArray();
assertTrue(Arrays.equals(bytes, result));
}
public void testReadByteBuffer() throws Exception { public void testReadByteBuffer() throws Exception {
ByteString.Output rawOutput = ByteString.newOutput(); ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);

@ -0,0 +1,157 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import static org.junit.Assert.assertEquals;
import protobuf_unittest.UnittestProto;
import proto3_unittest.UnittestProto3;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for discard or preserve unknown fields. */
@RunWith(JUnit4.class)
public class DiscardUnknownFieldsTest {
@Test
public void testProto2() throws Exception {
testProto2Message(
UnittestProto.TestEmptyMessage.getDefaultInstance());
testProto2Message(
UnittestProto.TestEmptyMessageWithExtensions.getDefaultInstance());
testProto2Message(
DynamicMessage.getDefaultInstance(UnittestProto.TestEmptyMessage.getDescriptor()));
testProto2Message(
DynamicMessage.getDefaultInstance(
UnittestProto.TestEmptyMessageWithExtensions.getDescriptor()));
}
@Test
public void testProto3() throws Exception {
testProto3Message(UnittestProto3.TestEmptyMessage.getDefaultInstance());
testProto3Message(
DynamicMessage.getDefaultInstance(UnittestProto3.TestEmptyMessage.getDescriptor()));
}
private static void testProto2Message(Message message) throws Exception {
assertUnknownFieldsDefaultPreserved(message);
assertUnknownFieldsExplicitlyDiscarded(message);
assertReuseCodedInputStreamPreserve(message);
assertUnknownFieldsInUnknownFieldSetArePreserve(message);
}
private static void testProto3Message(Message message) throws Exception {
CodedInputStream.setProto3KeepUnknownsByDefaultForTest();
assertUnknownFieldsDefaultPreserved(message);
assertUnknownFieldsExplicitlyDiscarded(message);
assertReuseCodedInputStreamPreserve(message);
assertUnknownFieldsInUnknownFieldSetArePreserve(message);
CodedInputStream.setProto3DiscardUnknownsByDefaultForTest();
assertUnknownFieldsDefaultDiscarded(message);
assertUnknownFieldsExplicitlyDiscarded(message);
assertUnknownFieldsInUnknownFieldSetAreDiscarded(message);
}
private static void assertReuseCodedInputStreamPreserve(Message message) throws Exception {
final int messageSize = payload.size();
byte[] copied = new byte[messageSize * 2];
payload.copyTo(copied, 0);
payload.copyTo(copied, messageSize);
CodedInputStream input = CodedInputStream.newInstance(copied);
{
// Use DiscardUnknownFieldsParser to parse the first payload.
int oldLimit = input.pushLimit(messageSize);
Message parsed = DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(input);
assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
input.popLimit(oldLimit);
}
{
// Use the normal parser to parse the remaining payload should have unknown fields preserved.
Message parsed = message.getParserForType().parseFrom(input);
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
}
}
/**
* {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
* Message.Builder#mergeUnknownFields(UnknownFieldSet)} should preserve the unknown fields.
*/
private static void assertUnknownFieldsInUnknownFieldSetArePreserve(Message message)
throws Exception {
UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
assertEquals(message.getClass().getName(), payload, built.toByteString());
}
/**
* {@link Message.Builder#setUnknownFields(UnknownFieldSet)} and {@link
* Message.Builder#mergeUnknownFields(UnknownFieldSet)} should discard the unknown fields.
*/
private static void assertUnknownFieldsInUnknownFieldSetAreDiscarded(Message message)
throws Exception {
UnknownFieldSet unknownFields = UnknownFieldSet.newBuilder().mergeFrom(payload).build();
Message built = message.newBuilderForType().setUnknownFields(unknownFields).build();
assertEquals(message.getClass().getName(), 0, built.getSerializedSize());
}
private static void assertUnknownFieldsDefaultPreserved(MessageLite message) throws Exception {
{
MessageLite parsed = message.getParserForType().parseFrom(payload);
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
}
{
MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
assertEquals(message.getClass().getName(), payload, parsed.toByteString());
}
}
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);
assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
}
private static final ByteString payload =
TestUtilLite.getAllLiteSetBuilder().build().toByteString();
}

@ -108,7 +108,7 @@ public class FieldPresenceTest extends TestCase {
assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage()); assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage()); assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
// oneof fields don't have hasFoo() methods (even for message types). // oneof fields don't have hasFoo() methods for non-message types.
assertHasMethodRemoved( assertHasMethodRemoved(
UnittestProto.TestAllTypes.class, UnittestProto.TestAllTypes.class,
TestAllTypes.class, TestAllTypes.class,
@ -121,10 +121,8 @@ public class FieldPresenceTest extends TestCase {
UnittestProto.TestAllTypes.class, UnittestProto.TestAllTypes.class,
TestAllTypes.class, TestAllTypes.class,
"OneofBytes"); "OneofBytes");
assertHasMethodRemoved( assertFalse(TestAllTypes.newBuilder().build().hasOneofNestedMessage());
UnittestProto.TestAllTypes.class, assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
TestAllTypes.class,
"OneofNestedMessage");
assertHasMethodRemoved( assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class, UnittestProto.TestAllTypes.Builder.class,
@ -138,10 +136,6 @@ public class FieldPresenceTest extends TestCase {
UnittestProto.TestAllTypes.Builder.class, UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class, TestAllTypes.Builder.class,
"OneofBytes"); "OneofBytes");
assertHasMethodRemoved(
UnittestProto.TestAllTypes.Builder.class,
TestAllTypes.Builder.class,
"OneofNestedMessage");
} }
public void testOneofEquals() throws Exception { public void testOneofEquals() throws Exception {

@ -923,15 +923,9 @@ public class GeneratedMessageTest extends TestCase {
} }
public void testEnumValues() { public void testEnumValues() {
assertEquals( assertEquals(TestAllTypes.NestedEnum.BAR_VALUE, TestAllTypes.NestedEnum.BAR.getNumber());
TestAllTypes.NestedEnum.BAR.getNumber(), assertEquals(TestAllTypes.NestedEnum.BAZ_VALUE, TestAllTypes.NestedEnum.BAZ.getNumber());
TestAllTypes.NestedEnum.BAR_VALUE); assertEquals(TestAllTypes.NestedEnum.FOO_VALUE, TestAllTypes.NestedEnum.FOO.getNumber());
assertEquals(
TestAllTypes.NestedEnum.BAZ.getNumber(),
TestAllTypes.NestedEnum.BAZ_VALUE);
assertEquals(
TestAllTypes.NestedEnum.FOO.getNumber(),
TestAllTypes.NestedEnum.FOO_VALUE);
} }
public void testNonNestedExtensionInitialization() { public void testNonNestedExtensionInitialization() {
@ -1319,51 +1313,51 @@ public class GeneratedMessageTest extends TestCase {
assertFalse(builder.clearFooInt().hasFooInt()); assertFalse(builder.clearFooInt().hasFooInt());
TestOneof2 message2 = builder.build(); TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooInt()); assertFalse(message2.hasFooInt());
assertEquals(message2.getFooInt(), 0); assertEquals(0, message2.getFooInt());
} }
// Enum // Enum
{ {
TestOneof2.Builder builder = TestOneof2.newBuilder(); TestOneof2.Builder builder = TestOneof2.newBuilder();
assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.FOO); assertEquals(TestOneof2.NestedEnum.FOO, builder.getFooEnum());
assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum()); assertTrue(builder.setFooEnum(TestOneof2.NestedEnum.BAR).hasFooEnum());
assertEquals(builder.getFooEnum(), TestOneof2.NestedEnum.BAR); assertEquals(TestOneof2.NestedEnum.BAR, builder.getFooEnum());
TestOneof2 message = builder.buildPartial(); TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooEnum()); assertTrue(message.hasFooEnum());
assertEquals(message.getFooEnum(), TestOneof2.NestedEnum.BAR); assertEquals(TestOneof2.NestedEnum.BAR, message.getFooEnum());
assertFalse(builder.clearFooEnum().hasFooEnum()); assertFalse(builder.clearFooEnum().hasFooEnum());
TestOneof2 message2 = builder.build(); TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooEnum()); assertFalse(message2.hasFooEnum());
assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.FOO); assertEquals(TestOneof2.NestedEnum.FOO, message2.getFooEnum());
} }
// String // String
{ {
TestOneof2.Builder builder = TestOneof2.newBuilder(); TestOneof2.Builder builder = TestOneof2.newBuilder();
assertEquals(builder.getFooString(), ""); assertEquals("", builder.getFooString());
builder.setFooString("foo"); builder.setFooString("foo");
assertTrue(builder.hasFooString()); assertTrue(builder.hasFooString());
assertEquals(builder.getFooString(), "foo"); assertEquals("foo", builder.getFooString());
TestOneof2 message = builder.buildPartial(); TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooString()); assertTrue(message.hasFooString());
assertEquals(message.getFooString(), "foo"); assertEquals("foo", message.getFooString());
assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo")); assertEquals(message.getFooStringBytes(), TestUtil.toBytes("foo"));
assertFalse(builder.clearFooString().hasFooString()); assertFalse(builder.clearFooString().hasFooString());
TestOneof2 message2 = builder.buildPartial(); TestOneof2 message2 = builder.buildPartial();
assertFalse(message2.hasFooString()); assertFalse(message2.hasFooString());
assertEquals(message2.getFooString(), ""); assertEquals("", message2.getFooString());
assertEquals(message2.getFooStringBytes(), TestUtil.toBytes("")); assertEquals(message2.getFooStringBytes(), TestUtil.toBytes(""));
// Get method should not change the oneof value. // Get method should not change the oneof value.
builder.setFooInt(123); builder.setFooInt(123);
assertEquals(builder.getFooString(), ""); assertEquals("", builder.getFooString());
assertEquals(builder.getFooStringBytes(), TestUtil.toBytes("")); assertEquals(builder.getFooStringBytes(), TestUtil.toBytes(""));
assertEquals(123, builder.getFooInt()); assertEquals(123, builder.getFooInt());
message = builder.build(); message = builder.build();
assertEquals(message.getFooString(), ""); assertEquals("", message.getFooString());
assertEquals(message.getFooStringBytes(), TestUtil.toBytes("")); assertEquals(message.getFooStringBytes(), TestUtil.toBytes(""));
assertEquals(123, message.getFooInt()); assertEquals(123, message.getFooInt());
} }
@ -1371,38 +1365,38 @@ public class GeneratedMessageTest extends TestCase {
// Cord // Cord
{ {
TestOneof2.Builder builder = TestOneof2.newBuilder(); TestOneof2.Builder builder = TestOneof2.newBuilder();
assertEquals(builder.getFooCord(), ""); assertEquals("", builder.getFooCord());
builder.setFooCord("foo"); builder.setFooCord("foo");
assertTrue(builder.hasFooCord()); assertTrue(builder.hasFooCord());
assertEquals(builder.getFooCord(), "foo"); assertEquals("foo", builder.getFooCord());
TestOneof2 message = builder.buildPartial(); TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooCord()); assertTrue(message.hasFooCord());
assertEquals(message.getFooCord(), "foo"); assertEquals("foo", message.getFooCord());
assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo")); assertEquals(message.getFooCordBytes(), TestUtil.toBytes("foo"));
assertFalse(builder.clearFooCord().hasFooCord()); assertFalse(builder.clearFooCord().hasFooCord());
TestOneof2 message2 = builder.build(); TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooCord()); assertFalse(message2.hasFooCord());
assertEquals(message2.getFooCord(), ""); assertEquals("", message2.getFooCord());
assertEquals(message2.getFooCordBytes(), TestUtil.toBytes("")); assertEquals(message2.getFooCordBytes(), TestUtil.toBytes(""));
} }
// StringPiece // StringPiece
{ {
TestOneof2.Builder builder = TestOneof2.newBuilder(); TestOneof2.Builder builder = TestOneof2.newBuilder();
assertEquals(builder.getFooStringPiece(), ""); assertEquals("", builder.getFooStringPiece());
builder.setFooStringPiece("foo"); builder.setFooStringPiece("foo");
assertTrue(builder.hasFooStringPiece()); assertTrue(builder.hasFooStringPiece());
assertEquals(builder.getFooStringPiece(), "foo"); assertEquals("foo", builder.getFooStringPiece());
TestOneof2 message = builder.buildPartial(); TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooStringPiece()); assertTrue(message.hasFooStringPiece());
assertEquals(message.getFooStringPiece(), "foo"); assertEquals("foo", message.getFooStringPiece());
assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo")); assertEquals(message.getFooStringPieceBytes(), TestUtil.toBytes("foo"));
assertFalse(builder.clearFooStringPiece().hasFooStringPiece()); assertFalse(builder.clearFooStringPiece().hasFooStringPiece());
TestOneof2 message2 = builder.build(); TestOneof2 message2 = builder.build();
assertFalse(message2.hasFooStringPiece()); assertFalse(message2.hasFooStringPiece());
assertEquals(message2.getFooStringPiece(), ""); assertEquals("", message2.getFooStringPiece());
assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes("")); assertEquals(message2.getFooStringPieceBytes(), TestUtil.toBytes(""));
} }
@ -1410,20 +1404,20 @@ public class GeneratedMessageTest extends TestCase {
{ {
// set // set
TestOneof2.Builder builder = TestOneof2.newBuilder(); TestOneof2.Builder builder = TestOneof2.newBuilder();
assertEquals(builder.getFooMessage().getQuxInt(), 0); assertEquals(0, builder.getFooMessage().getQuxInt());
builder.setFooMessage( builder.setFooMessage(
TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()); TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build());
assertTrue(builder.hasFooMessage()); assertTrue(builder.hasFooMessage());
assertEquals(builder.getFooMessage().getQuxInt(), 234); assertEquals(234, builder.getFooMessage().getQuxInt());
TestOneof2 message = builder.buildPartial(); TestOneof2 message = builder.buildPartial();
assertTrue(message.hasFooMessage()); assertTrue(message.hasFooMessage());
assertEquals(message.getFooMessage().getQuxInt(), 234); assertEquals(234, message.getFooMessage().getQuxInt());
// clear // clear
assertFalse(builder.clearFooMessage().hasFooString()); assertFalse(builder.clearFooMessage().hasFooString());
message = builder.build(); message = builder.build();
assertFalse(message.hasFooMessage()); assertFalse(message.hasFooMessage());
assertEquals(message.getFooMessage().getQuxInt(), 0); assertEquals(0, message.getFooMessage().getQuxInt());
// nested builder // nested builder
builder = TestOneof2.newBuilder(); builder = TestOneof2.newBuilder();
@ -1432,10 +1426,10 @@ public class GeneratedMessageTest extends TestCase {
assertFalse(builder.hasFooMessage()); assertFalse(builder.hasFooMessage());
builder.getFooMessageBuilder().setQuxInt(123); builder.getFooMessageBuilder().setQuxInt(123);
assertTrue(builder.hasFooMessage()); assertTrue(builder.hasFooMessage());
assertEquals(builder.getFooMessage().getQuxInt(), 123); assertEquals(123, builder.getFooMessage().getQuxInt());
message = builder.build(); message = builder.build();
assertTrue(message.hasFooMessage()); assertTrue(message.hasFooMessage());
assertEquals(message.getFooMessage().getQuxInt(), 123); assertEquals(123, message.getFooMessage().getQuxInt());
} }
// LazyMessage is tested in LazyMessageLiteTest.java // LazyMessage is tested in LazyMessageLiteTest.java
@ -1448,7 +1442,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2 message = builder.setFooInt(123).build(); TestOneof2 message = builder.setFooInt(123).build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooInt()); assertTrue(message2.hasFooInt());
assertEquals(message2.getFooInt(), 123); assertEquals(123, message2.getFooInt());
} }
// String // String
@ -1457,7 +1451,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2 message = builder.setFooString("foo").build(); TestOneof2 message = builder.setFooString("foo").build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooString()); assertTrue(message2.hasFooString());
assertEquals(message2.getFooString(), "foo"); assertEquals("foo", message2.getFooString());
} }
// Enum // Enum
@ -1466,7 +1460,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build(); TestOneof2 message = builder.setFooEnum(TestOneof2.NestedEnum.BAR).build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooEnum()); assertTrue(message2.hasFooEnum());
assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR); assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
} }
// Message // Message
@ -1476,7 +1470,7 @@ public class GeneratedMessageTest extends TestCase {
TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build(); TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build(); TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
assertTrue(message2.hasFooMessage()); assertTrue(message2.hasFooMessage());
assertEquals(message2.getFooMessage().getQuxInt(), 234); assertEquals(234, message2.getFooMessage().getQuxInt());
} }
} }
@ -1488,7 +1482,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString(); ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized); TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooInt()); assertTrue(message2.hasFooInt());
assertEquals(message2.getFooInt(), 123); assertEquals(123, message2.getFooInt());
} }
// String // String
@ -1498,7 +1492,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString(); ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized); TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooString()); assertTrue(message2.hasFooString());
assertEquals(message2.getFooString(), "foo"); assertEquals("foo", message2.getFooString());
} }
// Enum // Enum
@ -1508,7 +1502,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString(); ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized); TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooEnum()); assertTrue(message2.hasFooEnum());
assertEquals(message2.getFooEnum(), TestOneof2.NestedEnum.BAR); assertEquals(TestOneof2.NestedEnum.BAR, message2.getFooEnum());
} }
// Message // Message
@ -1519,7 +1513,7 @@ public class GeneratedMessageTest extends TestCase {
ByteString serialized = message.toByteString(); ByteString serialized = message.toByteString();
TestOneof2 message2 = TestOneof2.parseFrom(serialized); TestOneof2 message2 = TestOneof2.parseFrom(serialized);
assertTrue(message2.hasFooMessage()); assertTrue(message2.hasFooMessage());
assertEquals(message2.getFooMessage().getQuxInt(), 234); assertEquals(234, message2.getFooMessage().getQuxInt());
} }
} }

@ -33,6 +33,7 @@ package com.google.protobuf;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
import com.google.protobuf.UnittestImportLite.ImportEnumLite; import com.google.protobuf.UnittestImportLite.ImportEnumLite;
import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite; import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
import com.google.protobuf.UnittestLite.ForeignEnumLite; import com.google.protobuf.UnittestLite.ForeignEnumLite;
@ -52,7 +53,12 @@ import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
import java.lang.reflect.Field;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -155,6 +161,31 @@ public class LiteTest extends TestCase {
// expected. // expected.
} }
} }
public void testMemoization() throws Exception {
TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet();
// Test serialized size is memoized
message.memoizedSerializedSize = -1;
int size = message.getSerializedSize();
assertTrue(size > 0);
assertEquals(size, message.memoizedSerializedSize);
// Test hashCode is memoized
assertEquals(0, message.memoizedHashCode);
int hashCode = message.hashCode();
assertTrue(hashCode != 0);
assertEquals(hashCode, message.memoizedHashCode);
// Test isInitialized is memoized
Field memo = message.getClass().getDeclaredField("memoizedIsInitialized");
memo.setAccessible(true);
memo.set(message, (byte) -1);
boolean initialized = message.isInitialized();
assertTrue(initialized);
// We have to cast to Byte first. Casting to byte causes a type error
assertEquals(1, ((Byte) memo.get(message)).intValue());
}
public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
// Since builders are implemented as a thin wrapper around a message // Since builders are implemented as a thin wrapper around a message
@ -2378,4 +2409,187 @@ public class LiteTest extends TestCase {
expected.getUnfinishedMessage()); expected.getUnfinishedMessage());
} }
} }
// Make sure we haven't screwed up the code generation for packing fields by default.
public void testPackedSerialization() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
builder.addRepeatedInt32(4321);
builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAZ);
TestAllTypes message = builder.build();
CodedInputStream in = CodedInputStream.newInstance(message.toByteArray());
while (!in.isAtEnd()) {
int tag = in.readTag();
assertEquals(WireFormat.WIRETYPE_LENGTH_DELIMITED, WireFormat.getTagWireType(tag));
in.skipField(tag);
}
}
public void testAddAllIteratesOnce() {
TestAllTypesLite message =
TestAllTypesLite.newBuilder()
.addAllRepeatedBool(new OneTimeIterableList(false))
.addAllRepeatedInt32(new OneTimeIterableList(0))
.addAllRepeatedInt64(new OneTimeIterableList(0L))
.addAllRepeatedFloat(new OneTimeIterableList(0f))
.addAllRepeatedDouble(new OneTimeIterableList(0d))
.addAllRepeatedBytes(new OneTimeIterableList(ByteString.EMPTY))
.addAllRepeatedString(new OneTimeIterableList(""))
.addAllRepeatedNestedMessage(
new OneTimeIterableList(NestedMessage.getDefaultInstance()))
.addAllRepeatedBool(new OneTimeIterable(false))
.addAllRepeatedInt32(new OneTimeIterable(0))
.addAllRepeatedInt64(new OneTimeIterable(0L))
.addAllRepeatedFloat(new OneTimeIterable(0f))
.addAllRepeatedDouble(new OneTimeIterable(0d))
.addAllRepeatedBytes(new OneTimeIterable(ByteString.EMPTY))
.addAllRepeatedString(new OneTimeIterable(""))
.addAllRepeatedNestedMessage(new OneTimeIterable(NestedMessage.getDefaultInstance()))
.build();
}
public void testAddAllIteratesOnce_throwsOnNull() {
TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
try {
builder.addAllRepeatedBool(new OneTimeIterableList(true, false, (Boolean) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedBoolCount());
}
try {
builder.addAllRepeatedBool(new OneTimeIterable(true, false, (Boolean) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedBoolCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedBool(new OneTimeIterableList((Boolean) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedBoolCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedInt32(new OneTimeIterableList((Integer) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedInt32Count());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedInt64(new OneTimeIterableList((Long) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedInt64Count());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedFloat(new OneTimeIterableList((Float) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedFloatCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedDouble(new OneTimeIterableList((Double) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedDoubleCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedBytes(new OneTimeIterableList((ByteString) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedBytesCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedString(new OneTimeIterableList("", "", (String) null, ""));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedStringCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedString(new OneTimeIterable("", "", (String) null, ""));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 2 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedStringCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedString(new OneTimeIterableList((String) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedStringCount());
}
try {
builder = TestAllTypesLite.newBuilder();
builder.addAllRepeatedNestedMessage(new OneTimeIterableList((NestedMessage) null));
fail();
} catch (NullPointerException expected) {
assertEquals("Element at index 0 is null.", expected.getMessage());
assertEquals(0, builder.getRepeatedNestedMessageCount());
}
}
private static final class OneTimeIterableList<T> extends ArrayList<T> {
private boolean wasIterated = false;
OneTimeIterableList(T... contents) {
addAll(Arrays.asList(contents));
}
@Override
public Iterator<T> iterator() {
if (wasIterated) {
fail();
}
wasIterated = true;
return super.iterator();
}
}
private static final class OneTimeIterable<T> implements Iterable<T> {
private final List<T> list;
private boolean wasIterated = false;
OneTimeIterable(T... contents) {
list = Arrays.asList(contents);
}
@Override
public Iterator<T> iterator() {
if (wasIterated) {
fail();
}
wasIterated = true;
return list.iterator();
}
}
} }

@ -408,12 +408,12 @@ public final class MapForProto2LiteTest extends TestCase {
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder() TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToInt32Field(5, bytes) .putInt32ToInt32Field(5, bytes)
.build()); .build());
assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0); assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToStringField(stringKey, 5) .putInt32ToStringField(stringKey, 5)
.build()); .build());
assertEquals(map.getInt32ToStringFieldOrDefault(0, null), ""); assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToBytesField(stringKey, 5) .putInt32ToBytesField(stringKey, 5)
@ -423,7 +423,7 @@ public final class MapForProto2LiteTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToEnumField(stringKey, bytes) .putInt32ToEnumField(stringKey, bytes)
.build()); .build());
assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO); assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try { try {
tryParseTestMap(BizarroTestMap.newBuilder() tryParseTestMap(BizarroTestMap.newBuilder()
@ -439,7 +439,7 @@ public final class MapForProto2LiteTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putStringToInt32Field(stringKey, bytes) .putStringToInt32Field(stringKey, bytes)
.build()); .build());
assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0); assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
} }
public void testMergeFrom() throws Exception { public void testMergeFrom() throws Exception {

@ -546,12 +546,12 @@ public class MapForProto2Test extends TestCase {
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder() TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToInt32Field(5, bytes) .putInt32ToInt32Field(5, bytes)
.build()); .build());
assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0); assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToStringField(stringKey, 5) .putInt32ToStringField(stringKey, 5)
.build()); .build());
assertEquals(map.getInt32ToStringFieldOrDefault(0, null), ""); assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToBytesField(stringKey, 5) .putInt32ToBytesField(stringKey, 5)
@ -561,7 +561,7 @@ public class MapForProto2Test extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToEnumField(stringKey, bytes) .putInt32ToEnumField(stringKey, bytes)
.build()); .build());
assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO); assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try { try {
tryParseTestMap(BizarroTestMap.newBuilder() tryParseTestMap(BizarroTestMap.newBuilder()
@ -577,7 +577,7 @@ public class MapForProto2Test extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putStringToInt32Field(stringKey, bytes) .putStringToInt32Field(stringKey, bytes)
.build()); .build());
assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0); assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
} }
public void testMergeFrom() throws Exception { public void testMergeFrom() throws Exception {

@ -576,12 +576,12 @@ public class MapTest extends TestCase {
TestMap map = tryParseTestMap(BizarroTestMap.newBuilder() TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToInt32Field(5, bytes) .putInt32ToInt32Field(5, bytes)
.build()); .build());
assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0); assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToStringField(stringKey, 5) .putInt32ToStringField(stringKey, 5)
.build()); .build());
assertEquals(map.getInt32ToStringFieldOrDefault(0, null), ""); assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToBytesField(stringKey, 5) .putInt32ToBytesField(stringKey, 5)
@ -591,7 +591,7 @@ public class MapTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putInt32ToEnumField(stringKey, bytes) .putInt32ToEnumField(stringKey, bytes)
.build()); .build());
assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO); assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
try { try {
tryParseTestMap(BizarroTestMap.newBuilder() tryParseTestMap(BizarroTestMap.newBuilder()
@ -607,7 +607,7 @@ public class MapTest extends TestCase {
map = tryParseTestMap(BizarroTestMap.newBuilder() map = tryParseTestMap(BizarroTestMap.newBuilder()
.putStringToInt32Field(stringKey, bytes) .putStringToInt32Field(stringKey, bytes)
.build()); .build());
assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0); assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
} }
public void testMergeFrom() throws Exception { public void testMergeFrom() throws Exception {

@ -321,8 +321,10 @@ public class MessageTest extends TestCase {
assertTrue(result.getField(result.getDescriptorForType() assertTrue(result.getField(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")) instanceof List<?>); .findFieldByName("repeated_foreign_message")) instanceof List<?>);
assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType() assertEquals(
.findFieldByName("repeated_foreign_message")), 0); 0,
result.getRepeatedFieldCount(
result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
} }
/** Test reading repeated message from DynamicMessage. */ /** Test reading repeated message from DynamicMessage. */
@ -345,7 +347,9 @@ public class MessageTest extends TestCase {
assertTrue(result.getField(result.getDescriptorForType() assertTrue(result.getField(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")) instanceof List<?>); .findFieldByName("repeated_foreign_message")) instanceof List<?>);
assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType() assertEquals(
.findFieldByName("repeated_foreign_message")), 2); 2,
result.getRepeatedFieldCount(
result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
} }
} }

@ -92,5 +92,31 @@ public class TestBadIdentifiers extends TestCase {
assertEquals(0L, message.getExtension( assertEquals(0L, message.getExtension(
TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue()); TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
assertEquals("", message.getFieldName32());
assertEquals("", message.getFieldName33());
assertEquals(0, message.get2Conflict34());
assertEquals(0, message.get2Conflict35());
}
public void testNumberFields() throws Exception {
TestBadIdentifiersProto.TestLeadingNumberFields message =
TestBadIdentifiersProto.TestLeadingNumberFields.getDefaultInstance();
// Make sure generated accessors are properly named.
assertFalse(message.has30DayImpressions());
assertEquals(0, message.get30DayImpressions());
assertEquals(0, message.get60DayImpressionsCount());
assertEquals(0, message.get60DayImpressionsList().size());
assertFalse(message.has2Underscores());
assertEquals("", message.get2Underscores());
assertEquals(0, message.get2RepeatedUnderscoresCount());
assertEquals(0, message.get2RepeatedUnderscoresList().size());
assertFalse(message.has32());
assertEquals(0, message.get32());
assertEquals(0, message.get64Count());
assertEquals(0, message.get64List().size());
} }
} }

@ -0,0 +1,83 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
/**
* Tests that proto2 api generation doesn't cause compile errors when compiling protocol buffers
* that have names that would otherwise conflict if not fully qualified (like @Deprecated
* and @Override).
*
* <p>Forked from {@link TestBadIdentifiers}.
*
* @author jonp@google.com (Jon Perlow)
*/
public final class TestBadIdentifiersLite extends TestCase {
public void testCompilation() {
// If this compiles, it means the generation was correct.
TestBadIdentifiersProto.Deprecated.newBuilder();
TestBadIdentifiersProto.Override.newBuilder();
}
public void testConflictingFieldNames() throws Exception {
TestBadIdentifiersProto.TestConflictingFieldNames message =
TestBadIdentifiersProto.TestConflictingFieldNames.getDefaultInstance();
// Make sure generated accessors are properly named.
assertEquals(0, message.getInt32Field1Count());
assertEquals(0, message.getEnumField2Count());
assertEquals(0, message.getStringField3Count());
assertEquals(0, message.getBytesField4Count());
assertEquals(0, message.getMessageField5Count());
assertEquals(0, message.getInt32FieldCount11());
assertEquals(0, message.getEnumFieldCount12().getNumber());
assertEquals("", message.getStringFieldCount13());
assertEquals(ByteString.EMPTY, message.getBytesFieldCount14());
assertEquals(0, message.getMessageFieldCount15().getSerializedSize());
assertEquals(0, message.getInt32Field21Count());
assertEquals(0, message.getEnumField22Count());
assertEquals(0, message.getStringField23Count());
assertEquals(0, message.getBytesField24Count());
assertEquals(0, message.getMessageField25Count());
assertEquals(0, message.getInt32Field1List().size());
assertEquals(0, message.getInt32FieldList31());
assertEquals(0, message.getInt64FieldCount());
assertEquals(0L, message.getExtension(
TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldCount).longValue());
assertEquals(0L, message.getExtension(
TestBadIdentifiersProto.TestConflictingFieldNames.int64FieldList).longValue());
}
}

@ -30,8 +30,6 @@
package com.google.protobuf; package com.google.protobuf;
import static com.google.common.truth.Truth.assertThat;
import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
@ -1079,12 +1077,12 @@ public class TextFormatTest extends TestCase {
{ {
TestMap.Builder dest = TestMap.newBuilder(); TestMap.Builder dest = TestMap.newBuilder();
TextFormat.merge(text, dest); TextFormat.merge(text, dest);
assertThat(dest.build()).isEqualTo(message); assertEquals(message, dest.build());
} }
{ {
TestMap.Builder dest = TestMap.newBuilder(); TestMap.Builder dest = TestMap.newBuilder();
parserWithOverwriteForbidden.merge(text, dest); parserWithOverwriteForbidden.merge(text, dest);
assertThat(dest.build()).isEqualTo(message); assertEquals(message, dest.build());
} }
} }
@ -1096,10 +1094,10 @@ public class TextFormatTest extends TestCase {
TestMap.Builder dest = TestMap.newBuilder(); TestMap.Builder dest = TestMap.newBuilder();
parserWithOverwriteForbidden.merge(text, dest); parserWithOverwriteForbidden.merge(text, dest);
TestMap message = dest.build(); TestMap message = dest.build();
assertThat(message.getStringToInt32Field().size()).isEqualTo(2); assertEquals(2, message.getStringToInt32Field().size());
assertThat(message.getInt32ToMessageField().size()).isEqualTo(2); assertEquals(2, message.getInt32ToMessageField().size());
assertThat(message.getStringToInt32Field().get("x")).isEqualTo(10); assertEquals(10, message.getStringToInt32Field().get("x").intValue());
assertThat(message.getInt32ToMessageField().get(2).getValue()).isEqualTo(200); assertEquals(200, message.getInt32ToMessageField().get(2).getValue());
} }
public void testMapShortFormEmpty() throws Exception { public void testMapShortFormEmpty() throws Exception {
@ -1108,8 +1106,8 @@ public class TextFormatTest extends TestCase {
TestMap.Builder dest = TestMap.newBuilder(); TestMap.Builder dest = TestMap.newBuilder();
parserWithOverwriteForbidden.merge(text, dest); parserWithOverwriteForbidden.merge(text, dest);
TestMap message = dest.build(); TestMap message = dest.build();
assertThat(message.getStringToInt32Field().size()).isEqualTo(0); assertEquals(0, message.getStringToInt32Field().size());
assertThat(message.getInt32ToMessageField().size()).isEqualTo(0); assertEquals(0, message.getInt32ToMessageField().size());
} }
public void testMapShortFormTrailingComma() throws Exception { public void testMapShortFormTrailingComma() throws Exception {
@ -1119,7 +1117,7 @@ public class TextFormatTest extends TestCase {
parserWithOverwriteForbidden.merge(text, dest); parserWithOverwriteForbidden.merge(text, dest);
fail("Expected parse exception."); fail("Expected parse exception.");
} catch (TextFormat.ParseException e) { } catch (TextFormat.ParseException e) {
assertThat(e).hasMessageThat().isEqualTo("1:48: Expected \"{\"."); assertEquals("1:48: Expected \"{\".", e.getMessage());
} }
} }
@ -1134,8 +1132,8 @@ public class TextFormatTest extends TestCase {
TestMap.Builder builder = TestMap.newBuilder(); TestMap.Builder builder = TestMap.newBuilder();
defaultParser.merge(text, builder); defaultParser.merge(text, builder);
TestMap map = builder.build(); TestMap map = builder.build();
assertThat(map.getInt32ToInt32Field().size()).isEqualTo(2); assertEquals(2, map.getInt32ToInt32Field().size());
assertThat(map.getInt32ToInt32Field().get(1).intValue()).isEqualTo(30); assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
} }
{ {
@ -1144,8 +1142,8 @@ public class TextFormatTest extends TestCase {
TestMap.Builder builder = TestMap.newBuilder(); TestMap.Builder builder = TestMap.newBuilder();
defaultParser.merge(text, builder); defaultParser.merge(text, builder);
TestMap map = builder.build(); TestMap map = builder.build();
assertThat(map.getInt32ToInt32Field().size()).isEqualTo(2); assertEquals(2, map.getInt32ToInt32Field().size());
assertThat(map.getInt32ToInt32Field().get(1).intValue()).isEqualTo(30); assertEquals(30, map.getInt32ToInt32Field().get(1).intValue());
} }
} }

@ -36,7 +36,6 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.FieldPresenceTestProto.TestAllTypes; import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
import com.google.protobuf.TextFormat.ParseException; import com.google.protobuf.TextFormat.ParseException;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -151,18 +150,15 @@ public class UnknownEnumValueTest extends TestCase {
assertEquals(4321, unknown4321.getNumber()); assertEquals(4321, unknown4321.getNumber());
assertEquals(5432, unknown5432.getNumber()); assertEquals(5432, unknown5432.getNumber());
assertEquals(6543, unknown6543.getNumber()); assertEquals(6543, unknown6543.getNumber());
// Unknown EnumValueDescriptor will map to UNRECOGNIZED. // Unknown EnumValueDescriptor will map to UNRECOGNIZED.
assertEquals( assertEquals(
TestAllTypes.NestedEnum.valueOf(unknown4321), TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown4321));
TestAllTypes.NestedEnum.UNRECOGNIZED);
assertEquals( assertEquals(
TestAllTypes.NestedEnum.valueOf(unknown5432), TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown5432));
TestAllTypes.NestedEnum.UNRECOGNIZED);
assertEquals( assertEquals(
TestAllTypes.NestedEnum.valueOf(unknown6543), TestAllTypes.NestedEnum.UNRECOGNIZED, TestAllTypes.NestedEnum.valueOf(unknown6543));
TestAllTypes.NestedEnum.UNRECOGNIZED);
// Setters also accept unknown EnumValueDescriptor. // Setters also accept unknown EnumValueDescriptor.
builder.setField(optionalNestedEnumField, unknown6543); builder.setField(optionalNestedEnumField, unknown6543);
builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321); builder.setRepeatedField(repeatedNestedEnumField, 0, unknown4321);

@ -148,6 +148,12 @@ message TestConflictingFieldNames {
// the method getInt32FieldList(). // the method getInt32FieldList().
required int32 int32_field_list = 31; // NO_PROTO3 required int32 int32_field_list = 31; // NO_PROTO3
// These field pairs have the same Java converted name
optional string field_name = 32; // NO_PROTO3
optional string field__name = 33; // NO_PROTO3
optional int32 _2conflict = 34; // NO_PROTO3
optional int32 __2conflict = 35;
extensions 1000 to max; // NO_PROTO3 extensions 1000 to max; // NO_PROTO3
repeated int64 int64_field = 41; repeated int64 int64_field = 41;
@ -166,3 +172,14 @@ message TestMapField {
map<int32, int32> map_field = 1; map<int32, int32> map_field = 1;
} }
message TestLeadingNumberFields {
optional int32 _30day_impressions = 1;
repeated string _60day_impressions = 2;
optional string __2_underscores = 3;
repeated string __2repeated_underscores = 4;
optional int32 _32 = 32;
repeated int64 _64 = 64;
}

@ -83,6 +83,17 @@ public final class Durations {
return COMPARATOR; return COMPARATOR;
} }
/**
* Compares two durations. The value returned is identical to what would be returned by:
* {@code Durations.comparator().compare(x, y)}.
*
* @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y};
* and a value greater than {@code 0} if {@code x > y}
*/
public static int compare(Duration x, Duration y) {
return COMPARATOR.compare(x, y);
}
/** /**
* Returns true if the given {@link Duration} is valid. The {@code seconds} value must be in the * Returns true if the given {@link Duration} is valid. The {@code seconds} value must be in the
* range [-315,576,000,000, +315,576,000,000]. The {@code nanos} value must be in the range * range [-315,576,000,000, +315,576,000,000]. The {@code nanos} value must be in the range

@ -311,16 +311,19 @@ public class FieldMaskUtil {
return replacePrimitiveFields; return replacePrimitiveFields;
} }
public void setReplaceMessageFields(boolean value) { public MergeOptions setReplaceMessageFields(boolean value) {
replaceMessageFields = value; replaceMessageFields = value;
return this;
} }
public void setReplaceRepeatedFields(boolean value) { public MergeOptions setReplaceRepeatedFields(boolean value) {
replaceRepeatedFields = value; replaceRepeatedFields = value;
return this;
} }
public void setReplacePrimitiveFields(boolean value) { public MergeOptions setReplacePrimitiveFields(boolean value) {
replacePrimitiveFields = value; replacePrimitiveFields = value;
return this;
} }
} }

@ -1686,7 +1686,11 @@ public class JsonFormat {
} }
private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException { private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString())); try {
return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()));
} catch (IllegalArgumentException e) {
return ByteString.copyFrom(BaseEncoding.base64Url().decode(json.getAsString()));
}
} }
private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json) private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json)

@ -114,6 +114,17 @@ public final class Timestamps {
return COMPARATOR; return COMPARATOR;
} }
/**
* Compares two timestamps. The value returned is identical to what would be returned by:
* {@code Timestamps.comparator().compare(x, y)}.
*
* @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y};
* and a value greater than {@code 0} if {@code x > y}
*/
public static int compare(Timestamp x, Timestamp y) {
return COMPARATOR.compare(x, y);
}
/** /**
* Returns true if the given {@link Timestamp} is valid. The {@code seconds} value must be in the * Returns true if the given {@link Timestamp} is valid. The {@code seconds} value must be in the
* range [-62,135,596,800, +253,402,300,799] (i.e., between 0001-01-01T00:00:00Z and * range [-62,135,596,800, +253,402,300,799] (i.e., between 0001-01-01T00:00:00Z and

@ -73,7 +73,6 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -1144,7 +1143,8 @@ public class JsonFormatTest extends TestCase {
} }
public void testParserAcceptBase64Variants() throws Exception { public void testParserAcceptBase64Variants() throws Exception {
assertAccepts("optionalBytes", "AQI"); assertAccepts("optionalBytes", "AQI"); // No padding
assertAccepts("optionalBytes", "-_w"); // base64Url, no padding
} }
public void testParserRejectInvalidEnumValue() throws Exception { public void testParserRejectInvalidEnumValue() throws Exception {

@ -390,11 +390,13 @@ jspb.BinaryEncoder.prototype.writeDouble = function(value) {
/** /**
* Writes a boolean value to the buffer as a varint. * Writes a boolean value to the buffer as a varint. We allow numbers as input
* @param {boolean} value The value to write. * because the JSPB code generator uses 0/1 instead of true/false to save space
* in the string representation of the proto.
* @param {boolean|number} value The value to write.
*/ */
jspb.BinaryEncoder.prototype.writeBool = function(value) { jspb.BinaryEncoder.prototype.writeBool = function(value) {
goog.asserts.assert(goog.isBoolean(value)); goog.asserts.assert(goog.isBoolean(value) || goog.isNumber(value));
this.buffer_.push(value ? 1 : 0); this.buffer_.push(value ? 1 : 0);
}; };

@ -970,10 +970,6 @@ jspb.utils.byteSourceToUint8Array = function(data) {
return /** @type {!Uint8Array} */(new Uint8Array(data)); return /** @type {!Uint8Array} */(new Uint8Array(data));
} }
if (data.constructor === Buffer) {
return /** @type {!Uint8Array} */(new Uint8Array(data));
}
if (data.constructor === Array) { if (data.constructor === Array) {
data = /** @type {!Array.<number>} */(data); data = /** @type {!Array.<number>} */(data);
return /** @type {!Uint8Array} */(new Uint8Array(data)); return /** @type {!Uint8Array} */(new Uint8Array(data));

@ -235,7 +235,7 @@ jspb.BinaryWriter.prototype.getResultBuffer = function() {
/** /**
* Converts the encoded data into a bas64-encoded string. * Converts the encoded data into a base64-encoded string.
* @return {string} * @return {string}
*/ */
jspb.BinaryWriter.prototype.getResultBase64String = function() { jspb.BinaryWriter.prototype.getResultBase64String = function() {
@ -716,13 +716,15 @@ jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
/** /**
* Writes a boolean field to the buffer. * Writes a boolean field to the buffer. We allow numbers as input
* because the JSPB code generator uses 0/1 instead of true/false to save space
* in the string representation of the proto.
* @param {number} field The field number. * @param {number} field The field number.
* @param {boolean?} value The value to write. * @param {boolean?|number?} value The value to write.
*/ */
jspb.BinaryWriter.prototype.writeBool = function(field, value) { jspb.BinaryWriter.prototype.writeBool = function(field, value) {
if (value == null) return; if (value == null) return;
goog.asserts.assert(goog.isBoolean(value)); goog.asserts.assert(goog.isBoolean(value) || goog.isNumber(value));
this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
this.encoder_.writeBool(value); this.encoder_.writeBool(value);
}; };

@ -0,0 +1,355 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview Test cases for Int64-manipulation functions.
*
* Test suite is written using Jasmine -- see http://jasmine.github.io/
*
* @author cfallin@google.com (Chris Fallin)
*/
goog.require('goog.testing.asserts');
goog.require('jspb.arith.Int64');
goog.require('jspb.arith.UInt64');
describe('binaryArithTest', function() {
/**
* Tests comparison operations.
*/
it('testCompare', function() {
var a = new jspb.arith.UInt64(1234, 5678);
var b = new jspb.arith.UInt64(1234, 5678);
assertEquals(a.cmp(b), 0);
assertEquals(b.cmp(a), 0);
b.lo -= 1;
assertEquals(a.cmp(b), 1);
assertEquals(b.cmp(a), -1);
b.lo += 2;
assertEquals(a.cmp(b), -1);
assertEquals(b.cmp(a), 1);
b.lo = a.lo;
b.hi = a.hi - 1;
assertEquals(a.cmp(b), 1);
assertEquals(b.cmp(a), -1);
assertEquals(a.zero(), false);
assertEquals(a.msb(), false);
assertEquals(a.lsb(), false);
a.hi = 0;
a.lo = 0;
assertEquals(a.zero(), true);
a.hi = 0x80000000;
assertEquals(a.zero(), false);
assertEquals(a.msb(), true);
a.lo = 0x00000001;
assertEquals(a.lsb(), true);
});
/**
* Tests shifts.
*/
it('testShifts', function() {
var a = new jspb.arith.UInt64(1, 0);
assertEquals(a.lo, 1);
assertEquals(a.hi, 0);
var orig = a;
a = a.leftShift();
assertEquals(orig.lo, 1); // original unmodified.
assertEquals(orig.hi, 0);
assertEquals(a.lo, 2);
assertEquals(a.hi, 0);
a = a.leftShift();
assertEquals(a.lo, 4);
assertEquals(a.hi, 0);
for (var i = 0; i < 29; i++) {
a = a.leftShift();
}
assertEquals(a.lo, 0x80000000);
assertEquals(a.hi, 0);
a = a.leftShift();
assertEquals(a.lo, 0);
assertEquals(a.hi, 1);
a = a.leftShift();
assertEquals(a.lo, 0);
assertEquals(a.hi, 2);
a = a.rightShift();
a = a.rightShift();
assertEquals(a.lo, 0x80000000);
assertEquals(a.hi, 0);
a = a.rightShift();
assertEquals(a.lo, 0x40000000);
assertEquals(a.hi, 0);
});
/**
* Tests additions.
*/
it('testAdd', function() {
var a = new jspb.arith.UInt64(/* lo = */ 0x89abcdef,
/* hi = */ 0x01234567);
var b = new jspb.arith.UInt64(/* lo = */ 0xff52ab91,
/* hi = */ 0x92fa2123);
// Addition with carry.
var c = a.add(b);
assertEquals(a.lo, 0x89abcdef); // originals unmodified.
assertEquals(a.hi, 0x01234567);
assertEquals(b.lo, 0xff52ab91);
assertEquals(b.hi, 0x92fa2123);
assertEquals(c.lo, 0x88fe7980);
assertEquals(c.hi, 0x941d668b);
// Simple addition without carry.
a.lo = 2;
a.hi = 0;
b.lo = 3;
b.hi = 0;
c = a.add(b);
assertEquals(c.lo, 5);
assertEquals(c.hi, 0);
});
/**
* Test subtractions.
*/
it('testSub', function() {
var kLength = 10;
var hiValues = [0x1682ef32,
0x583902f7,
0xb62f5955,
0x6ea99bbf,
0x25a39c20,
0x0700a08b,
0x00f7304d,
0x91a5b5af,
0x89077fd2,
0xe09e347c];
var loValues = [0xe1538b18,
0xbeacd556,
0x74100758,
0x96e3cb26,
0x56c37c3f,
0xe00b3f7d,
0x859f25d7,
0xc2ee614a,
0xe1d21cd7,
0x30aae6a4];
for (var i = 0; i < kLength; i++) {
for (var j = 0; j < kLength; j++) {
var a = new jspb.arith.UInt64(loValues[i], hiValues[j]);
var b = new jspb.arith.UInt64(loValues[j], hiValues[i]);
var c = a.add(b).sub(b);
assertEquals(c.hi, a.hi);
assertEquals(c.lo, a.lo);
}
}
});
/**
* Tests 32-by-32 multiplication.
*/
it('testMul32x32', function() {
var testData = [
// a b low(a*b) high(a*b)
[0xc0abe2f8, 0x1607898a, 0x5de711b0, 0x109471b8],
[0x915eb3cb, 0x4fb66d0e, 0xbd0d441a, 0x2d43d0bc],
[0xfe4efe70, 0x80b48c37, 0xbcddea10, 0x7fdada0c],
[0xe222fd4a, 0xe43d524a, 0xd5e0eb64, 0xc99d549c],
[0xd171f469, 0xb94ebd01, 0x4be17969, 0x979bc4fa],
[0x829cc1df, 0xe2598b38, 0xf4157dc8, 0x737c12ad],
[0xf10c3767, 0x8382881e, 0x942b3612, 0x7bd428b8],
[0xb0f6dd24, 0x232597e1, 0x079c98a4, 0x184bbce7],
[0xfcdb05a7, 0x902f55bc, 0x636199a4, 0x8e69f412],
[0x0dd0bfa9, 0x916e27b1, 0x6e2542d9, 0x07d92e65]
];
for (var i = 0; i < testData.length; i++) {
var a = testData[i][0] >>> 0;
var b = testData[i][1] >>> 0;
var cLow = testData[i][2] >>> 0;
var cHigh = testData[i][3] >>> 0;
var c = jspb.arith.UInt64.mul32x32(a, b);
assertEquals(c.lo, cLow);
assertEquals(c.hi, cHigh);
}
});
/**
* Tests 64-by-32 multiplication.
*/
it('testMul', function() {
// 64x32 bits produces 96 bits of product. The multiplication function under
// test truncates the top 32 bits, so we compare against a 64-bit expected
// product.
var testData = [
// low(a) high(a) low(a*b) high(a*b)
[0xec10955b, 0x360eb168, 0x4b7f3f5b, 0xbfcb7c59, 0x9517da5f],
[0x42b000fc, 0x9d101642, 0x6fa1ab72, 0x2584c438, 0x6a9e6d2b],
[0xf42d4fb4, 0xae366403, 0xa65a1000, 0x92434000, 0x1ff978df],
[0x17e2f56b, 0x25487693, 0xf13f98c7, 0x73794e2d, 0xa96b0c6a],
[0x492f241f, 0x76c0eb67, 0x7377ac44, 0xd4336c3c, 0xfc4b1ebe],
[0xd6b92321, 0xe184fa48, 0xd6e76904, 0x93141584, 0xcbf44da1],
[0x4bf007ea, 0x968c0a9e, 0xf5e4026a, 0x4fdb1ae4, 0x61b9fb7d],
[0x10a83be7, 0x2d685ba6, 0xc9e5fb7f, 0x2ad43499, 0x3742473d],
[0x2f261829, 0x1aca681a, 0x3d3494e3, 0x8213205b, 0x283719f8],
[0xe4f2ce21, 0x2e74b7bd, 0xd801b38b, 0xbc17feeb, 0xc6c44e0f]
];
for (var i = 0; i < testData.length; i++) {
var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
var prod = a.mul(testData[i][2]);
assertEquals(prod.lo, testData[i][3]);
assertEquals(prod.hi, testData[i][4]);
}
});
/**
* Tests 64-div-by-32 division.
*/
it('testDiv', function() {
// Compute a/b, yielding quot = a/b and rem = a%b.
var testData = [
// --- divisors in (0, 2^32-1) to test full divisor range
// low(a) high(a) b low(quot) high(quot) rem
[0x712443f1, 0xe85cefcc, 0xc1a7050b, 0x332c79ad, 0x00000001, 0x92ffa882],
[0x11912915, 0xb2699eb5, 0x30467cbe, 0xb21b4be4, 0x00000003, 0x283465dd],
[0x0d917982, 0x201f2a6e, 0x3f35bf03, 0x8217c8e4, 0x00000000, 0x153402d6],
[0xa072c108, 0x74020c96, 0xc60568fd, 0x95f9613e, 0x00000000, 0x3f4676c2],
[0xd845d5d8, 0xcdd235c4, 0x20426475, 0x6154e78b, 0x00000006, 0x202fb751],
[0xa4dbf71f, 0x9e90465e, 0xf08e022f, 0xa8be947f, 0x00000000, 0xbe43b5ce],
[0x3dbe627f, 0xa791f4b9, 0x28a5bd89, 0x1f5dfe93, 0x00000004, 0x02bf9ed4],
[0x5c1c53ee, 0xccf5102e, 0x198576e7, 0x07e3ae31, 0x00000008, 0x02ea8fb7],
[0xfef1e581, 0x04714067, 0xca6540c1, 0x059e73ec, 0x00000000, 0x31658095],
[0x1e2dd90c, 0x13dd6667, 0x8b2184c3, 0x248d1a42, 0x00000000, 0x4ca6d0c6],
// --- divisors in (0, 2^16-1) to test larger quotient high-words
// low(a) high(a) b low(quot) high(quot) rem
[0x86722b47, 0x2cd57c9a, 0x00003123, 0x2ae41b7a, 0x0000e995, 0x00000f99],
[0x1dd7884c, 0xf5e839bc, 0x00009eeb, 0x5c886242, 0x00018c21, 0x000099b6],
[0x5c53d625, 0x899fc7e5, 0x000087d7, 0xd625007a, 0x0001035c, 0x000019af],
[0x6932d932, 0x9d0a5488, 0x000051fb, 0x9d976143, 0x0001ea63, 0x00004981],
[0x4d18bb85, 0x0c92fb31, 0x00001d9f, 0x03265ab4, 0x00006cac, 0x000001b9],
[0xbe756768, 0xdea67ccb, 0x00008a03, 0x58add442, 0x00019cff, 0x000056a2],
[0xe2466f9a, 0x2521f114, 0x0000c350, 0xa0c0860d, 0x000030ab, 0x0000a48a],
[0xf00ddad1, 0xe2f5446a, 0x00002cfc, 0x762697a6, 0x00050b96, 0x00000b69],
[0xa879152a, 0x0a70e0a5, 0x00007cdf, 0xb44151b3, 0x00001567, 0x0000363d],
[0x7179a74c, 0x46083fff, 0x0000253c, 0x4d39ba6e, 0x0001e17f, 0x00000f84]
];
for (var i = 0; i < testData.length; i++) {
var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
var result = a.div(testData[i][2]);
var quotient = result[0];
var remainder = result[1];
assertEquals(quotient.lo, testData[i][3]);
assertEquals(quotient.hi, testData[i][4]);
assertEquals(remainder.lo, testData[i][5]);
}
});
/**
* Tests .toString() and .fromString().
*/
it('testStrings', function() {
var testData = [
[0x5e84c935, 0xcae33d0e, '14619595947299359029'],
[0x62b3b8b8, 0x93480544, '10612738313170434232'],
[0x319bfb13, 0xc01c4172, '13843011313344445203'],
[0x5b8a65fb, 0xa5885b31, '11927883880638080507'],
[0x6bdb80f1, 0xb0d1b16b, '12741159895737008369'],
[0x4b82b442, 0x2e0d8c97, '3318463081876730946'],
[0x780d5208, 0x7d76752c, '9040542135845999112'],
[0x2e46800f, 0x0993778d, '690026616168284175'],
[0xf00a7e32, 0xcd8e3931, '14811839111111540274'],
[0x1baeccd6, 0x923048c4, '10533999535534820566'],
[0x03669d29, 0xbff3ab72, '13831587386756603177'],
[0x2526073e, 0x01affc81, '121593346566522686'],
[0xc24244e0, 0xd7f40d0e, '15561076969511732448'],
[0xc56a341e, 0xa68b66a7, '12000798502816461854'],
[0x8738d64d, 0xbfe78604, '13828168534871037517'],
[0x5baff03b, 0xd7572aea, '15516918227177304123'],
[0x4a843d8a, 0x864e132b, '9677693725920476554'],
[0x25b4e94d, 0x22b54dc6, '2500990681505655117'],
[0x6bbe664b, 0x55a5cc0e, '6171563226690381387'],
[0xee916c81, 0xb00aabb3, '12685140089732426881']
];
for (var i = 0; i < testData.length; i++) {
var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
var roundtrip = jspb.arith.UInt64.fromString(a.toString());
assertEquals(roundtrip.lo, a.lo);
assertEquals(roundtrip.hi, a.hi);
assertEquals(a.toString(), testData[i][2]);
}
});
/**
* Tests signed Int64s. These are built on UInt64s, so we only need to test
* the explicit overrides: .toString() and .fromString().
*/
it('testSignedInt64', function() {
var testStrings = [
'-7847499644178593666',
'3771946501229139523',
'2872856549054995060',
'-5780049594274350904',
'3383785956695105201',
'2973055184857072610',
'-3879428459215627206',
'4589812431064156631',
'8484075557333689940',
'1075325817098092407',
'-4346697501012292314',
'2488620459718316637',
'6112655187423520672',
'-3655278273928612104',
'3439154019435803196',
'1004112478843763757',
'-6587790776614368413',
'664320065099714586',
'4760412909973292912',
'-7911903989602274672'
];
for (var i = 0; i < testStrings.length; i++) {
var roundtrip =
jspb.arith.Int64.fromString(testStrings[i]).toString();
assertEquals(roundtrip, testStrings[i]);
}
});
});

@ -0,0 +1,334 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview Test cases for jspb's binary protocol buffer decoder.
*
* There are two particular magic numbers that need to be pointed out -
* 2^64-1025 is the largest number representable as both a double and an
* unsigned 64-bit integer, and 2^63-513 is the largest number representable as
* both a double and a signed 64-bit integer.
*
* Test suite is written using Jasmine -- see http://jasmine.github.io/
*
* @author aappleby@google.com (Austin Appleby)
*/
goog.require('goog.testing.asserts');
goog.require('jspb.BinaryConstants');
goog.require('jspb.BinaryDecoder');
goog.require('jspb.BinaryEncoder');
/**
* Tests encoding and decoding of unsigned types.
* @param {Function} readValue
* @param {Function} writeValue
* @param {number} epsilon
* @param {number} upperLimit
* @param {Function} filter
* @suppress {missingProperties|visibility}
*/
function doTestUnsignedValue(readValue,
writeValue, epsilon, upperLimit, filter) {
var encoder = new jspb.BinaryEncoder();
// Encode zero and limits.
writeValue.call(encoder, filter(0));
writeValue.call(encoder, filter(epsilon));
writeValue.call(encoder, filter(upperLimit));
// Encode positive values.
for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
writeValue.call(encoder, filter(cursor));
}
var decoder = jspb.BinaryDecoder.alloc(encoder.end());
// Check zero and limits.
assertEquals(filter(0), readValue.call(decoder));
assertEquals(filter(epsilon), readValue.call(decoder));
assertEquals(filter(upperLimit), readValue.call(decoder));
// Check positive values.
for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
if (filter(cursor) != readValue.call(decoder)) throw 'fail!';
}
// Encoding values outside the valid range should assert.
assertThrows(function() {writeValue.call(encoder, -1);});
assertThrows(function() {writeValue.call(encoder, upperLimit * 1.1);});
}
/**
* Tests encoding and decoding of signed types.
* @param {Function} readValue
* @param {Function} writeValue
* @param {number} epsilon
* @param {number} lowerLimit
* @param {number} upperLimit
* @param {Function} filter
* @suppress {missingProperties}
*/
function doTestSignedValue(readValue,
writeValue, epsilon, lowerLimit, upperLimit, filter) {
var encoder = new jspb.BinaryEncoder();
// Encode zero and limits.
writeValue.call(encoder, filter(lowerLimit));
writeValue.call(encoder, filter(-epsilon));
writeValue.call(encoder, filter(0));
writeValue.call(encoder, filter(epsilon));
writeValue.call(encoder, filter(upperLimit));
var inputValues = [];
// Encode negative values.
for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
var val = filter(cursor);
writeValue.call(encoder, val);
inputValues.push(val);
}
// Encode positive values.
for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
var val = filter(cursor);
writeValue.call(encoder, val);
inputValues.push(val);
}
var decoder = jspb.BinaryDecoder.alloc(encoder.end());
// Check zero and limits.
assertEquals(filter(lowerLimit), readValue.call(decoder));
assertEquals(filter(-epsilon), readValue.call(decoder));
assertEquals(filter(0), readValue.call(decoder));
assertEquals(filter(epsilon), readValue.call(decoder));
assertEquals(filter(upperLimit), readValue.call(decoder));
// Verify decoded values.
for (var i = 0; i < inputValues.length; i++) {
assertEquals(inputValues[i], readValue.call(decoder));
}
// Encoding values outside the valid range should assert.
assertThrows(function() {writeValue.call(encoder, lowerLimit * 1.1);});
assertThrows(function() {writeValue.call(encoder, upperLimit * 1.1);});
}
describe('binaryDecoderTest', function() {
/**
* Tests the decoder instance cache.
*/
it('testInstanceCache', /** @suppress {visibility} */ function() {
// Empty the instance caches.
jspb.BinaryDecoder.instanceCache_ = [];
// Allocating and then freeing a decoder should put it in the instance
// cache.
jspb.BinaryDecoder.alloc().free();
assertEquals(1, jspb.BinaryDecoder.instanceCache_.length);
// Allocating and then freeing three decoders should leave us with three in
// the cache.
var decoder1 = jspb.BinaryDecoder.alloc();
var decoder2 = jspb.BinaryDecoder.alloc();
var decoder3 = jspb.BinaryDecoder.alloc();
decoder1.free();
decoder2.free();
decoder3.free();
assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
});
/**
* Tests reading 64-bit integers as hash strings.
*/
it('testHashStrings', function() {
var encoder = new jspb.BinaryEncoder();
var hashA = String.fromCharCode(0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00);
var hashB = String.fromCharCode(0x12, 0x34, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00);
var hashC = String.fromCharCode(0x12, 0x34, 0x56, 0x78,
0x87, 0x65, 0x43, 0x21);
var hashD = String.fromCharCode(0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF);
encoder.writeVarintHash64(hashA);
encoder.writeVarintHash64(hashB);
encoder.writeVarintHash64(hashC);
encoder.writeVarintHash64(hashD);
encoder.writeFixedHash64(hashA);
encoder.writeFixedHash64(hashB);
encoder.writeFixedHash64(hashC);
encoder.writeFixedHash64(hashD);
var decoder = jspb.BinaryDecoder.alloc(encoder.end());
assertEquals(hashA, decoder.readVarintHash64());
assertEquals(hashB, decoder.readVarintHash64());
assertEquals(hashC, decoder.readVarintHash64());
assertEquals(hashD, decoder.readVarintHash64());
assertEquals(hashA, decoder.readFixedHash64());
assertEquals(hashB, decoder.readFixedHash64());
assertEquals(hashC, decoder.readFixedHash64());
assertEquals(hashD, decoder.readFixedHash64());
});
/**
* Verifies that misuse of the decoder class triggers assertions.
* @suppress {checkTypes|visibility}
*/
it('testDecodeErrors', function() {
// Reading a value past the end of the stream should trigger an assertion.
var decoder = jspb.BinaryDecoder.alloc([0, 1, 2]);
assertThrows(function() {decoder.readUint64()});
// Overlong varints should trigger assertions.
decoder.setBlock([255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 0]);
assertThrows(function() {decoder.readUnsignedVarint64()});
decoder.reset();
assertThrows(function() {decoder.readSignedVarint64()});
decoder.reset();
assertThrows(function() {decoder.readZigzagVarint64()});
// Positive 32-bit varints encoded with 1 bits in positions 33 through 35
// should trigger assertions.
decoder.setBlock([255, 255, 255, 255, 0x1F]);
assertThrows(function() {decoder.readUnsignedVarint32()});
decoder.setBlock([255, 255, 255, 255, 0x2F]);
assertThrows(function() {decoder.readUnsignedVarint32()});
decoder.setBlock([255, 255, 255, 255, 0x4F]);
assertThrows(function() {decoder.readUnsignedVarint32()});
// Negative 32-bit varints encoded with non-1 bits in the high dword should
// trigger assertions.
decoder.setBlock([255, 255, 255, 255, 255, 255, 0, 255, 255, 1]);
assertThrows(function() {decoder.readUnsignedVarint32()});
decoder.setBlock([255, 255, 255, 255, 255, 255, 255, 255, 255, 0]);
assertThrows(function() {decoder.readUnsignedVarint32()});
});
/**
* Tests encoding and decoding of unsigned integers.
*/
it('testUnsignedIntegers', function() {
doTestUnsignedValue(
jspb.BinaryDecoder.prototype.readUint8,
jspb.BinaryEncoder.prototype.writeUint8,
1, 0xFF, Math.round);
doTestUnsignedValue(
jspb.BinaryDecoder.prototype.readUint16,
jspb.BinaryEncoder.prototype.writeUint16,
1, 0xFFFF, Math.round);
doTestUnsignedValue(
jspb.BinaryDecoder.prototype.readUint32,
jspb.BinaryEncoder.prototype.writeUint32,
1, 0xFFFFFFFF, Math.round);
doTestUnsignedValue(
jspb.BinaryDecoder.prototype.readUint64,
jspb.BinaryEncoder.prototype.writeUint64,
1, Math.pow(2, 64) - 1025, Math.round);
});
/**
* Tests encoding and decoding of signed integers.
*/
it('testSignedIntegers', function() {
doTestSignedValue(
jspb.BinaryDecoder.prototype.readInt8,
jspb.BinaryEncoder.prototype.writeInt8,
1, -0x80, 0x7F, Math.round);
doTestSignedValue(
jspb.BinaryDecoder.prototype.readInt16,
jspb.BinaryEncoder.prototype.writeInt16,
1, -0x8000, 0x7FFF, Math.round);
doTestSignedValue(
jspb.BinaryDecoder.prototype.readInt32,
jspb.BinaryEncoder.prototype.writeInt32,
1, -0x80000000, 0x7FFFFFFF, Math.round);
doTestSignedValue(
jspb.BinaryDecoder.prototype.readInt64,
jspb.BinaryEncoder.prototype.writeInt64,
1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
});
/**
* Tests encoding and decoding of floats.
*/
it('testFloats', function() {
/**
* @param {number} x
* @return {number}
*/
function truncate(x) {
var temp = new Float32Array(1);
temp[0] = x;
return temp[0];
}
doTestSignedValue(
jspb.BinaryDecoder.prototype.readFloat,
jspb.BinaryEncoder.prototype.writeFloat,
jspb.BinaryConstants.FLOAT32_EPS,
-jspb.BinaryConstants.FLOAT32_MAX,
jspb.BinaryConstants.FLOAT32_MAX,
truncate);
doTestSignedValue(
jspb.BinaryDecoder.prototype.readDouble,
jspb.BinaryEncoder.prototype.writeDouble,
jspb.BinaryConstants.FLOAT64_EPS * 10,
-jspb.BinaryConstants.FLOAT64_MAX,
jspb.BinaryConstants.FLOAT64_MAX,
function(x) { return x; });
});
});

@ -0,0 +1,628 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test suite is written using Jasmine -- see http://jasmine.github.io/
goog.require('goog.crypt.base64');
goog.require('goog.testing.asserts');
goog.require('jspb.Message');
// CommonJS-LoadFromFile: ../testbinary_pb proto.jspb.test
goog.require('proto.jspb.test.ExtendsWithMessage');
goog.require('proto.jspb.test.ForeignEnum');
goog.require('proto.jspb.test.ForeignMessage');
goog.require('proto.jspb.test.TestAllTypes');
goog.require('proto.jspb.test.TestExtendable');
goog.require('proto.jspb.test.extendOptionalBool');
goog.require('proto.jspb.test.extendOptionalBytes');
goog.require('proto.jspb.test.extendOptionalDouble');
goog.require('proto.jspb.test.extendOptionalFixed32');
goog.require('proto.jspb.test.extendOptionalFixed64');
goog.require('proto.jspb.test.extendOptionalFloat');
goog.require('proto.jspb.test.extendOptionalForeignEnum');
goog.require('proto.jspb.test.extendOptionalInt32');
goog.require('proto.jspb.test.extendOptionalInt64');
goog.require('proto.jspb.test.extendOptionalSfixed32');
goog.require('proto.jspb.test.extendOptionalSfixed64');
goog.require('proto.jspb.test.extendOptionalSint32');
goog.require('proto.jspb.test.extendOptionalSint64');
goog.require('proto.jspb.test.extendOptionalString');
goog.require('proto.jspb.test.extendOptionalUint32');
goog.require('proto.jspb.test.extendOptionalUint64');
goog.require('proto.jspb.test.extendPackedRepeatedBoolList');
goog.require('proto.jspb.test.extendPackedRepeatedDoubleList');
goog.require('proto.jspb.test.extendPackedRepeatedFixed32List');
goog.require('proto.jspb.test.extendPackedRepeatedFixed64List');
goog.require('proto.jspb.test.extendPackedRepeatedFloatList');
goog.require('proto.jspb.test.extendPackedRepeatedForeignEnumList');
goog.require('proto.jspb.test.extendPackedRepeatedInt32List');
goog.require('proto.jspb.test.extendPackedRepeatedInt64List');
goog.require('proto.jspb.test.extendPackedRepeatedSfixed32List');
goog.require('proto.jspb.test.extendPackedRepeatedSfixed64List');
goog.require('proto.jspb.test.extendPackedRepeatedSint32List');
goog.require('proto.jspb.test.extendPackedRepeatedSint64List');
goog.require('proto.jspb.test.extendPackedRepeatedUint32List');
goog.require('proto.jspb.test.extendPackedRepeatedUint64List');
goog.require('proto.jspb.test.extendRepeatedBoolList');
goog.require('proto.jspb.test.extendRepeatedBytesList');
goog.require('proto.jspb.test.extendRepeatedDoubleList');
goog.require('proto.jspb.test.extendRepeatedFixed32List');
goog.require('proto.jspb.test.extendRepeatedFixed64List');
goog.require('proto.jspb.test.extendRepeatedFloatList');
goog.require('proto.jspb.test.extendRepeatedForeignEnumList');
goog.require('proto.jspb.test.extendRepeatedInt32List');
goog.require('proto.jspb.test.extendRepeatedInt64List');
goog.require('proto.jspb.test.extendRepeatedSfixed32List');
goog.require('proto.jspb.test.extendRepeatedSfixed64List');
goog.require('proto.jspb.test.extendRepeatedSint32List');
goog.require('proto.jspb.test.extendRepeatedSint64List');
goog.require('proto.jspb.test.extendRepeatedStringList');
goog.require('proto.jspb.test.extendRepeatedUint32List');
goog.require('proto.jspb.test.extendRepeatedUint64List');
var suite = {};
var BYTES = new Uint8Array([1, 2, 8, 9]);
var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
/**
* Helper: fill all fields on a TestAllTypes message.
* @param {proto.jspb.test.TestAllTypes} msg
*/
function fillAllFields(msg) {
msg.setOptionalInt32(-42);
// can be exactly represented by JS number (64-bit double, i.e., 52-bit
// mantissa).
msg.setOptionalInt64(-0x7fffffff00000000);
msg.setOptionalUint32(0x80000000);
msg.setOptionalUint64(0xf000000000000000);
msg.setOptionalSint32(-100);
msg.setOptionalSint64(-0x8000000000000000);
msg.setOptionalFixed32(1234);
msg.setOptionalFixed64(0x1234567800000000);
msg.setOptionalSfixed32(-1234);
msg.setOptionalSfixed64(-0x1234567800000000);
msg.setOptionalFloat(1.5);
msg.setOptionalDouble(-1.5);
msg.setOptionalBool(true);
msg.setOptionalString('hello world');
msg.setOptionalBytes(BYTES);
msg.setOptionalGroup(new proto.jspb.test.TestAllTypes.OptionalGroup());
msg.getOptionalGroup().setA(100);
var submsg = new proto.jspb.test.ForeignMessage();
submsg.setC(16);
msg.setOptionalForeignMessage(submsg);
msg.setOptionalForeignEnum(proto.jspb.test.ForeignEnum.FOREIGN_FOO);
msg.setOneofString('oneof');
msg.setRepeatedInt32List([-42]);
msg.setRepeatedInt64List([-0x7fffffff00000000]);
msg.setRepeatedUint32List([0x80000000]);
msg.setRepeatedUint64List([0xf000000000000000]);
msg.setRepeatedSint32List([-100]);
msg.setRepeatedSint64List([-0x8000000000000000]);
msg.setRepeatedFixed32List([1234]);
msg.setRepeatedFixed64List([0x1234567800000000]);
msg.setRepeatedSfixed32List([-1234]);
msg.setRepeatedSfixed64List([-0x1234567800000000]);
msg.setRepeatedFloatList([1.5]);
msg.setRepeatedDoubleList([-1.5]);
msg.setRepeatedBoolList([true]);
msg.setRepeatedStringList(['hello world']);
msg.setRepeatedBytesList([BYTES, BYTES]);
msg.setRepeatedGroupList([new proto.jspb.test.TestAllTypes.RepeatedGroup()]);
msg.getRepeatedGroupList()[0].setA(100);
submsg = new proto.jspb.test.ForeignMessage();
submsg.setC(1000);
msg.setRepeatedForeignMessageList([submsg]);
msg.setRepeatedForeignEnumList([proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
msg.setPackedRepeatedInt32List([-42]);
msg.setPackedRepeatedInt64List([-0x7fffffff00000000]);
msg.setPackedRepeatedUint32List([0x80000000]);
msg.setPackedRepeatedUint64List([0xf000000000000000]);
msg.setPackedRepeatedSint32List([-100]);
msg.setPackedRepeatedSint64List([-0x8000000000000000]);
msg.setPackedRepeatedFixed32List([1234]);
msg.setPackedRepeatedFixed64List([0x1234567800000000]);
msg.setPackedRepeatedSfixed32List([-1234]);
msg.setPackedRepeatedSfixed64List([-0x1234567800000000]);
msg.setPackedRepeatedFloatList([1.5]);
msg.setPackedRepeatedDoubleList([-1.5]);
msg.setPackedRepeatedBoolList([true]);
}
/**
* Helper: compare a bytes field to an expected value
* @param {Uint8Array|string} arr
* @param {Uint8Array} expected
* @return {boolean}
*/
function bytesCompare(arr, expected) {
if (goog.isString(arr)) {
arr = goog.crypt.base64.decodeStringToUint8Array(arr);
}
if (arr.length != expected.length) {
return false;
}
for (var i = 0; i < arr.length; i++) {
if (arr[i] != expected[i]) {
return false;
}
}
return true;
}
/**
* Helper: verify contents of given TestAllTypes message as set by
* fillAllFields().
* @param {proto.jspb.test.TestAllTypes} original
* @param {proto.jspb.test.TestAllTypes} copy
*/
function checkAllFields(original, copy) {
assertTrue(jspb.Message.equals(original, copy));
assertEquals(copy.getOptionalInt32(), -42);
assertEquals(copy.getOptionalInt64(), -0x7fffffff00000000);
assertEquals(copy.getOptionalUint32(), 0x80000000);
assertEquals(copy.getOptionalUint64(), 0xf000000000000000);
assertEquals(copy.getOptionalSint32(), -100);
assertEquals(copy.getOptionalSint64(), -0x8000000000000000);
assertEquals(copy.getOptionalFixed32(), 1234);
assertEquals(copy.getOptionalFixed64(), 0x1234567800000000);
assertEquals(copy.getOptionalSfixed32(), -1234);
assertEquals(copy.getOptionalSfixed64(), -0x1234567800000000);
assertEquals(copy.getOptionalFloat(), 1.5);
assertEquals(copy.getOptionalDouble(), -1.5);
assertEquals(copy.getOptionalBool(), true);
assertEquals(copy.getOptionalString(), 'hello world');
assertEquals(true, bytesCompare(copy.getOptionalBytes(), BYTES));
assertEquals(true, bytesCompare(copy.getOptionalBytes_asU8(), BYTES));
assertEquals(
copy.getOptionalBytes_asB64(), goog.crypt.base64.encodeByteArray(BYTES));
assertEquals(copy.getOptionalGroup().getA(), 100);
assertEquals(copy.getOptionalForeignMessage().getC(), 16);
assertEquals(copy.getOptionalForeignEnum(),
proto.jspb.test.ForeignEnum.FOREIGN_FOO);
assertEquals(copy.getOneofString(), 'oneof');
assertEquals(copy.getOneofFieldCase(),
proto.jspb.test.TestAllTypes.OneofFieldCase.ONEOF_STRING);
assertElementsEquals(copy.getRepeatedInt32List(), [-42]);
assertElementsEquals(copy.getRepeatedInt64List(), [-0x7fffffff00000000]);
assertElementsEquals(copy.getRepeatedUint32List(), [0x80000000]);
assertElementsEquals(copy.getRepeatedUint64List(), [0xf000000000000000]);
assertElementsEquals(copy.getRepeatedSint32List(), [-100]);
assertElementsEquals(copy.getRepeatedSint64List(), [-0x8000000000000000]);
assertElementsEquals(copy.getRepeatedFixed32List(), [1234]);
assertElementsEquals(copy.getRepeatedFixed64List(), [0x1234567800000000]);
assertElementsEquals(copy.getRepeatedSfixed32List(), [-1234]);
assertElementsEquals(copy.getRepeatedSfixed64List(), [-0x1234567800000000]);
assertElementsEquals(copy.getRepeatedFloatList(), [1.5]);
assertElementsEquals(copy.getRepeatedDoubleList(), [-1.5]);
assertElementsEquals(copy.getRepeatedBoolList(), [true]);
assertElementsEquals(copy.getRepeatedStringList(), ['hello world']);
assertEquals(copy.getRepeatedBytesList().length, 2);
assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[0], BYTES));
assertEquals(true, bytesCompare(copy.getRepeatedBytesList()[0], BYTES));
assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[1], BYTES));
assertEquals(copy.getRepeatedBytesList_asB64()[0], BYTES_B64);
assertEquals(copy.getRepeatedBytesList_asB64()[1], BYTES_B64);
assertEquals(copy.getRepeatedGroupList().length, 1);
assertEquals(copy.getRepeatedGroupList()[0].getA(), 100);
assertEquals(copy.getRepeatedForeignMessageList().length, 1);
assertEquals(copy.getRepeatedForeignMessageList()[0].getC(), 1000);
assertElementsEquals(copy.getRepeatedForeignEnumList(),
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
assertElementsEquals(copy.getPackedRepeatedInt32List(), [-42]);
assertElementsEquals(copy.getPackedRepeatedInt64List(),
[-0x7fffffff00000000]);
assertElementsEquals(copy.getPackedRepeatedUint32List(), [0x80000000]);
assertElementsEquals(copy.getPackedRepeatedUint64List(),
[0xf000000000000000]);
assertElementsEquals(copy.getPackedRepeatedSint32List(), [-100]);
assertElementsEquals(copy.getPackedRepeatedSint64List(),
[-0x8000000000000000]);
assertElementsEquals(copy.getPackedRepeatedFixed32List(), [1234]);
assertElementsEquals(copy.getPackedRepeatedFixed64List(),
[0x1234567800000000]);
assertElementsEquals(copy.getPackedRepeatedSfixed32List(), [-1234]);
assertElementsEquals(copy.getPackedRepeatedSfixed64List(),
[-0x1234567800000000]);
assertElementsEquals(copy.getPackedRepeatedFloatList(), [1.5]);
assertElementsEquals(copy.getPackedRepeatedDoubleList(), [-1.5]);
}
/**
* Helper: verify that all expected extensions are present.
* @param {!proto.jspb.test.TestExtendable} msg
*/
function checkExtensions(msg) {
assertEquals(-42,
msg.getExtension(proto.jspb.test.extendOptionalInt32));
assertEquals(-0x7fffffff00000000,
msg.getExtension(proto.jspb.test.extendOptionalInt64));
assertEquals(0x80000000,
msg.getExtension(proto.jspb.test.extendOptionalUint32));
assertEquals(0xf000000000000000,
msg.getExtension(proto.jspb.test.extendOptionalUint64));
assertEquals(-100,
msg.getExtension(proto.jspb.test.extendOptionalSint32));
assertEquals(-0x8000000000000000,
msg.getExtension(proto.jspb.test.extendOptionalSint64));
assertEquals(1234,
msg.getExtension(proto.jspb.test.extendOptionalFixed32));
assertEquals(0x1234567800000000,
msg.getExtension(proto.jspb.test.extendOptionalFixed64));
assertEquals(-1234,
msg.getExtension(proto.jspb.test.extendOptionalSfixed32));
assertEquals(-0x1234567800000000,
msg.getExtension(proto.jspb.test.extendOptionalSfixed64));
assertEquals(1.5,
msg.getExtension(proto.jspb.test.extendOptionalFloat));
assertEquals(-1.5,
msg.getExtension(proto.jspb.test.extendOptionalDouble));
assertEquals(true,
msg.getExtension(proto.jspb.test.extendOptionalBool));
assertEquals('hello world',
msg.getExtension(proto.jspb.test.extendOptionalString));
assertEquals(
true, bytesCompare(
msg.getExtension(proto.jspb.test.extendOptionalBytes), BYTES));
assertEquals(16,
msg.getExtension(
proto.jspb.test.ExtendsWithMessage.optionalExtension).getFoo());
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedInt32List),
[-42]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedInt64List),
[-0x7fffffff00000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedUint32List),
[0x80000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedUint64List),
[0xf000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSint32List),
[-100]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSint64List),
[-0x8000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedFixed32List),
[1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedFixed64List),
[0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSfixed32List),
[-1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedSfixed64List),
[-0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedFloatList),
[1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedDoubleList),
[-1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedBoolList),
[true]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedStringList),
['hello world']);
assertEquals(
true,
bytesCompare(
msg.getExtension(proto.jspb.test.extendRepeatedBytesList)[0], BYTES));
assertEquals(1000,
msg.getExtension(
proto.jspb.test.ExtendsWithMessage.repeatedExtensionList)[0]
.getFoo());
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendRepeatedForeignEnumList),
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedInt32List),
[-42]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedInt64List),
[-0x7fffffff00000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedUint32List),
[0x80000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedUint64List),
[0xf000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSint32List),
[-100]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSint64List),
[-0x8000000000000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed32List),
[1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed64List),
[0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed32List),
[-1234]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed64List),
[-0x1234567800000000]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedFloatList),
[1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedDoubleList),
[-1.5]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedBoolList),
[true]);
assertElementsEquals(
msg.getExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList),
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
}
describe('protoBinaryTest', function() {
/**
* Tests a basic serialization-deserializaton round-trip with all supported
* field types (on the TestAllTypes message type).
*/
it('testRoundTrip', function() {
var msg = new proto.jspb.test.TestAllTypes();
fillAllFields(msg);
var encoded = msg.serializeBinary();
var decoded = proto.jspb.test.TestAllTypes.deserializeBinary(encoded);
checkAllFields(msg, decoded);
});
/**
* Test that base64 string and Uint8Array are interchangeable in bytes fields.
*/
it('testBytesFieldsGettersInterop', function() {
var msg = new proto.jspb.test.TestAllTypes();
// Set from a base64 string and check all the getters work.
msg.setOptionalBytes(BYTES_B64);
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
// Test binary serialize round trip doesn't break it.
msg = proto.jspb.test.TestAllTypes.deserializeBinary(msg.serializeBinary());
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg = new proto.jspb.test.TestAllTypes();
// Set from a Uint8Array and check all the getters work.
msg.setOptionalBytes(BYTES);
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
});
/**
* Test that bytes setters will receive result of any of the getters.
*/
it('testBytesFieldsSettersInterop', function() {
var msg = new proto.jspb.test.TestAllTypes();
msg.setOptionalBytes(BYTES);
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg.setOptionalBytes(msg.getOptionalBytes());
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg.setOptionalBytes(msg.getOptionalBytes_asB64());
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg.setOptionalBytes(msg.getOptionalBytes_asU8());
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
});
/**
* Test that bytes setters will receive result of any of the getters.
*/
it('testRepeatedBytesGetters', function() {
var msg = new proto.jspb.test.TestAllTypes();
function assertGetters() {
assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[0]));
assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[1]));
assertTrue(msg.getRepeatedBytesList_asU8()[0] instanceof Uint8Array);
assertTrue(msg.getRepeatedBytesList_asU8()[1] instanceof Uint8Array);
assertTrue(bytesCompare(msg.getRepeatedBytesList()[0], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList()[1], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[0], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[1], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[0], BYTES));
assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[1], BYTES));
}
msg.setRepeatedBytesList([BYTES, BYTES]);
assertGetters();
msg.setRepeatedBytesList([BYTES_B64, BYTES_B64]);
assertGetters();
msg.setRepeatedBytesList([]);
assertEquals(0, msg.getRepeatedBytesList().length);
assertEquals(0, msg.getRepeatedBytesList_asB64().length);
assertEquals(0, msg.getRepeatedBytesList_asU8().length);
});
/**
* Helper: fill all extension values.
* @param {proto.jspb.test.TestExtendable} msg
*/
function fillExtensions(msg) {
msg.setExtension(
proto.jspb.test.extendOptionalInt32, -42);
msg.setExtension(
proto.jspb.test.extendOptionalInt64, -0x7fffffff00000000);
msg.setExtension(
proto.jspb.test.extendOptionalUint32, 0x80000000);
msg.setExtension(
proto.jspb.test.extendOptionalUint64, 0xf000000000000000);
msg.setExtension(
proto.jspb.test.extendOptionalSint32, -100);
msg.setExtension(
proto.jspb.test.extendOptionalSint64, -0x8000000000000000);
msg.setExtension(
proto.jspb.test.extendOptionalFixed32, 1234);
msg.setExtension(
proto.jspb.test.extendOptionalFixed64, 0x1234567800000000);
msg.setExtension(
proto.jspb.test.extendOptionalSfixed32, -1234);
msg.setExtension(
proto.jspb.test.extendOptionalSfixed64, -0x1234567800000000);
msg.setExtension(
proto.jspb.test.extendOptionalFloat, 1.5);
msg.setExtension(
proto.jspb.test.extendOptionalDouble, -1.5);
msg.setExtension(
proto.jspb.test.extendOptionalBool, true);
msg.setExtension(
proto.jspb.test.extendOptionalString, 'hello world');
msg.setExtension(proto.jspb.test.extendOptionalBytes, BYTES);
var submsg = new proto.jspb.test.ExtendsWithMessage();
submsg.setFoo(16);
msg.setExtension(
proto.jspb.test.ExtendsWithMessage.optionalExtension, submsg);
msg.setExtension(
proto.jspb.test.extendOptionalForeignEnum,
proto.jspb.test.ForeignEnum.FOREIGN_FOO);
msg.setExtension(
proto.jspb.test.extendRepeatedInt32List, [-42]);
msg.setExtension(
proto.jspb.test.extendRepeatedInt64List, [-0x7fffffff00000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedUint32List, [0x80000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedUint64List, [0xf000000000000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedSint32List, [-100]);
msg.setExtension(
proto.jspb.test.extendRepeatedSint64List, [-0x8000000000000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedFixed32List, [1234]);
msg.setExtension(
proto.jspb.test.extendRepeatedFixed64List, [0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedSfixed32List, [-1234]);
msg.setExtension(
proto.jspb.test.extendRepeatedSfixed64List, [-0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendRepeatedFloatList, [1.5]);
msg.setExtension(
proto.jspb.test.extendRepeatedDoubleList, [-1.5]);
msg.setExtension(
proto.jspb.test.extendRepeatedBoolList, [true]);
msg.setExtension(
proto.jspb.test.extendRepeatedStringList, ['hello world']);
msg.setExtension(proto.jspb.test.extendRepeatedBytesList, [BYTES]);
submsg = new proto.jspb.test.ExtendsWithMessage();
submsg.setFoo(1000);
msg.setExtension(
proto.jspb.test.ExtendsWithMessage.repeatedExtensionList, [submsg]);
msg.setExtension(proto.jspb.test.extendRepeatedForeignEnumList,
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedInt32List, [-42]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedInt64List, [-0x7fffffff00000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedUint32List, [0x80000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedUint64List, [0xf000000000000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSint32List, [-100]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSint64List, [-0x8000000000000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedFixed32List, [1234]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedFixed64List, [0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSfixed32List, [-1234]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedSfixed64List,
[-0x1234567800000000]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedFloatList, [1.5]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedDoubleList, [-1.5]);
msg.setExtension(
proto.jspb.test.extendPackedRepeatedBoolList, [true]);
msg.setExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList,
[proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
}
/**
* Tests extension serialization and deserialization.
*/
it('testExtensions', function() {
var msg = new proto.jspb.test.TestExtendable();
fillExtensions(msg);
var encoded = msg.serializeBinary();
var decoded = proto.jspb.test.TestExtendable.deserializeBinary(encoded);
checkExtensions(decoded);
});
});

@ -0,0 +1,922 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview Test cases for jspb's binary protocol buffer reader.
*
* There are two particular magic numbers that need to be pointed out -
* 2^64-1025 is the largest number representable as both a double and an
* unsigned 64-bit integer, and 2^63-513 is the largest number representable as
* both a double and a signed 64-bit integer.
*
* Test suite is written using Jasmine -- see http://jasmine.github.io/
*
* @author aappleby@google.com (Austin Appleby)
*/
goog.require('goog.testing.asserts');
goog.require('jspb.BinaryConstants');
goog.require('jspb.BinaryDecoder');
goog.require('jspb.BinaryReader');
goog.require('jspb.BinaryWriter');
describe('binaryReaderTest', function() {
/**
* Tests the reader instance cache.
*/
it('testInstanceCaches', /** @suppress {visibility} */ function() {
var writer = new jspb.BinaryWriter();
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
writer.writeMessage(1, dummyMessage, goog.nullFunction);
writer.writeMessage(2, dummyMessage, goog.nullFunction);
var buffer = writer.getResultBuffer();
// Empty the instance caches.
jspb.BinaryReader.instanceCache_ = [];
// Allocating and then freeing three decoders should leave us with three in
// the cache.
var decoder1 = jspb.BinaryDecoder.alloc();
var decoder2 = jspb.BinaryDecoder.alloc();
var decoder3 = jspb.BinaryDecoder.alloc();
decoder1.free();
decoder2.free();
decoder3.free();
assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
assertEquals(0, jspb.BinaryReader.instanceCache_.length);
// Allocating and then freeing a reader should remove one decoder from its
// cache, but it should stay stuck to the reader afterwards since we can't
// have a reader without a decoder.
jspb.BinaryReader.alloc().free();
assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
assertEquals(1, jspb.BinaryReader.instanceCache_.length);
// Allocating a reader should remove a reader from the cache.
var reader = jspb.BinaryReader.alloc(buffer);
assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
assertEquals(0, jspb.BinaryReader.instanceCache_.length);
// Processing the message reuses the current reader.
reader.nextField();
assertEquals(1, reader.getFieldNumber());
reader.readMessage(dummyMessage, function() {
assertEquals(0, jspb.BinaryReader.instanceCache_.length);
});
reader.nextField();
assertEquals(2, reader.getFieldNumber());
reader.readMessage(dummyMessage, function() {
assertEquals(0, jspb.BinaryReader.instanceCache_.length);
});
assertEquals(false, reader.nextField());
assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
assertEquals(0, jspb.BinaryReader.instanceCache_.length);
// Freeing the reader should put it back into the cache.
reader.free();
assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
assertEquals(1, jspb.BinaryReader.instanceCache_.length);
});
/**
* @param {number} x
* @return {number}
*/
function truncate(x) {
var temp = new Float32Array(1);
temp[0] = x;
return temp[0];
}
/**
* Verifies that misuse of the reader class triggers assertions.
*/
it('testReadErrors', /** @suppress {checkTypes|visibility} */ function() {
// Calling readMessage on a non-delimited field should trigger an
// assertion.
var reader = jspb.BinaryReader.alloc([8, 1]);
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
reader.nextField();
assertThrows(function() {
reader.readMessage(dummyMessage, goog.nullFunction);
});
// Reading past the end of the stream should trigger an assertion.
reader = jspb.BinaryReader.alloc([9, 1]);
reader.nextField();
assertThrows(function() {reader.readFixed64()});
// Reading past the end of a submessage should trigger an assertion.
reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]);
reader.nextField();
reader.readMessage(dummyMessage, function() {
reader.nextField();
assertThrows(function() {reader.readFixed32()});
});
// Skipping an invalid field should trigger an assertion.
reader = jspb.BinaryReader.alloc([12, 1]);
reader.nextWireType_ = 1000;
assertThrows(function() {reader.skipField()});
// Reading fields with the wrong wire type should assert.
reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]);
reader.nextField();
assertThrows(function() {reader.readInt32()});
assertThrows(function() {reader.readInt32String()});
assertThrows(function() {reader.readInt64()});
assertThrows(function() {reader.readInt64String()});
assertThrows(function() {reader.readUint32()});
assertThrows(function() {reader.readUint32String()});
assertThrows(function() {reader.readUint64()});
assertThrows(function() {reader.readUint64String()});
assertThrows(function() {reader.readSint32()});
assertThrows(function() {reader.readBool()});
assertThrows(function() {reader.readEnum()});
reader = jspb.BinaryReader.alloc([8, 1]);
reader.nextField();
assertThrows(function() {reader.readFixed32()});
assertThrows(function() {reader.readFixed64()});
assertThrows(function() {reader.readSfixed32()});
assertThrows(function() {reader.readSfixed64()});
assertThrows(function() {reader.readFloat()});
assertThrows(function() {reader.readDouble()});
assertThrows(function() {reader.readString()});
assertThrows(function() {reader.readBytes()});
});
/**
* Tests encoding and decoding of unsigned field types.
* @param {Function} readField
* @param {Function} writeField
* @param {number} epsilon
* @param {number} upperLimit
* @param {Function} filter
* @private
* @suppress {missingProperties}
*/
var doTestUnsignedField_ = function(readField,
writeField, epsilon, upperLimit, filter) {
assertNotNull(readField);
assertNotNull(writeField);
var writer = new jspb.BinaryWriter();
// Encode zero and limits.
writeField.call(writer, 1, filter(0));
writeField.call(writer, 2, filter(epsilon));
writeField.call(writer, 3, filter(upperLimit));
// Encode positive values.
for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
writeField.call(writer, 4, filter(cursor));
}
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
// Check zero and limits.
reader.nextField();
assertEquals(1, reader.getFieldNumber());
assertEquals(filter(0), readField.call(reader));
reader.nextField();
assertEquals(2, reader.getFieldNumber());
assertEquals(filter(epsilon), readField.call(reader));
reader.nextField();
assertEquals(3, reader.getFieldNumber());
assertEquals(filter(upperLimit), readField.call(reader));
// Check positive values.
for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
reader.nextField();
if (4 != reader.getFieldNumber()) throw 'fail!';
if (filter(cursor) != readField.call(reader)) throw 'fail!';
}
};
/**
* Tests encoding and decoding of signed field types.
* @param {Function} readField
* @param {Function} writeField
* @param {number} epsilon
* @param {number} lowerLimit
* @param {number} upperLimit
* @param {Function} filter
* @private
* @suppress {missingProperties}
*/
var doTestSignedField_ = function(readField,
writeField, epsilon, lowerLimit, upperLimit, filter) {
var writer = new jspb.BinaryWriter();
// Encode zero and limits.
writeField.call(writer, 1, filter(lowerLimit));
writeField.call(writer, 2, filter(-epsilon));
writeField.call(writer, 3, filter(0));
writeField.call(writer, 4, filter(epsilon));
writeField.call(writer, 5, filter(upperLimit));
var inputValues = [];
// Encode negative values.
for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
var val = filter(cursor);
writeField.call(writer, 6, val);
inputValues.push({
fieldNumber: 6,
value: val
});
}
// Encode positive values.
for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
var val = filter(cursor);
writeField.call(writer, 7, val);
inputValues.push({
fieldNumber: 7,
value: val
});
}
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
// Check zero and limits.
reader.nextField();
assertEquals(1, reader.getFieldNumber());
assertEquals(filter(lowerLimit), readField.call(reader));
reader.nextField();
assertEquals(2, reader.getFieldNumber());
assertEquals(filter(-epsilon), readField.call(reader));
reader.nextField();
assertEquals(3, reader.getFieldNumber());
assertEquals(filter(0), readField.call(reader));
reader.nextField();
assertEquals(4, reader.getFieldNumber());
assertEquals(filter(epsilon), readField.call(reader));
reader.nextField();
assertEquals(5, reader.getFieldNumber());
assertEquals(filter(upperLimit), readField.call(reader));
for (var i = 0; i < inputValues.length; i++) {
var expected = inputValues[i];
reader.nextField();
assertEquals(expected.fieldNumber, reader.getFieldNumber());
assertEquals(expected.value, readField.call(reader));
}
};
/**
* Tests fields that use varint encoding.
*/
it('testVarintFields', function() {
assertNotUndefined(jspb.BinaryReader.prototype.readUint32);
assertNotUndefined(jspb.BinaryWriter.prototype.writeUint32);
assertNotUndefined(jspb.BinaryReader.prototype.readUint64);
assertNotUndefined(jspb.BinaryWriter.prototype.writeUint64);
assertNotUndefined(jspb.BinaryReader.prototype.readBool);
assertNotUndefined(jspb.BinaryWriter.prototype.writeBool);
doTestUnsignedField_(
jspb.BinaryReader.prototype.readUint32,
jspb.BinaryWriter.prototype.writeUint32,
1, Math.pow(2, 32) - 1, Math.round);
doTestUnsignedField_(
jspb.BinaryReader.prototype.readUint64,
jspb.BinaryWriter.prototype.writeUint64,
1, Math.pow(2, 64) - 1025, Math.round);
doTestSignedField_(
jspb.BinaryReader.prototype.readInt32,
jspb.BinaryWriter.prototype.writeInt32,
1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
doTestSignedField_(
jspb.BinaryReader.prototype.readInt64,
jspb.BinaryWriter.prototype.writeInt64,
1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
doTestSignedField_(
jspb.BinaryReader.prototype.readEnum,
jspb.BinaryWriter.prototype.writeEnum,
1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
doTestUnsignedField_(
jspb.BinaryReader.prototype.readBool,
jspb.BinaryWriter.prototype.writeBool,
1, 1, function(x) { return !!x; });
});
/**
* Tests reading a field from hexadecimal string (format: '08 BE EF').
* @param {Function} readField
* @param {number} expected
* @param {string} hexString
*/
function doTestHexStringVarint_(readField, expected, hexString) {
var bytesCount = (hexString.length + 1) / 3;
var bytes = new Uint8Array(bytesCount);
for (var i = 0; i < bytesCount; i++) {
bytes[i] = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
}
var reader = jspb.BinaryReader.alloc(bytes);
reader.nextField();
assertEquals(expected, readField.call(reader));
}
/**
* Tests non-canonical redundant varint decoding.
*/
it('testRedundantVarintFields', function() {
assertNotNull(jspb.BinaryReader.prototype.readUint32);
assertNotNull(jspb.BinaryReader.prototype.readUint64);
assertNotNull(jspb.BinaryReader.prototype.readSint32);
assertNotNull(jspb.BinaryReader.prototype.readSint64);
// uint32 and sint32 take no more than 5 bytes
// 08 - field prefix (type = 0 means varint)
doTestHexStringVarint_(
jspb.BinaryReader.prototype.readUint32,
12, '08 8C 80 80 80 00');
// 11 stands for -6 in zigzag encoding
doTestHexStringVarint_(
jspb.BinaryReader.prototype.readSint32,
-6, '08 8B 80 80 80 00');
// uint64 and sint64 take no more than 10 bytes
// 08 - field prefix (type = 0 means varint)
doTestHexStringVarint_(
jspb.BinaryReader.prototype.readUint64,
12, '08 8C 80 80 80 80 80 80 80 80 00');
// 11 stands for -6 in zigzag encoding
doTestHexStringVarint_(
jspb.BinaryReader.prototype.readSint64,
-6, '08 8B 80 80 80 80 80 80 80 80 00');
});
/**
* Tests 64-bit fields that are handled as strings.
*/
it('testStringInt64Fields', function() {
var writer = new jspb.BinaryWriter();
var testSignedData = [
'2730538252207801776',
'-2688470994844604560',
'3398529779486536359',
'3568577411627971000',
'272477188847484900',
'-6649058714086158188',
'-7695254765712060806',
'-4525541438037104029',
'-4993706538836508568',
'4990160321893729138'
];
var testUnsignedData = [
'7822732630241694882',
'6753602971916687352',
'2399935075244442116',
'8724292567325338867',
'16948784802625696584',
'4136275908516066934',
'3575388346793700364',
'5167142028379259461',
'1557573948689737699',
'17100725280812548567'
];
for (var i = 0; i < testSignedData.length; i++) {
writer.writeInt64String(2 * i + 1, testSignedData[i]);
writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
}
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
for (var i = 0; i < testSignedData.length; i++) {
reader.nextField();
assertEquals(2 * i + 1, reader.getFieldNumber());
assertEquals(testSignedData[i], reader.readInt64String());
reader.nextField();
assertEquals(2 * i + 2, reader.getFieldNumber());
assertEquals(testUnsignedData[i], reader.readUint64String());
}
});
/**
* Tests fields that use zigzag encoding.
*/
it('testZigzagFields', function() {
doTestSignedField_(
jspb.BinaryReader.prototype.readSint32,
jspb.BinaryWriter.prototype.writeSint32,
1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
doTestSignedField_(
jspb.BinaryReader.prototype.readSint64,
jspb.BinaryWriter.prototype.writeSint64,
1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
});
/**
* Tests fields that use fixed-length encoding.
*/
it('testFixedFields', function() {
doTestUnsignedField_(
jspb.BinaryReader.prototype.readFixed32,
jspb.BinaryWriter.prototype.writeFixed32,
1, Math.pow(2, 32) - 1, Math.round);
doTestUnsignedField_(
jspb.BinaryReader.prototype.readFixed64,
jspb.BinaryWriter.prototype.writeFixed64,
1, Math.pow(2, 64) - 1025, Math.round);
doTestSignedField_(
jspb.BinaryReader.prototype.readSfixed32,
jspb.BinaryWriter.prototype.writeSfixed32,
1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
doTestSignedField_(
jspb.BinaryReader.prototype.readSfixed64,
jspb.BinaryWriter.prototype.writeSfixed64,
1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
});
/**
* Tests floating point fields.
*/
it('testFloatFields', function() {
doTestSignedField_(
jspb.BinaryReader.prototype.readFloat,
jspb.BinaryWriter.prototype.writeFloat,
jspb.BinaryConstants.FLOAT32_MIN,
-jspb.BinaryConstants.FLOAT32_MAX,
jspb.BinaryConstants.FLOAT32_MAX,
truncate);
doTestSignedField_(
jspb.BinaryReader.prototype.readDouble,
jspb.BinaryWriter.prototype.writeDouble,
jspb.BinaryConstants.FLOAT64_EPS * 10,
-jspb.BinaryConstants.FLOAT64_MIN,
jspb.BinaryConstants.FLOAT64_MIN,
function(x) { return x; });
});
/**
* Tests length-delimited string fields.
*/
it('testStringFields', function() {
var s1 = 'The quick brown fox jumps over the lazy dog.';
var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
var writer = new jspb.BinaryWriter();
writer.writeString(1, s1);
writer.writeString(2, s2);
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
reader.nextField();
assertEquals(1, reader.getFieldNumber());
assertEquals(s1, reader.readString());
reader.nextField();
assertEquals(2, reader.getFieldNumber());
assertEquals(s2, reader.readString());
});
/**
* Tests length-delimited byte fields.
*/
it('testByteFields', function() {
var message = [];
var lowerLimit = 1;
var upperLimit = 256;
var scale = 1.1;
var writer = new jspb.BinaryWriter();
for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
var len = Math.round(cursor);
var bytes = [];
for (var i = 0; i < len; i++) bytes.push(i % 256);
writer.writeBytes(len, bytes);
}
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
var len = Math.round(cursor);
if (len != reader.getFieldNumber()) throw 'fail!';
var bytes = reader.readBytes();
if (len != bytes.length) throw 'fail!';
for (var i = 0; i < bytes.length; i++) {
if (i % 256 != bytes[i]) throw 'fail!';
}
}
});
/**
* Tests nested messages.
*/
it('testNesting', function() {
var writer = new jspb.BinaryWriter();
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
writer.writeInt32(1, 100);
// Add one message with 3 int fields.
writer.writeMessage(2, dummyMessage, function() {
writer.writeInt32(3, 300);
writer.writeInt32(4, 400);
writer.writeInt32(5, 500);
});
// Add one empty message.
writer.writeMessage(6, dummyMessage, goog.nullFunction);
writer.writeInt32(7, 700);
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
// Validate outermost message.
reader.nextField();
assertEquals(1, reader.getFieldNumber());
assertEquals(100, reader.readInt32());
reader.nextField();
assertEquals(2, reader.getFieldNumber());
reader.readMessage(dummyMessage, function() {
// Validate embedded message 1.
reader.nextField();
assertEquals(3, reader.getFieldNumber());
assertEquals(300, reader.readInt32());
reader.nextField();
assertEquals(4, reader.getFieldNumber());
assertEquals(400, reader.readInt32());
reader.nextField();
assertEquals(5, reader.getFieldNumber());
assertEquals(500, reader.readInt32());
assertEquals(false, reader.nextField());
});
reader.nextField();
assertEquals(6, reader.getFieldNumber());
reader.readMessage(dummyMessage, function() {
// Validate embedded message 2.
assertEquals(false, reader.nextField());
});
reader.nextField();
assertEquals(7, reader.getFieldNumber());
assertEquals(700, reader.readInt32());
assertEquals(false, reader.nextField());
});
/**
* Tests skipping fields of each type by interleaving them with sentinel
* values and skipping everything that's not a sentinel.
*/
it('testSkipField', function() {
var writer = new jspb.BinaryWriter();
var sentinel = 123456789;
// Write varint fields of different sizes.
writer.writeInt32(1, sentinel);
writer.writeInt32(1, 1);
writer.writeInt32(1, 1000);
writer.writeInt32(1, 1000000);
writer.writeInt32(1, 1000000000);
// Write fixed 64-bit encoded fields.
writer.writeInt32(2, sentinel);
writer.writeDouble(2, 1);
writer.writeFixed64(2, 1);
writer.writeSfixed64(2, 1);
// Write fixed 32-bit encoded fields.
writer.writeInt32(3, sentinel);
writer.writeFloat(3, 1);
writer.writeFixed32(3, 1);
writer.writeSfixed32(3, 1);
// Write delimited fields.
writer.writeInt32(4, sentinel);
writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
// Write a group with a nested group inside.
writer.writeInt32(5, sentinel);
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
writer.writeGroup(5, dummyMessage, function() {
writer.writeInt64(42, 42);
writer.writeGroup(6, dummyMessage, function() {
writer.writeInt64(84, 42);
});
});
// Write final sentinel.
writer.writeInt32(6, sentinel);
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
function skip(field, count) {
for (var i = 0; i < count; i++) {
reader.nextField();
if (field != reader.getFieldNumber()) throw 'fail!';
reader.skipField();
}
}
reader.nextField();
assertEquals(1, reader.getFieldNumber());
assertEquals(sentinel, reader.readInt32());
skip(1, 4);
reader.nextField();
assertEquals(2, reader.getFieldNumber());
assertEquals(sentinel, reader.readInt32());
skip(2, 3);
reader.nextField();
assertEquals(3, reader.getFieldNumber());
assertEquals(sentinel, reader.readInt32());
skip(3, 3);
reader.nextField();
assertEquals(4, reader.getFieldNumber());
assertEquals(sentinel, reader.readInt32());
skip(4, 2);
reader.nextField();
assertEquals(5, reader.getFieldNumber());
assertEquals(sentinel, reader.readInt32());
skip(5, 1);
reader.nextField();
assertEquals(6, reader.getFieldNumber());
assertEquals(sentinel, reader.readInt32());
});
/**
* Tests packed fields.
*/
it('testPackedFields', function() {
var writer = new jspb.BinaryWriter();
var sentinel = 123456789;
var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
var boolData = [true, false, true, true, false, false, true, false];
for (var i = 0; i < floatData.length; i++) {
floatData[i] = truncate(floatData[i]);
}
writer.writeInt32(1, sentinel);
writer.writePackedInt32(2, signedData);
writer.writePackedInt64(2, signedData);
writer.writePackedUint32(2, unsignedData);
writer.writePackedUint64(2, unsignedData);
writer.writePackedSint32(2, signedData);
writer.writePackedSint64(2, signedData);
writer.writePackedFixed32(2, unsignedData);
writer.writePackedFixed64(2, unsignedData);
writer.writePackedSfixed32(2, signedData);
writer.writePackedSfixed64(2, signedData);
writer.writePackedFloat(2, floatData);
writer.writePackedDouble(2, doubleData);
writer.writePackedBool(2, boolData);
writer.writePackedEnum(2, unsignedData);
writer.writeInt32(3, sentinel);
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
reader.nextField();
assertEquals(sentinel, reader.readInt32());
reader.nextField();
assertElementsEquals(reader.readPackedInt32(), signedData);
reader.nextField();
assertElementsEquals(reader.readPackedInt64(), signedData);
reader.nextField();
assertElementsEquals(reader.readPackedUint32(), unsignedData);
reader.nextField();
assertElementsEquals(reader.readPackedUint64(), unsignedData);
reader.nextField();
assertElementsEquals(reader.readPackedSint32(), signedData);
reader.nextField();
assertElementsEquals(reader.readPackedSint64(), signedData);
reader.nextField();
assertElementsEquals(reader.readPackedFixed32(), unsignedData);
reader.nextField();
assertElementsEquals(reader.readPackedFixed64(), unsignedData);
reader.nextField();
assertElementsEquals(reader.readPackedSfixed32(), signedData);
reader.nextField();
assertElementsEquals(reader.readPackedSfixed64(), signedData);
reader.nextField();
assertElementsEquals(reader.readPackedFloat(), floatData);
reader.nextField();
assertElementsEquals(reader.readPackedDouble(), doubleData);
reader.nextField();
assertElementsEquals(reader.readPackedBool(), boolData);
reader.nextField();
assertElementsEquals(reader.readPackedEnum(), unsignedData);
reader.nextField();
assertEquals(sentinel, reader.readInt32());
});
/**
* Byte blobs inside nested messages should always have their byte offset set
* relative to the start of the outermost blob, not the start of their parent
* blob.
*/
it('testNestedBlobs', function() {
// Create a proto consisting of two nested messages, with the inner one
// containing a blob of bytes.
var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
var blob = [1, 2, 3, 4, 5];
var writer = new jspb.BinaryWriter();
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
writer.writeMessage(1, dummyMessage, function() {
writer.writeMessage(1, dummyMessage, function() {
writer.writeBytes(1, blob);
});
});
// Peel off the outer two message layers. Each layer should have two bytes
// of overhead, one for the field tag and one for the length of the inner
// blob.
var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
assertEquals(fieldTag, decoder1.readUnsignedVarint32());
assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
assertEquals(fieldTag, decoder2.readUnsignedVarint32());
assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
assertEquals(fieldTag, decoder2.readUnsignedVarint32());
assertEquals(blob.length, decoder2.readUnsignedVarint32());
var bytes = decoder2.readBytes(blob.length);
assertElementsEquals(bytes, blob);
});
/**
* Tests read callbacks.
*/
it('testReadCallbacks', function() {
var writer = new jspb.BinaryWriter();
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
// Add an int, a submessage, and another int.
writer.writeInt32(1, 100);
writer.writeMessage(2, dummyMessage, function() {
writer.writeInt32(3, 300);
writer.writeInt32(4, 400);
writer.writeInt32(5, 500);
});
writer.writeInt32(7, 700);
// Create the reader and register a custom read callback.
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
/**
* @param {!jspb.BinaryReader} reader
* @return {*}
*/
function readCallback(reader) {
reader.nextField();
assertEquals(3, reader.getFieldNumber());
assertEquals(300, reader.readInt32());
reader.nextField();
assertEquals(4, reader.getFieldNumber());
assertEquals(400, reader.readInt32());
reader.nextField();
assertEquals(5, reader.getFieldNumber());
assertEquals(500, reader.readInt32());
assertEquals(false, reader.nextField());
};
reader.registerReadCallback('readCallback', readCallback);
// Read the container message.
reader.nextField();
assertEquals(1, reader.getFieldNumber());
assertEquals(100, reader.readInt32());
reader.nextField();
assertEquals(2, reader.getFieldNumber());
reader.readMessage(dummyMessage, function() {
// Decode the embedded message using the registered callback.
reader.runReadCallback('readCallback');
});
reader.nextField();
assertEquals(7, reader.getFieldNumber());
assertEquals(700, reader.readInt32());
assertEquals(false, reader.nextField());
});
});

@ -0,0 +1,668 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview Test cases for jspb's helper functions.
*
* Test suite is written using Jasmine -- see http://jasmine.github.io/
*
* @author aappleby@google.com (Austin Appleby)
*/
goog.require('goog.crypt.base64');
goog.require('goog.testing.asserts');
goog.require('jspb.BinaryConstants');
goog.require('jspb.BinaryWriter');
goog.require('jspb.utils');
/**
* @param {number} x
* @return {number}
*/
function truncate(x) {
var temp = new Float32Array(1);
temp[0] = x;
return temp[0];
}
/**
* Converts an 64-bit integer in split representation to a 64-bit hash string
* (8 bits encoded per character).
* @param {number} bitsLow The low 32 bits of the split 64-bit integer.
* @param {number} bitsHigh The high 32 bits of the split 64-bit integer.
* @return {string} The encoded hash string, 8 bits per character.
*/
function toHashString(bitsLow, bitsHigh) {
return String.fromCharCode((bitsLow >>> 0) & 0xFF,
(bitsLow >>> 8) & 0xFF,
(bitsLow >>> 16) & 0xFF,
(bitsLow >>> 24) & 0xFF,
(bitsHigh >>> 0) & 0xFF,
(bitsHigh >>> 8) & 0xFF,
(bitsHigh >>> 16) & 0xFF,
(bitsHigh >>> 24) & 0xFF);
}
describe('binaryUtilsTest', function() {
/**
* Tests lossless binary-to-decimal conversion.
*/
it('testDecimalConversion', function() {
// Check some magic numbers.
var result =
jspb.utils.joinUnsignedDecimalString(0x89e80001, 0x8ac72304);
assertEquals('10000000000000000001', result);
result = jspb.utils.joinUnsignedDecimalString(0xacd05f15, 0x1b69b4b);
assertEquals('123456789123456789', result);
result = jspb.utils.joinUnsignedDecimalString(0xeb1f0ad2, 0xab54a98c);
assertEquals('12345678901234567890', result);
result = jspb.utils.joinUnsignedDecimalString(0xe3b70cb1, 0x891087b8);
assertEquals('9876543210987654321', result);
// Check limits.
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00000000);
assertEquals('0', result);
result = jspb.utils.joinUnsignedDecimalString(0xFFFFFFFF, 0xFFFFFFFF);
assertEquals('18446744073709551615', result);
// Check each bit of the low dword.
for (var i = 0; i < 32; i++) {
var low = (1 << i) >>> 0;
result = jspb.utils.joinUnsignedDecimalString(low, 0);
assertEquals('' + Math.pow(2, i), result);
}
// Check the first 20 bits of the high dword.
for (var i = 0; i < 20; i++) {
var high = (1 << i) >>> 0;
result = jspb.utils.joinUnsignedDecimalString(0, high);
assertEquals('' + Math.pow(2, 32 + i), result);
}
// V8's internal double-to-string conversion is inaccurate for values above
// 2^52, even if they're representable integers - check the rest of the bits
// manually against the correct string representations of 2^N.
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00100000);
assertEquals('4503599627370496', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00200000);
assertEquals('9007199254740992', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00400000);
assertEquals('18014398509481984', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00800000);
assertEquals('36028797018963968', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x01000000);
assertEquals('72057594037927936', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x02000000);
assertEquals('144115188075855872', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x04000000);
assertEquals('288230376151711744', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x08000000);
assertEquals('576460752303423488', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x10000000);
assertEquals('1152921504606846976', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x20000000);
assertEquals('2305843009213693952', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x40000000);
assertEquals('4611686018427387904', result);
result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x80000000);
assertEquals('9223372036854775808', result);
});
/**
* Going from hash strings to decimal strings should also be lossless.
*/
it('testHashToDecimalConversion', function() {
var result;
var convert = jspb.utils.hash64ToDecimalString;
result = convert(toHashString(0x00000000, 0x00000000), false);
assertEquals('0', result);
result = convert(toHashString(0x00000000, 0x00000000), true);
assertEquals('0', result);
result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), false);
assertEquals('18446744073709551615', result);
result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), true);
assertEquals('-1', result);
result = convert(toHashString(0x00000000, 0x80000000), false);
assertEquals('9223372036854775808', result);
result = convert(toHashString(0x00000000, 0x80000000), true);
assertEquals('-9223372036854775808', result);
result = convert(toHashString(0xacd05f15, 0x01b69b4b), false);
assertEquals('123456789123456789', result);
result = convert(toHashString(~0xacd05f15 + 1, ~0x01b69b4b), true);
assertEquals('-123456789123456789', result);
// And converting arrays of hashes should work the same way.
result = jspb.utils.hash64ArrayToDecimalStrings([
toHashString(0xFFFFFFFF, 0xFFFFFFFF),
toHashString(0x00000000, 0x80000000),
toHashString(0xacd05f15, 0x01b69b4b)], false);
assertEquals(3, result.length);
assertEquals('18446744073709551615', result[0]);
assertEquals('9223372036854775808', result[1]);
assertEquals('123456789123456789', result[2]);
});
/*
* Going from decimal strings to hash strings should be lossless.
*/
it('testDecimalToHashConversion', function() {
var result;
var convert = jspb.utils.decimalStringToHash64;
result = convert('0');
assertEquals(String.fromCharCode.apply(null,
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
result = convert('-1');
assertEquals(String.fromCharCode.apply(null,
[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
result = convert('18446744073709551615');
assertEquals(String.fromCharCode.apply(null,
[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
result = convert('9223372036854775808');
assertEquals(String.fromCharCode.apply(null,
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result);
result = convert('-9223372036854775808');
assertEquals(String.fromCharCode.apply(null,
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result);
result = convert('123456789123456789');
assertEquals(String.fromCharCode.apply(null,
[0x15, 0x5F, 0xD0, 0xAC, 0x4B, 0x9B, 0xB6, 0x01]), result);
result = convert('-123456789123456789');
assertEquals(String.fromCharCode.apply(null,
[0xEB, 0xA0, 0x2F, 0x53, 0xB4, 0x64, 0x49, 0xFE]), result);
});
/**
* Going from hash strings to hex strings should be lossless.
*/
it('testHashToHexConversion', function() {
var result;
var convert = jspb.utils.hash64ToHexString;
result = convert(toHashString(0x00000000, 0x00000000));
assertEquals('0x0000000000000000', result);
result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF));
assertEquals('0xffffffffffffffff', result);
result = convert(toHashString(0x12345678, 0x9ABCDEF0));
assertEquals('0x9abcdef012345678', result);
});
/**
* Going from hex strings to hash strings should be lossless.
*/
it('testHexToHashConversion', function() {
var result;
var convert = jspb.utils.hexStringToHash64;
result = convert('0x0000000000000000');
assertEquals(String.fromCharCode.apply(null,
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
result = convert('0xffffffffffffffff');
assertEquals(String.fromCharCode.apply(null,
[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
// Hex string is big-endian, hash string is little-endian.
result = convert('0x123456789ABCDEF0');
assertEquals(String.fromCharCode.apply(null,
[0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]), result);
// Capitalization should not matter.
result = convert('0x0000abcdefABCDEF');
assertEquals(String.fromCharCode.apply(null,
[0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB, 0x00, 0x00]), result);
});
/**
* Going from numbers to hash strings should be lossless for up to 53 bits of
* precision.
*/
it('testNumberToHashConversion', function() {
var result;
var convert = jspb.utils.numberToHash64;
result = convert(0x0000000000000);
assertEquals('0x0000000000000000', jspb.utils.hash64ToHexString(result));
result = convert(0xFFFFFFFFFFFFF);
assertEquals('0x000fffffffffffff', jspb.utils.hash64ToHexString(result));
result = convert(0x123456789ABCD);
assertEquals('0x000123456789abcd', jspb.utils.hash64ToHexString(result));
result = convert(0xDCBA987654321);
assertEquals('0x000dcba987654321', jspb.utils.hash64ToHexString(result));
// 53 bits of precision should not be truncated.
result = convert(0x10000000000001);
assertEquals('0x0010000000000001', jspb.utils.hash64ToHexString(result));
// 54 bits of precision should be truncated.
result = convert(0x20000000000001);
assertNotEquals(
'0x0020000000000001', jspb.utils.hash64ToHexString(result));
});
/**
* Sanity check the behavior of Javascript's strings when doing funny things
* with unicode characters.
*/
it('sanityCheckUnicodeStrings', function() {
var strings = new Array(65536);
// All possible unsigned 16-bit values should be storable in a string, they
// shouldn't do weird things with the length of the string, and they should
// come back out of the string unchanged.
for (var i = 0; i < 65536; i++) {
strings[i] = 'a' + String.fromCharCode(i) + 'a';
if (3 != strings[i].length) throw 'fail!';
if (i != strings[i].charCodeAt(1)) throw 'fail!';
}
// Each unicode character should compare equal to itself and not equal to a
// different unicode character.
for (var i = 0; i < 65536; i++) {
if (strings[i] != strings[i]) throw 'fail!';
if (strings[i] == strings[(i + 1) % 65536]) throw 'fail!';
}
});
/**
* Tests conversion from 32-bit floating point numbers to split64 numbers.
*/
it('testFloat32ToSplit64', function() {
var f32_eps = jspb.BinaryConstants.FLOAT32_EPS;
var f32_min = jspb.BinaryConstants.FLOAT32_MIN;
var f32_max = jspb.BinaryConstants.FLOAT32_MAX;
// NaN.
jspb.utils.splitFloat32(NaN);
if (!isNaN(jspb.utils.joinFloat32(jspb.utils.split64Low,
jspb.utils.split64High))) {
throw 'fail!';
}
/**
* @param {number} x
* @param {number=} opt_bits
*/
function test(x, opt_bits) {
jspb.utils.splitFloat32(x);
if (goog.isDef(opt_bits)) {
if (opt_bits != jspb.utils.split64Low) throw 'fail!';
}
if (truncate(x) != jspb.utils.joinFloat32(jspb.utils.split64Low,
jspb.utils.split64High)) {
throw 'fail!';
}
}
// Positive and negative infinity.
test(Infinity, 0x7f800000);
test(-Infinity, 0xff800000);
// Positive and negative zero.
test(0, 0x00000000);
test(-0, 0x80000000);
// Positive and negative epsilon.
test(f32_eps, 0x00000001);
test(-f32_eps, 0x80000001);
// Positive and negative min.
test(f32_min, 0x00800000);
test(-f32_min, 0x80800000);
// Positive and negative max.
test(f32_max, 0x7F7FFFFF);
test(-f32_max, 0xFF7FFFFF);
// Various positive values.
var cursor = f32_eps * 10;
while (cursor != Infinity) {
test(cursor);
cursor *= 1.1;
}
// Various negative values.
cursor = -f32_eps * 10;
while (cursor != -Infinity) {
test(cursor);
cursor *= 1.1;
}
});
/**
* Tests conversion from 64-bit floating point numbers to split64 numbers.
*/
it('testFloat64ToSplit64', function() {
var f64_eps = jspb.BinaryConstants.FLOAT64_EPS;
var f64_min = jspb.BinaryConstants.FLOAT64_MIN;
var f64_max = jspb.BinaryConstants.FLOAT64_MAX;
// NaN.
jspb.utils.splitFloat64(NaN);
if (!isNaN(jspb.utils.joinFloat64(jspb.utils.split64Low,
jspb.utils.split64High))) {
throw 'fail!';
}
/**
* @param {number} x
* @param {number=} opt_highBits
* @param {number=} opt_lowBits
*/
function test(x, opt_highBits, opt_lowBits) {
jspb.utils.splitFloat64(x);
if (goog.isDef(opt_highBits)) {
if (opt_highBits != jspb.utils.split64High) throw 'fail!';
}
if (goog.isDef(opt_lowBits)) {
if (opt_lowBits != jspb.utils.split64Low) throw 'fail!';
}
if (x != jspb.utils.joinFloat64(jspb.utils.split64Low,
jspb.utils.split64High)) {
throw 'fail!';
}
}
// Positive and negative infinity.
test(Infinity, 0x7ff00000, 0x00000000);
test(-Infinity, 0xfff00000, 0x00000000);
// Positive and negative zero.
test(0, 0x00000000, 0x00000000);
test(-0, 0x80000000, 0x00000000);
// Positive and negative epsilon.
test(f64_eps, 0x00000000, 0x00000001);
test(-f64_eps, 0x80000000, 0x00000001);
// Positive and negative min.
test(f64_min, 0x00100000, 0x00000000);
test(-f64_min, 0x80100000, 0x00000000);
// Positive and negative max.
test(f64_max, 0x7FEFFFFF, 0xFFFFFFFF);
test(-f64_max, 0xFFEFFFFF, 0xFFFFFFFF);
// Various positive values.
var cursor = f64_eps * 10;
while (cursor != Infinity) {
test(cursor);
cursor *= 1.1;
}
// Various negative values.
cursor = -f64_eps * 10;
while (cursor != -Infinity) {
test(cursor);
cursor *= 1.1;
}
});
/**
* Tests counting packed varints.
*/
it('testCountVarints', function() {
var values = [];
for (var i = 1; i < 1000000000; i *= 1.1) {
values.push(Math.floor(i));
}
var writer = new jspb.BinaryWriter();
writer.writePackedUint64(1, values);
var buffer = new Uint8Array(writer.getResultBuffer());
// We should have two more varints than we started with - one for the field
// tag, one for the packed length.
assertEquals(values.length + 2,
jspb.utils.countVarints(buffer, 0, buffer.length));
});
/**
* Tests counting matching varint fields.
*/
it('testCountVarintFields', function() {
var writer = new jspb.BinaryWriter();
var count = 0;
for (var i = 1; i < 1000000000; i *= 1.1) {
writer.writeUint64(1, Math.floor(i));
count++;
}
writer.writeString(2, 'terminator');
var buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countVarintFields(buffer, 0, buffer.length, 1));
writer = new jspb.BinaryWriter();
count = 0;
for (var i = 1; i < 1000000000; i *= 1.1) {
writer.writeUint64(123456789, Math.floor(i));
count++;
}
writer.writeString(2, 'terminator');
buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countVarintFields(buffer, 0, buffer.length, 123456789));
});
/**
* Tests counting matching fixed32 fields.
*/
it('testCountFixed32Fields', function() {
var writer = new jspb.BinaryWriter();
var count = 0;
for (var i = 1; i < 1000000000; i *= 1.1) {
writer.writeFixed32(1, Math.floor(i));
count++;
}
writer.writeString(2, 'terminator');
var buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 1));
writer = new jspb.BinaryWriter();
count = 0;
for (var i = 1; i < 1000000000; i *= 1.1) {
writer.writeFixed32(123456789, Math.floor(i));
count++;
}
writer.writeString(2, 'terminator');
buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 123456789));
});
/**
* Tests counting matching fixed64 fields.
*/
it('testCountFixed64Fields', function() {
var writer = new jspb.BinaryWriter();
var count = 0;
for (var i = 1; i < 1000000000; i *= 1.1) {
writer.writeDouble(1, i);
count++;
}
writer.writeString(2, 'terminator');
var buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 1));
writer = new jspb.BinaryWriter();
count = 0;
for (var i = 1; i < 1000000000; i *= 1.1) {
writer.writeDouble(123456789, i);
count++;
}
writer.writeString(2, 'terminator');
buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 123456789));
});
/**
* Tests counting matching delimited fields.
*/
it('testCountDelimitedFields', function() {
var writer = new jspb.BinaryWriter();
var count = 0;
for (var i = 1; i < 1000; i *= 1.1) {
writer.writeBytes(1, [Math.floor(i)]);
count++;
}
writer.writeString(2, 'terminator');
var buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 1));
writer = new jspb.BinaryWriter();
count = 0;
for (var i = 1; i < 1000; i *= 1.1) {
writer.writeBytes(123456789, [Math.floor(i)]);
count++;
}
writer.writeString(2, 'terminator');
buffer = new Uint8Array(writer.getResultBuffer());
assertEquals(count,
jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 123456789));
});
/**
* Tests byte format for debug strings.
*/
it('testDebugBytesToTextFormat', function() {
assertEquals('""', jspb.utils.debugBytesToTextFormat(null));
assertEquals('"\\x00\\x10\\xff"',
jspb.utils.debugBytesToTextFormat([0, 16, 255]));
});
/**
* Tests converting byte blob sources into byte blobs.
*/
it('testByteSourceToUint8Array', function() {
var convert = jspb.utils.byteSourceToUint8Array;
var sourceData = [];
for (var i = 0; i < 256; i++) {
sourceData.push(i);
}
var sourceBytes = new Uint8Array(sourceData);
var sourceBuffer = sourceBytes.buffer;
var sourceBase64 = goog.crypt.base64.encodeByteArray(sourceData);
var sourceString = String.fromCharCode.apply(null, sourceData);
function check(result) {
assertEquals(Uint8Array, result.constructor);
assertEquals(sourceData.length, result.length);
for (var i = 0; i < result.length; i++) {
assertEquals(sourceData[i], result[i]);
}
}
// Converting Uint8Arrays into Uint8Arrays should be a no-op.
assertEquals(sourceBytes, convert(sourceBytes));
// Converting Array.<numbers> into Uint8Arrays should work.
check(convert(sourceData));
// Converting ArrayBuffers into Uint8Arrays should work.
check(convert(sourceBuffer));
// Converting base64-encoded strings into Uint8Arrays should work.
check(convert(sourceBase64));
});
});

@ -0,0 +1,122 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview Test cases for jspb's binary protocol buffer writer. In
* practice BinaryWriter is used to drive the Decoder and Reader test cases,
* so only writer-specific tests are here.
*
* Test suite is written using Jasmine -- see http://jasmine.github.io/
*
* @author aappleby@google.com (Austin Appleby)
*/
goog.require('goog.crypt');
goog.require('goog.testing.asserts');
goog.require('jspb.BinaryWriter');
/**
* @param {function()} func This function should throw an error when run.
*/
function assertFails(func) {
var e = assertThrows(func);
//assertNotNull(e.toString().match(/Error/));
}
describe('binaryWriterTest', function() {
/**
* Verifies that misuse of the writer class triggers assertions.
*/
it('testWriteErrors', function() {
// Submessages with invalid field indices should assert.
var writer = new jspb.BinaryWriter();
var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
assertFails(function() {
writer.writeMessage(-1, dummyMessage, goog.nullFunction);
});
// Writing invalid field indices should assert.
writer = new jspb.BinaryWriter();
assertFails(function() {writer.writeUint64(-1, 1);});
// Writing out-of-range field values should assert.
writer = new jspb.BinaryWriter();
assertFails(function() {writer.writeInt32(1, -Infinity);});
assertFails(function() {writer.writeInt32(1, Infinity);});
assertFails(function() {writer.writeInt64(1, -Infinity);});
assertFails(function() {writer.writeInt64(1, Infinity);});
assertFails(function() {writer.writeUint32(1, -1);});
assertFails(function() {writer.writeUint32(1, Infinity);});
assertFails(function() {writer.writeUint64(1, -1);});
assertFails(function() {writer.writeUint64(1, Infinity);});
assertFails(function() {writer.writeSint32(1, -Infinity);});
assertFails(function() {writer.writeSint32(1, Infinity);});
assertFails(function() {writer.writeSint64(1, -Infinity);});
assertFails(function() {writer.writeSint64(1, Infinity);});
assertFails(function() {writer.writeFixed32(1, -1);});
assertFails(function() {writer.writeFixed32(1, Infinity);});
assertFails(function() {writer.writeFixed64(1, -1);});
assertFails(function() {writer.writeFixed64(1, Infinity);});
assertFails(function() {writer.writeSfixed32(1, -Infinity);});
assertFails(function() {writer.writeSfixed32(1, Infinity);});
assertFails(function() {writer.writeSfixed64(1, -Infinity);});
assertFails(function() {writer.writeSfixed64(1, Infinity);});
});
/**
* Basic test of retrieving the result as a Uint8Array buffer
*/
it('testGetResultBuffer', function() {
var expected = '0864120b48656c6c6f20776f726c641a0301020320c801';
var writer = new jspb.BinaryWriter();
writer.writeUint32(1, 100);
writer.writeString(2, 'Hello world');
writer.writeBytes(3, new Uint8Array([1, 2, 3]));
writer.writeUint32(4, 200);
var buffer = writer.getResultBuffer();
assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
});
});

@ -0,0 +1,40 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.test.importing;
message ImportedMessage {
string string_value = 1;
}

@ -0,0 +1,42 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2016 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.test.framing;
import "test6/test6.proto";
message FramingMessage {
jspb.test.importing.ImportedMessage imported_message = 1;
}

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: mwr@google.com (Mark Rawling)
syntax = "proto2";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.test;
// legacy data, must be nested
message data {
message NestedData {
required string str = 1;
}
}
// new data, does not require nesting
message UnnestedData {
required string str = 1;
}

@ -0,0 +1,105 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
goog.setTestOnly();
goog.require('goog.testing.asserts');
// CommonJS-LoadFromFile: google-protobuf
goog.require('jspb.debug');
// CommonJS-LoadFromFile: test_pb
goog.require('proto.jspb.test.HasExtensions');
goog.require('proto.jspb.test.IsExtension');
goog.require('proto.jspb.test.Simple1');
describe('debugTest', function() {
it('testSimple1', function() {
if (COMPILED) {
return;
}
var message = new proto.jspb.test.Simple1();
message.setAString('foo');
assertObjectEquals({
$name: 'proto.jspb.test.Simple1',
'aString': 'foo',
'aRepeatedStringList': []
}, jspb.debug.dump(message));
message.setABoolean(true);
message.setARepeatedStringList(['1', '2']);
assertObjectEquals({
$name: 'proto.jspb.test.Simple1',
'aString': 'foo',
'aRepeatedStringList': ['1', '2'],
'aBoolean': true
}, jspb.debug.dump(message));
message.clearAString();
assertObjectEquals({
$name: 'proto.jspb.test.Simple1',
'aRepeatedStringList': ['1', '2'],
'aBoolean': true
}, jspb.debug.dump(message));
});
it('testExtensions', function() {
if (COMPILED) {
return;
}
var extension = new proto.jspb.test.IsExtension();
extension.setExt1('ext1field');
var extendable = new proto.jspb.test.HasExtensions();
extendable.setStr1('v1');
extendable.setStr2('v2');
extendable.setStr3('v3');
extendable.setExtension(proto.jspb.test.IsExtension.extField, extension);
assertObjectEquals({
'$name': 'proto.jspb.test.HasExtensions',
'str1': 'v1',
'str2': 'v2',
'str3': 'v3',
'$extensions': {
'extField': {
'$name': 'proto.jspb.test.IsExtension',
'ext1': 'ext1field'
},
'repeatedSimpleList': []
}
}, jspb.debug.dump(extendable));
});
});

@ -0,0 +1,301 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
goog.require('goog.testing.asserts');
goog.require('goog.userAgent');
// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
goog.require('proto.jspb.test.MapValueEnum');
goog.require('proto.jspb.test.MapValueMessage');
goog.require('proto.jspb.test.TestMapFields');
// CommonJS-LoadFromFile: test_pb proto.jspb.test
goog.require('proto.jspb.test.MapValueMessageNoBinary');
goog.require('proto.jspb.test.TestMapFieldsNoBinary');
/**
* Helper: check that the given map has exactly this set of (sorted) entries.
* @param {!jspb.Map} map
* @param {!Array<!Array<?>>} entries
*/
function checkMapEquals(map, entries) {
var arr = map.toArray();
assertEquals(arr.length, entries.length);
for (var i = 0; i < arr.length; i++) {
assertElementsEquals(arr[i], entries[i]);
}
}
/**
* Converts an ES6 iterator to an array.
* @template T
* @param {!Iterator<T>} iter an iterator
* @return {!Array<T>}
*/
function toArray(iter) {
var arr = [];
while (true) {
var val = iter.next();
if (val.done) {
break;
}
arr.push(val.value);
}
return arr;
}
/**
* Helper: generate test methods for this TestMapFields class.
* @param {?} msgInfo
* @param {?} submessageCtor
* @param {!string} suffix
*/
function makeTests(msgInfo, submessageCtor, suffix) {
/**
* Helper: fill all maps on a TestMapFields.
* @param {?} msg
*/
var fillMapFields = function(msg) {
msg.getMapStringStringMap().set('asdf', 'jkl;').set('key 2', 'hello world');
msg.getMapStringInt32Map().set('a', 1).set('b', -2);
msg.getMapStringInt64Map().set('c', 0x100000000).set('d', 0x200000000);
msg.getMapStringBoolMap().set('e', true).set('f', false);
msg.getMapStringDoubleMap().set('g', 3.14159).set('h', 2.71828);
msg.getMapStringEnumMap()
.set('i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR)
.set('j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ);
msg.getMapStringMsgMap()
.set('k', new submessageCtor())
.set('l', new submessageCtor());
msg.getMapStringMsgMap().get('k').setFoo(42);
msg.getMapStringMsgMap().get('l').setFoo(84);
msg.getMapInt32StringMap().set(-1, 'a').set(42, 'b');
msg.getMapInt64StringMap().set(0x123456789abc, 'c').set(0xcba987654321, 'd');
msg.getMapBoolStringMap().set(false, 'e').set(true, 'f');
};
/**
* Helper: check all maps on a TestMapFields.
* @param {?} msg
*/
var checkMapFields = function(msg) {
checkMapEquals(msg.getMapStringStringMap(), [
['asdf', 'jkl;'],
['key 2', 'hello world']
]);
checkMapEquals(msg.getMapStringInt32Map(), [
['a', 1],
['b', -2]
]);
checkMapEquals(msg.getMapStringInt64Map(), [
['c', 0x100000000],
['d', 0x200000000]
]);
checkMapEquals(msg.getMapStringBoolMap(), [
['e', true],
['f', false]
]);
checkMapEquals(msg.getMapStringDoubleMap(), [
['g', 3.14159],
['h', 2.71828]
]);
checkMapEquals(msg.getMapStringEnumMap(), [
['i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR],
['j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ]
]);
checkMapEquals(msg.getMapInt32StringMap(), [
[-1, 'a'],
[42, 'b']
]);
checkMapEquals(msg.getMapInt64StringMap(), [
[0x123456789abc, 'c'],
[0xcba987654321, 'd']
]);
checkMapEquals(msg.getMapBoolStringMap(), [
[false, 'e'],
[true, 'f']
]);
assertEquals(msg.getMapStringMsgMap().getLength(), 2);
assertEquals(msg.getMapStringMsgMap().get('k').getFoo(), 42);
assertEquals(msg.getMapStringMsgMap().get('l').getFoo(), 84);
var entries = toArray(msg.getMapStringMsgMap().entries());
assertEquals(entries.length, 2);
entries.forEach(function(entry) {
var key = entry[0];
var val = entry[1];
assert(val === msg.getMapStringMsgMap().get(key));
});
msg.getMapStringMsgMap().forEach(function(val, key) {
assert(val === msg.getMapStringMsgMap().get(key));
});
};
it('testMapStringStringField' + suffix, function() {
var msg = new msgInfo.constructor();
assertEquals(msg.getMapStringStringMap().getLength(), 0);
assertEquals(msg.getMapStringInt32Map().getLength(), 0);
assertEquals(msg.getMapStringInt64Map().getLength(), 0);
assertEquals(msg.getMapStringBoolMap().getLength(), 0);
assertEquals(msg.getMapStringDoubleMap().getLength(), 0);
assertEquals(msg.getMapStringEnumMap().getLength(), 0);
assertEquals(msg.getMapStringMsgMap().getLength(), 0);
// Re-create to clear out any internally-cached wrappers, etc.
msg = new msgInfo.constructor();
var m = msg.getMapStringStringMap();
assertEquals(m.has('asdf'), false);
assertEquals(m.get('asdf'), undefined);
m.set('asdf', 'hello world');
assertEquals(m.has('asdf'), true);
assertEquals(m.get('asdf'), 'hello world');
m.set('jkl;', 'key 2');
assertEquals(m.has('jkl;'), true);
assertEquals(m.get('jkl;'), 'key 2');
assertEquals(m.getLength(), 2);
var it = m.entries();
assertElementsEquals(it.next().value, ['asdf', 'hello world']);
assertElementsEquals(it.next().value, ['jkl;', 'key 2']);
assertEquals(it.next().done, true);
checkMapEquals(m, [
['asdf', 'hello world'],
['jkl;', 'key 2']
]);
m.del('jkl;');
assertEquals(m.has('jkl;'), false);
assertEquals(m.get('jkl;'), undefined);
assertEquals(m.getLength(), 1);
it = m.keys();
assertEquals(it.next().value, 'asdf');
assertEquals(it.next().done, true);
it = m.values();
assertEquals(it.next().value, 'hello world');
assertEquals(it.next().done, true);
var count = 0;
m.forEach(function(value, key, map) {
assertEquals(map, m);
assertEquals(key, 'asdf');
assertEquals(value, 'hello world');
count++;
});
assertEquals(count, 1);
m.clear();
assertEquals(m.getLength(), 0);
});
/**
* Tests operations on maps with all key and value types.
*/
it('testAllMapTypes' + suffix, function() {
var msg = new msgInfo.constructor();
fillMapFields(msg);
checkMapFields(msg);
});
if (msgInfo.deserializeBinary) {
/**
* Tests serialization and deserialization in binary format.
*/
it('testBinaryFormat' + suffix, function() {
if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
// IE8/9 currently doesn't support binary format because they lack
// TypedArray.
return;
}
// Check that the format is correct.
var msg = new msgInfo.constructor();
msg.getMapStringStringMap().set('A', 'a');
var serialized = msg.serializeBinary();
var expectedSerialized = [
0x0a, 0x6, // field 1 (map_string_string), delimited, length 6
0x0a, 0x1, // field 1 in submessage (key), delimited, length 1
0x41, // ASCII 'A'
0x12, 0x1, // field 2 in submessage (value), delimited, length 1
0x61 // ASCII 'a'
];
assertEquals(serialized.length, expectedSerialized.length);
for (var i = 0; i < serialized.length; i++) {
assertEquals(serialized[i], expectedSerialized[i]);
}
// Check that all map fields successfully round-trip.
msg = new msgInfo.constructor();
fillMapFields(msg);
serialized = msg.serializeBinary();
var decoded = msgInfo.deserializeBinary(serialized);
checkMapFields(decoded);
});
}
/**
* Exercises the lazy map<->underlying array sync.
*/
it('testLazyMapSync' + suffix, function() {
// Start with a JSPB array containing a few map entries.
var entries = [
['a', 'entry 1'],
['c', 'entry 2'],
['b', 'entry 3']
];
var msg = new msgInfo.constructor([entries]);
assertEquals(entries.length, 3);
assertEquals(entries[0][0], 'a');
assertEquals(entries[1][0], 'c');
assertEquals(entries[2][0], 'b');
msg.getMapStringStringMap().del('a');
assertEquals(entries.length, 3); // not yet sync'd
msg.toArray(); // force a sync
assertEquals(entries.length, 2);
assertEquals(entries[0][0], 'b'); // now in sorted order
assertEquals(entries[1][0], 'c');
var a = msg.toArray();
assertEquals(a[0], entries); // retains original reference
});
}
describe('mapsTest', function() {
makeTests({
constructor: proto.jspb.test.TestMapFields,
deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary
}, proto.jspb.test.MapValueMessage, "_Binary");
makeTests({
constructor: proto.jspb.test.TestMapFieldsNoBinary,
deserializeBinary: null
}, proto.jspb.test.MapValueMessageNoBinary, "_NoBinary");
});

File diff suppressed because it is too large Load Diff

@ -0,0 +1,329 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
goog.require('goog.crypt.base64');
goog.require('goog.testing.asserts');
// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
goog.require('proto.jspb.test.ForeignMessage');
// CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
goog.require('proto.jspb.test.Proto3Enum');
goog.require('proto.jspb.test.TestProto3');
var BYTES = new Uint8Array([1, 2, 8, 9]);
var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
/**
* Helper: compare a bytes field to an expected value
* @param {Uint8Array|string} arr
* @param {Uint8Array} expected
* @return {boolean}
*/
function bytesCompare(arr, expected) {
if (goog.isString(arr)) {
arr = goog.crypt.base64.decodeStringToUint8Array(arr);
}
if (arr.length != expected.length) {
return false;
}
for (var i = 0; i < arr.length; i++) {
if (arr[i] != expected[i]) {
return false;
}
}
return true;
}
describe('proto3Test', function() {
/**
* Test defaults for proto3 message fields.
*/
it('testProto3FieldDefaults', function() {
var msg = new proto.jspb.test.TestProto3();
assertEquals(msg.getOptionalInt32(), 0);
assertEquals(msg.getOptionalInt64(), 0);
assertEquals(msg.getOptionalUint32(), 0);
assertEquals(msg.getOptionalUint64(), 0);
assertEquals(msg.getOptionalSint32(), 0);
assertEquals(msg.getOptionalSint64(), 0);
assertEquals(msg.getOptionalFixed32(), 0);
assertEquals(msg.getOptionalFixed64(), 0);
assertEquals(msg.getOptionalSfixed32(), 0);
assertEquals(msg.getOptionalSfixed64(), 0);
assertEquals(msg.getOptionalFloat(), 0);
assertEquals(msg.getOptionalDouble(), 0);
assertEquals(msg.getOptionalString(), '');
// TODO(b/26173701): when we change bytes fields default getter to return
// Uint8Array, we'll want to switch this assertion to match the u8 case.
assertEquals(typeof msg.getOptionalBytes(), 'string');
assertEquals(msg.getOptionalBytes_asU8() instanceof Uint8Array, true);
assertEquals(typeof msg.getOptionalBytes_asB64(), 'string');
assertEquals(msg.getOptionalBytes().length, 0);
assertEquals(msg.getOptionalBytes_asU8().length, 0);
assertEquals(msg.getOptionalBytes_asB64(), '');
assertEquals(msg.getOptionalForeignEnum(),
proto.jspb.test.Proto3Enum.PROTO3_FOO);
assertEquals(msg.getOptionalForeignMessage(), undefined);
assertEquals(msg.getOptionalForeignMessage(), undefined);
assertEquals(msg.getRepeatedInt32List().length, 0);
assertEquals(msg.getRepeatedInt64List().length, 0);
assertEquals(msg.getRepeatedUint32List().length, 0);
assertEquals(msg.getRepeatedUint64List().length, 0);
assertEquals(msg.getRepeatedSint32List().length, 0);
assertEquals(msg.getRepeatedSint64List().length, 0);
assertEquals(msg.getRepeatedFixed32List().length, 0);
assertEquals(msg.getRepeatedFixed64List().length, 0);
assertEquals(msg.getRepeatedSfixed32List().length, 0);
assertEquals(msg.getRepeatedSfixed64List().length, 0);
assertEquals(msg.getRepeatedFloatList().length, 0);
assertEquals(msg.getRepeatedDoubleList().length, 0);
assertEquals(msg.getRepeatedStringList().length, 0);
assertEquals(msg.getRepeatedBytesList().length, 0);
assertEquals(msg.getRepeatedForeignEnumList().length, 0);
assertEquals(msg.getRepeatedForeignMessageList().length, 0);
});
/**
* Test that all fields can be set and read via a serialization roundtrip.
*/
it('testProto3FieldSetGet', function() {
var msg = new proto.jspb.test.TestProto3();
msg.setOptionalInt32(-42);
msg.setOptionalInt64(-0x7fffffff00000000);
msg.setOptionalUint32(0x80000000);
msg.setOptionalUint64(0xf000000000000000);
msg.setOptionalSint32(-100);
msg.setOptionalSint64(-0x8000000000000000);
msg.setOptionalFixed32(1234);
msg.setOptionalFixed64(0x1234567800000000);
msg.setOptionalSfixed32(-1234);
msg.setOptionalSfixed64(-0x1234567800000000);
msg.setOptionalFloat(1.5);
msg.setOptionalDouble(-1.5);
msg.setOptionalBool(true);
msg.setOptionalString('hello world');
msg.setOptionalBytes(BYTES);
var submsg = new proto.jspb.test.ForeignMessage();
submsg.setC(16);
msg.setOptionalForeignMessage(submsg);
msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
msg.setRepeatedInt32List([-42]);
msg.setRepeatedInt64List([-0x7fffffff00000000]);
msg.setRepeatedUint32List([0x80000000]);
msg.setRepeatedUint64List([0xf000000000000000]);
msg.setRepeatedSint32List([-100]);
msg.setRepeatedSint64List([-0x8000000000000000]);
msg.setRepeatedFixed32List([1234]);
msg.setRepeatedFixed64List([0x1234567800000000]);
msg.setRepeatedSfixed32List([-1234]);
msg.setRepeatedSfixed64List([-0x1234567800000000]);
msg.setRepeatedFloatList([1.5]);
msg.setRepeatedDoubleList([-1.5]);
msg.setRepeatedBoolList([true]);
msg.setRepeatedStringList(['hello world']);
msg.setRepeatedBytesList([BYTES]);
submsg = new proto.jspb.test.ForeignMessage();
submsg.setC(1000);
msg.setRepeatedForeignMessageList([submsg]);
msg.setRepeatedForeignEnumList([proto.jspb.test.Proto3Enum.PROTO3_BAR]);
msg.setOneofString('asdf');
var serialized = msg.serializeBinary();
msg = proto.jspb.test.TestProto3.deserializeBinary(serialized);
assertEquals(msg.getOptionalInt32(), -42);
assertEquals(msg.getOptionalInt64(), -0x7fffffff00000000);
assertEquals(msg.getOptionalUint32(), 0x80000000);
assertEquals(msg.getOptionalUint64(), 0xf000000000000000);
assertEquals(msg.getOptionalSint32(), -100);
assertEquals(msg.getOptionalSint64(), -0x8000000000000000);
assertEquals(msg.getOptionalFixed32(), 1234);
assertEquals(msg.getOptionalFixed64(), 0x1234567800000000);
assertEquals(msg.getOptionalSfixed32(), -1234);
assertEquals(msg.getOptionalSfixed64(), -0x1234567800000000);
assertEquals(msg.getOptionalFloat(), 1.5);
assertEquals(msg.getOptionalDouble(), -1.5);
assertEquals(msg.getOptionalBool(), true);
assertEquals(msg.getOptionalString(), 'hello world');
assertEquals(true, bytesCompare(msg.getOptionalBytes(), BYTES));
assertEquals(msg.getOptionalForeignMessage().getC(), 16);
assertEquals(msg.getOptionalForeignEnum(),
proto.jspb.test.Proto3Enum.PROTO3_BAR);
assertElementsEquals(msg.getRepeatedInt32List(), [-42]);
assertElementsEquals(msg.getRepeatedInt64List(), [-0x7fffffff00000000]);
assertElementsEquals(msg.getRepeatedUint32List(), [0x80000000]);
assertElementsEquals(msg.getRepeatedUint64List(), [0xf000000000000000]);
assertElementsEquals(msg.getRepeatedSint32List(), [-100]);
assertElementsEquals(msg.getRepeatedSint64List(), [-0x8000000000000000]);
assertElementsEquals(msg.getRepeatedFixed32List(), [1234]);
assertElementsEquals(msg.getRepeatedFixed64List(), [0x1234567800000000]);
assertElementsEquals(msg.getRepeatedSfixed32List(), [-1234]);
assertElementsEquals(msg.getRepeatedSfixed64List(), [-0x1234567800000000]);
assertElementsEquals(msg.getRepeatedFloatList(), [1.5]);
assertElementsEquals(msg.getRepeatedDoubleList(), [-1.5]);
assertElementsEquals(msg.getRepeatedBoolList(), [true]);
assertElementsEquals(msg.getRepeatedStringList(), ['hello world']);
assertEquals(msg.getRepeatedBytesList().length, 1);
assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], BYTES));
assertEquals(msg.getRepeatedForeignMessageList().length, 1);
assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000);
assertElementsEquals(msg.getRepeatedForeignEnumList(),
[proto.jspb.test.Proto3Enum.PROTO3_BAR]);
assertEquals(msg.getOneofString(), 'asdf');
});
/**
* Test that oneofs continue to have a notion of field presence.
*/
it('testOneofs', function() {
var msg = new proto.jspb.test.TestProto3();
assertEquals(msg.getOneofUint32(), 0);
assertEquals(msg.getOneofForeignMessage(), undefined);
assertEquals(msg.getOneofString(), '');
assertEquals(msg.getOneofBytes(), '');
assertFalse(msg.hasOneofUint32());
assertFalse(msg.hasOneofString());
assertFalse(msg.hasOneofBytes());
msg.setOneofUint32(42);
assertEquals(msg.getOneofUint32(), 42);
assertEquals(msg.getOneofForeignMessage(), undefined);
assertEquals(msg.getOneofString(), '');
assertEquals(msg.getOneofBytes(), '');
assertTrue(msg.hasOneofUint32());
assertFalse(msg.hasOneofString());
assertFalse(msg.hasOneofBytes());
var submsg = new proto.jspb.test.ForeignMessage();
msg.setOneofForeignMessage(submsg);
assertEquals(msg.getOneofUint32(), 0);
assertEquals(msg.getOneofForeignMessage(), submsg);
assertEquals(msg.getOneofString(), '');
assertEquals(msg.getOneofBytes(), '');
assertFalse(msg.hasOneofUint32());
assertFalse(msg.hasOneofString());
assertFalse(msg.hasOneofBytes());
msg.setOneofString('hello');
assertEquals(msg.getOneofUint32(), 0);
assertEquals(msg.getOneofForeignMessage(), undefined);
assertEquals(msg.getOneofString(), 'hello');
assertEquals(msg.getOneofBytes(), '');
assertFalse(msg.hasOneofUint32());
assertTrue(msg.hasOneofString());
assertFalse(msg.hasOneofBytes());
msg.setOneofBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
assertEquals(msg.getOneofUint32(), 0);
assertEquals(msg.getOneofForeignMessage(), undefined);
assertEquals(msg.getOneofString(), '');
assertEquals(msg.getOneofBytes_asB64(),
goog.crypt.base64.encodeString('\u00FF\u00FF'));
assertFalse(msg.hasOneofUint32());
assertFalse(msg.hasOneofString());
assertTrue(msg.hasOneofBytes());
});
/**
* Test that "default"-valued primitive fields are not emitted on the wire.
*/
it('testNoSerializeDefaults', function() {
var msg = new proto.jspb.test.TestProto3();
// Set each primitive to a non-default value, then back to its default, to
// ensure that the serialization is actually checking the value and not just
// whether it has ever been set.
msg.setOptionalInt32(42);
msg.setOptionalInt32(0);
msg.setOptionalDouble(3.14);
msg.setOptionalDouble(0.0);
msg.setOptionalBool(true);
msg.setOptionalBool(false);
msg.setOptionalString('hello world');
msg.setOptionalString('');
msg.setOptionalBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
msg.setOptionalBytes('');
msg.setOptionalForeignMessage(new proto.jspb.test.ForeignMessage());
msg.setOptionalForeignMessage(null);
msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_FOO);
msg.setOneofUint32(32);
msg.clearOneofUint32();
var serialized = msg.serializeBinary();
assertEquals(0, serialized.length);
});
/**
* Test that base64 string and Uint8Array are interchangeable in bytes fields.
*/
it('testBytesFieldsInterop', function() {
var msg = new proto.jspb.test.TestProto3();
// Set as a base64 string and check all the getters work.
msg.setOptionalBytes(BYTES_B64);
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
// Test binary serialize round trip doesn't break it.
msg = proto.jspb.test.TestProto3.deserializeBinary(msg.serializeBinary());
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
msg = new proto.jspb.test.TestProto3();
// Set as a Uint8Array and check all the getters work.
msg.setOptionalBytes(BYTES);
assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES));
assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES));
});
});

@ -0,0 +1,89 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
import "testbinary.proto";
package jspb.test;
message TestProto3 {
int32 optional_int32 = 1;
int64 optional_int64 = 2;
uint32 optional_uint32 = 3;
uint64 optional_uint64 = 4;
sint32 optional_sint32 = 5;
sint64 optional_sint64 = 6;
fixed32 optional_fixed32 = 7;
fixed64 optional_fixed64 = 8;
sfixed32 optional_sfixed32 = 9;
sfixed64 optional_sfixed64 = 10;
float optional_float = 11;
double optional_double = 12;
bool optional_bool = 13;
string optional_string = 14;
bytes optional_bytes = 15;
ForeignMessage optional_foreign_message = 19;
Proto3Enum optional_foreign_enum = 22;
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
repeated uint32 repeated_uint32 = 33;
repeated uint64 repeated_uint64 = 34;
repeated sint32 repeated_sint32 = 35;
repeated sint64 repeated_sint64 = 36;
repeated fixed32 repeated_fixed32 = 37;
repeated fixed64 repeated_fixed64 = 38;
repeated sfixed32 repeated_sfixed32 = 39;
repeated sfixed64 repeated_sfixed64 = 40;
repeated float repeated_float = 41;
repeated double repeated_double = 42;
repeated bool repeated_bool = 43;
repeated string repeated_string = 44;
repeated bytes repeated_bytes = 45;
repeated ForeignMessage repeated_foreign_message = 49;
repeated Proto3Enum repeated_foreign_enum = 52;
oneof oneof_field {
uint32 oneof_uint32 = 111;
ForeignMessage oneof_foreign_message = 112;
string oneof_string = 113;
bytes oneof_bytes = 114;
}
}
enum Proto3Enum {
PROTO3_FOO = 0;
PROTO3_BAR = 1;
PROTO3_BAZ = 2;
}

@ -0,0 +1,262 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: mwr@google.com (Mark Rawling)
syntax = "proto2";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
import "google/protobuf/descriptor.proto";
package jspb.test;
message Empty {
}
enum OuterEnum {
FOO = 1;
BAR = 2;
}
message EnumContainer {
optional OuterEnum outer_enum = 1;
}
message Simple1 {
required string a_string = 1;
repeated string a_repeated_string = 2;
optional bool a_boolean = 3;
}
// A message that differs from Simple1 only by name
message Simple2 {
required string a_string = 1;
repeated string a_repeated_string = 2;
}
message SpecialCases {
required string normal = 1;
// Examples of Js reserved names that are converted to pb_<name>.
required string default = 2;
required string function = 3;
required string var = 4;
}
message OptionalFields {
message Nested {
optional int32 an_int = 1;
}
optional string a_string = 1;
required bool a_bool = 2;
optional Nested a_nested_message = 3;
repeated Nested a_repeated_message = 4;
repeated string a_repeated_string = 5;
}
message HasExtensions {
optional string str1 = 1;
optional string str2 = 2;
optional string str3 = 3;
extensions 10 to max;
}
message Complex {
message Nested {
required int32 an_int = 2;
}
required string a_string = 1;
required bool an_out_of_order_bool = 9;
optional Nested a_nested_message = 4;
repeated Nested a_repeated_message = 5;
repeated string a_repeated_string = 7;
}
message OuterMessage {
// Make sure this doesn't conflict with the other Complex message.
message Complex {
optional int32 inner_complex_field = 1;
}
}
message IsExtension {
extend HasExtensions {
optional IsExtension ext_field = 100;
}
optional string ext1 = 1;
// Extensions of proto2 Descriptor messages will be ignored.
extend google.protobuf.EnumOptions {
optional string simple_option = 42113038;
}
}
message IndirectExtension {
extend HasExtensions {
optional Simple1 simple = 101;
optional string str = 102;
repeated string repeated_str = 103;
repeated Simple1 repeated_simple = 104;
}
}
extend HasExtensions {
optional Simple1 simple1 = 105;
}
message DefaultValues {
enum Enum {
E1 = 13;
E2 = 77;
}
optional string string_field = 1 [default="default<>\'\"abc"];
optional bool bool_field = 2 [default=true];
optional int64 int_field = 3 [default=11];
optional Enum enum_field = 4 [default=E1];
optional string empty_field = 6 [default=""];
optional bytes bytes_field = 8 [default="moo"]; // Base64 encoding is "bW9v"
}
message FloatingPointFields {
optional float optional_float_field = 1;
required float required_float_field = 2;
repeated float repeated_float_field = 3;
optional float default_float_field = 4 [default = 2.0];
optional double optional_double_field = 5;
required double required_double_field = 6;
repeated double repeated_double_field = 7;
optional double default_double_field = 8 [default = 2.0];
}
message TestClone {
optional string str = 1;
optional Simple1 simple1 = 3;
repeated Simple1 simple2 = 5;
optional bytes bytes_field = 6;
optional string unused = 7;
extensions 10 to max;
}
message CloneExtension {
extend TestClone {
optional CloneExtension ext_field = 100;
}
optional string ext = 2;
}
message TestGroup {
repeated group RepeatedGroup = 1 {
required string id = 1;
repeated bool some_bool = 2;
}
required group RequiredGroup = 2 {
required string id = 1;
}
optional group OptionalGroup = 3 {
required string id = 1;
}
optional string id = 4;
required Simple2 required_simple = 5;
optional Simple2 optional_simple = 6;
}
message TestGroup1 {
optional TestGroup.RepeatedGroup group = 1;
}
message TestReservedNames {
optional int32 extension = 1;
extensions 10 to max;
}
message TestReservedNamesExtension {
extend TestReservedNames {
optional int32 foo = 10;
}
}
message TestMessageWithOneof {
oneof partial_oneof {
string pone = 3;
string pthree = 5;
}
oneof recursive_oneof {
TestMessageWithOneof rone = 6;
string rtwo = 7;
}
optional bool normal_field = 8;
repeated string repeated_field = 9;
oneof default_oneof_a {
int32 aone = 10 [default = 1234];
int32 atwo = 11;
}
oneof default_oneof_b {
int32 bone = 12;
int32 btwo = 13 [default = 1234];
}
}
message TestEndsWithBytes {
optional int32 value = 1;
optional bytes data = 2;
}
message TestMapFieldsNoBinary {
map<string, string> map_string_string = 1;
map<string, int32> map_string_int32 = 2;
map<string, int64> map_string_int64 = 3;
map<string, bool> map_string_bool = 4;
map<string, double> map_string_double = 5;
map<string, MapValueEnumNoBinary> map_string_enum = 6;
map<string, MapValueMessageNoBinary> map_string_msg = 7;
map<int32, string> map_int32_string = 8;
map<int64, string> map_int64_string = 9;
map<bool, string> map_bool_string = 10;
optional TestMapFieldsNoBinary test_map_fields = 11;
map<string, TestMapFieldsNoBinary> map_string_testmapfields = 12;
}
enum MapValueEnumNoBinary {
MAP_VALUE_FOO_NOBINARY = 0;
MAP_VALUE_BAR_NOBINARY = 1;
MAP_VALUE_BAZ_NOBINARY = 2;
}
message MapValueMessageNoBinary {
optional int32 foo = 1;
}

@ -0,0 +1,54 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.test;
message TestExtensionsMessage {
optional int32 intfield = 1;
extensions 100 to max;
}
message ExtensionMessage {
extend TestExtensionsMessage {
optional ExtensionMessage ext_field = 100;
}
optional string ext1 = 1;
}
// Floating extensions are only supported when generating a _lib.js library.
extend TestExtensionsMessage {
optional ExtensionMessage floating_msg_field = 101;
optional string floating_str_field = 102;
}

@ -0,0 +1,53 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.exttest;
message TestExtensionsMessage {
optional int32 intfield = 1;
extensions 100 to max;
}
message ExtensionMessage {
extend TestExtensionsMessage {
optional ExtensionMessage ext_field = 100;
}
optional string ext1 = 1;
}
extend TestExtensionsMessage {
optional ExtensionMessage floating_msg_field = 101;
optional string floating_str_field = 102;
}

@ -0,0 +1,42 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.exttest;
import "test3.proto";
extend TestExtensionsMessage {
optional ExtensionMessage floating_msg_field_two = 103;
}

@ -0,0 +1,44 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
option java_package = "com.google.apps.jspb.proto";
option java_multiple_files = true;
package jspb.exttest.beta;
message TestBetaExtensionsMessage {
extensions 100 to max;
}
extend TestBetaExtensionsMessage {
optional string floating_str_field = 101;
}

@ -0,0 +1,212 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// LINT: ALLOW_GROUPS
syntax = "proto2";
package jspb.test;
// These types are borrowed from `unittest.proto` in the protobuf tree. We want
// to ensure that the binary-format support will handle all field types
// properly.
message TestAllTypes {
optional int32 optional_int32 = 1;
optional int64 optional_int64 = 2;
optional uint32 optional_uint32 = 3;
optional uint64 optional_uint64 = 4;
optional sint32 optional_sint32 = 5;
optional sint64 optional_sint64 = 6;
optional fixed32 optional_fixed32 = 7;
optional fixed64 optional_fixed64 = 8;
optional sfixed32 optional_sfixed32 = 9;
optional sfixed64 optional_sfixed64 = 10;
optional float optional_float = 11;
optional double optional_double = 12;
optional bool optional_bool = 13;
optional string optional_string = 14;
optional bytes optional_bytes = 15;
optional group OptionalGroup = 16 {
optional int32 a = 17;
}
optional ForeignMessage optional_foreign_message = 19;
optional ForeignEnum optional_foreign_enum = 22;
// Repeated
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
repeated uint32 repeated_uint32 = 33;
repeated uint64 repeated_uint64 = 34;
repeated sint32 repeated_sint32 = 35;
repeated sint64 repeated_sint64 = 36;
repeated fixed32 repeated_fixed32 = 37;
repeated fixed64 repeated_fixed64 = 38;
repeated sfixed32 repeated_sfixed32 = 39;
repeated sfixed64 repeated_sfixed64 = 40;
repeated float repeated_float = 41;
repeated double repeated_double = 42;
repeated bool repeated_bool = 43;
repeated string repeated_string = 44;
repeated bytes repeated_bytes = 45;
repeated group RepeatedGroup = 46 {
optional int32 a = 47;
}
repeated ForeignMessage repeated_foreign_message = 49;
repeated ForeignEnum repeated_foreign_enum = 52;
// Packed repeated
repeated int32 packed_repeated_int32 = 61 [packed=true];
repeated int64 packed_repeated_int64 = 62 [packed=true];
repeated uint32 packed_repeated_uint32 = 63 [packed=true];
repeated uint64 packed_repeated_uint64 = 64 [packed=true];
repeated sint32 packed_repeated_sint32 = 65 [packed=true];
repeated sint64 packed_repeated_sint64 = 66 [packed=true];
repeated fixed32 packed_repeated_fixed32 = 67 [packed=true];
repeated fixed64 packed_repeated_fixed64 = 68 [packed=true];
repeated sfixed32 packed_repeated_sfixed32 = 69 [packed=true];
repeated sfixed64 packed_repeated_sfixed64 = 70 [packed=true];
repeated float packed_repeated_float = 71 [packed=true];
repeated double packed_repeated_double = 72 [packed=true];
repeated bool packed_repeated_bool = 73 [packed=true];
oneof oneof_field {
uint32 oneof_uint32 = 111;
ForeignMessage oneof_foreign_message = 112;
string oneof_string = 113;
bytes oneof_bytes = 114;
}
}
message ForeignMessage {
optional int32 c = 1;
}
enum ForeignEnum {
FOREIGN_FOO = 4;
FOREIGN_BAR = 5;
FOREIGN_BAZ = 6;
}
message TestExtendable {
extensions 1 to max;
}
message ExtendsWithMessage {
extend TestExtendable {
optional ExtendsWithMessage optional_extension = 19;
repeated ExtendsWithMessage repeated_extension = 49;
}
optional int32 foo = 1;
}
extend TestExtendable {
optional int32 extend_optional_int32 = 1;
optional int64 extend_optional_int64 = 2;
optional uint32 extend_optional_uint32 = 3;
optional uint64 extend_optional_uint64 = 4;
optional sint32 extend_optional_sint32 = 5;
optional sint64 extend_optional_sint64 = 6;
optional fixed32 extend_optional_fixed32 = 7;
optional fixed64 extend_optional_fixed64 = 8;
optional sfixed32 extend_optional_sfixed32 = 9;
optional sfixed64 extend_optional_sfixed64 = 10;
optional float extend_optional_float = 11;
optional double extend_optional_double = 12;
optional bool extend_optional_bool = 13;
optional string extend_optional_string = 14;
optional bytes extend_optional_bytes = 15;
optional ForeignEnum extend_optional_foreign_enum = 22;
repeated int32 extend_repeated_int32 = 31;
repeated int64 extend_repeated_int64 = 32;
repeated uint32 extend_repeated_uint32 = 33;
repeated uint64 extend_repeated_uint64 = 34;
repeated sint32 extend_repeated_sint32 = 35;
repeated sint64 extend_repeated_sint64 = 36;
repeated fixed32 extend_repeated_fixed32 = 37;
repeated fixed64 extend_repeated_fixed64 = 38;
repeated sfixed32 extend_repeated_sfixed32 = 39;
repeated sfixed64 extend_repeated_sfixed64 = 40;
repeated float extend_repeated_float = 41;
repeated double extend_repeated_double = 42;
repeated bool extend_repeated_bool = 43;
repeated string extend_repeated_string = 44;
repeated bytes extend_repeated_bytes = 45;
repeated ForeignEnum extend_repeated_foreign_enum = 52;
repeated int32 extend_packed_repeated_int32 = 61 [packed=true];
repeated int64 extend_packed_repeated_int64 = 62 [packed=true];
repeated uint32 extend_packed_repeated_uint32 = 63 [packed=true];
repeated uint64 extend_packed_repeated_uint64 = 64 [packed=true];
repeated sint32 extend_packed_repeated_sint32 = 65 [packed=true];
repeated sint64 extend_packed_repeated_sint64 = 66 [packed=true];
repeated fixed32 extend_packed_repeated_fixed32 = 67 [packed=true];
repeated fixed64 extend_packed_repeated_fixed64 = 68 [packed=true];
repeated sfixed32 extend_packed_repeated_sfixed32 = 69 [packed=true];
repeated sfixed64 extend_packed_repeated_sfixed64 = 70 [packed=true];
repeated float extend_packed_repeated_float = 71 [packed=true];
repeated double extend_packed_repeated_double = 72 [packed=true];
repeated bool extend_packed_repeated_bool = 73 [packed=true];
repeated ForeignEnum extend_packed_repeated_foreign_enum = 82
[packed=true];
}
message TestMapFields {
map<string, string> map_string_string = 1;
map<string, int32> map_string_int32 = 2;
map<string, int64> map_string_int64 = 3;
map<string, bool> map_string_bool = 4;
map<string, double> map_string_double = 5;
map<string, MapValueEnum> map_string_enum = 6;
map<string, MapValueMessage> map_string_msg = 7;
map<int32, string> map_int32_string = 8;
map<int64, string> map_int64_string = 9;
map<bool, string> map_bool_string = 10;
optional TestMapFields test_map_fields = 11;
map<string, TestMapFields> map_string_testmapfields = 12;
}
enum MapValueEnum {
MAP_VALUE_FOO = 0;
MAP_VALUE_BAR = 1;
MAP_VALUE_BAZ = 2;
}
message MapValueMessage {
optional int32 foo = 1;
}

@ -0,0 +1,34 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
package javatests.com.google.apps.jspb;

@ -41,7 +41,6 @@ goog.provide('jspb.Message');
goog.require('goog.array'); goog.require('goog.array');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.crypt.base64'); goog.require('goog.crypt.base64');
goog.require('goog.json');
goog.require('jspb.Map'); goog.require('jspb.Map');
// Not needed in compilation units that have no protos with xids. // Not needed in compilation units that have no protos with xids.
@ -192,8 +191,8 @@ goog.define('jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
/** /**
* @define {boolean} Whether to generate toString methods for objects. Turn * @define {boolean} Whether to generate toString methods for objects. Turn
* this off if you do use toString in your project and want to trim it from * this off if you do not use toString in your project and want to trim it
* compiled JS. * from the compiled JS.
*/ */
goog.define('jspb.Message.GENERATE_TO_STRING', true); goog.define('jspb.Message.GENERATE_TO_STRING', true);
@ -351,7 +350,7 @@ jspb.Message.initialize = function(
// which would otherwise go unused. // which would otherwise go unused.
msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0; msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0;
msg.array = data; msg.array = data;
jspb.Message.materializeExtensionObject_(msg, suggestedPivot); jspb.Message.initPivotAndExtensionObject_(msg, suggestedPivot);
msg.convertedFloatingPointFields_ = {}; msg.convertedFloatingPointFields_ = {};
if (repeatedFields) { if (repeatedFields) {
@ -364,6 +363,7 @@ jspb.Message.initialize = function(
jspb.Message.EMPTY_LIST_SENTINEL_ : jspb.Message.EMPTY_LIST_SENTINEL_ :
[]); []);
} else { } else {
jspb.Message.maybeInitEmptyExtensionObject_(msg);
msg.extensionObject_[fieldNumber] = msg.extensionObject_[fieldNumber] =
msg.extensionObject_[fieldNumber] || msg.extensionObject_[fieldNumber] ||
(jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ? (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
@ -408,17 +408,16 @@ jspb.Message.isArray_ = function(o) {
/** /**
* Ensures that the array contains an extension object if necessary.
* If the array contains an extension object in its last position, then the * If the array contains an extension object in its last position, then the
* object is kept in place and its position is used as the pivot. If not, then * object is kept in place and its position is used as the pivot. If not,
* create an extension object using suggestedPivot. If suggestedPivot is -1, * decides the pivot of the message based on suggestedPivot without
* we don't have an extension object at all, in which case all fields are stored * materializing the extension object.
* in the array. *
* @param {!jspb.Message} msg The JsPb proto to modify. * @param {!jspb.Message} msg The JsPb proto to modify.
* @param {number} suggestedPivot See description for initialize(). * @param {number} suggestedPivot See description for initialize().
* @private * @private
*/ */
jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) { jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
if (msg.array.length) { if (msg.array.length) {
var foundIndex = msg.array.length - 1; var foundIndex = msg.array.length - 1;
var obj = msg.array[foundIndex]; var obj = msg.array[foundIndex];
@ -434,26 +433,17 @@ jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) {
return; return;
} }
} }
// This complexity exists because we keep all extension fields in the
// extensionObject_ regardless of proto field number. Changing this would
// simplify the code here, but it would require changing the serialization
// format from the server, which is not backwards compatible.
// TODO(jshneier): Should we just treat extension fields the same as
// non-extension fields, and select whether they appear in the object or in
// the array purely based on tag number? This would allow simplifying all the
// get/setExtension logic, but it would require the breaking change described
// above.
if (suggestedPivot > -1) { if (suggestedPivot > -1) {
msg.pivot_ = suggestedPivot; msg.pivot_ = suggestedPivot;
var pivotIndex = jspb.Message.getIndex_(msg, suggestedPivot); // Avoid changing the shape of the proto with an empty extension object by
if (!jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS) { // deferring the materialization of the extension object until the first
msg.extensionObject_ = msg.array[pivotIndex] = {}; // time a field set into it (may be due to getting a repeated proto field
} else { // from it, in which case a new empty array is set into it at first).
// Initialize to null to avoid changing the shape of the proto when it msg.extensionObject_ = null;
// gets eventually set.
msg.extensionObject_ = null;
}
} else { } else {
// suggestedPivot is -1, which means that we don't have an extension object
// at all, in which case all fields are stored in the array.
msg.pivot_ = Number.MAX_VALUE; msg.pivot_ = Number.MAX_VALUE;
} }
}; };
@ -513,7 +503,7 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions,
for (var fieldNumber in extensions) { for (var fieldNumber in extensions) {
var fieldInfo = extensions[fieldNumber]; var fieldInfo = extensions[fieldNumber];
var value = getExtensionFn.call(proto, fieldInfo); var value = getExtensionFn.call(proto, fieldInfo);
if (goog.isDefAndNotNull(value)) { if (value != null) {
for (var name in fieldInfo.fieldName) { for (var name in fieldInfo.fieldName) {
if (fieldInfo.fieldName.hasOwnProperty(name)) { if (fieldInfo.fieldName.hasOwnProperty(name)) {
break; // the compiled field name break; // the compiled field name
@ -557,7 +547,7 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
'without binary serialization support'); 'without binary serialization support');
} }
var value = getExtensionFn.call(proto, fieldInfo); var value = getExtensionFn.call(proto, fieldInfo);
if (goog.isDefAndNotNull(value)) { if (value != null) {
if (fieldInfo.isMessageType()) { if (fieldInfo.isMessageType()) {
// If the message type of the extension was generated without binary // If the message type of the extension was generated without binary
// support, there may not be a binary message serializer function, and // support, there may not be a binary message serializer function, and
@ -647,6 +637,9 @@ jspb.Message.getField = function(msg, fieldNumber) {
} }
return val; return val;
} else { } else {
if (!msg.extensionObject_) {
return undefined;
}
var val = msg.extensionObject_[fieldNumber]; var val = msg.extensionObject_[fieldNumber];
if (val === jspb.Message.EMPTY_LIST_SENTINEL_) { if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
return msg.extensionObject_[fieldNumber] = []; return msg.extensionObject_[fieldNumber] = [];
@ -656,6 +649,32 @@ jspb.Message.getField = function(msg, fieldNumber) {
}; };
/**
* Gets the value of a non-extension repeated field.
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
* @return {!Array}
* The field's value.
* @protected
*/
jspb.Message.getRepeatedField = function(msg, fieldNumber) {
if (fieldNumber < msg.pivot_) {
var index = jspb.Message.getIndex_(msg, fieldNumber);
var val = msg.array[index];
if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
return msg.array[index] = [];
}
return val;
}
var val = msg.extensionObject_[fieldNumber];
if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
return msg.extensionObject_[fieldNumber] = [];
}
return val;
};
/** /**
* Gets the value of an optional float or double field. * Gets the value of an optional float or double field.
* @param {!jspb.Message} msg A jspb proto. * @param {!jspb.Message} msg A jspb proto.
@ -678,7 +697,7 @@ jspb.Message.getOptionalFloatingPointField = function(msg, fieldNumber) {
* @protected * @protected
*/ */
jspb.Message.getRepeatedFloatingPointField = function(msg, fieldNumber) { jspb.Message.getRepeatedFloatingPointField = function(msg, fieldNumber) {
var values = jspb.Message.getField(msg, fieldNumber); var values = jspb.Message.getRepeatedField(msg, fieldNumber);
if (!msg.convertedFloatingPointFields_) { if (!msg.convertedFloatingPointFields_) {
msg.convertedFloatingPointFields_ = {}; msg.convertedFloatingPointFields_ = {};
} }
@ -864,6 +883,7 @@ jspb.Message.setField = function(msg, fieldNumber, value) {
if (fieldNumber < msg.pivot_) { if (fieldNumber < msg.pivot_) {
msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = value; msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = value;
} else { } else {
jspb.Message.maybeInitEmptyExtensionObject_(msg);
msg.extensionObject_[fieldNumber] = value; msg.extensionObject_[fieldNumber] = value;
} }
}; };
@ -878,7 +898,7 @@ jspb.Message.setField = function(msg, fieldNumber, value) {
* @protected * @protected
*/ */
jspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) { jspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) {
var arr = jspb.Message.getField(msg, fieldNumber); var arr = jspb.Message.getRepeatedField(msg, fieldNumber);
if (opt_index != undefined) { if (opt_index != undefined) {
arr.splice(opt_index, 0, value); arr.splice(opt_index, 0, value);
} else { } else {
@ -1006,7 +1026,7 @@ jspb.Message.wrapRepeatedField_ = function(msg, ctor, fieldNumber) {
msg.wrappers_ = {}; msg.wrappers_ = {};
} }
if (!msg.wrappers_[fieldNumber]) { if (!msg.wrappers_[fieldNumber]) {
var data = jspb.Message.getField(msg, fieldNumber); var data = jspb.Message.getRepeatedField(msg, fieldNumber);
for (var wrappers = [], i = 0; i < data.length; i++) { for (var wrappers = [], i = 0; i < data.length; i++) {
wrappers[i] = new ctor(data[i]); wrappers[i] = new ctor(data[i]);
} }
@ -1101,7 +1121,7 @@ jspb.Message.addToRepeatedWrapperField = function(
wrapperArray = msg.wrappers_[fieldNumber] = []; wrapperArray = msg.wrappers_[fieldNumber] = [];
} }
var insertedValue = value ? value : new ctor(); var insertedValue = value ? value : new ctor();
var array = jspb.Message.getField(msg, fieldNumber); var array = jspb.Message.getRepeatedField(msg, fieldNumber);
if (index != undefined) { if (index != undefined) {
wrapperArray.splice(index, 0, insertedValue); wrapperArray.splice(index, 0, insertedValue);
array.splice(index, 0, insertedValue.toArray()); array.splice(index, 0, insertedValue.toArray());

@ -33,6 +33,7 @@
goog.setTestOnly(); goog.setTestOnly();
goog.require('goog.json'); goog.require('goog.json');
goog.require('goog.string');
goog.require('goog.testing.asserts'); goog.require('goog.testing.asserts');
goog.require('goog.userAgent'); goog.require('goog.userAgent');
@ -64,11 +65,13 @@ goog.require('proto.jspb.test.floatingStrField');
goog.require('proto.jspb.test.HasExtensions'); goog.require('proto.jspb.test.HasExtensions');
goog.require('proto.jspb.test.IndirectExtension'); goog.require('proto.jspb.test.IndirectExtension');
goog.require('proto.jspb.test.IsExtension'); goog.require('proto.jspb.test.IsExtension');
goog.require('proto.jspb.test.MessageWithLargeFieldTags');
goog.require('proto.jspb.test.OptionalFields'); goog.require('proto.jspb.test.OptionalFields');
goog.require('proto.jspb.test.OuterEnum'); goog.require('proto.jspb.test.OuterEnum');
goog.require('proto.jspb.test.OuterMessage.Complex'); goog.require('proto.jspb.test.OuterMessage.Complex');
goog.require('proto.jspb.test.Simple1'); goog.require('proto.jspb.test.Simple1');
goog.require('proto.jspb.test.Simple2'); goog.require('proto.jspb.test.Simple2');
goog.require('proto.jspb.test.SingularsWithLargeFieldTags');
goog.require('proto.jspb.test.SpecialCases'); goog.require('proto.jspb.test.SpecialCases');
goog.require('proto.jspb.test.TestClone'); goog.require('proto.jspb.test.TestClone');
goog.require('proto.jspb.test.TestEndsWithBytes'); goog.require('proto.jspb.test.TestEndsWithBytes');
@ -83,8 +86,6 @@ goog.require('proto.jspb.test.ExtensionMessage');
goog.require('proto.jspb.test.TestExtensionsMessage'); goog.require('proto.jspb.test.TestExtensionsMessage');
describe('Message test suite', function() { describe('Message test suite', function() {
it('testEmptyProto', function() { it('testEmptyProto', function() {
var empty1 = new proto.jspb.test.Empty([]); var empty1 = new proto.jspb.test.Empty([]);
@ -273,12 +274,6 @@ describe('Message test suite', function() {
assertFalse(response.hasEnumField()); assertFalse(response.hasEnumField());
}); });
it('testMessageRegistration', /** @suppress {visibility} */ function() {
// goog.require(SomeResponse) will include its library, which will in
// turn add SomeResponse to the message registry.
assertEquals(jspb.Message.registry_['res'], proto.jspb.test.SomeResponse);
});
it('testClearFields', function() { it('testClearFields', function() {
var data = ['str', true, [11], [[22], [33]], ['s1', 's2']]; var data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
var foo = new proto.jspb.test.OptionalFields(data); var foo = new proto.jspb.test.OptionalFields(data);
@ -661,12 +656,7 @@ describe('Message test suite', function() {
it('testInitialization_emptyArray', function() { it('testInitialization_emptyArray', function() {
var msg = new proto.jspb.test.HasExtensions([]); var msg = new proto.jspb.test.HasExtensions([]);
if (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS) { assertArrayEquals([], msg.toArray());
assertArrayEquals([], msg.toArray());
} else {
// Extension object is created past all regular fields.
assertArrayEquals([,,, {}], msg.toArray());
}
}); });
it('testInitialization_justExtensionObject', function() { it('testInitialization_justExtensionObject', function() {

@ -86,4 +86,5 @@ enum Proto3Enum {
PROTO3_FOO = 0; PROTO3_FOO = 0;
PROTO3_BAR = 1; PROTO3_BAR = 1;
PROTO3_BAZ = 2; PROTO3_BAZ = 2;
MSG_PROTO3_BAH = 3;
} }

@ -235,6 +235,13 @@ message TestEndsWithBytes {
} }
message Int64Types {
optional int64 int64_normal = 1 [jstype=JS_NORMAL];
optional sint64 int64_string = 2 [jstype=JS_STRING];
optional uint64 int64_number = 3 [jstype=JS_NUMBER];
}
message TestMapFieldsNoBinary { message TestMapFieldsNoBinary {
map<string, string> map_string_string = 1; map<string, string> map_string_string = 1;
@ -271,3 +278,4 @@ message Deeply {
} }
} }
} }

@ -370,9 +370,8 @@ class TextFormatTest(unittest.TestCase):
def testMergeBadExtension(self): def testMergeBadExtension(self):
message = unittest_pb2.TestAllExtensions() message = unittest_pb2.TestAllExtensions()
text = '[unknown_extension]: 8\n' text = '[unknown_extension]: 8\n'
self.assertRaisesWithMessage( self.assertRaises(
text_format.ParseError, text_format.ParseError,
'1:2 : Extension "unknown_extension" not registered.',
text_format.Merge, text, message) text_format.Merge, text, message)
message = unittest_pb2.TestAllTypes() message = unittest_pb2.TestAllTypes()
self.assertRaisesWithMessage( self.assertRaisesWithMessage(

@ -406,6 +406,8 @@ class FieldDescriptor(DescriptorBase):
containing_oneof: (OneofDescriptor) If the field is a member of a oneof containing_oneof: (OneofDescriptor) If the field is a member of a oneof
union, contains its descriptor. Otherwise, None. union, contains its descriptor. Otherwise, None.
file: (FileDescriptor) Reference to file descriptor.
""" """
# Must be consistent with C++ FieldDescriptor::Type enum in # Must be consistent with C++ FieldDescriptor::Type enum in
@ -490,7 +492,8 @@ class FieldDescriptor(DescriptorBase):
def __new__(cls, name, full_name, index, number, type, cpp_type, label, def __new__(cls, name, full_name, index, number, type, cpp_type, label,
default_value, message_type, enum_type, containing_type, default_value, message_type, enum_type, containing_type,
is_extension, extension_scope, options=None, is_extension, extension_scope, options=None,
has_default_value=True, containing_oneof=None, json_name=None): has_default_value=True, containing_oneof=None, json_name=None,
file=None):
_message.Message._CheckCalledFromGeneratedFile() _message.Message._CheckCalledFromGeneratedFile()
if is_extension: if is_extension:
return _message.default_pool.FindExtensionByName(full_name) return _message.default_pool.FindExtensionByName(full_name)
@ -500,7 +503,8 @@ class FieldDescriptor(DescriptorBase):
def __init__(self, name, full_name, index, number, type, cpp_type, label, def __init__(self, name, full_name, index, number, type, cpp_type, label,
default_value, message_type, enum_type, containing_type, default_value, message_type, enum_type, containing_type,
is_extension, extension_scope, options=None, is_extension, extension_scope, options=None,
has_default_value=True, containing_oneof=None, json_name=None): has_default_value=True, containing_oneof=None, json_name=None,
file=None):
"""The arguments are as described in the description of FieldDescriptor """The arguments are as described in the description of FieldDescriptor
attributes above. attributes above.
@ -511,6 +515,7 @@ class FieldDescriptor(DescriptorBase):
super(FieldDescriptor, self).__init__(options, 'FieldOptions') super(FieldDescriptor, self).__init__(options, 'FieldOptions')
self.name = name self.name = name
self.full_name = full_name self.full_name = full_name
self.file = file
self._camelcase_name = None self._camelcase_name = None
if json_name is None: if json_name is None:
self.json_name = _ToJsonName(name) self.json_name = _ToJsonName(name)

@ -134,8 +134,7 @@ def _ExtractSymbols(desc_proto, package):
Yields: Yields:
The fully qualified name found in the descriptor. The fully qualified name found in the descriptor.
""" """
message_name = package + '.' + desc_proto.name if package else desc_proto.name
message_name = '.'.join((package, desc_proto.name))
yield message_name yield message_name
for nested_type in desc_proto.nested_type: for nested_type in desc_proto.nested_type:
for symbol in _ExtractSymbols(nested_type, message_name): for symbol in _ExtractSymbols(nested_type, message_name):

@ -257,7 +257,7 @@ class DescriptorPool(object):
self._AddFileDescriptor(file_desc) self._AddFileDescriptor(file_desc)
# TODO(jieluo): This is a temporary solution for FieldDescriptor.file. # TODO(jieluo): This is a temporary solution for FieldDescriptor.file.
# Remove it when FieldDescriptor.file is added in code gen. # Remove it when FieldDescriptor.file is added in code gen.
for extension in file_desc.extensions_by_name.values(): for extension in file_desc.extensions_by_name.itervalues():
self._file_desc_by_toplevel_extension[ self._file_desc_by_toplevel_extension[
extension.full_name] = file_desc extension.full_name] = file_desc
@ -328,6 +328,11 @@ class DescriptorPool(object):
except KeyError: except KeyError:
pass pass
try:
return self._service_descriptors[symbol].file
except KeyError:
pass
try: try:
return self._FindFileContainingSymbolInDb(symbol) return self._FindFileContainingSymbolInDb(symbol)
except KeyError: except KeyError:
@ -344,7 +349,6 @@ class DescriptorPool(object):
message = self.FindMessageTypeByName(message_name) message = self.FindMessageTypeByName(message_name)
assert message.extensions_by_name[extension_name] assert message.extensions_by_name[extension_name]
return message.file return message.file
except KeyError: except KeyError:
raise KeyError('Cannot find a file containing %s' % symbol) raise KeyError('Cannot find a file containing %s' % symbol)
@ -557,7 +561,8 @@ class DescriptorPool(object):
for index, extension_proto in enumerate(file_proto.extension): for index, extension_proto in enumerate(file_proto.extension):
extension_desc = self._MakeFieldDescriptor( extension_desc = self._MakeFieldDescriptor(
extension_proto, file_proto.package, index, is_extension=True) extension_proto, file_proto.package, index, file_descriptor,
is_extension=True)
extension_desc.containing_type = self._GetTypeFromScope( extension_desc.containing_type = self._GetTypeFromScope(
file_descriptor.package, extension_proto.extendee, scope) file_descriptor.package, extension_proto.extendee, scope)
self._SetFieldType(extension_proto, extension_desc, self._SetFieldType(extension_proto, extension_desc,
@ -623,10 +628,10 @@ class DescriptorPool(object):
enums = [ enums = [
self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope) self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
for enum in desc_proto.enum_type] for enum in desc_proto.enum_type]
fields = [self._MakeFieldDescriptor(field, desc_name, index) fields = [self._MakeFieldDescriptor(field, desc_name, index, file_desc)
for index, field in enumerate(desc_proto.field)] for index, field in enumerate(desc_proto.field)]
extensions = [ extensions = [
self._MakeFieldDescriptor(extension, desc_name, index, self._MakeFieldDescriptor(extension, desc_name, index, file_desc,
is_extension=True) is_extension=True)
for index, extension in enumerate(desc_proto.extension)] for index, extension in enumerate(desc_proto.extension)]
oneofs = [ oneofs = [
@ -708,7 +713,7 @@ class DescriptorPool(object):
return desc return desc
def _MakeFieldDescriptor(self, field_proto, message_name, index, def _MakeFieldDescriptor(self, field_proto, message_name, index,
is_extension=False): file_desc, is_extension=False):
"""Creates a field descriptor from a FieldDescriptorProto. """Creates a field descriptor from a FieldDescriptorProto.
For message and enum type fields, this method will do a look up For message and enum type fields, this method will do a look up
@ -721,6 +726,7 @@ class DescriptorPool(object):
field_proto: The proto describing the field. field_proto: The proto describing the field.
message_name: The name of the containing message. message_name: The name of the containing message.
index: Index of the field index: Index of the field
file_desc: The file containing the field descriptor.
is_extension: Indication that this field is for an extension. is_extension: Indication that this field is for an extension.
Returns: Returns:
@ -747,7 +753,8 @@ class DescriptorPool(object):
default_value=None, default_value=None,
is_extension=is_extension, is_extension=is_extension,
extension_scope=None, extension_scope=None,
options=_OptionsOrNone(field_proto)) options=_OptionsOrNone(field_proto),
file=file_desc)
def _SetAllFieldTypes(self, package, desc_proto, scope): def _SetAllFieldTypes(self, package, desc_proto, scope):
"""Sets all the descriptor's fields's types. """Sets all the descriptor's fields's types.

@ -100,6 +100,27 @@ if _implementation_version_str != '2':
_implementation_version = int(_implementation_version_str) _implementation_version = int(_implementation_version_str)
# Detect if serialization should be deterministic by default
try:
# The presence of this module in a build allows the proto implementation to
# be upgraded merely via build deps.
#
# NOTE: Merely importing this automatically enables deterministic proto
# serialization for C++ code, but we still need to export it as a boolean so
# that we can do the same for `_implementation_type == 'python'`.
#
# NOTE2: It is possible for C++ code to enable deterministic serialization by
# default _without_ affecting Python code, if the C++ implementation is not in
# use by this module. That is intended behavior, so we don't actually expose
# this boolean outside of this module.
#
# pylint: disable=g-import-not-at-top,unused-import
from google.protobuf import enable_deterministic_proto_serialization
_python_deterministic_proto_serialization = True
except ImportError:
_python_deterministic_proto_serialization = False
# Usage of this function is discouraged. Clients shouldn't care which # Usage of this function is discouraged. Clients shouldn't care which
# implementation of the API is in use. Note that there is no guarantee # implementation of the API is in use. Note that there is no guarantee
# that differences between APIs will be maintained. # that differences between APIs will be maintained.
@ -111,3 +132,8 @@ def Type():
# See comment on 'Type' above. # See comment on 'Type' above.
def Version(): def Version():
return _implementation_version return _implementation_version
# For internal use only
def IsPythonDefaultSerializationDeterministic():
return _python_deterministic_proto_serialization

@ -131,11 +131,19 @@ class DescriptorPoolTest(unittest.TestCase):
self.assertEqual('google/protobuf/internal/factory_test2.proto', self.assertEqual('google/protobuf/internal/factory_test2.proto',
file_desc4.name) file_desc4.name)
file_desc5 = self.pool.FindFileContainingSymbol(
'protobuf_unittest.TestService')
self.assertIsInstance(file_desc5, descriptor.FileDescriptor)
self.assertEqual('google/protobuf/unittest.proto',
file_desc5.name)
# Tests the generated pool. # Tests the generated pool.
assert descriptor_pool.Default().FindFileContainingSymbol( assert descriptor_pool.Default().FindFileContainingSymbol(
'google.protobuf.python.internal.Factory2Message.one_more_field') 'google.protobuf.python.internal.Factory2Message.one_more_field')
assert descriptor_pool.Default().FindFileContainingSymbol( assert descriptor_pool.Default().FindFileContainingSymbol(
'google.protobuf.python.internal.another_field') 'google.protobuf.python.internal.another_field')
assert descriptor_pool.Default().FindFileContainingSymbol(
'protobuf_unittest.TestService')
def testFindFileContainingSymbolFailure(self): def testFindFileContainingSymbolFailure(self):
with self.assertRaises(KeyError): with self.assertRaises(KeyError):
@ -506,10 +514,10 @@ class MessageType(object):
subtype.CheckType(test, desc, name, file_desc) subtype.CheckType(test, desc, name, file_desc)
for index, (name, field) in enumerate(self.field_list): for index, (name, field) in enumerate(self.field_list):
field.CheckField(test, desc, name, index) field.CheckField(test, desc, name, index, file_desc)
for index, (name, field) in enumerate(self.extensions): for index, (name, field) in enumerate(self.extensions):
field.CheckField(test, desc, name, index) field.CheckField(test, desc, name, index, file_desc)
class EnumField(object): class EnumField(object):
@ -519,7 +527,7 @@ class EnumField(object):
self.type_name = type_name self.type_name = type_name
self.default_value = default_value self.default_value = default_value
def CheckField(self, test, msg_desc, name, index): def CheckField(self, test, msg_desc, name, index, file_desc):
field_desc = msg_desc.fields_by_name[name] field_desc = msg_desc.fields_by_name[name]
enum_desc = msg_desc.enum_types_by_name[self.type_name] enum_desc = msg_desc.enum_types_by_name[self.type_name]
test.assertEqual(name, field_desc.name) test.assertEqual(name, field_desc.name)
@ -536,6 +544,7 @@ class EnumField(object):
test.assertFalse(enum_desc.values_by_name[self.default_value].has_options) test.assertFalse(enum_desc.values_by_name[self.default_value].has_options)
test.assertEqual(msg_desc, field_desc.containing_type) test.assertEqual(msg_desc, field_desc.containing_type)
test.assertEqual(enum_desc, field_desc.enum_type) test.assertEqual(enum_desc, field_desc.enum_type)
test.assertEqual(file_desc, enum_desc.file)
class MessageField(object): class MessageField(object):
@ -544,7 +553,7 @@ class MessageField(object):
self.number = number self.number = number
self.type_name = type_name self.type_name = type_name
def CheckField(self, test, msg_desc, name, index): def CheckField(self, test, msg_desc, name, index, file_desc):
field_desc = msg_desc.fields_by_name[name] field_desc = msg_desc.fields_by_name[name]
field_type_desc = msg_desc.nested_types_by_name[self.type_name] field_type_desc = msg_desc.nested_types_by_name[self.type_name]
test.assertEqual(name, field_desc.name) test.assertEqual(name, field_desc.name)
@ -558,6 +567,7 @@ class MessageField(object):
test.assertFalse(field_desc.has_default_value) test.assertFalse(field_desc.has_default_value)
test.assertEqual(msg_desc, field_desc.containing_type) test.assertEqual(msg_desc, field_desc.containing_type)
test.assertEqual(field_type_desc, field_desc.message_type) test.assertEqual(field_type_desc, field_desc.message_type)
test.assertEqual(file_desc, field_desc.file)
class StringField(object): class StringField(object):
@ -566,7 +576,7 @@ class StringField(object):
self.number = number self.number = number
self.default_value = default_value self.default_value = default_value
def CheckField(self, test, msg_desc, name, index): def CheckField(self, test, msg_desc, name, index, file_desc):
field_desc = msg_desc.fields_by_name[name] field_desc = msg_desc.fields_by_name[name]
test.assertEqual(name, field_desc.name) test.assertEqual(name, field_desc.name)
expected_field_full_name = '.'.join([msg_desc.full_name, name]) expected_field_full_name = '.'.join([msg_desc.full_name, name])
@ -578,6 +588,7 @@ class StringField(object):
field_desc.cpp_type) field_desc.cpp_type)
test.assertTrue(field_desc.has_default_value) test.assertTrue(field_desc.has_default_value)
test.assertEqual(self.default_value, field_desc.default_value) test.assertEqual(self.default_value, field_desc.default_value)
test.assertEqual(file_desc, field_desc.file)
class ExtensionField(object): class ExtensionField(object):
@ -586,7 +597,7 @@ class ExtensionField(object):
self.number = number self.number = number
self.extended_type = extended_type self.extended_type = extended_type
def CheckField(self, test, msg_desc, name, index): def CheckField(self, test, msg_desc, name, index, file_desc):
field_desc = msg_desc.extensions_by_name[name] field_desc = msg_desc.extensions_by_name[name]
test.assertEqual(name, field_desc.name) test.assertEqual(name, field_desc.name)
expected_field_full_name = '.'.join([msg_desc.full_name, name]) expected_field_full_name = '.'.join([msg_desc.full_name, name])
@ -601,6 +612,7 @@ class ExtensionField(object):
test.assertEqual(msg_desc, field_desc.extension_scope) test.assertEqual(msg_desc, field_desc.extension_scope)
test.assertEqual(msg_desc, field_desc.message_type) test.assertEqual(msg_desc, field_desc.message_type)
test.assertEqual(self.extended_type, field_desc.containing_type.name) test.assertEqual(self.extended_type, field_desc.containing_type.name)
test.assertEqual(file_desc, field_desc.file)
class AddDescriptorTest(unittest.TestCase): class AddDescriptorTest(unittest.TestCase):
@ -746,15 +758,10 @@ class AddDescriptorTest(unittest.TestCase):
self.assertIs(options, file_descriptor.GetOptions()) self.assertIs(options, file_descriptor.GetOptions())
@unittest.skipIf(
api_implementation.Type() != 'cpp',
'default_pool is only supported by the C++ implementation')
class DefaultPoolTest(unittest.TestCase): class DefaultPoolTest(unittest.TestCase):
def testFindMethods(self): def testFindMethods(self):
# pylint: disable=g-import-not-at-top pool = descriptor_pool.Default()
from google.protobuf.pyext import _message
pool = _message.default_pool
self.assertIs( self.assertIs(
pool.FindFileByName('google/protobuf/unittest.proto'), pool.FindFileByName('google/protobuf/unittest.proto'),
unittest_pb2.DESCRIPTOR) unittest_pb2.DESCRIPTOR)
@ -764,20 +771,23 @@ class DefaultPoolTest(unittest.TestCase):
self.assertIs( self.assertIs(
pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'), pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'),
unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32']) unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
self.assertIs(
pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
self.assertIs( self.assertIs(
pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'), pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
unittest_pb2.ForeignEnum.DESCRIPTOR) unittest_pb2.ForeignEnum.DESCRIPTOR)
if api_implementation.Type() != 'cpp':
self.skipTest('Only the C++ implementation correctly indexes all types')
self.assertIs(
pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
self.assertIs( self.assertIs(
pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'), pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field']) unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
self.assertIs(
pool.FindServiceByName('protobuf_unittest.TestService'),
unittest_pb2.DESCRIPTOR.services_by_name['TestService'])
def testAddFileDescriptor(self): def testAddFileDescriptor(self):
# pylint: disable=g-import-not-at-top pool = descriptor_pool.Default()
from google.protobuf.pyext import _message
pool = _message.default_pool
file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
pool.Add(file_desc) pool.Add(file_desc)
pool.AddSerializedFile(file_desc.SerializeToString()) pool.AddSerializedFile(file_desc.SerializeToString())

@ -521,6 +521,12 @@ class GeneratedDescriptorTest(unittest.TestCase):
del enum del enum
self.assertEqual('FOO', next(values_iter).name) self.assertEqual('FOO', next(values_iter).name)
def testServiceDescriptor(self):
service_descriptor = unittest_pb2.DESCRIPTOR.services_by_name['TestService']
self.assertEqual(service_descriptor.name, 'TestService')
self.assertEqual(service_descriptor.methods[0].name, 'Foo')
self.assertIs(service_descriptor.file, unittest_pb2.DESCRIPTOR)
class DescriptorCopyToProtoTest(unittest.TestCase): class DescriptorCopyToProtoTest(unittest.TestCase):
"""Tests for CopyTo functions of Descriptor.""" """Tests for CopyTo functions of Descriptor."""

@ -372,7 +372,7 @@ def MapSizer(field_descriptor, is_message_map):
def _VarintEncoder(): def _VarintEncoder():
"""Return an encoder for a basic varint value (does not include tag).""" """Return an encoder for a basic varint value (does not include tag)."""
def EncodeVarint(write, value): def EncodeVarint(write, value, unused_deterministic):
bits = value & 0x7f bits = value & 0x7f
value >>= 7 value >>= 7
while value: while value:
@ -388,7 +388,7 @@ def _SignedVarintEncoder():
"""Return an encoder for a basic signed varint value (does not include """Return an encoder for a basic signed varint value (does not include
tag).""" tag)."""
def EncodeSignedVarint(write, value): def EncodeSignedVarint(write, value, unused_deterministic):
if value < 0: if value < 0:
value += (1 << 64) value += (1 << 64)
bits = value & 0x7f bits = value & 0x7f
@ -411,7 +411,7 @@ def _VarintBytes(value):
called at startup time so it doesn't need to be fast.""" called at startup time so it doesn't need to be fast."""
pieces = [] pieces = []
_EncodeVarint(pieces.append, value) _EncodeVarint(pieces.append, value, True)
return b"".join(pieces) return b"".join(pieces)
@ -440,27 +440,27 @@ def _SimpleEncoder(wire_type, encode_value, compute_value_size):
if is_packed: if is_packed:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
def EncodePackedField(write, value): def EncodePackedField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
size = 0 size = 0
for element in value: for element in value:
size += compute_value_size(element) size += compute_value_size(element)
local_EncodeVarint(write, size) local_EncodeVarint(write, size, deterministic)
for element in value: for element in value:
encode_value(write, element) encode_value(write, element, deterministic)
return EncodePackedField return EncodePackedField
elif is_repeated: elif is_repeated:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, deterministic):
for element in value: for element in value:
write(tag_bytes) write(tag_bytes)
encode_value(write, element) encode_value(write, element, deterministic)
return EncodeRepeatedField return EncodeRepeatedField
else: else:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeField(write, value): def EncodeField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
return encode_value(write, value) return encode_value(write, value, deterministic)
return EncodeField return EncodeField
return SpecificEncoder return SpecificEncoder
@ -474,27 +474,27 @@ def _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value):
if is_packed: if is_packed:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
def EncodePackedField(write, value): def EncodePackedField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
size = 0 size = 0
for element in value: for element in value:
size += compute_value_size(modify_value(element)) size += compute_value_size(modify_value(element))
local_EncodeVarint(write, size) local_EncodeVarint(write, size, deterministic)
for element in value: for element in value:
encode_value(write, modify_value(element)) encode_value(write, modify_value(element), deterministic)
return EncodePackedField return EncodePackedField
elif is_repeated: elif is_repeated:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, deterministic):
for element in value: for element in value:
write(tag_bytes) write(tag_bytes)
encode_value(write, modify_value(element)) encode_value(write, modify_value(element), deterministic)
return EncodeRepeatedField return EncodeRepeatedField
else: else:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeField(write, value): def EncodeField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
return encode_value(write, modify_value(value)) return encode_value(write, modify_value(value), deterministic)
return EncodeField return EncodeField
return SpecificEncoder return SpecificEncoder
@ -515,22 +515,22 @@ def _StructPackEncoder(wire_type, format):
if is_packed: if is_packed:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
def EncodePackedField(write, value): def EncodePackedField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
local_EncodeVarint(write, len(value) * value_size) local_EncodeVarint(write, len(value) * value_size, deterministic)
for element in value: for element in value:
write(local_struct_pack(format, element)) write(local_struct_pack(format, element))
return EncodePackedField return EncodePackedField
elif is_repeated: elif is_repeated:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, unused_deterministic):
for element in value: for element in value:
write(tag_bytes) write(tag_bytes)
write(local_struct_pack(format, element)) write(local_struct_pack(format, element))
return EncodeRepeatedField return EncodeRepeatedField
else: else:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeField(write, value): def EncodeField(write, value, unused_deterministic):
write(tag_bytes) write(tag_bytes)
return write(local_struct_pack(format, value)) return write(local_struct_pack(format, value))
return EncodeField return EncodeField
@ -581,9 +581,9 @@ def _FloatingPointEncoder(wire_type, format):
if is_packed: if is_packed:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
def EncodePackedField(write, value): def EncodePackedField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
local_EncodeVarint(write, len(value) * value_size) local_EncodeVarint(write, len(value) * value_size, deterministic)
for element in value: for element in value:
# This try/except block is going to be faster than any code that # This try/except block is going to be faster than any code that
# we could write to check whether element is finite. # we could write to check whether element is finite.
@ -594,7 +594,7 @@ def _FloatingPointEncoder(wire_type, format):
return EncodePackedField return EncodePackedField
elif is_repeated: elif is_repeated:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, unused_deterministic):
for element in value: for element in value:
write(tag_bytes) write(tag_bytes)
try: try:
@ -604,7 +604,7 @@ def _FloatingPointEncoder(wire_type, format):
return EncodeRepeatedField return EncodeRepeatedField
else: else:
tag_bytes = TagBytes(field_number, wire_type) tag_bytes = TagBytes(field_number, wire_type)
def EncodeField(write, value): def EncodeField(write, value, unused_deterministic):
write(tag_bytes) write(tag_bytes)
try: try:
write(local_struct_pack(format, value)) write(local_struct_pack(format, value))
@ -650,9 +650,9 @@ def BoolEncoder(field_number, is_repeated, is_packed):
if is_packed: if is_packed:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
def EncodePackedField(write, value): def EncodePackedField(write, value, deterministic):
write(tag_bytes) write(tag_bytes)
local_EncodeVarint(write, len(value)) local_EncodeVarint(write, len(value), deterministic)
for element in value: for element in value:
if element: if element:
write(true_byte) write(true_byte)
@ -661,7 +661,7 @@ def BoolEncoder(field_number, is_repeated, is_packed):
return EncodePackedField return EncodePackedField
elif is_repeated: elif is_repeated:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, unused_deterministic):
for element in value: for element in value:
write(tag_bytes) write(tag_bytes)
if element: if element:
@ -671,7 +671,7 @@ def BoolEncoder(field_number, is_repeated, is_packed):
return EncodeRepeatedField return EncodeRepeatedField
else: else:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT) tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
def EncodeField(write, value): def EncodeField(write, value, unused_deterministic):
write(tag_bytes) write(tag_bytes)
if value: if value:
return write(true_byte) return write(true_byte)
@ -687,18 +687,18 @@ def StringEncoder(field_number, is_repeated, is_packed):
local_len = len local_len = len
assert not is_packed assert not is_packed
if is_repeated: if is_repeated:
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, deterministic):
for element in value: for element in value:
encoded = element.encode('utf-8') encoded = element.encode('utf-8')
write(tag) write(tag)
local_EncodeVarint(write, local_len(encoded)) local_EncodeVarint(write, local_len(encoded), deterministic)
write(encoded) write(encoded)
return EncodeRepeatedField return EncodeRepeatedField
else: else:
def EncodeField(write, value): def EncodeField(write, value, deterministic):
encoded = value.encode('utf-8') encoded = value.encode('utf-8')
write(tag) write(tag)
local_EncodeVarint(write, local_len(encoded)) local_EncodeVarint(write, local_len(encoded), deterministic)
return write(encoded) return write(encoded)
return EncodeField return EncodeField
@ -711,16 +711,16 @@ def BytesEncoder(field_number, is_repeated, is_packed):
local_len = len local_len = len
assert not is_packed assert not is_packed
if is_repeated: if is_repeated:
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, deterministic):
for element in value: for element in value:
write(tag) write(tag)
local_EncodeVarint(write, local_len(element)) local_EncodeVarint(write, local_len(element), deterministic)
write(element) write(element)
return EncodeRepeatedField return EncodeRepeatedField
else: else:
def EncodeField(write, value): def EncodeField(write, value, deterministic):
write(tag) write(tag)
local_EncodeVarint(write, local_len(value)) local_EncodeVarint(write, local_len(value), deterministic)
return write(value) return write(value)
return EncodeField return EncodeField
@ -732,16 +732,16 @@ def GroupEncoder(field_number, is_repeated, is_packed):
end_tag = TagBytes(field_number, wire_format.WIRETYPE_END_GROUP) end_tag = TagBytes(field_number, wire_format.WIRETYPE_END_GROUP)
assert not is_packed assert not is_packed
if is_repeated: if is_repeated:
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, deterministic):
for element in value: for element in value:
write(start_tag) write(start_tag)
element._InternalSerialize(write) element._InternalSerialize(write, deterministic)
write(end_tag) write(end_tag)
return EncodeRepeatedField return EncodeRepeatedField
else: else:
def EncodeField(write, value): def EncodeField(write, value, deterministic):
write(start_tag) write(start_tag)
value._InternalSerialize(write) value._InternalSerialize(write, deterministic)
return write(end_tag) return write(end_tag)
return EncodeField return EncodeField
@ -753,17 +753,17 @@ def MessageEncoder(field_number, is_repeated, is_packed):
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
assert not is_packed assert not is_packed
if is_repeated: if is_repeated:
def EncodeRepeatedField(write, value): def EncodeRepeatedField(write, value, deterministic):
for element in value: for element in value:
write(tag) write(tag)
local_EncodeVarint(write, element.ByteSize()) local_EncodeVarint(write, element.ByteSize(), deterministic)
element._InternalSerialize(write) element._InternalSerialize(write, deterministic)
return EncodeRepeatedField return EncodeRepeatedField
else: else:
def EncodeField(write, value): def EncodeField(write, value, deterministic):
write(tag) write(tag)
local_EncodeVarint(write, value.ByteSize()) local_EncodeVarint(write, value.ByteSize(), deterministic)
return value._InternalSerialize(write) return value._InternalSerialize(write, deterministic)
return EncodeField return EncodeField
@ -790,10 +790,10 @@ def MessageSetItemEncoder(field_number):
end_bytes = TagBytes(1, wire_format.WIRETYPE_END_GROUP) end_bytes = TagBytes(1, wire_format.WIRETYPE_END_GROUP)
local_EncodeVarint = _EncodeVarint local_EncodeVarint = _EncodeVarint
def EncodeField(write, value): def EncodeField(write, value, deterministic):
write(start_bytes) write(start_bytes)
local_EncodeVarint(write, value.ByteSize()) local_EncodeVarint(write, value.ByteSize(), deterministic)
value._InternalSerialize(write) value._InternalSerialize(write, deterministic)
return write(end_bytes) return write(end_bytes)
return EncodeField return EncodeField
@ -818,9 +818,10 @@ def MapEncoder(field_descriptor):
message_type = field_descriptor.message_type message_type = field_descriptor.message_type
encode_message = MessageEncoder(field_descriptor.number, False, False) encode_message = MessageEncoder(field_descriptor.number, False, False)
def EncodeField(write, value): def EncodeField(write, value, deterministic):
for key in value: value_keys = sorted(value.iterkeys()) if deterministic else value.iterkeys()
for key in value_keys:
entry_msg = message_type._concrete_class(key=key, value=value[key]) entry_msg = message_type._concrete_class(key=key, value=value[key])
encode_message(write, entry_msg) encode_message(write, entry_msg, deterministic)
return EncodeField return EncodeField

@ -97,3 +97,8 @@ message MessageWithNestedEnumOnly {
extend Factory1Message { extend Factory1Message {
optional string another_field = 1002; optional string another_field = 1002;
} }
message MessageWithOption {
option no_standard_descriptor_accessor = true;
optional int32 field1 = 1;
}

@ -49,6 +49,7 @@ from google.protobuf import field_mask_pb2
from google.protobuf import struct_pb2 from google.protobuf import struct_pb2
from google.protobuf import timestamp_pb2 from google.protobuf import timestamp_pb2
from google.protobuf import wrappers_pb2 from google.protobuf import wrappers_pb2
from google.protobuf import unittest_mset_pb2
from google.protobuf.internal import well_known_types from google.protobuf.internal import well_known_types
from google.protobuf import json_format from google.protobuf import json_format
from google.protobuf.util import json_format_proto3_pb2 from google.protobuf.util import json_format_proto3_pb2
@ -158,6 +159,84 @@ class JsonFormatTest(JsonFormatBase):
json_format.Parse(text, parsed_message) json_format.Parse(text, parsed_message)
self.assertEqual(message, parsed_message) self.assertEqual(message, parsed_message)
def testExtensionToJsonAndBack(self):
message = unittest_mset_pb2.TestMessageSetContainer()
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
message.message_set.Extensions[ext1].i = 23
message.message_set.Extensions[ext2].str = 'foo'
message_text = json_format.MessageToJson(
message
)
parsed_message = unittest_mset_pb2.TestMessageSetContainer()
json_format.Parse(message_text, parsed_message)
self.assertEqual(message, parsed_message)
def testExtensionToDictAndBack(self):
message = unittest_mset_pb2.TestMessageSetContainer()
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
message.message_set.Extensions[ext1].i = 23
message.message_set.Extensions[ext2].str = 'foo'
message_dict = json_format.MessageToDict(
message
)
parsed_message = unittest_mset_pb2.TestMessageSetContainer()
json_format.ParseDict(message_dict, parsed_message)
self.assertEqual(message, parsed_message)
def testExtensionSerializationDictMatchesProto3Spec(self):
"""See go/proto3-json-spec for spec.
"""
message = unittest_mset_pb2.TestMessageSetContainer()
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
message.message_set.Extensions[ext1].i = 23
message.message_set.Extensions[ext2].str = 'foo'
message_dict = json_format.MessageToDict(
message
)
golden_dict = {
'messageSet': {
'[protobuf_unittest.'
'TestMessageSetExtension1.messageSetExtension]': {
'i': 23,
},
'[protobuf_unittest.'
'TestMessageSetExtension2.messageSetExtension]': {
'str': u'foo',
},
},
}
self.assertEqual(golden_dict, message_dict)
def testExtensionSerializationJsonMatchesProto3Spec(self):
"""See go/proto3-json-spec for spec.
"""
message = unittest_mset_pb2.TestMessageSetContainer()
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
message.message_set.Extensions[ext1].i = 23
message.message_set.Extensions[ext2].str = 'foo'
message_text = json_format.MessageToJson(
message
)
ext1_text = ('protobuf_unittest.TestMessageSetExtension1.'
'messageSetExtension')
ext2_text = ('protobuf_unittest.TestMessageSetExtension2.'
'messageSetExtension')
golden_text = ('{"messageSet": {'
' "[%s]": {'
' "i": 23'
' },'
' "[%s]": {'
' "str": "foo"'
' }'
'}}') % (ext1_text, ext2_text)
self.assertEqual(json.loads(golden_text), json.loads(message_text))
def testJsonEscapeString(self): def testJsonEscapeString(self):
message = json_format_proto3_pb2.TestMessage() message = json_format_proto3_pb2.TestMessage()
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
@ -768,7 +847,7 @@ class JsonFormatTest(JsonFormatBase):
text = '{"value": "0000-01-01T00:00:00Z"}' text = '{"value": "0000-01-01T00:00:00Z"}'
self.assertRaisesRegexp( self.assertRaisesRegexp(
json_format.ParseError, json_format.ParseError,
'Failed to parse value field: year is out of range.', 'Failed to parse value field: year (0 )?is out of range.',
json_format.Parse, text, message) json_format.Parse, text, message)
# Time bigger than maxinum time. # Time bigger than maxinum time.
message.value.seconds = 253402300800 message.value.seconds = 253402300800
@ -840,6 +919,12 @@ class JsonFormatTest(JsonFormatBase):
json_format.Parse('{"int32_value": 12345}', message) json_format.Parse('{"int32_value": 12345}', message)
self.assertEqual(12345, message.int32_value) self.assertEqual(12345, message.int32_value)
def testIndent(self):
message = json_format_proto3_pb2.TestMessage()
message.int32_value = 12345
self.assertEqual('{\n"int32Value": 12345\n}',
json_format.MessageToJson(message, indent=0))
def testParseDict(self): def testParseDict(self):
expected = 12345 expected = 12345
js_dict = {'int32Value': expected} js_dict = {'int32Value': expected}
@ -862,6 +947,22 @@ class JsonFormatTest(JsonFormatBase):
parsed_message = json_format_proto3_pb2.TestCustomJsonName() parsed_message = json_format_proto3_pb2.TestCustomJsonName()
self.CheckParseBack(message, parsed_message) self.CheckParseBack(message, parsed_message)
def testSortKeys(self):
# Testing sort_keys is not perfectly working, as by random luck we could
# get the output sorted. We just use a selection of names.
message = json_format_proto3_pb2.TestMessage(bool_value=True,
int32_value=1,
int64_value=3,
uint32_value=4,
string_value='bla')
self.assertEqual(
json_format.MessageToJson(message, sort_keys=True),
# We use json.dumps() instead of a hardcoded string due to differences
# between Python 2 and Python 3.
json.dumps({'boolValue': True, 'int32Value': 1, 'int64Value': '3',
'uint32Value': 4, 'stringValue': 'bla'},
indent=2, sort_keys=True))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

@ -136,6 +136,39 @@ class MessageTest(BaseTestCase):
golden_copy = copy.deepcopy(golden_message) golden_copy = copy.deepcopy(golden_message)
self.assertEqual(golden_data, golden_copy.SerializeToString()) self.assertEqual(golden_data, golden_copy.SerializeToString())
def testDeterminismParameters(self, message_module):
# This message is always deterministically serialized, even if determinism
# is disabled, so we can use it to verify that all the determinism
# parameters work correctly.
golden_data = (b'\xe2\x02\nOne string'
b'\xe2\x02\nTwo string'
b'\xe2\x02\nRed string'
b'\xe2\x02\x0bBlue string')
golden_message = message_module.TestAllTypes()
golden_message.repeated_string.extend([
'One string',
'Two string',
'Red string',
'Blue string',
])
self.assertEqual(golden_data,
golden_message.SerializeToString(deterministic=None))
self.assertEqual(golden_data,
golden_message.SerializeToString(deterministic=False))
self.assertEqual(golden_data,
golden_message.SerializeToString(deterministic=True))
class BadArgError(Exception):
pass
class BadArg(object):
def __nonzero__(self):
raise BadArgError()
with self.assertRaises(BadArgError):
golden_message.SerializeToString(deterministic=BadArg())
def testPickleSupport(self, message_module): def testPickleSupport(self, message_module):
golden_data = test_util.GoldenFileData('golden_message') golden_data = test_util.GoldenFileData('golden_message')
golden_message = message_module.TestAllTypes() golden_message = message_module.TestAllTypes()
@ -377,6 +410,7 @@ class MessageTest(BaseTestCase):
self.assertEqual(message.repeated_int32[0], 1) self.assertEqual(message.repeated_int32[0], 1)
self.assertEqual(message.repeated_int32[1], 2) self.assertEqual(message.repeated_int32[1], 2)
self.assertEqual(message.repeated_int32[2], 3) self.assertEqual(message.repeated_int32[2], 3)
self.assertEqual(str(message.repeated_int32), str([1, 2, 3]))
message.repeated_float.append(1.1) message.repeated_float.append(1.1)
message.repeated_float.append(1.3) message.repeated_float.append(1.3)
@ -393,6 +427,7 @@ class MessageTest(BaseTestCase):
self.assertEqual(message.repeated_string[0], 'a') self.assertEqual(message.repeated_string[0], 'a')
self.assertEqual(message.repeated_string[1], 'b') self.assertEqual(message.repeated_string[1], 'b')
self.assertEqual(message.repeated_string[2], 'c') self.assertEqual(message.repeated_string[2], 'c')
self.assertEqual(str(message.repeated_string), str([u'a', u'b', u'c']))
message.repeated_bytes.append(b'a') message.repeated_bytes.append(b'a')
message.repeated_bytes.append(b'c') message.repeated_bytes.append(b'c')
@ -401,6 +436,7 @@ class MessageTest(BaseTestCase):
self.assertEqual(message.repeated_bytes[0], b'a') self.assertEqual(message.repeated_bytes[0], b'a')
self.assertEqual(message.repeated_bytes[1], b'b') self.assertEqual(message.repeated_bytes[1], b'b')
self.assertEqual(message.repeated_bytes[2], b'c') self.assertEqual(message.repeated_bytes[2], b'c')
self.assertEqual(str(message.repeated_bytes), str([b'a', b'b', b'c']))
def testSortingRepeatedScalarFieldsCustomComparator(self, message_module): def testSortingRepeatedScalarFieldsCustomComparator(self, message_module):
"""Check some different types with custom comparator.""" """Check some different types with custom comparator."""
@ -439,6 +475,8 @@ class MessageTest(BaseTestCase):
self.assertEqual(message.repeated_nested_message[3].bb, 4) self.assertEqual(message.repeated_nested_message[3].bb, 4)
self.assertEqual(message.repeated_nested_message[4].bb, 5) self.assertEqual(message.repeated_nested_message[4].bb, 5)
self.assertEqual(message.repeated_nested_message[5].bb, 6) self.assertEqual(message.repeated_nested_message[5].bb, 6)
self.assertEqual(str(message.repeated_nested_message),
'[bb: 1\n, bb: 2\n, bb: 3\n, bb: 4\n, bb: 5\n, bb: 6\n]')
def testSortingRepeatedCompositeFieldsStable(self, message_module): def testSortingRepeatedCompositeFieldsStable(self, message_module):
"""Check passing a custom comparator to sort a repeated composite field.""" """Check passing a custom comparator to sort a repeated composite field."""
@ -1266,6 +1304,14 @@ class Proto3Test(BaseTestCase):
self.assertEqual(1234567, m2.optional_nested_enum) self.assertEqual(1234567, m2.optional_nested_enum)
self.assertEqual(7654321, m2.repeated_nested_enum[0]) self.assertEqual(7654321, m2.repeated_nested_enum[0])
# ParseFromString in Proto2 should accept unknown enums too.
m3 = unittest_pb2.TestAllTypes()
m3.ParseFromString(serialized)
m2.Clear()
m2.ParseFromString(m3.SerializeToString())
self.assertEqual(1234567, m2.optional_nested_enum)
self.assertEqual(7654321, m2.repeated_nested_enum[0])
# Map isn't really a proto3-only feature. But there is no proto2 equivalent # Map isn't really a proto3-only feature. But there is no proto2 equivalent
# of google/protobuf/map_unittest.proto right now, so it's not easy to # of google/protobuf/map_unittest.proto right now, so it's not easy to
# test both with the same test like we do for the other proto2/proto3 tests. # test both with the same test like we do for the other proto2/proto3 tests.
@ -1437,6 +1483,23 @@ class Proto3Test(BaseTestCase):
self.assertIn(-456, msg2.map_int32_foreign_message) self.assertIn(-456, msg2.map_int32_foreign_message)
self.assertEqual(2, len(msg2.map_int32_foreign_message)) self.assertEqual(2, len(msg2.map_int32_foreign_message))
def testNestedMessageMapItemDelete(self):
msg = map_unittest_pb2.TestMap()
msg.map_int32_all_types[1].optional_nested_message.bb = 1
del msg.map_int32_all_types[1]
msg.map_int32_all_types[2].optional_nested_message.bb = 2
self.assertEqual(1, len(msg.map_int32_all_types))
msg.map_int32_all_types[1].optional_nested_message.bb = 1
self.assertEqual(2, len(msg.map_int32_all_types))
serialized = msg.SerializeToString()
msg2 = map_unittest_pb2.TestMap()
msg2.ParseFromString(serialized)
keys = [1, 2]
# The loop triggers PyErr_Occurred() in c extension.
for key in keys:
del msg2.map_int32_all_types[key]
def testMapByteSize(self): def testMapByteSize(self):
msg = map_unittest_pb2.TestMap() msg = map_unittest_pb2.TestMap()
msg.map_int32_int32[1] = 1 msg.map_int32_int32[1] = 1
@ -1651,6 +1714,35 @@ class Proto3Test(BaseTestCase):
items2 = msg.map_string_string.items() items2 = msg.map_string_string.items()
self.assertEqual(items1, items2) self.assertEqual(items1, items2)
def testMapDeterministicSerialization(self):
golden_data = (b'r\x0c\n\x07init_op\x12\x01d'
b'r\n\n\x05item1\x12\x01e'
b'r\n\n\x05item2\x12\x01f'
b'r\n\n\x05item3\x12\x01g'
b'r\x0b\n\x05item4\x12\x02QQ'
b'r\x12\n\rlocal_init_op\x12\x01a'
b'r\x0e\n\tsummaries\x12\x01e'
b'r\x18\n\x13trainable_variables\x12\x01b'
b'r\x0e\n\tvariables\x12\x01c')
msg = map_unittest_pb2.TestMap()
msg.map_string_string['local_init_op'] = 'a'
msg.map_string_string['trainable_variables'] = 'b'
msg.map_string_string['variables'] = 'c'
msg.map_string_string['init_op'] = 'd'
msg.map_string_string['summaries'] = 'e'
msg.map_string_string['item1'] = 'e'
msg.map_string_string['item2'] = 'f'
msg.map_string_string['item3'] = 'g'
msg.map_string_string['item4'] = 'QQ'
# If deterministic serialization is not working correctly, this will be
# "flaky" depending on the exact python dict hash seed.
#
# Fortunately, there are enough items in this map that it is extremely
# unlikely to ever hit the "right" in-order combination, so the test
# itself should fail reliably.
self.assertEqual(golden_data, msg.SerializeToString(deterministic=True))
def testMapIterationClearMessage(self): def testMapIterationClearMessage(self):
# Iterator needs to work even if message and map are deleted. # Iterator needs to work even if message and map are deleted.
msg = map_unittest_pb2.TestMap() msg = map_unittest_pb2.TestMap()

@ -47,4 +47,5 @@ message DynamicMessageType {
extend ExtendedMessage { extend ExtendedMessage {
optional int32 dynamic_int32_extension = 100; optional int32 dynamic_int32_extension = 100;
optional DynamicMessageType dynamic_message_extension = 101; optional DynamicMessageType dynamic_message_extension = 101;
repeated DynamicMessageType repeated_dynamic_message_extension = 102;
} }

@ -58,6 +58,7 @@ import weakref
import six import six
# We use "as" to avoid name collisions with variables. # We use "as" to avoid name collisions with variables.
from google.protobuf.internal import api_implementation
from google.protobuf.internal import containers from google.protobuf.internal import containers
from google.protobuf.internal import decoder from google.protobuf.internal import decoder
from google.protobuf.internal import encoder from google.protobuf.internal import encoder
@ -1026,29 +1027,34 @@ def _AddByteSizeMethod(message_descriptor, cls):
def _AddSerializeToStringMethod(message_descriptor, cls): def _AddSerializeToStringMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods().""" """Helper for _AddMessageMethods()."""
def SerializeToString(self): def SerializeToString(self, **kwargs):
# Check if the message has all of its required fields set. # Check if the message has all of its required fields set.
errors = [] errors = []
if not self.IsInitialized(): if not self.IsInitialized():
raise message_mod.EncodeError( raise message_mod.EncodeError(
'Message %s is missing required fields: %s' % ( 'Message %s is missing required fields: %s' % (
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors()))) self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
return self.SerializePartialToString() return self.SerializePartialToString(**kwargs)
cls.SerializeToString = SerializeToString cls.SerializeToString = SerializeToString
def _AddSerializePartialToStringMethod(message_descriptor, cls): def _AddSerializePartialToStringMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods().""" """Helper for _AddMessageMethods()."""
def SerializePartialToString(self): def SerializePartialToString(self, **kwargs):
out = BytesIO() out = BytesIO()
self._InternalSerialize(out.write) self._InternalSerialize(out.write, **kwargs)
return out.getvalue() return out.getvalue()
cls.SerializePartialToString = SerializePartialToString cls.SerializePartialToString = SerializePartialToString
def InternalSerialize(self, write_bytes): def InternalSerialize(self, write_bytes, deterministic=None):
if deterministic is None:
deterministic = (
api_implementation.IsPythonDefaultSerializationDeterministic())
else:
deterministic = bool(deterministic)
for field_descriptor, field_value in self.ListFields(): for field_descriptor, field_value in self.ListFields():
field_descriptor._encoder(write_bytes, field_value) field_descriptor._encoder(write_bytes, field_value, deterministic)
for tag_bytes, value_bytes in self._unknown_fields: for tag_bytes, value_bytes in self._unknown_fields:
write_bytes(tag_bytes) write_bytes(tag_bytes)
write_bytes(value_bytes) write_bytes(value_bytes)

@ -452,16 +452,18 @@ class TextFormatTest(TextFormatBase):
text_format.Parse(text_format.MessageToString(m), m2) text_format.Parse(text_format.MessageToString(m), m2)
self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
def testMergeMultipleOneof(self, message_module):
m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
m2 = message_module.TestAllTypes()
text_format.Merge(m_string, m2)
self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
def testParseMultipleOneof(self, message_module): def testParseMultipleOneof(self, message_module):
m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"']) m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
m2 = message_module.TestAllTypes() m2 = message_module.TestAllTypes()
if message_module is unittest_pb2: with self.assertRaisesRegexp(text_format.ParseError,
with self.assertRaisesRegexp(text_format.ParseError, ' is specified along with field '):
' is specified along with field '):
text_format.Parse(m_string, m2)
else:
text_format.Parse(m_string, m2) text_format.Parse(m_string, m2)
self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
# These are tests that aren't fundamentally specific to proto2, but are at # These are tests that aren't fundamentally specific to proto2, but are at
@ -1026,8 +1028,7 @@ class Proto3Tests(unittest.TestCase):
packed_message.data = 'string1' packed_message.data = 'string1'
message.repeated_any_value.add().Pack(packed_message) message.repeated_any_value.add().Pack(packed_message)
self.assertEqual( self.assertEqual(
text_format.MessageToString(message, text_format.MessageToString(message),
descriptor_pool=descriptor_pool.Default()),
'repeated_any_value {\n' 'repeated_any_value {\n'
' [type.googleapis.com/protobuf_unittest.OneString] {\n' ' [type.googleapis.com/protobuf_unittest.OneString] {\n'
' data: "string0"\n' ' data: "string0"\n'
@ -1039,18 +1040,6 @@ class Proto3Tests(unittest.TestCase):
' }\n' ' }\n'
'}\n') '}\n')
def testPrintMessageExpandAnyNoDescriptorPool(self):
packed_message = unittest_pb2.OneString()
packed_message.data = 'string'
message = any_test_pb2.TestAny()
message.any_value.Pack(packed_message)
self.assertEqual(
text_format.MessageToString(message, descriptor_pool=None),
'any_value {\n'
' type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
' value: "\\n\\006string"\n'
'}\n')
def testPrintMessageExpandAnyDescriptorPoolMissingType(self): def testPrintMessageExpandAnyDescriptorPoolMissingType(self):
packed_message = unittest_pb2.OneString() packed_message = unittest_pb2.OneString()
packed_message.data = 'string' packed_message.data = 'string'
@ -1071,8 +1060,7 @@ class Proto3Tests(unittest.TestCase):
message.any_value.Pack(packed_message) message.any_value.Pack(packed_message)
self.assertEqual( self.assertEqual(
text_format.MessageToString(message, text_format.MessageToString(message,
pointy_brackets=True, pointy_brackets=True),
descriptor_pool=descriptor_pool.Default()),
'any_value <\n' 'any_value <\n'
' [type.googleapis.com/protobuf_unittest.OneString] <\n' ' [type.googleapis.com/protobuf_unittest.OneString] <\n'
' data: "string"\n' ' data: "string"\n'
@ -1086,8 +1074,7 @@ class Proto3Tests(unittest.TestCase):
message.any_value.Pack(packed_message) message.any_value.Pack(packed_message)
self.assertEqual( self.assertEqual(
text_format.MessageToString(message, text_format.MessageToString(message,
as_one_line=True, as_one_line=True),
descriptor_pool=descriptor_pool.Default()),
'any_value {' 'any_value {'
' [type.googleapis.com/protobuf_unittest.OneString]' ' [type.googleapis.com/protobuf_unittest.OneString]'
' { data: "string" } ' ' { data: "string" } '
@ -1115,12 +1102,12 @@ class Proto3Tests(unittest.TestCase):
' data: "string"\n' ' data: "string"\n'
' }\n' ' }\n'
'}\n') '}\n')
text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default()) text_format.Merge(text, message)
packed_message = unittest_pb2.OneString() packed_message = unittest_pb2.OneString()
message.any_value.Unpack(packed_message) message.any_value.Unpack(packed_message)
self.assertEqual('string', packed_message.data) self.assertEqual('string', packed_message.data)
message.Clear() message.Clear()
text_format.Parse(text, message, descriptor_pool=descriptor_pool.Default()) text_format.Parse(text, message)
packed_message = unittest_pb2.OneString() packed_message = unittest_pb2.OneString()
message.any_value.Unpack(packed_message) message.any_value.Unpack(packed_message)
self.assertEqual('string', packed_message.data) self.assertEqual('string', packed_message.data)
@ -1137,7 +1124,7 @@ class Proto3Tests(unittest.TestCase):
' data: "string1"\n' ' data: "string1"\n'
' }\n' ' }\n'
'}\n') '}\n')
text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default()) text_format.Merge(text, message)
packed_message = unittest_pb2.OneString() packed_message = unittest_pb2.OneString()
message.repeated_any_value[0].Unpack(packed_message) message.repeated_any_value[0].Unpack(packed_message)
self.assertEqual('string0', packed_message.data) self.assertEqual('string0', packed_message.data)
@ -1151,22 +1138,22 @@ class Proto3Tests(unittest.TestCase):
' data: "string"\n' ' data: "string"\n'
' >\n' ' >\n'
'}\n') '}\n')
text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default()) text_format.Merge(text, message)
packed_message = unittest_pb2.OneString() packed_message = unittest_pb2.OneString()
message.any_value.Unpack(packed_message) message.any_value.Unpack(packed_message)
self.assertEqual('string', packed_message.data) self.assertEqual('string', packed_message.data)
def testMergeExpandedAnyNoDescriptorPool(self): def testMergeAlternativeUrl(self):
message = any_test_pb2.TestAny() message = any_test_pb2.TestAny()
text = ('any_value {\n' text = ('any_value {\n'
' [type.googleapis.com/protobuf_unittest.OneString] {\n' ' [type.otherapi.com/protobuf_unittest.OneString] {\n'
' data: "string"\n' ' data: "string"\n'
' }\n' ' }\n'
'}\n') '}\n')
with self.assertRaises(text_format.ParseError) as e: text_format.Merge(text, message)
text_format.Merge(text, message, descriptor_pool=None) packed_message = unittest_pb2.OneString()
self.assertEqual(str(e.exception), self.assertEqual('type.otherapi.com/protobuf_unittest.OneString',
'Descriptor pool required to parse expanded Any field') message.any_value.type_url)
def testMergeExpandedAnyDescriptorPoolMissingType(self): def testMergeExpandedAnyDescriptorPoolMissingType(self):
message = any_test_pb2.TestAny() message = any_test_pb2.TestAny()
@ -1425,5 +1412,101 @@ class TokenizerTest(unittest.TestCase):
tokenizer.ConsumeCommentOrTrailingComment()) tokenizer.ConsumeCommentOrTrailingComment())
self.assertTrue(tokenizer.AtEnd()) self.assertTrue(tokenizer.AtEnd())
# Tests for pretty printer functionality.
@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2))
class PrettyPrinterTest(TextFormatBase):
def testPrettyPrintNoMatch(self, message_module):
def printer(message, indent, as_one_line):
del message, indent, as_one_line
return None
message = message_module.TestAllTypes()
msg = message.repeated_nested_message.add()
msg.bb = 42
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=True, message_formatter=printer),
'repeated_nested_message { bb: 42 }')
def testPrettyPrintOneLine(self, message_module):
def printer(m, indent, as_one_line):
del indent, as_one_line
if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR:
return 'My lucky number is %s' % m.bb
message = message_module.TestAllTypes()
msg = message.repeated_nested_message.add()
msg.bb = 42
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=True, message_formatter=printer),
'repeated_nested_message { My lucky number is 42 }')
def testPrettyPrintMultiLine(self, message_module):
def printer(m, indent, as_one_line):
if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR:
line_deliminator = (' ' if as_one_line else '\n') + ' ' * indent
return 'My lucky number is:%s%s' % (line_deliminator, m.bb)
return None
message = message_module.TestAllTypes()
msg = message.repeated_nested_message.add()
msg.bb = 42
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=True, message_formatter=printer),
'repeated_nested_message { My lucky number is: 42 }')
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=False, message_formatter=printer),
'repeated_nested_message {\n My lucky number is:\n 42\n}\n')
def testPrettyPrintEntireMessage(self, message_module):
def printer(m, indent, as_one_line):
del indent, as_one_line
if m.DESCRIPTOR == message_module.TestAllTypes.DESCRIPTOR:
return 'The is the message!'
return None
message = message_module.TestAllTypes()
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=False, message_formatter=printer),
'The is the message!\n')
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=True, message_formatter=printer),
'The is the message!')
def testPrettyPrintMultipleParts(self, message_module):
def printer(m, indent, as_one_line):
del indent, as_one_line
if m.DESCRIPTOR == message_module.TestAllTypes.NestedMessage.DESCRIPTOR:
return 'My lucky number is %s' % m.bb
return None
message = message_module.TestAllTypes()
message.optional_int32 = 61
msg = message.repeated_nested_message.add()
msg.bb = 42
msg = message.repeated_nested_message.add()
msg.bb = 99
msg = message.optional_nested_message
msg.bb = 1
self.CompareToGoldenText(
text_format.MessageToString(
message, as_one_line=True, message_formatter=printer),
('optional_int32: 61 '
'optional_nested_message { My lucky number is 1 } '
'repeated_nested_message { My lucky number is 42 } '
'repeated_nested_message { My lucky number is 99 }'))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

@ -350,12 +350,12 @@ class Duration(object):
self.nanos, _NANOS_PER_MICROSECOND)) self.nanos, _NANOS_PER_MICROSECOND))
def FromTimedelta(self, td): def FromTimedelta(self, td):
"""Convertd timedelta to Duration.""" """Converts timedelta to Duration."""
self._NormalizeDuration(td.seconds + td.days * _SECONDS_PER_DAY, self._NormalizeDuration(td.seconds + td.days * _SECONDS_PER_DAY,
td.microseconds * _NANOS_PER_MICROSECOND) td.microseconds * _NANOS_PER_MICROSECOND)
def _NormalizeDuration(self, seconds, nanos): def _NormalizeDuration(self, seconds, nanos):
"""Set Duration by seconds and nonas.""" """Set Duration by seconds and nanos."""
# Force nanos to be negative if the duration is negative. # Force nanos to be negative if the duration is negative.
if seconds < 0 and nanos > 0: if seconds < 0 and nanos > 0:
seconds += 1 seconds += 1

@ -284,7 +284,7 @@ class TimeUtilTest(TimeUtilTestBase):
'1972-01-01T01:00:00.01+08',) '1972-01-01T01:00:00.01+08',)
self.assertRaisesRegexp( self.assertRaisesRegexp(
ValueError, ValueError,
'year is out of range', 'year (0 )?is out of range',
message.FromJsonString, message.FromJsonString,
'0000-01-01T00:00:00Z') '0000-01-01T00:00:00Z')
message.seconds = 253402300800 message.seconds = 253402300800

@ -74,6 +74,9 @@ _UNPAIRED_SURROGATE_PATTERN = re.compile(six.u(
r'[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]' r'[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]'
)) ))
_VALID_EXTENSION_NAME = re.compile(r'\[[a-zA-Z0-9\._]*\]$')
class Error(Exception): class Error(Exception):
"""Top-level module error for json_format.""" """Top-level module error for json_format."""
@ -88,7 +91,9 @@ class ParseError(Error):
def MessageToJson(message, def MessageToJson(message,
including_default_value_fields=False, including_default_value_fields=False,
preserving_proto_field_name=False): preserving_proto_field_name=False,
indent=2,
sort_keys=False):
"""Converts protobuf message to JSON format. """Converts protobuf message to JSON format.
Args: Args:
@ -100,19 +105,24 @@ def MessageToJson(message,
preserving_proto_field_name: If True, use the original proto field preserving_proto_field_name: If True, use the original proto field
names as defined in the .proto file. If False, convert the field names as defined in the .proto file. If False, convert the field
names to lowerCamelCase. names to lowerCamelCase.
indent: The JSON object will be pretty-printed with this indent level.
An indent level of 0 or negative will only insert newlines.
sort_keys: If True, then the output will be sorted by field names.
Returns: Returns:
A string containing the JSON formatted protocol buffer message. A string containing the JSON formatted protocol buffer message.
""" """
printer = _Printer(including_default_value_fields, printer = _Printer(including_default_value_fields,
preserving_proto_field_name) preserving_proto_field_name)
return printer.ToJsonString(message) return printer.ToJsonString(message, indent, sort_keys)
def MessageToDict(message, def MessageToDict(message,
including_default_value_fields=False, including_default_value_fields=False,
preserving_proto_field_name=False): preserving_proto_field_name=False):
"""Converts protobuf message to a JSON dictionary. """Converts protobuf message to a dictionary.
When the dictionary is encoded to JSON, it conforms to proto3 JSON spec.
Args: Args:
message: The protocol buffers message instance to serialize. message: The protocol buffers message instance to serialize.
@ -125,7 +135,7 @@ def MessageToDict(message,
names to lowerCamelCase. names to lowerCamelCase.
Returns: Returns:
A dict representation of the JSON formatted protocol buffer message. A dict representation of the protocol buffer message.
""" """
printer = _Printer(including_default_value_fields, printer = _Printer(including_default_value_fields,
preserving_proto_field_name) preserving_proto_field_name)
@ -148,9 +158,9 @@ class _Printer(object):
self.including_default_value_fields = including_default_value_fields self.including_default_value_fields = including_default_value_fields
self.preserving_proto_field_name = preserving_proto_field_name self.preserving_proto_field_name = preserving_proto_field_name
def ToJsonString(self, message): def ToJsonString(self, message, indent, sort_keys):
js = self._MessageToJsonObject(message) js = self._MessageToJsonObject(message)
return json.dumps(js, indent=2) return json.dumps(js, indent=indent, sort_keys=sort_keys)
def _MessageToJsonObject(self, message): def _MessageToJsonObject(self, message):
"""Converts message to an object according to Proto3 JSON Specification.""" """Converts message to an object according to Proto3 JSON Specification."""
@ -192,6 +202,14 @@ class _Printer(object):
# Convert a repeated field. # Convert a repeated field.
js[name] = [self._FieldToJsonObject(field, k) js[name] = [self._FieldToJsonObject(field, k)
for k in value] for k in value]
elif field.is_extension:
f = field
if (f.containing_type.GetOptions().message_set_wire_format and
f.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
f.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
f = f.message_type
name = '[%s.%s]' % (f.full_name, name)
js[name] = self._FieldToJsonObject(field, value)
else: else:
js[name] = self._FieldToJsonObject(field, value) js[name] = self._FieldToJsonObject(field, value)
@ -433,12 +451,23 @@ class _Parser(object):
field = fields_by_json_name.get(name, None) field = fields_by_json_name.get(name, None)
if not field: if not field:
field = message_descriptor.fields_by_name.get(name, None) field = message_descriptor.fields_by_name.get(name, None)
if not field and _VALID_EXTENSION_NAME.match(name):
if not message_descriptor.is_extendable:
raise ParseError('Message type {0} does not have extensions'.format(
message_descriptor.full_name))
identifier = name[1:-1] # strip [] brackets
identifier = '.'.join(identifier.split('.')[:-1])
# pylint: disable=protected-access
field = message.Extensions._FindExtensionByName(identifier)
# pylint: enable=protected-access
if not field: if not field:
if self.ignore_unknown_fields: if self.ignore_unknown_fields:
continue continue
raise ParseError( raise ParseError(
'Message type "{0}" has no field named "{1}".'.format( ('Message type "{0}" has no field named "{1}".\n'
message_descriptor.full_name, name)) ' Available Fields(except extensions): {2}').format(
message_descriptor.full_name, name,
message_descriptor.fields))
if name in names: if name in names:
raise ParseError('Message type "{0}" should not have multiple ' raise ParseError('Message type "{0}" should not have multiple '
'"{1}" fields.'.format( '"{1}" fields.'.format(
@ -491,7 +520,10 @@ class _Parser(object):
getattr(message, field.name).append( getattr(message, field.name).append(
_ConvertScalarFieldValue(item, field)) _ConvertScalarFieldValue(item, field))
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
sub_message = getattr(message, field.name) if field.is_extension:
sub_message = message.Extensions[field]
else:
sub_message = getattr(message, field.name)
sub_message.SetInParent() sub_message.SetInParent()
self.ConvertMessage(value, sub_message) self.ConvertMessage(value, sub_message)
else: else:
@ -532,8 +564,8 @@ class _Parser(object):
def _ConvertGenericMessage(self, value, message): def _ConvertGenericMessage(self, value, message):
"""Convert a JSON representation into message with FromJsonString.""" """Convert a JSON representation into message with FromJsonString."""
# Durantion, Timestamp, FieldMask have FromJsonString method to do the # Duration, Timestamp, FieldMask have a FromJsonString method to do the
# convert. Users can also call the method directly. # conversion. Users can also call the method directly.
message.FromJsonString(value) message.FromJsonString(value)
def _ConvertValueMessage(self, value, message): def _ConvertValueMessage(self, value, message):

@ -184,9 +184,15 @@ class Message(object):
self.Clear() self.Clear()
self.MergeFromString(serialized) self.MergeFromString(serialized)
def SerializeToString(self): def SerializeToString(self, **kwargs):
"""Serializes the protocol message to a binary string. """Serializes the protocol message to a binary string.
Arguments:
**kwargs: Keyword arguments to the serialize method, accepts
the following keyword args:
deterministic: If true, requests deterministic serialization of the
protobuf, with predictable ordering of map keys.
Returns: Returns:
A binary string representation of the message if all of the required A binary string representation of the message if all of the required
fields in the message are set (i.e. the message is initialized). fields in the message are set (i.e. the message is initialized).
@ -196,12 +202,18 @@ class Message(object):
""" """
raise NotImplementedError raise NotImplementedError
def SerializePartialToString(self): def SerializePartialToString(self, **kwargs):
"""Serializes the protocol message to a binary string. """Serializes the protocol message to a binary string.
This method is similar to SerializeToString but doesn't check if the This method is similar to SerializeToString but doesn't check if the
message is initialized. message is initialized.
Arguments:
**kwargs: Keyword arguments to the serialize method, accepts
the following keyword args:
deterministic: If true, requests deterministic serialization of the
protobuf, with predictable ordering of map keys.
Returns: Returns:
A string representation of the partial message. A string representation of the partial message.
""" """

@ -66,7 +66,7 @@ class MessageFactory(object):
Returns: Returns:
A class describing the passed in descriptor. A class describing the passed in descriptor.
""" """
if descriptor.full_name not in self._classes: if descriptor not in self._classes:
descriptor_name = descriptor.name descriptor_name = descriptor.name
if str is bytes: # PY2 if str is bytes: # PY2
descriptor_name = descriptor.name.encode('ascii', 'ignore') descriptor_name = descriptor.name.encode('ascii', 'ignore')
@ -75,16 +75,16 @@ class MessageFactory(object):
(message.Message,), (message.Message,),
{'DESCRIPTOR': descriptor, '__module__': None}) {'DESCRIPTOR': descriptor, '__module__': None})
# If module not set, it wrongly points to the reflection.py module. # If module not set, it wrongly points to the reflection.py module.
self._classes[descriptor.full_name] = result_class self._classes[descriptor] = result_class
for field in descriptor.fields: for field in descriptor.fields:
if field.message_type: if field.message_type:
self.GetPrototype(field.message_type) self.GetPrototype(field.message_type)
for extension in result_class.DESCRIPTOR.extensions: for extension in result_class.DESCRIPTOR.extensions:
if extension.containing_type.full_name not in self._classes: if extension.containing_type not in self._classes:
self.GetPrototype(extension.containing_type) self.GetPrototype(extension.containing_type)
extended_class = self._classes[extension.containing_type.full_name] extended_class = self._classes[extension.containing_type]
extended_class.RegisterExtension(extension) extended_class.RegisterExtension(extension)
return self._classes[descriptor.full_name] return self._classes[descriptor]
def GetMessages(self, files): def GetMessages(self, files):
"""Gets all the messages from a specified file. """Gets all the messages from a specified file.
@ -116,9 +116,9 @@ class MessageFactory(object):
# an error if they were different. # an error if they were different.
for extension in file_desc.extensions_by_name.values(): for extension in file_desc.extensions_by_name.values():
if extension.containing_type.full_name not in self._classes: if extension.containing_type not in self._classes:
self.GetPrototype(extension.containing_type) self.GetPrototype(extension.containing_type)
extended_class = self._classes[extension.containing_type.full_name] extended_class = self._classes[extension.containing_type]
extended_class.RegisterExtension(extension) extended_class.RegisterExtension(extension)
return result return result

@ -709,6 +709,10 @@ static PyObject* GetJsonName(PyBaseDescriptor* self, void *closure) {
return PyString_FromCppString(_GetDescriptor(self)->json_name()); return PyString_FromCppString(_GetDescriptor(self)->json_name());
} }
static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
}
static PyObject* GetType(PyBaseDescriptor *self, void *closure) { static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
return PyInt_FromLong(_GetDescriptor(self)->type()); return PyInt_FromLong(_GetDescriptor(self)->type());
} }
@ -899,6 +903,7 @@ static PyGetSetDef Getters[] = {
{ "name", (getter)GetName, NULL, "Unqualified name"}, { "name", (getter)GetName, NULL, "Unqualified name"},
{ "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"}, { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"},
{ "json_name", (getter)GetJsonName, NULL, "Json name"}, { "json_name", (getter)GetJsonName, NULL, "Json name"},
{ "file", (getter)GetFile, NULL, "File Descriptor"},
{ "type", (getter)GetType, NULL, "C++ Type"}, { "type", (getter)GetType, NULL, "C++ Type"},
{ "cpp_type", (getter)GetCppType, NULL, "C++ Type"}, { "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
{ "label", (getter)GetLabel, NULL, "Label"}, { "label", (getter)GetLabel, NULL, "Label"},
@ -1570,6 +1575,10 @@ static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
return PyString_FromCppString(_GetDescriptor(self)->full_name()); return PyString_FromCppString(_GetDescriptor(self)->full_name());
} }
static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
}
static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
return PyInt_FromLong(_GetDescriptor(self)->index()); return PyInt_FromLong(_GetDescriptor(self)->index());
} }
@ -1611,6 +1620,7 @@ static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
static PyGetSetDef Getters[] = { static PyGetSetDef Getters[] = {
{ "name", (getter)GetName, NULL, "Name", NULL}, { "name", (getter)GetName, NULL, "Name", NULL},
{ "full_name", (getter)GetFullName, NULL, "Full name", NULL}, { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
{ "file", (getter)GetFile, NULL, "File descriptor"},
{ "index", (getter)GetIndex, NULL, "Index", NULL}, { "index", (getter)GetIndex, NULL, "Index", NULL},
{ "methods", (getter)GetMethods, NULL, "Methods", NULL}, { "methods", (getter)GetMethods, NULL, "Methods", NULL},

@ -712,8 +712,30 @@ int MapReflectionFriend::MessageMapSetItem(PyObject* _self, PyObject* key,
} }
// Delete key from map. // Delete key from map.
if (reflection->DeleteMapValue(message, self->parent_field_descriptor, if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
map_key)) { map_key)) {
// Delete key from CMessage dict.
MapValueRef value;
reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
map_key, &value);
ScopedPyObjectPtr key(PyLong_FromVoidPtr(value.MutableMessageValue()));
// PyDict_DelItem will have key error if the key is not in the map. We do
// not want to call PyErr_Clear() which may clear other errors. Thus
// PyDict_Contains() check is called before delete.
int contains = PyDict_Contains(self->message_dict, key.get());
if (contains < 0) {
return -1;
}
if (contains) {
if (PyDict_DelItem(self->message_dict, key.get()) < 0) {
return -1;
}
}
// Delete key from map.
reflection->DeleteMapValue(message, self->parent_field_descriptor,
map_key);
return 0; return 0;
} else { } else {
PyErr_Format(PyExc_KeyError, "Key not present in map"); PyErr_Format(PyExc_KeyError, "Key not present in map");

@ -52,6 +52,7 @@
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/logging.h>
#include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/util/message_differencer.h> #include <google/protobuf/util/message_differencer.h>
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h> #include <google/protobuf/message.h>
@ -1808,8 +1809,25 @@ static string GetMessageName(CMessage* self) {
} }
} }
static PyObject* SerializeToString(CMessage* self, PyObject* args) { static PyObject* InternalSerializeToString(
if (!self->message->IsInitialized()) { CMessage* self, PyObject* args, PyObject* kwargs,
bool require_initialized) {
// Parse the "deterministic" kwarg; defaults to False.
static char* kwlist[] = { "deterministic", 0 };
PyObject* deterministic_obj = Py_None;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist,
&deterministic_obj)) {
return NULL;
}
// Preemptively convert to a bool first, so we don't need to back out of
// allocating memory if this raises an exception.
// NOTE: This is unused later if deterministic == Py_None, but that's fine.
int deterministic = PyObject_IsTrue(deterministic_obj);
if (deterministic < 0) {
return NULL;
}
if (require_initialized && !self->message->IsInitialized()) {
ScopedPyObjectPtr errors(FindInitializationErrors(self)); ScopedPyObjectPtr errors(FindInitializationErrors(self));
if (errors == NULL) { if (errors == NULL) {
return NULL; return NULL;
@ -1847,24 +1865,36 @@ static PyObject* SerializeToString(CMessage* self, PyObject* args) {
GetMessageName(self).c_str(), PyString_AsString(joined.get())); GetMessageName(self).c_str(), PyString_AsString(joined.get()));
return NULL; return NULL;
} }
int size = self->message->ByteSize();
if (size <= 0) { // Ok, arguments parsed and errors checked, now encode to a string
const size_t size = self->message->ByteSizeLong();
if (size == 0) {
return PyBytes_FromString(""); return PyBytes_FromString("");
} }
PyObject* result = PyBytes_FromStringAndSize(NULL, size); PyObject* result = PyBytes_FromStringAndSize(NULL, size);
if (result == NULL) { if (result == NULL) {
return NULL; return NULL;
} }
char* buffer = PyBytes_AS_STRING(result); io::ArrayOutputStream out(PyBytes_AS_STRING(result), size);
self->message->SerializeWithCachedSizesToArray( io::CodedOutputStream coded_out(&out);
reinterpret_cast<uint8*>(buffer)); if (deterministic_obj != Py_None) {
coded_out.SetSerializationDeterministic(deterministic);
}
self->message->SerializeWithCachedSizes(&coded_out);
GOOGLE_CHECK(!coded_out.HadError());
return result; return result;
} }
static PyObject* SerializePartialToString(CMessage* self) { static PyObject* SerializeToString(
string contents; CMessage* self, PyObject* args, PyObject* kwargs) {
self->message->SerializePartialToString(&contents); return InternalSerializeToString(self, args, kwargs,
return PyBytes_FromStringAndSize(contents.c_str(), contents.size()); /*require_initialized=*/true);
}
static PyObject* SerializePartialToString(
CMessage* self, PyObject* args, PyObject* kwargs) {
return InternalSerializeToString(self, args, kwargs,
/*require_initialized=*/false);
} }
// Formats proto fields for ascii dumps using python formatting functions where // Formats proto fields for ascii dumps using python formatting functions where
@ -2535,7 +2565,10 @@ PyObject* Reduce(CMessage* self) {
if (state == NULL) { if (state == NULL) {
return NULL; return NULL;
} }
ScopedPyObjectPtr serialized(SerializePartialToString(self)); string contents;
self->message->SerializePartialToString(&contents);
ScopedPyObjectPtr serialized(
PyBytes_FromStringAndSize(contents.c_str(), contents.size()));
if (serialized == NULL) { if (serialized == NULL) {
return NULL; return NULL;
} }
@ -2656,9 +2689,10 @@ static PyMethodDef Methods[] = {
{ "RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS, { "RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS,
"Registers an extension with the current message." }, "Registers an extension with the current message." },
{ "SerializePartialToString", (PyCFunction)SerializePartialToString, { "SerializePartialToString", (PyCFunction)SerializePartialToString,
METH_NOARGS, METH_VARARGS | METH_KEYWORDS,
"Serializes the message to a string, even if it isn't initialized." }, "Serializes the message to a string, even if it isn't initialized." },
{ "SerializeToString", (PyCFunction)SerializeToString, METH_NOARGS, { "SerializeToString", (PyCFunction)SerializeToString,
METH_VARARGS | METH_KEYWORDS,
"Serializes the message to a string, only for initialized messages." }, "Serializes the message to a string, only for initialized messages." },
{ "SetInParent", (PyCFunction)SetInParent, METH_NOARGS, { "SetInParent", (PyCFunction)SetInParent, METH_NOARGS,
"Sets the has bit of the given field in its parent message." }, "Sets the has bit of the given field in its parent message." },

@ -133,11 +133,7 @@ int RegisterMessageClass(PyMessageFactory* self,
CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self, CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self,
const Descriptor* descriptor) { const Descriptor* descriptor) {
// This is the same implementation as MessageFactory.GetPrototype(). // This is the same implementation as MessageFactory.GetPrototype().
ScopedPyObjectPtr py_descriptor(
PyMessageDescriptor_FromDescriptor(descriptor));
if (py_descriptor == NULL) {
return NULL;
}
// Do not create a MessageClass that already exists. // Do not create a MessageClass that already exists.
hash_map<const Descriptor*, CMessageClass*>::iterator it = hash_map<const Descriptor*, CMessageClass*>::iterator it =
self->classes_by_descriptor->find(descriptor); self->classes_by_descriptor->find(descriptor);
@ -145,6 +141,11 @@ CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self,
Py_INCREF(it->second); Py_INCREF(it->second);
return it->second; return it->second;
} }
ScopedPyObjectPtr py_descriptor(
PyMessageDescriptor_FromDescriptor(descriptor));
if (py_descriptor == NULL) {
return NULL;
}
// Create a new message class. // Create a new message class.
ScopedPyObjectPtr args(Py_BuildValue( ScopedPyObjectPtr args(Py_BuildValue(
"s(){sOsOsO}", descriptor->name().c_str(), "s(){sOsOsO}", descriptor->name().c_str(),

@ -46,6 +46,7 @@
#include <google/protobuf/pyext/descriptor.h> #include <google/protobuf/pyext/descriptor.h>
#include <google/protobuf/pyext/descriptor_pool.h> #include <google/protobuf/pyext/descriptor_pool.h>
#include <google/protobuf/pyext/message.h> #include <google/protobuf/pyext/message.h>
#include <google/protobuf/pyext/message_factory.h>
#include <google/protobuf/pyext/scoped_pyobject_ptr.h> #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
#include <google/protobuf/reflection.h> #include <google/protobuf/reflection.h>
@ -137,9 +138,12 @@ static PyObject* AddToAttached(RepeatedCompositeContainer* self,
if (cmessage::AssureWritable(self->parent) == -1) if (cmessage::AssureWritable(self->parent) == -1)
return NULL; return NULL;
Message* message = self->message; Message* message = self->message;
Message* sub_message = Message* sub_message =
message->GetReflection()->AddMessage(message, message->GetReflection()->AddMessage(
self->parent_field_descriptor); message,
self->parent_field_descriptor,
self->child_message_class->py_message_factory->message_factory);
CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class); CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class);
if (cmsg == NULL) if (cmsg == NULL)
return NULL; return NULL;
@ -335,6 +339,18 @@ static PyObject* RichCompare(RepeatedCompositeContainer* self,
} }
} }
static PyObject* ToStr(RepeatedCompositeContainer* self) {
ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
if (full_slice == NULL) {
return NULL;
}
ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
if (list == NULL) {
return NULL;
}
return PyObject_Repr(list.get());
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// sort() // sort()
@ -607,7 +623,7 @@ PyTypeObject RepeatedCompositeContainer_Type = {
0, // tp_getattr 0, // tp_getattr
0, // tp_setattr 0, // tp_setattr
0, // tp_compare 0, // tp_compare
0, // tp_repr (reprfunc)repeated_composite_container::ToStr, // tp_repr
0, // tp_as_number 0, // tp_as_number
&repeated_composite_container::SqMethods, // tp_as_sequence &repeated_composite_container::SqMethods, // tp_as_sequence
&repeated_composite_container::MpMethods, // tp_as_mapping &repeated_composite_container::MpMethods, // tp_as_mapping

@ -656,6 +656,18 @@ static PyObject* Pop(RepeatedScalarContainer* self,
return item; return item;
} }
static PyObject* ToStr(RepeatedScalarContainer* self) {
ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
if (full_slice == NULL) {
return NULL;
}
ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
if (list == NULL) {
return NULL;
}
return PyObject_Repr(list.get());
}
// The private constructor of RepeatedScalarContainer objects. // The private constructor of RepeatedScalarContainer objects.
PyObject *NewContainer( PyObject *NewContainer(
CMessage* parent, const FieldDescriptor* parent_field_descriptor) { CMessage* parent, const FieldDescriptor* parent_field_descriptor) {
@ -778,7 +790,7 @@ PyTypeObject RepeatedScalarContainer_Type = {
0, // tp_getattr 0, // tp_getattr
0, // tp_setattr 0, // tp_setattr
0, // tp_compare 0, // tp_compare
0, // tp_repr (reprfunc)repeated_scalar_container::ToStr, // tp_repr
0, // tp_as_number 0, // tp_as_number
&repeated_scalar_container::SqMethods, // tp_as_sequence &repeated_scalar_container::SqMethods, // tp_as_sequence
&repeated_scalar_container::MpMethods, // tp_as_mapping &repeated_scalar_container::MpMethods, // tp_as_mapping

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

Loading…
Cancel
Save