Browse Source

Down-integrate from google3.

Feng Xiao 7 years ago
parent
commit
6bbe197e9c
100 changed files with 4985 additions and 3167 deletions
  1. 1 0
      Makefile.am
  2. 1 1
      benchmarks/cpp/cpp_benchmark.cc
  3. 3 0
      cmake/libprotoc.cmake
  4. 2 0
      cmake/tests.cmake
  5. 7 3
      conformance/ConformanceJava.java
  6. 2 0
      conformance/Makefile.am
  7. 16 1
      conformance/conformance.proto
  8. 7 1
      conformance/conformance_cpp.cc
  9. 5 1
      conformance/conformance_php.php
  10. 5 1
      conformance/conformance_python.py
  11. 116 2308
      conformance/conformance_test.cc
  12. 64 91
      conformance/conformance_test.h
  13. 2368 0
      conformance/conformance_test_impl.cc
  14. 16 6
      conformance/conformance_test_runner.cc
  15. 0 6
      conformance/failure_list_cpp.txt
  16. 0 6
      conformance/failure_list_csharp.txt
  17. 0 6
      conformance/failure_list_java.txt
  18. 20 0
      conformance/failure_list_php_c.txt
  19. 0 6
      conformance/failure_list_python-post26.txt
  20. 0 6
      conformance/failure_list_python.txt
  21. 0 6
      conformance/failure_list_python_cpp.txt
  22. 0 8
      conformance/failure_list_ruby.txt
  23. 1 5
      java/core/src/main/java/com/google/protobuf/AbstractMessage.java
  24. 2 1
      java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
  25. 83 7
      java/core/src/main/java/com/google/protobuf/ByteString.java
  26. 17 101
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  27. 2 1
      java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
  28. 0 8
      java/core/src/main/java/com/google/protobuf/DynamicMessage.java
  29. 2 1
      java/core/src/main/java/com/google/protobuf/FloatArrayList.java
  30. 1 2
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  31. 90 17
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  32. 2 1
      java/core/src/main/java/com/google/protobuf/IntArrayList.java
  33. 5 0
      java/core/src/main/java/com/google/protobuf/Internal.java
  34. 16 16
      java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
  35. 2 1
      java/core/src/main/java/com/google/protobuf/LongArrayList.java
  36. 6 12
      java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
  37. 4 8
      java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
  38. 2 2
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  39. 17 0
      java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
  40. 5 6
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  41. 3 2
      java/core/src/main/java/com/google/protobuf/Utf8.java
  42. 2 2
      java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
  43. 5 3
      java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
  44. 66 0
      java/core/src/test/java/com/google/protobuf/ByteStringTest.java
  45. 3 20
      java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java
  46. 26 24
      java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
  47. 5 5
      java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
  48. 26 24
      java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
  49. 2 2
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  50. 5 3
      java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
  51. 61 0
      java/core/src/test/java/com/google/protobuf/LiteTest.java
  52. 5 3
      java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
  53. 155 49
      java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
  54. 31 6
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  55. 9 16
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  56. 2 2
      java/core/src/test/java/com/google/protobuf/WireFormatTest.java
  57. 0 2
      java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
  58. 0 1
      java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
  59. 2 3
      java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
  60. 0 1
      java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
  61. 0 1
      java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
  62. 3 0
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  63. 9 7
      java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
  64. 1 1
      java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
  65. 1 1
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  66. 110 40
      java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
  67. 8 5
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  68. 1 1
      js/binary/constants.js
  69. 8 9
      js/binary/reader.js
  70. 15 0
      js/binary/reader_test.js
  71. 3 2
      js/binary/utils.js
  72. 7 7
      js/map.js
  73. 31 19
      js/message.js
  74. 1 0
      js/message_test.js
  75. 7 0
      js/test.proto
  76. 6 3
      python/compatibility_tests/v2.5.0/tests/google/protobuf/internal/text_format_test.py
  77. 11 0
      python/google/protobuf/descriptor_database.py
  78. 170 26
      python/google/protobuf/descriptor_pool.py
  79. 30 0
      python/google/protobuf/internal/__init__.py
  80. 0 26
      python/google/protobuf/internal/api_implementation.py
  81. 127 0
      python/google/protobuf/internal/containers.py
  82. 176 16
      python/google/protobuf/internal/decoder.py
  83. 8 0
      python/google/protobuf/internal/descriptor_database_test.py
  84. 39 24
      python/google/protobuf/internal/descriptor_pool_test.py
  85. 11 0
      python/google/protobuf/internal/descriptor_test.py
  86. 14 0
      python/google/protobuf/internal/factory_test1.proto
  87. 1 3
      python/google/protobuf/internal/message_factory_test.py
  88. 244 18
      python/google/protobuf/internal/message_test.py
  89. 30 0
      python/google/protobuf/internal/no_package.proto
  90. 128 22
      python/google/protobuf/internal/python_message.py
  91. 43 10
      python/google/protobuf/internal/reflection_test.py
  92. 256 42
      python/google/protobuf/internal/text_format_test.py
  93. 8 0
      python/google/protobuf/internal/type_checkers.py
  94. 123 42
      python/google/protobuf/internal/unknown_fields_test.py
  95. 1 1
      python/google/protobuf/json_format.py
  96. 4 0
      python/google/protobuf/message.py
  97. 12 3
      python/google/protobuf/message_factory.py
  98. 5 6
      python/google/protobuf/proto_api.h
  99. 34 17
      python/google/protobuf/pyext/descriptor.cc
  100. 1 1
      python/google/protobuf/pyext/descriptor.h

+ 1 - 0
Makefile.am

@@ -804,6 +804,7 @@ python_EXTRA_DIST=                                                           \
   python/google/protobuf/json_format.py                                      \
   python/google/protobuf/json_format.py                                      \
   python/google/protobuf/message.py                                          \
   python/google/protobuf/message.py                                          \
   python/google/protobuf/message_factory.py                                  \
   python/google/protobuf/message_factory.py                                  \
+  python/google/protobuf/python_api.h                                        \
   python/google/protobuf/python_protobuf.h                                   \
   python/google/protobuf/python_protobuf.h                                   \
   python/google/protobuf/proto_api.h                                         \
   python/google/protobuf/proto_api.h                                         \
   python/google/protobuf/proto_builder.py                                    \
   python/google/protobuf/proto_builder.py                                    \

+ 1 - 1
benchmarks/cpp/cpp_benchmark.cc

@@ -30,7 +30,7 @@
 
 
 #include <fstream>
 #include <fstream>
 #include <iostream>
 #include <iostream>
-#include "benchmark/benchmark_api.h"
+#include "benchmark/benchmark.h"
 #include "benchmarks.pb.h"
 #include "benchmarks.pb.h"
 #include "datasets/google_message1/proto2/benchmark_message1_proto2.pb.h"
 #include "datasets/google_message1/proto2/benchmark_message1_proto2.pb.h"
 #include "datasets/google_message1/proto3/benchmark_message1_proto3.pb.h"
 #include "datasets/google_message1/proto3/benchmark_message1_proto3.pb.h"

+ 3 - 0
cmake/libprotoc.cmake

@@ -78,6 +78,7 @@ set(libprotoc_files
   ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/scc.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
 )
 )
@@ -153,6 +154,7 @@ set(libprotoc_headers
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
+  ${protobuf_source_dir}/src/google/protobuf/compiler/scc.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.h
 )
 )
@@ -177,3 +179,4 @@ set_target_properties(libprotoc PROPERTIES
     OUTPUT_NAME ${LIB_PREFIX}protoc
     OUTPUT_NAME ${LIB_PREFIX}protoc
     DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
     DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
 add_library(protobuf::libprotoc ALIAS libprotoc)
 add_library(protobuf::libprotoc ALIAS libprotoc)
+

+ 2 - 0
cmake/tests.cmake

@@ -63,6 +63,7 @@ set(tests_protos
   google/protobuf/unittest_optimize_for.proto
   google/protobuf/unittest_optimize_for.proto
   google/protobuf/unittest_preserve_unknown_enum.proto
   google/protobuf/unittest_preserve_unknown_enum.proto
   google/protobuf/unittest_preserve_unknown_enum2.proto
   google/protobuf/unittest_preserve_unknown_enum2.proto
+  google/protobuf/unittest_proto3.proto
   google/protobuf/unittest_proto3_arena.proto
   google/protobuf/unittest_proto3_arena.proto
   google/protobuf/unittest_proto3_arena_lite.proto
   google/protobuf/unittest_proto3_arena_lite.proto
   google/protobuf/unittest_proto3_lite.proto
   google/protobuf/unittest_proto3_lite.proto
@@ -78,6 +79,7 @@ set(tests_protos
   google/protobuf/util/internal/testdata/struct.proto
   google/protobuf/util/internal/testdata/struct.proto
   google/protobuf/util/internal/testdata/timestamp_duration.proto
   google/protobuf/util/internal/testdata/timestamp_duration.proto
   google/protobuf/util/internal/testdata/wrappers.proto
   google/protobuf/util/internal/testdata/wrappers.proto
+  google/protobuf/util/json_format.proto
   google/protobuf/util/json_format_proto3.proto
   google/protobuf/util/json_format_proto3.proto
   google/protobuf/util/message_differencer_unittest.proto
   google/protobuf/util/message_differencer_unittest.proto
 )
 )

+ 7 - 3
conformance/ConformanceJava.java

@@ -233,10 +233,14 @@ class ConformanceJava {
       }
       }
       case JSON_PAYLOAD: {
       case JSON_PAYLOAD: {
         try {
         try {
-          TestMessagesProto3.TestAllTypesProto3.Builder builder = 
+          TestMessagesProto3.TestAllTypesProto3.Builder builder =
               TestMessagesProto3.TestAllTypesProto3.newBuilder();
               TestMessagesProto3.TestAllTypesProto3.newBuilder();
-          JsonFormat.parser().usingTypeRegistry(typeRegistry)
-              .merge(request.getJsonPayload(), builder);
+          JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(typeRegistry);
+          if (request.getTestCategory()
+              == Conformance.TestCategory.JSON_IGNORE_UNKNOWN_PARSING_TEST) {
+            parser = parser.ignoringUnknownFields();
+          }
+          parser.merge(request.getJsonPayload(), builder);
           testMessage = builder.build();
           testMessage = builder.build();
         } catch (InvalidProtocolBufferException e) {
         } catch (InvalidProtocolBufferException e) {
           return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
           return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();

+ 2 - 0
conformance/Makefile.am

@@ -279,6 +279,8 @@ $(protoc_outputs): protoc_middleman
 
 
 $(other_language_protoc_outputs): protoc_middleman
 $(other_language_protoc_outputs): protoc_middleman
 
 
+BUILT_SOURCES = $(protoc_outputs) $(other_language_protoc_outputs)
+
 CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java javac_middleman_lite conformance-java-lite conformance-csharp conformance-php conformance-php-c $(other_language_protoc_outputs)
 CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java javac_middleman_lite conformance-java-lite conformance-csharp conformance-php conformance-php-c $(other_language_protoc_outputs)
 
 
 MAINTAINERCLEANFILES =   \
 MAINTAINERCLEANFILES =   \

+ 16 - 1
conformance/conformance.proto

@@ -57,6 +57,18 @@ enum WireFormat {
   JSON = 2;
   JSON = 2;
 }
 }
 
 
+enum TestCategory {
+  UNSPECIFIED_TEST = 0;
+  BINARY_TEST = 1;  // Test binary wire format.
+  JSON_TEST = 2;  // Test json wire format.
+  // Similar to JSON_TEST. However, during parsing json, testee should ignore
+  // unknown fields. This feature is optional. Each implementation can descide
+  // whether to support it.  See
+  // https://developers.google.com/protocol-buffers/docs/proto3#json_options
+  // for more detail.
+  JSON_IGNORE_UNKNOWN_PARSING_TEST = 3;
+}
+
 // Represents a single test case's input.  The testee should:
 // Represents a single test case's input.  The testee should:
 //
 //
 //   1. parse this proto (which should always succeed)
 //   1. parse this proto (which should always succeed)
@@ -83,7 +95,10 @@ message ConformanceRequest {
   // protobuf_test_messages.proto2.TestAllTypesProto2.
   // protobuf_test_messages.proto2.TestAllTypesProto2.
   string message_type = 4;
   string message_type = 4;
 
 
-  bool ignore_unknown_json = 5;
+  // Each test is given a specific test category. Some category may need
+  // spedific support in testee programs. Refer to the defintion of TestCategory
+  // for more information.
+  TestCategory test_category = 5;
 }
 }
 
 
 // Represents a single test case's output.
 // Represents a single test case's output.

+ 7 - 1
conformance/conformance_cpp.cc

@@ -46,6 +46,7 @@ using google::protobuf::DescriptorPool;
 using google::protobuf::Message;
 using google::protobuf::Message;
 using google::protobuf::MessageFactory;
 using google::protobuf::MessageFactory;
 using google::protobuf::util::BinaryToJsonString;
 using google::protobuf::util::BinaryToJsonString;
+using google::protobuf::util::JsonParseOptions;
 using google::protobuf::util::JsonToBinaryString;
 using google::protobuf::util::JsonToBinaryString;
 using google::protobuf::util::NewTypeResolverForDescriptorPool;
 using google::protobuf::util::NewTypeResolverForDescriptorPool;
 using google::protobuf::util::Status;
 using google::protobuf::util::Status;
@@ -112,8 +113,13 @@ void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
 
 
     case ConformanceRequest::kJsonPayload: {
     case ConformanceRequest::kJsonPayload: {
       string proto_binary;
       string proto_binary;
+      JsonParseOptions options;
+      options.ignore_unknown_fields =
+          (request.test_category() ==
+              conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
       Status status = JsonToBinaryString(type_resolver, *type_url,
       Status status = JsonToBinaryString(type_resolver, *type_url,
-                                         request.json_payload(), &proto_binary);
+                                         request.json_payload(), &proto_binary,
+                                         options);
       if (!status.ok()) {
       if (!status.ok()) {
         response->set_parse_error(string("Parse error: ") +
         response->set_parse_error(string("Parse error: ") +
                                   status.error_message().as_string());
                                   status.error_message().as_string());

+ 5 - 1
conformance/conformance_php.php

@@ -3,6 +3,7 @@
 require_once("Conformance/WireFormat.php");
 require_once("Conformance/WireFormat.php");
 require_once("Conformance/ConformanceResponse.php");
 require_once("Conformance/ConformanceResponse.php");
 require_once("Conformance/ConformanceRequest.php");
 require_once("Conformance/ConformanceRequest.php");
+require_once("Conformance/TestCategory.php");
 require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
 require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
 require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
 require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
@@ -12,6 +13,7 @@ require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php");
 require_once("GPBMetadata/Conformance.php");
 require_once("GPBMetadata/Conformance.php");
 require_once("GPBMetadata/Google/Protobuf/TestMessagesProto3.php");
 require_once("GPBMetadata/Google/Protobuf/TestMessagesProto3.php");
 
 
+use  \Conformance\TestCategory;
 use  \Conformance\WireFormat;
 use  \Conformance\WireFormat;
 
 
 if (!ini_get("date.timezone")) {
 if (!ini_get("date.timezone")) {
@@ -39,7 +41,9 @@ function doTest($request)
         trigger_error("Protobuf request doesn't have specific payload type", E_USER_ERROR);
         trigger_error("Protobuf request doesn't have specific payload type", E_USER_ERROR);
       }
       }
     } elseif ($request->getPayload() == "json_payload") {
     } elseif ($request->getPayload() == "json_payload") {
-      $ignore_json_unknown = $request->getIgnoreUnknownJson();
+      $ignore_json_unknown =
+          ($request->getTestCategory() ==
+              TestCategory::JSON_IGNORE_UNKNOWN_PARSING_TEST);
       try {
       try {
           $test_message->mergeFromJsonString($request->getJsonPayload(),
           $test_message->mergeFromJsonString($request->getJsonPayload(),
                                              $ignore_json_unknown);
                                              $ignore_json_unknown);

+ 5 - 1
conformance/conformance_python.py

@@ -78,7 +78,11 @@ def do_test(request):
       
       
     elif request.WhichOneof('payload') == 'json_payload':
     elif request.WhichOneof('payload') == 'json_payload':
       try:
       try:
-        json_format.Parse(request.json_payload, test_message)
+        ignore_unknown_fields = \
+            request.test_category == \
+                conformance_pb2.JSON_IGNORE_UNKNOWN_PARSING_TEST
+        json_format.Parse(request.json_payload, test_message,
+                          ignore_unknown_fields)
       except Exception as e:
       except Exception as e:
         response.parse_error = str(e)
         response.parse_error = str(e)
         return response
         return response

+ 116 - 2308
conformance/conformance_test.cc

@@ -28,199 +28,83 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+#include <set>
 #include <stdarg.h>
 #include <stdarg.h>
 #include <string>
 #include <string>
 #include <fstream>
 #include <fstream>
 
 
 #include "conformance.pb.h"
 #include "conformance.pb.h"
 #include "conformance_test.h"
 #include "conformance_test.h"
-#include <google/protobuf/test_messages_proto3.pb.h>
-#include <google/protobuf/test_messages_proto2.pb.h>
 
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/util/field_comparator.h>
 #include <google/protobuf/util/field_comparator.h>
 #include <google/protobuf/util/json_util.h>
 #include <google/protobuf/util/json_util.h>
 #include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/util/message_differencer.h>
-#include <google/protobuf/util/type_resolver_util.h>
-#include <google/protobuf/wire_format_lite.h>
-
-#include "third_party/jsoncpp/json.h"
 
 
 using conformance::ConformanceRequest;
 using conformance::ConformanceRequest;
 using conformance::ConformanceResponse;
 using conformance::ConformanceResponse;
 using conformance::WireFormat;
 using conformance::WireFormat;
-using google::protobuf::Descriptor;
-using google::protobuf::FieldDescriptor;
-using google::protobuf::internal::WireFormatLite;
 using google::protobuf::TextFormat;
 using google::protobuf::TextFormat;
 using google::protobuf::util::DefaultFieldComparator;
 using google::protobuf::util::DefaultFieldComparator;
 using google::protobuf::util::JsonToBinaryString;
 using google::protobuf::util::JsonToBinaryString;
 using google::protobuf::util::MessageDifferencer;
 using google::protobuf::util::MessageDifferencer;
-using google::protobuf::util::NewTypeResolverForDescriptorPool;
 using google::protobuf::util::Status;
 using google::protobuf::util::Status;
-using protobuf_test_messages::proto3::TestAllTypesProto3;
-using protobuf_test_messages::proto2::TestAllTypesProto2;
 using std::string;
 using std::string;
 
 
-namespace {
-
-static const char kTypeUrlPrefix[] = "type.googleapis.com";
-
-static string GetTypeUrl(const Descriptor* message) {
-  return string(kTypeUrlPrefix) + "/" + message->full_name();
-}
-
-/* Routines for building arbitrary protos *************************************/
-
-// We would use CodedOutputStream except that we want more freedom to build
-// arbitrary protos (even invalid ones).
-
-const string empty;
-
-string cat(const string& a, const string& b,
-           const string& c = empty,
-           const string& d = empty,
-           const string& e = empty,
-           const string& f = empty,
-           const string& g = empty,
-           const string& h = empty,
-           const string& i = empty,
-           const string& j = empty,
-           const string& k = empty,
-           const string& l = empty) {
-  string ret;
-  ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() +
-              g.size() + h.size() + i.size() + j.size() + k.size() + l.size());
-  ret.append(a);
-  ret.append(b);
-  ret.append(c);
-  ret.append(d);
-  ret.append(e);
-  ret.append(f);
-  ret.append(g);
-  ret.append(h);
-  ret.append(i);
-  ret.append(j);
-  ret.append(k);
-  ret.append(l);
-  return ret;
-}
+namespace google {
+namespace protobuf {
 
 
-// The maximum number of bytes that it takes to encode a 64-bit varint.
-#define VARINT_MAX_LEN 10
+std::set<ConformanceTestSuite*> *conformance_test_suite_set;
+GOOGLE_PROTOBUF_DECLARE_ONCE(conformance_test_suite_set_init_);
 
 
-size_t vencode64(uint64_t val, int over_encoded_bytes, char *buf) {
-  if (val == 0) { buf[0] = 0; return 1; }
-  size_t i = 0;
-  while (val) {
-    uint8_t byte = val & 0x7fU;
-    val >>= 7;
-    if (val || over_encoded_bytes) byte |= 0x80U;
-    buf[i++] = byte;
-  }
-  while (over_encoded_bytes--) {
-    assert(i < 10);
-    uint8_t byte = over_encoded_bytes ? 0x80 : 0;
-    buf[i++] = byte;
-  }
-  return i;
+void DeleteConformanceTestSuiteSet() {
+  delete conformance_test_suite_set;
 }
 }
 
 
-string varint(uint64_t x) {
-  char buf[VARINT_MAX_LEN];
-  size_t len = vencode64(x, 0, buf);
-  return string(buf, len);
+static void InitConformanceTestSuiteSet() {
+  conformance_test_suite_set = new std::set<ConformanceTestSuite*>();
+  internal::OnShutdown(&DeleteConformanceTestSuiteSet);
 }
 }
 
 
-// Encodes a varint that is |extra| bytes longer than it needs to be, but still
-// valid.
-string longvarint(uint64_t x, int extra) {
-  char buf[VARINT_MAX_LEN];
-  size_t len = vencode64(x, extra, buf);
-  return string(buf, len);
+static void InitConformanceTestSuiteSetOnce() {
+  ::google::protobuf::GoogleOnceInit(
+      &conformance_test_suite_set_init_,
+      &InitConformanceTestSuiteSet);
 }
 }
 
 
-// TODO: proper byte-swapping for big-endian machines.
-string fixed32(void *data) { return string(static_cast<char*>(data), 4); }
-string fixed64(void *data) { return string(static_cast<char*>(data), 8); }
-
-string delim(const string& buf) { return cat(varint(buf.size()), buf); }
-string u32(uint32_t u32) { return fixed32(&u32); }
-string u64(uint64_t u64) { return fixed64(&u64); }
-string flt(float f) { return fixed32(&f); }
-string dbl(double d) { return fixed64(&d); }
-string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); }
-string zz64(int64_t x) { return varint(WireFormatLite::ZigZagEncode64(x)); }
-
-string tag(uint32_t fieldnum, char wire_type) {
-  return varint((fieldnum << 3) | wire_type);
+void AddTestSuite(ConformanceTestSuite* suite) {
+  InitConformanceTestSuiteSetOnce();
+  conformance_test_suite_set->insert(suite);
 }
 }
 
 
-string submsg(uint32_t fn, const string& buf) {
-  return cat( tag(fn, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), delim(buf) );
+const std::set<ConformanceTestSuite*>& GetTestSuiteSet() {
+  InitConformanceTestSuiteSetOnce();
+  return *conformance_test_suite_set;
 }
 }
 
 
-#define UNKNOWN_FIELD 666
-
-const FieldDescriptor* GetFieldForType(FieldDescriptor::Type type,
-                                       bool repeated, bool isProto3) {
-
-  const Descriptor* d = isProto3 ?
-      TestAllTypesProto3().GetDescriptor() : TestAllTypesProto2().GetDescriptor();
-  for (int i = 0; i < d->field_count(); i++) {
-    const FieldDescriptor* f = d->field(i);
-    if (f->type() == type && f->is_repeated() == repeated) {
-      return f;
-    }
-  }
-  GOOGLE_LOG(FATAL) << "Couldn't find field with type " << (int)type;
-  return nullptr;
-}
-
-string UpperCase(string str) {
-  for (int i = 0; i < str.size(); i++) {
-    str[i] = toupper(str[i]);
-  }
-  return str;
-}
-
-}  // anonymous namespace
-
-namespace google {
-namespace protobuf {
-
 ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
 ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
-    ConformanceLevel level, conformance::WireFormat input_format,
-    conformance::WireFormat output_format, bool is_proto3,
+    ConformanceLevel level,
+    conformance::WireFormat input_format,
+    conformance::WireFormat output_format,
+    conformance::TestCategory test_category,
+    const Message& prototype_message,
     const string& test_name, const string& input)
     const string& test_name, const string& input)
-    : level_(level), input_format_(input_format),
-      output_format_(output_format), is_proto3_(is_proto3) {
-  auto newTestMessage = [&is_proto3]() {
-    Message* newMessage;
-    if (is_proto3) {
-      newMessage = new TestAllTypesProto3;
-    } else {
-      newMessage = new TestAllTypesProto2;
-    }
-    return newMessage;
-  };
-
-  string input_format_string;
-  string output_format_string;
-  string rname = is_proto3 ? ".Proto3" : ".Proto2";
-
+    : level_(level),
+      input_format_(input_format),
+      output_format_(output_format),
+      prototype_message_(prototype_message),
+      test_name_(test_name) {
   switch (input_format) {
   switch (input_format) {
     case conformance::PROTOBUF: {
     case conformance::PROTOBUF: {
       request_.set_protobuf_payload(input);
       request_.set_protobuf_payload(input);
-      input_format_string = ".ProtobufInput.";
       break;
       break;
     }
     }
 
 
     case conformance::JSON: {
     case conformance::JSON: {
       request_.set_json_payload(input);
       request_.set_json_payload(input);
-      input_format_string = ".JsonInput.";
       break;
       break;
     }
     }
 
 
@@ -228,39 +112,74 @@ ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
       GOOGLE_LOG(FATAL) << "Unspecified input format";
       GOOGLE_LOG(FATAL) << "Unspecified input format";
   }
   }
 
 
-  switch (output_format) {
-    case conformance::PROTOBUF: {
-      output_format_string = ".ProtobufOutput";
-      break;
-    }
+  request_.set_test_category(test_category);
 
 
-    case conformance::JSON: {
-      output_format_string = ".JsonOutput";
-      break;
-    }
+  request_.set_message_type(prototype_message.GetDescriptor()->full_name());
+  request_.set_requested_output_format(output_format);
+}
+
+Message* ConformanceTestSuite::ConformanceRequestSetting::
+    GetTestMessage() const {
+  return prototype_message_.New();
+}
+
+string ConformanceTestSuite::ConformanceRequestSetting::
+    GetTestName() const {
+  string rname =
+      prototype_message_.GetDescriptor()->file()->syntax() ==
+        FileDescriptor::SYNTAX_PROTO3 ? "Proto3" : "Proto2";
+
+  return StrCat(ConformanceLevelToString(level_), ".",
+                rname, ".",
+                InputFormatString(input_format_),
+                ".", test_name_, ".",
+                OutputFormatString(output_format_));
+}
+
+string ConformanceTestSuite::ConformanceRequestSetting::
+    ConformanceLevelToString(
+        ConformanceLevel level) const {
+  switch (level) {
+    case REQUIRED: return "Required";
+    case RECOMMENDED: return "Recommended";
+  }
+  GOOGLE_LOG(FATAL) << "Unknown value: " << level;
+  return "";
+}
 
 
+string ConformanceTestSuite::ConformanceRequestSetting::
+    InputFormatString(conformance::WireFormat format) const {
+  switch (format) {
+    case conformance::PROTOBUF:
+      return "ProtobufInput";
+    case conformance::JSON:
+      return "JsonInput";
     default:
     default:
       GOOGLE_LOG(FATAL) << "Unspecified output format";
       GOOGLE_LOG(FATAL) << "Unspecified output format";
   }
   }
+  return "";
+}
 
 
-  test_name_ = ConformanceLevelToString(level) + rname +
-               input_format_string + test_name +
-               output_format_string;
-
-  if (is_proto3) {
-    request_.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-  } else {
-    request_.set_message_type("protobuf_test_messages.proto2.TestAllTypesProto2");
+string ConformanceTestSuite::ConformanceRequestSetting::
+    OutputFormatString(conformance::WireFormat format) const {
+  switch (format) {
+    case conformance::PROTOBUF:
+      return "ProtobufOutput";
+    case conformance::JSON:
+      return "JsonOutput";
+    default:
+      GOOGLE_LOG(FATAL) << "Unspecified output format";
   }
   }
-  request_.set_requested_output_format(output_format);
+  return "";
 }
 }
 
 
-Message* ConformanceTestSuite::ConformanceRequestSetting::GetTestMessage() const {
-  if (is_proto3_) {
-    return new TestAllTypesProto3();
-  } else {
-    return new TestAllTypesProto2();
-  }
+void ConformanceTestSuite::SetFailureList(
+    const string& filename,
+    const std::vector<string>& failure_list) {
+  failure_list_filename_ = filename;
+  expected_to_fail_.clear();
+  std::copy(failure_list.begin(), failure_list.end(),
+            std::inserter(expected_to_fail_, expected_to_fail_.end()));
 }
 }
 
 
 void ConformanceTestSuite::ReportSuccess(const string& test_name) {
 void ConformanceTestSuite::ReportSuccess(const string& test_name) {
@@ -309,41 +228,6 @@ void ConformanceTestSuite::ReportSkip(const string& test_name,
   skipped_.insert(test_name);
   skipped_.insert(test_name);
 }
 }
 
 
-string ConformanceTestSuite::ConformanceLevelToString(ConformanceLevel level) {
-  switch (level) {
-    case REQUIRED: return "Required";
-    case RECOMMENDED: return "Recommended";
-  }
-  GOOGLE_LOG(FATAL) << "Unknown value: " << level;
-  return "";
-}
-
-void ConformanceTestSuite::RunTest(const string& test_name,
-                                   const ConformanceRequest& request,
-                                   ConformanceResponse* response) {
-  if (test_names_.insert(test_name).second == false) {
-    GOOGLE_LOG(FATAL) << "Duplicated test name: " << test_name;
-  }
-
-  string serialized_request;
-  string serialized_response;
-  request.SerializeToString(&serialized_request);
-
-  runner_->RunTest(test_name, serialized_request, &serialized_response);
-
-  if (!response->ParseFromString(serialized_response)) {
-    response->Clear();
-    response->set_runtime_error("response proto could not be parsed.");
-  }
-
-  if (verbose_) {
-    StringAppendF(&output_, "conformance test: name=%s, request=%s, response=%s\n",
-                  test_name.c_str(),
-                  request.ShortDebugString().c_str(),
-                  response->ShortDebugString().c_str());
-  }
-}
-
 void ConformanceTestSuite::RunValidInputTest(
 void ConformanceTestSuite::RunValidInputTest(
     const ConformanceRequestSetting& setting,
     const ConformanceRequestSetting& setting,
     const string& equivalent_text_format) {
     const string& equivalent_text_format) {
@@ -459,348 +343,38 @@ void ConformanceTestSuite::RunValidBinaryInputTest(
                   differences.c_str());
                   differences.c_str());
   }
   }
 }
 }
-void ConformanceTestSuite::ExpectParseFailureForProtoWithProtoVersion (
-    const string& proto, const string& test_name, ConformanceLevel level,
-    bool isProto3) {
-  ConformanceRequest request;
-  ConformanceResponse response;
-  request.set_protobuf_payload(proto);
-  if (isProto3) {
-    request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-  } else {
-    request.set_message_type("protobuf_test_messages.proto2.TestAllTypesProto2");
-  }
-  string effective_test_name = ConformanceLevelToString(level) +
-      (isProto3 ? ".Proto3" : ".Proto2") +
-      ".ProtobufInput." + test_name;
 
 
-  // We don't expect output, but if the program erroneously accepts the protobuf
-  // we let it send its response as this.  We must not leave it unspecified.
-  request.set_requested_output_format(conformance::PROTOBUF);
-
-  RunTest(effective_test_name, request, &response);
-  if (response.result_case() == ConformanceResponse::kParseError) {
-    ReportSuccess(effective_test_name);
-  } else if (response.result_case() == ConformanceResponse::kSkipped) {
-    ReportSkip(effective_test_name, request, response);
-  } else {
-    ReportFailure(effective_test_name, level, request, response,
-                  "Should have failed to parse, but didn't.");
-  }
-}
-
-// Expect that this precise protobuf will cause a parse error.
-void ConformanceTestSuite::ExpectParseFailureForProto(
-    const string& proto, const string& test_name, ConformanceLevel level) {
-  ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, true);
-  ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, false);
-}
-
-// Expect that this protobuf will cause a parse error, even if it is followed
-// by valid protobuf data.  We can try running this twice: once with this
-// data verbatim and once with this data followed by some valid data.
-//
-// TODO(haberman): implement the second of these.
-void ConformanceTestSuite::ExpectHardParseFailureForProto(
-    const string& proto, const string& test_name, ConformanceLevel level) {
-  return ExpectParseFailureForProto(proto, test_name, level);
-}
-
-void ConformanceTestSuite::RunValidJsonTest(
-    const string& test_name, ConformanceLevel level, const string& input_json,
-    const string& equivalent_text_format) {
-  ConformanceRequestSetting setting1(
-      level, conformance::JSON, conformance::PROTOBUF,
-      true, test_name, input_json);
-  RunValidInputTest(setting1, equivalent_text_format);
-
-  ConformanceRequestSetting setting2(
-      level, conformance::JSON, conformance::JSON,
-      true, test_name, input_json);
-  RunValidInputTest(setting2, equivalent_text_format);
-}
-
-void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
-    const string& test_name, ConformanceLevel level, const TestAllTypesProto3& input,
-    const string& equivalent_text_format) {
-  ConformanceRequestSetting setting(
-      level, conformance::PROTOBUF, conformance::JSON,
-      true, test_name, input.SerializeAsString());
-  RunValidInputTest(setting, equivalent_text_format);
-}
-
-void ConformanceTestSuite::RunValidJsonIgnoreUnknownTest(
-    const string& test_name, ConformanceLevel level, const string& input_json,
-    const string& equivalent_text_format) {
-  ConformanceRequestSetting setting(
-      level, conformance::JSON, conformance::PROTOBUF,
-      true, test_name, input_json);
-  setting.SetIgnoreUnknownJson(true);
-  RunValidInputTest(setting, equivalent_text_format);
-}
-
-void ConformanceTestSuite::RunValidProtobufTest(
-    const string& test_name, ConformanceLevel level,
-    const string& input_protobuf, const string& equivalent_text_format,
-    bool isProto3) {
-  ConformanceRequestSetting setting1(
-      level, conformance::PROTOBUF, conformance::PROTOBUF,
-      isProto3, test_name, input_protobuf);
-  RunValidInputTest(setting1, equivalent_text_format);
-
-  if (isProto3) {
-    ConformanceRequestSetting setting2(
-        level, conformance::PROTOBUF, conformance::JSON,
-        true, test_name, input_protobuf);
-    RunValidInputTest(setting2, equivalent_text_format);
-  }
-}
-
-void ConformanceTestSuite::RunValidBinaryProtobufTest(
-    const string& test_name, ConformanceLevel level,
-    const string& input_protobuf, bool isProto3) {
-  ConformanceRequestSetting setting(
-      level, conformance::PROTOBUF, conformance::PROTOBUF,
-      isProto3, test_name, input_protobuf);
-  RunValidBinaryInputTest(setting, input_protobuf);
-}
-
-void ConformanceTestSuite::RunValidProtobufTestWithMessage(
-    const string& test_name, ConformanceLevel level, const Message *input,
-    const string& equivalent_text_format, bool isProto3) {
-  RunValidProtobufTest(test_name, level, input->SerializeAsString(), equivalent_text_format, isProto3);
-}
-
-// According to proto3 JSON specification, JSON serializers follow more strict
-// rules than parsers (e.g., a serializer must serialize int32 values as JSON
-// numbers while the parser is allowed to accept them as JSON strings). This
-// method allows strict checking on a proto3 JSON serializer by inspecting
-// the JSON output directly.
-void ConformanceTestSuite::RunValidJsonTestWithValidator(
-    const string& test_name, ConformanceLevel level, const string& input_json,
-    const Validator& validator) {
-  ConformanceRequest request;
-  ConformanceResponse response;
-  request.set_json_payload(input_json);
-  request.set_requested_output_format(conformance::JSON);
-  request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-
-  string effective_test_name = ConformanceLevelToString(level) +
-      ".Proto3.JsonInput." + test_name + ".Validator";
-
-  RunTest(effective_test_name, request, &response);
-
-  if (response.result_case() == ConformanceResponse::kSkipped) {
-    ReportSkip(effective_test_name, request, response);
-    return;
-  }
-
-  if (response.result_case() != ConformanceResponse::kJsonPayload) {
-    ReportFailure(effective_test_name, level, request, response,
-                  "Expected JSON payload but got type %d.",
-                  response.result_case());
-    return;
-  }
-  Json::Reader reader;
-  Json::Value value;
-  if (!reader.parse(response.json_payload(), value)) {
-    ReportFailure(effective_test_name, level, request, response,
-                  "JSON payload cannot be parsed as valid JSON: %s",
-                  reader.getFormattedErrorMessages().c_str());
-    return;
-  }
-  if (!validator(value)) {
-    ReportFailure(effective_test_name, level, request, response,
-                  "JSON payload validation failed.");
-    return;
-  }
-  ReportSuccess(effective_test_name);
-}
-
-void ConformanceTestSuite::ExpectParseFailureForJson(
-    const string& test_name, ConformanceLevel level, const string& input_json) {
-  ConformanceRequest request;
-  ConformanceResponse response;
-  request.set_json_payload(input_json);
-  request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-  string effective_test_name =
-      ConformanceLevelToString(level) + ".Proto3.JsonInput." + test_name;
-
-  // We don't expect output, but if the program erroneously accepts the protobuf
-  // we let it send its response as this.  We must not leave it unspecified.
-  request.set_requested_output_format(conformance::JSON);
-
-  RunTest(effective_test_name, request, &response);
-  if (response.result_case() == ConformanceResponse::kParseError) {
-    ReportSuccess(effective_test_name);
-  } else if (response.result_case() == ConformanceResponse::kSkipped) {
-    ReportSkip(effective_test_name, request, response);
-  } else {
-    ReportFailure(effective_test_name, level, request, response,
-                  "Should have failed to parse, but didn't.");
-  }
-}
-
-void ConformanceTestSuite::ExpectSerializeFailureForJson(
-    const string& test_name, ConformanceLevel level, const string& text_format) {
-  TestAllTypesProto3 payload_message;
-  GOOGLE_CHECK(
-      TextFormat::ParseFromString(text_format, &payload_message))
-          << "Failed to parse: " << text_format;
-
-  ConformanceRequest request;
-  ConformanceResponse response;
-  request.set_protobuf_payload(payload_message.SerializeAsString());
-  request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-  string effective_test_name =
-      ConformanceLevelToString(level) + "." + test_name + ".JsonOutput";
-  request.set_requested_output_format(conformance::JSON);
-
-  RunTest(effective_test_name, request, &response);
-  if (response.result_case() == ConformanceResponse::kSerializeError) {
-    ReportSuccess(effective_test_name);
-  } else if (response.result_case() == ConformanceResponse::kSkipped) {
-    ReportSkip(effective_test_name, request, response);
-  } else {
-    ReportFailure(effective_test_name, level, request, response,
-                  "Should have failed to serialize, but didn't.");
+void ConformanceTestSuite::RunTest(const string& test_name,
+                                   const ConformanceRequest& request,
+                                   ConformanceResponse* response) {
+  if (test_names_.insert(test_name).second == false) {
+    GOOGLE_LOG(FATAL) << "Duplicated test name: " << test_name;
   }
   }
-}
-
-//TODO: proto2?
-void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
-  // Incomplete values for each wire type.
-  static const string incompletes[6] = {
-    string("\x80"),     // VARINT
-    string("abcdefg"),  // 64BIT
-    string("\x80"),     // DELIMITED (partial length)
-    string(),           // START_GROUP (no value required)
-    string(),           // END_GROUP (no value required)
-    string("abc")       // 32BIT
-  };
-
-  const FieldDescriptor* field = GetFieldForType(type, false, true);
-  const FieldDescriptor* rep_field = GetFieldForType(type, true, true);
-  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
-      static_cast<WireFormatLite::FieldType>(type));
-  const string& incomplete = incompletes[wire_type];
-  const string type_name =
-      UpperCase(string(".") + FieldDescriptor::TypeName(type));
-
-  ExpectParseFailureForProto(
-      tag(field->number(), wire_type),
-      "PrematureEofBeforeKnownNonRepeatedValue" + type_name, REQUIRED);
-
-  ExpectParseFailureForProto(
-      tag(rep_field->number(), wire_type),
-      "PrematureEofBeforeKnownRepeatedValue" + type_name, REQUIRED);
-
-  ExpectParseFailureForProto(
-      tag(UNKNOWN_FIELD, wire_type),
-      "PrematureEofBeforeUnknownValue" + type_name, REQUIRED);
-
-  ExpectParseFailureForProto(
-      cat( tag(field->number(), wire_type), incomplete ),
-      "PrematureEofInsideKnownNonRepeatedValue" + type_name, REQUIRED);
 
 
-  ExpectParseFailureForProto(
-      cat( tag(rep_field->number(), wire_type), incomplete ),
-      "PrematureEofInsideKnownRepeatedValue" + type_name, REQUIRED);
-
-  ExpectParseFailureForProto(
-      cat( tag(UNKNOWN_FIELD, wire_type), incomplete ),
-      "PrematureEofInsideUnknownValue" + type_name, REQUIRED);
-
-  if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
-    ExpectParseFailureForProto(
-        cat( tag(field->number(), wire_type), varint(1) ),
-        "PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name,
-        REQUIRED);
-
-    ExpectParseFailureForProto(
-        cat( tag(rep_field->number(), wire_type), varint(1) ),
-        "PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name,
-        REQUIRED);
-
-    // EOF in the middle of delimited data for unknown value.
-    ExpectParseFailureForProto(
-        cat( tag(UNKNOWN_FIELD, wire_type), varint(1) ),
-        "PrematureEofInDelimitedDataForUnknownValue" + type_name, REQUIRED);
-
-    if (type == FieldDescriptor::TYPE_MESSAGE) {
-      // Submessage ends in the middle of a value.
-      string incomplete_submsg =
-          cat( tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT),
-                incompletes[WireFormatLite::WIRETYPE_VARINT] );
-      ExpectHardParseFailureForProto(
-          cat( tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
-               varint(incomplete_submsg.size()),
-               incomplete_submsg ),
-          "PrematureEofInSubmessageValue" + type_name, REQUIRED);
-    }
-  } else if (type != FieldDescriptor::TYPE_GROUP) {
-    // Non-delimited, non-group: eligible for packing.
+  string serialized_request;
+  string serialized_response;
+  request.SerializeToString(&serialized_request);
 
 
-    // Packed region ends in the middle of a value.
-    ExpectHardParseFailureForProto(
-        cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
-            varint(incomplete.size()), incomplete),
-        "PrematureEofInPackedFieldValue" + type_name, REQUIRED);
+  runner_->RunTest(test_name, serialized_request, &serialized_response);
 
 
-    // EOF in the middle of packed region.
-    ExpectParseFailureForProto(
-        cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
-            varint(1)),
-        "PrematureEofInPackedField" + type_name, REQUIRED);
+  if (!response->ParseFromString(serialized_response)) {
+    response->Clear();
+    response->set_runtime_error("response proto could not be parsed.");
   }
   }
-}
-
-void ConformanceTestSuite::TestValidDataForType(
-    FieldDescriptor::Type type,
-    std::vector<std::pair<std::string, std::string>> values) {
-  for (int isProto3 = 0; isProto3 < 2; isProto3++) {
-    const string type_name =
-        UpperCase(string(".") + FieldDescriptor::TypeName(type));
-    WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
-        static_cast<WireFormatLite::FieldType>(type));
-    const FieldDescriptor* field = GetFieldForType(type, false, isProto3);
-    const FieldDescriptor* rep_field = GetFieldForType(type, true, isProto3);
 
 
-    RunValidProtobufTest("ValidDataScalar" + type_name, REQUIRED,
-                         cat(tag(field->number(), wire_type), values[0].first),
-                         field->name() + ": " + values[0].second, isProto3);
-
-    string proto;
-    string text = field->name() + ": " + values.back().second;
-    for (size_t i = 0; i < values.size(); i++) {
-      proto += cat(tag(field->number(), wire_type), values[i].first);
-    }
-    RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED,
-                         proto, text, isProto3);
-
-    proto.clear();
-    text.clear();
-
-    for (size_t i = 0; i < values.size(); i++) {
-      proto += cat(tag(rep_field->number(), wire_type), values[i].first);
-      text += rep_field->name() + ": " + values[i].second + " ";
-    }
-    RunValidProtobufTest("ValidDataRepeated" + type_name, REQUIRED,
-                         proto, text, isProto3);
+  if (verbose_) {
+    StringAppendF(&output_,
+                  "conformance test: name=%s, request=%s, response=%s\n",
+                  test_name.c_str(),
+                  request.ShortDebugString().c_str(),
+                  response->ShortDebugString().c_str());
   }
   }
 }
 }
 
 
-void ConformanceTestSuite::SetFailureList(const string& filename,
-                                          const std::vector<string>& failure_list) {
-  failure_list_filename_ = filename;
-  expected_to_fail_.clear();
-  std::copy(failure_list.begin(), failure_list.end(),
-            std::inserter(expected_to_fail_, expected_to_fail_.end()));
-}
-
-bool ConformanceTestSuite::CheckSetEmpty(const std::set<string>& set_to_check,
-                                         const std::string& write_to_file,
-                                         const std::string& msg) {
+bool ConformanceTestSuite::CheckSetEmpty(
+    const std::set<string>& set_to_check,
+    const std::string& write_to_file,
+    const std::string& msg) {
   if (set_to_check.empty()) {
   if (set_to_check.empty()) {
     return true;
     return true;
   } else {
   } else {
@@ -829,70 +403,8 @@ bool ConformanceTestSuite::CheckSetEmpty(const std::set<string>& set_to_check,
   }
   }
 }
 }
 
 
-// TODO: proto2?
-void ConformanceTestSuite::TestIllegalTags() {
-  // field num 0 is illegal
-  string nullfield[] = {
-    "\1DEADBEEF",
-    "\2\1\1",
-    "\3\4",
-    "\5DEAD"
-  };
-  for (int i = 0; i < 4; i++) {
-    string name = "IllegalZeroFieldNum_Case_0";
-    name.back() += i;
-    ExpectParseFailureForProto(nullfield[i], name, REQUIRED);
-  }
-}
-template <class MessageType>
-void ConformanceTestSuite::TestOneofMessage (MessageType &message,
-                                             bool isProto3) {
-  message.set_oneof_uint32(0);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroUint32", RECOMMENDED, &message, "oneof_uint32: 0", isProto3);
-  message.mutable_oneof_nested_message()->set_a(0);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroMessage", RECOMMENDED, &message,
-      isProto3 ? "oneof_nested_message: {}" : "oneof_nested_message: {a: 0}",
-      isProto3);
-  message.mutable_oneof_nested_message()->set_a(1);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroMessageSetTwice", RECOMMENDED, &message,
-      "oneof_nested_message: {a: 1}",
-      isProto3);
-  message.set_oneof_string("");
-  RunValidProtobufTestWithMessage(
-      "OneofZeroString", RECOMMENDED, &message, "oneof_string: \"\"", isProto3);
-  message.set_oneof_bytes("");
-  RunValidProtobufTestWithMessage(
-      "OneofZeroBytes", RECOMMENDED, &message, "oneof_bytes: \"\"", isProto3);
-  message.set_oneof_bool(false);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroBool", RECOMMENDED, &message, "oneof_bool: false", isProto3);
-  message.set_oneof_uint64(0);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroUint64", RECOMMENDED, &message, "oneof_uint64: 0", isProto3);
-  message.set_oneof_float(0.0f);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroFloat", RECOMMENDED, &message, "oneof_float: 0", isProto3);
-  message.set_oneof_double(0.0);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroDouble", RECOMMENDED, &message, "oneof_double: 0", isProto3);
-  message.set_oneof_enum(MessageType::FOO);
-  RunValidProtobufTestWithMessage(
-      "OneofZeroEnum", RECOMMENDED, &message, "oneof_enum: FOO", isProto3);
-}
-
-template <class MessageType>
-void ConformanceTestSuite::TestUnknownMessage(MessageType& message,
-                                              bool isProto3) {
-  message.ParseFromString("\xA8\x1F\x01");
-  RunValidBinaryProtobufTest("UnknownVarint", REQUIRED,
-                             message.SerializeAsString(), isProto3);
-}
-
-bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
-                                    std::string* output) {
+bool ConformanceTestSuite::RunSuite(
+    ConformanceTestRunner* runner, std::string* output) {
   runner_ = runner;
   runner_ = runner;
   successes_ = 0;
   successes_ = 0;
   expected_failures_ = 0;
   expected_failures_ = 0;
@@ -900,1714 +412,10 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
   test_names_.clear();
   test_names_.clear();
   unexpected_failing_tests_.clear();
   unexpected_failing_tests_.clear();
   unexpected_succeeding_tests_.clear();
   unexpected_succeeding_tests_.clear();
-  type_resolver_.reset(NewTypeResolverForDescriptorPool(
-      kTypeUrlPrefix, DescriptorPool::generated_pool()));
-  type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor());
 
 
   output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n";
   output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n";
 
 
-  for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) {
-    if (i == FieldDescriptor::TYPE_GROUP) continue;
-    TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
-  }
-
-  TestIllegalTags();
-
-  int64 kInt64Min = -9223372036854775808ULL;
-  int64 kInt64Max = 9223372036854775807ULL;
-  uint64 kUint64Max = 18446744073709551615ULL;
-  int32 kInt32Max = 2147483647;
-  int32 kInt32Min = -2147483648;
-  uint32 kUint32Max = 4294967295UL;
-
-  TestValidDataForType(FieldDescriptor::TYPE_DOUBLE, {
-    {dbl(0.1), "0.1"},
-    {dbl(1.7976931348623157e+308), "1.7976931348623157e+308"},
-    {dbl(2.22507385850720138309e-308), "2.22507385850720138309e-308"}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_FLOAT, {
-    {flt(0.1), "0.1"},
-    {flt(1.00000075e-36), "1.00000075e-36"},
-    {flt(3.402823e+38), "3.402823e+38"},  // 3.40282347e+38
-    {flt(1.17549435e-38f), "1.17549435e-38"}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_INT64, {
-    {varint(12345), "12345"},
-    {varint(kInt64Max), std::to_string(kInt64Max)},
-    {varint(kInt64Min), std::to_string(kInt64Min)}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_UINT64, {
-    {varint(12345), "12345"},
-    {varint(kUint64Max), std::to_string(kUint64Max)},
-    {varint(0), "0"}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_INT32, {
-    {varint(12345), "12345"},
-    {longvarint(12345, 2), "12345"},
-    {longvarint(12345, 7), "12345"},
-    {varint(kInt32Max), std::to_string(kInt32Max)},
-    {varint(kInt32Min), std::to_string(kInt32Min)},
-    {varint(1LL << 33), std::to_string(static_cast<int32>(1LL << 33))},
-    {varint((1LL << 33) - 1),
-     std::to_string(static_cast<int32>((1LL << 33) - 1))},
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_UINT32, {
-    {varint(12345), "12345"},
-    {longvarint(12345, 2), "12345"},
-    {longvarint(12345, 7), "12345"},
-    {varint(kUint32Max), std::to_string(kUint32Max)},  // UINT32_MAX
-    {varint(0), "0"},
-    {varint(1LL << 33), std::to_string(static_cast<uint32>(1LL << 33))},
-    {varint((1LL << 33) - 1),
-     std::to_string(static_cast<uint32>((1LL << 33) - 1))},
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_FIXED64, {
-    {u64(12345), "12345"},
-    {u64(kUint64Max), std::to_string(kUint64Max)},
-    {u64(0), "0"}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_FIXED32, {
-    {u32(12345), "12345"},
-    {u32(kUint32Max), std::to_string(kUint32Max)},  // UINT32_MAX
-    {u32(0), "0"}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, {
-    {u64(12345), "12345"},
-    {u64(kInt64Max), std::to_string(kInt64Max)},
-    {u64(kInt64Min), std::to_string(kInt64Min)}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, {
-    {u32(12345), "12345"},
-    {u32(kInt32Max), std::to_string(kInt32Max)},
-    {u32(kInt32Min), std::to_string(kInt32Min)}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_BOOL, {
-    {varint(1), "true"},
-    {varint(0), "false"},
-    {varint(12345678), "true"}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_SINT32, {
-    {zz32(12345), "12345"},
-    {zz32(kInt32Max), std::to_string(kInt32Max)},
-    {zz32(kInt32Min), std::to_string(kInt32Min)}
-  });
-  TestValidDataForType(FieldDescriptor::TYPE_SINT64, {
-    {zz64(12345), "12345"},
-    {zz64(kInt64Max), std::to_string(kInt64Max)},
-    {zz64(kInt64Min), std::to_string(kInt64Min)}
-  });
-
-  // TODO(haberman):
-  // TestValidDataForType(FieldDescriptor::TYPE_STRING
-  // TestValidDataForType(FieldDescriptor::TYPE_GROUP
-  // TestValidDataForType(FieldDescriptor::TYPE_MESSAGE
-  // TestValidDataForType(FieldDescriptor::TYPE_BYTES
-  // TestValidDataForType(FieldDescriptor::TYPE_ENUM
-
-  RunValidJsonTest("HelloWorld", REQUIRED,
-                   "{\"optionalString\":\"Hello, World!\"}",
-                   "optional_string: 'Hello, World!'");
-
-  // NOTE: The spec for JSON support is still being sorted out, these may not
-  // all be correct.
-  // Test field name conventions.
-  RunValidJsonTest(
-      "FieldNameInSnakeCase", REQUIRED,
-      R"({
-        "fieldname1": 1,
-        "fieldName2": 2,
-        "FieldName3": 3,
-        "fieldName4": 4
-      })",
-      R"(
-        fieldname1: 1
-        field_name2: 2
-        _field_name3: 3
-        field__name4_: 4
-      )");
-  RunValidJsonTest(
-      "FieldNameWithNumbers", REQUIRED,
-      R"({
-        "field0name5": 5,
-        "field0Name6": 6
-      })",
-      R"(
-        field0name5: 5
-        field_0_name6: 6
-      )");
-  RunValidJsonTest(
-      "FieldNameWithMixedCases", REQUIRED,
-      R"({
-        "fieldName7": 7,
-        "FieldName8": 8,
-        "fieldName9": 9,
-        "FieldName10": 10,
-        "FIELDNAME11": 11,
-        "FIELDName12": 12
-      })",
-      R"(
-        fieldName7: 7
-        FieldName8: 8
-        field_Name9: 9
-        Field_Name10: 10
-        FIELD_NAME11: 11
-        FIELD_name12: 12
-      )");
-  RunValidJsonTest(
-      "FieldNameWithDoubleUnderscores", RECOMMENDED,
-      R"({
-        "FieldName13": 13,
-        "FieldName14": 14,
-        "fieldName15": 15,
-        "fieldName16": 16,
-        "fieldName17": 17,
-        "FieldName18": 18
-      })",
-      R"(
-        __field_name13: 13
-        __Field_name14: 14
-        field__name15: 15
-        field__Name16: 16
-        field_name17__: 17
-        Field_name18__: 18
-      )");
-  // Using the original proto field name in JSON is also allowed.
-  RunValidJsonTest(
-      "OriginalProtoFieldName", REQUIRED,
-      R"({
-        "fieldname1": 1,
-        "field_name2": 2,
-        "_field_name3": 3,
-        "field__name4_": 4,
-        "field0name5": 5,
-        "field_0_name6": 6,
-        "fieldName7": 7,
-        "FieldName8": 8,
-        "field_Name9": 9,
-        "Field_Name10": 10,
-        "FIELD_NAME11": 11,
-        "FIELD_name12": 12,
-        "__field_name13": 13,
-        "__Field_name14": 14,
-        "field__name15": 15,
-        "field__Name16": 16,
-        "field_name17__": 17,
-        "Field_name18__": 18
-      })",
-      R"(
-        fieldname1: 1
-        field_name2: 2
-        _field_name3: 3
-        field__name4_: 4
-        field0name5: 5
-        field_0_name6: 6
-        fieldName7: 7
-        FieldName8: 8
-        field_Name9: 9
-        Field_Name10: 10
-        FIELD_NAME11: 11
-        FIELD_name12: 12
-        __field_name13: 13
-        __Field_name14: 14
-        field__name15: 15
-        field__Name16: 16
-        field_name17__: 17
-        Field_name18__: 18
-      )");
-  // Field names can be escaped.
-  RunValidJsonTest(
-      "FieldNameEscaped", REQUIRED,
-      R"({"fieldn\u0061me1": 1})",
-      "fieldname1: 1");
-  // String ends with escape character.
-  ExpectParseFailureForJson(
-      "StringEndsWithEscapeChar", RECOMMENDED,
-      "{\"optionalString\": \"abc\\");
-  // Field names must be quoted (or it's not valid JSON).
-  ExpectParseFailureForJson(
-      "FieldNameNotQuoted", RECOMMENDED,
-      "{fieldname1: 1}");
-  // Trailing comma is not allowed (not valid JSON).
-  ExpectParseFailureForJson(
-      "TrailingCommaInAnObject", RECOMMENDED,
-      R"({"fieldname1":1,})");
-  ExpectParseFailureForJson(
-      "TrailingCommaInAnObjectWithSpace", RECOMMENDED,
-      R"({"fieldname1":1 ,})");
-  ExpectParseFailureForJson(
-      "TrailingCommaInAnObjectWithSpaceCommaSpace", RECOMMENDED,
-      R"({"fieldname1":1 , })");
-  ExpectParseFailureForJson(
-      "TrailingCommaInAnObjectWithNewlines", RECOMMENDED,
-      R"({
-        "fieldname1":1,
-      })");
-  // JSON doesn't support comments.
-  ExpectParseFailureForJson(
-      "JsonWithComments", RECOMMENDED,
-      R"({
-        // This is a comment.
-        "fieldname1": 1
-      })");
-  // JSON spec says whitespace doesn't matter, so try a few spacings to be sure.
-  RunValidJsonTest(
-      "OneLineNoSpaces", RECOMMENDED,
-      "{\"optionalInt32\":1,\"optionalInt64\":2}",
-      R"(
-        optional_int32: 1
-        optional_int64: 2
-      )");
-  RunValidJsonTest(
-      "OneLineWithSpaces", RECOMMENDED,
-      "{ \"optionalInt32\" : 1 , \"optionalInt64\" : 2 }",
-      R"(
-        optional_int32: 1
-        optional_int64: 2
-      )");
-  RunValidJsonTest(
-      "MultilineNoSpaces", RECOMMENDED,
-      "{\n\"optionalInt32\"\n:\n1\n,\n\"optionalInt64\"\n:\n2\n}",
-      R"(
-        optional_int32: 1
-        optional_int64: 2
-      )");
-  RunValidJsonTest(
-      "MultilineWithSpaces", RECOMMENDED,
-      "{\n  \"optionalInt32\"  :  1\n  ,\n  \"optionalInt64\"  :  2\n}\n",
-      R"(
-        optional_int32: 1
-        optional_int64: 2
-      )");
-  // Missing comma between key/value pairs.
-  ExpectParseFailureForJson(
-      "MissingCommaOneLine", RECOMMENDED,
-      "{ \"optionalInt32\": 1 \"optionalInt64\": 2 }");
-  ExpectParseFailureForJson(
-      "MissingCommaMultiline", RECOMMENDED,
-      "{\n  \"optionalInt32\": 1\n  \"optionalInt64\": 2\n}");
-  // Duplicated field names are not allowed.
-  ExpectParseFailureForJson(
-      "FieldNameDuplicate", RECOMMENDED,
-      R"({
-        "optionalNestedMessage": {a: 1},
-        "optionalNestedMessage": {}
-      })");
-  ExpectParseFailureForJson(
-      "FieldNameDuplicateDifferentCasing1", RECOMMENDED,
-      R"({
-        "optional_nested_message": {a: 1},
-        "optionalNestedMessage": {}
-      })");
-  ExpectParseFailureForJson(
-      "FieldNameDuplicateDifferentCasing2", RECOMMENDED,
-      R"({
-        "optionalNestedMessage": {a: 1},
-        "optional_nested_message": {}
-      })");
-  // Serializers should use lowerCamelCase by default.
-  RunValidJsonTestWithValidator(
-      "FieldNameInLowerCamelCase", REQUIRED,
-      R"({
-        "fieldname1": 1,
-        "fieldName2": 2,
-        "FieldName3": 3,
-        "fieldName4": 4
-      })",
-      [](const Json::Value& value) {
-        return value.isMember("fieldname1") &&
-            value.isMember("fieldName2") &&
-            value.isMember("FieldName3") &&
-            value.isMember("fieldName4");
-      });
-  RunValidJsonTestWithValidator(
-      "FieldNameWithNumbers", REQUIRED,
-      R"({
-        "field0name5": 5,
-        "field0Name6": 6
-      })",
-      [](const Json::Value& value) {
-        return value.isMember("field0name5") &&
-            value.isMember("field0Name6");
-      });
-  RunValidJsonTestWithValidator(
-      "FieldNameWithMixedCases", REQUIRED,
-      R"({
-        "fieldName7": 7,
-        "FieldName8": 8,
-        "fieldName9": 9,
-        "FieldName10": 10,
-        "FIELDNAME11": 11,
-        "FIELDName12": 12
-      })",
-      [](const Json::Value& value) {
-        return value.isMember("fieldName7") &&
-            value.isMember("FieldName8") &&
-            value.isMember("fieldName9") &&
-            value.isMember("FieldName10") &&
-            value.isMember("FIELDNAME11") &&
-            value.isMember("FIELDName12");
-      });
-  RunValidJsonTestWithValidator(
-      "FieldNameWithDoubleUnderscores", RECOMMENDED,
-      R"({
-        "FieldName13": 13,
-        "FieldName14": 14,
-        "fieldName15": 15,
-        "fieldName16": 16,
-        "fieldName17": 17,
-        "FieldName18": 18
-      })",
-      [](const Json::Value& value) {
-        return value.isMember("FieldName13") &&
-            value.isMember("FieldName14") &&
-            value.isMember("fieldName15") &&
-            value.isMember("fieldName16") &&
-            value.isMember("fieldName17") &&
-            value.isMember("FieldName18");
-      });
-
-  // Integer fields.
-  RunValidJsonTest(
-      "Int32FieldMaxValue", REQUIRED,
-      R"({"optionalInt32": 2147483647})",
-      "optional_int32: 2147483647");
-  RunValidJsonTest(
-      "Int32FieldMinValue", REQUIRED,
-      R"({"optionalInt32": -2147483648})",
-      "optional_int32: -2147483648");
-  RunValidJsonTest(
-      "Uint32FieldMaxValue", REQUIRED,
-      R"({"optionalUint32": 4294967295})",
-      "optional_uint32: 4294967295");
-  RunValidJsonTest(
-      "Int64FieldMaxValue", REQUIRED,
-      R"({"optionalInt64": "9223372036854775807"})",
-      "optional_int64: 9223372036854775807");
-  RunValidJsonTest(
-      "Int64FieldMinValue", REQUIRED,
-      R"({"optionalInt64": "-9223372036854775808"})",
-      "optional_int64: -9223372036854775808");
-  RunValidJsonTest(
-      "Uint64FieldMaxValue", REQUIRED,
-      R"({"optionalUint64": "18446744073709551615"})",
-      "optional_uint64: 18446744073709551615");
-  // While not the largest Int64, this is the largest
-  // Int64 which can be exactly represented within an
-  // IEEE-754 64-bit float, which is the expected level
-  // of interoperability guarantee. Larger values may
-  // work in some implementations, but should not be
-  // relied upon.
-  RunValidJsonTest(
-      "Int64FieldMaxValueNotQuoted", REQUIRED,
-      R"({"optionalInt64": 9223372036854774784})",
-      "optional_int64: 9223372036854774784");
-  RunValidJsonTest(
-      "Int64FieldMinValueNotQuoted", REQUIRED,
-      R"({"optionalInt64": -9223372036854775808})",
-      "optional_int64: -9223372036854775808");
-  // Largest interoperable Uint64; see comment above
-  // for Int64FieldMaxValueNotQuoted.
-  RunValidJsonTest(
-      "Uint64FieldMaxValueNotQuoted", REQUIRED,
-      R"({"optionalUint64": 18446744073709549568})",
-      "optional_uint64: 18446744073709549568");
-  // Values can be represented as JSON strings.
-  RunValidJsonTest(
-      "Int32FieldStringValue", REQUIRED,
-      R"({"optionalInt32": "2147483647"})",
-      "optional_int32: 2147483647");
-  RunValidJsonTest(
-      "Int32FieldStringValueEscaped", REQUIRED,
-      R"({"optionalInt32": "2\u003147483647"})",
-      "optional_int32: 2147483647");
-
-  // Parsers reject out-of-bound integer values.
-  ExpectParseFailureForJson(
-      "Int32FieldTooLarge", REQUIRED,
-      R"({"optionalInt32": 2147483648})");
-  ExpectParseFailureForJson(
-      "Int32FieldTooSmall", REQUIRED,
-      R"({"optionalInt32": -2147483649})");
-  ExpectParseFailureForJson(
-      "Uint32FieldTooLarge", REQUIRED,
-      R"({"optionalUint32": 4294967296})");
-  ExpectParseFailureForJson(
-      "Int64FieldTooLarge", REQUIRED,
-      R"({"optionalInt64": "9223372036854775808"})");
-  ExpectParseFailureForJson(
-      "Int64FieldTooSmall", REQUIRED,
-      R"({"optionalInt64": "-9223372036854775809"})");
-  ExpectParseFailureForJson(
-      "Uint64FieldTooLarge", REQUIRED,
-      R"({"optionalUint64": "18446744073709551616"})");
-  // Parser reject non-integer numeric values as well.
-  ExpectParseFailureForJson(
-      "Int32FieldNotInteger", REQUIRED,
-      R"({"optionalInt32": 0.5})");
-  ExpectParseFailureForJson(
-      "Uint32FieldNotInteger", REQUIRED,
-      R"({"optionalUint32": 0.5})");
-  ExpectParseFailureForJson(
-      "Int64FieldNotInteger", REQUIRED,
-      R"({"optionalInt64": "0.5"})");
-  ExpectParseFailureForJson(
-      "Uint64FieldNotInteger", REQUIRED,
-      R"({"optionalUint64": "0.5"})");
-
-  // Integers but represented as float values are accepted.
-  RunValidJsonTest(
-      "Int32FieldFloatTrailingZero", REQUIRED,
-      R"({"optionalInt32": 100000.000})",
-      "optional_int32: 100000");
-  RunValidJsonTest(
-      "Int32FieldExponentialFormat", REQUIRED,
-      R"({"optionalInt32": 1e5})",
-      "optional_int32: 100000");
-  RunValidJsonTest(
-      "Int32FieldMaxFloatValue", REQUIRED,
-      R"({"optionalInt32": 2.147483647e9})",
-      "optional_int32: 2147483647");
-  RunValidJsonTest(
-      "Int32FieldMinFloatValue", REQUIRED,
-      R"({"optionalInt32": -2.147483648e9})",
-      "optional_int32: -2147483648");
-  RunValidJsonTest(
-      "Uint32FieldMaxFloatValue", REQUIRED,
-      R"({"optionalUint32": 4.294967295e9})",
-      "optional_uint32: 4294967295");
-
-  // Parser reject non-numeric values.
-  ExpectParseFailureForJson(
-      "Int32FieldNotNumber", REQUIRED,
-      R"({"optionalInt32": "3x3"})");
-  ExpectParseFailureForJson(
-      "Uint32FieldNotNumber", REQUIRED,
-      R"({"optionalUint32": "3x3"})");
-  ExpectParseFailureForJson(
-      "Int64FieldNotNumber", REQUIRED,
-      R"({"optionalInt64": "3x3"})");
-  ExpectParseFailureForJson(
-      "Uint64FieldNotNumber", REQUIRED,
-      R"({"optionalUint64": "3x3"})");
-  // JSON does not allow "+" on numric values.
-  ExpectParseFailureForJson(
-      "Int32FieldPlusSign", REQUIRED,
-      R"({"optionalInt32": +1})");
-  // JSON doesn't allow leading 0s.
-  ExpectParseFailureForJson(
-      "Int32FieldLeadingZero", REQUIRED,
-      R"({"optionalInt32": 01})");
-  ExpectParseFailureForJson(
-      "Int32FieldNegativeWithLeadingZero", REQUIRED,
-      R"({"optionalInt32": -01})");
-  // String values must follow the same syntax rule. Specifically leading
-  // or trailing spaces are not allowed.
-  ExpectParseFailureForJson(
-      "Int32FieldLeadingSpace", REQUIRED,
-      R"({"optionalInt32": " 1"})");
-  ExpectParseFailureForJson(
-      "Int32FieldTrailingSpace", REQUIRED,
-      R"({"optionalInt32": "1 "})");
-
-  // 64-bit values are serialized as strings.
-  RunValidJsonTestWithValidator(
-      "Int64FieldBeString", RECOMMENDED,
-      R"({"optionalInt64": 1})",
-      [](const Json::Value& value) {
-        return value["optionalInt64"].type() == Json::stringValue &&
-            value["optionalInt64"].asString() == "1";
-      });
-  RunValidJsonTestWithValidator(
-      "Uint64FieldBeString", RECOMMENDED,
-      R"({"optionalUint64": 1})",
-      [](const Json::Value& value) {
-        return value["optionalUint64"].type() == Json::stringValue &&
-            value["optionalUint64"].asString() == "1";
-      });
-
-  // Bool fields.
-  RunValidJsonTest(
-      "BoolFieldTrue", REQUIRED,
-      R"({"optionalBool":true})",
-      "optional_bool: true");
-  RunValidJsonTest(
-      "BoolFieldFalse", REQUIRED,
-      R"({"optionalBool":false})",
-      "optional_bool: false");
-
-  // Other forms are not allowed.
-  ExpectParseFailureForJson(
-      "BoolFieldIntegerZero", RECOMMENDED,
-      R"({"optionalBool":0})");
-  ExpectParseFailureForJson(
-      "BoolFieldIntegerOne", RECOMMENDED,
-      R"({"optionalBool":1})");
-  ExpectParseFailureForJson(
-      "BoolFieldCamelCaseTrue", RECOMMENDED,
-      R"({"optionalBool":True})");
-  ExpectParseFailureForJson(
-      "BoolFieldCamelCaseFalse", RECOMMENDED,
-      R"({"optionalBool":False})");
-  ExpectParseFailureForJson(
-      "BoolFieldAllCapitalTrue", RECOMMENDED,
-      R"({"optionalBool":TRUE})");
-  ExpectParseFailureForJson(
-      "BoolFieldAllCapitalFalse", RECOMMENDED,
-      R"({"optionalBool":FALSE})");
-  ExpectParseFailureForJson(
-      "BoolFieldDoubleQuotedTrue", RECOMMENDED,
-      R"({"optionalBool":"true"})");
-  ExpectParseFailureForJson(
-      "BoolFieldDoubleQuotedFalse", RECOMMENDED,
-      R"({"optionalBool":"false"})");
-
-  // Float fields.
-  RunValidJsonTest(
-      "FloatFieldMinPositiveValue", REQUIRED,
-      R"({"optionalFloat": 1.175494e-38})",
-      "optional_float: 1.175494e-38");
-  RunValidJsonTest(
-      "FloatFieldMaxNegativeValue", REQUIRED,
-      R"({"optionalFloat": -1.175494e-38})",
-      "optional_float: -1.175494e-38");
-  RunValidJsonTest(
-      "FloatFieldMaxPositiveValue", REQUIRED,
-      R"({"optionalFloat": 3.402823e+38})",
-      "optional_float: 3.402823e+38");
-  RunValidJsonTest(
-      "FloatFieldMinNegativeValue", REQUIRED,
-      R"({"optionalFloat": 3.402823e+38})",
-      "optional_float: 3.402823e+38");
-  // Values can be quoted.
-  RunValidJsonTest(
-      "FloatFieldQuotedValue", REQUIRED,
-      R"({"optionalFloat": "1"})",
-      "optional_float: 1");
-  // Special values.
-  RunValidJsonTest(
-      "FloatFieldNan", REQUIRED,
-      R"({"optionalFloat": "NaN"})",
-      "optional_float: nan");
-  RunValidJsonTest(
-      "FloatFieldInfinity", REQUIRED,
-      R"({"optionalFloat": "Infinity"})",
-      "optional_float: inf");
-  RunValidJsonTest(
-      "FloatFieldNegativeInfinity", REQUIRED,
-      R"({"optionalFloat": "-Infinity"})",
-      "optional_float: -inf");
-  // Non-cannonical Nan will be correctly normalized.
-  {
-    TestAllTypesProto3 message;
-    // IEEE floating-point standard 32-bit quiet NaN:
-    //   0111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
-    message.set_optional_float(
-        WireFormatLite::DecodeFloat(0x7FA12345));
-    RunValidJsonTestWithProtobufInput(
-        "FloatFieldNormalizeQuietNan", REQUIRED, message,
-        "optional_float: nan");
-    // IEEE floating-point standard 64-bit signaling NaN:
-    //   1111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
-    message.set_optional_float(
-        WireFormatLite::DecodeFloat(0xFFB54321));
-    RunValidJsonTestWithProtobufInput(
-        "FloatFieldNormalizeSignalingNan", REQUIRED, message,
-        "optional_float: nan");
-  }
-
-  // Special values must be quoted.
-  ExpectParseFailureForJson(
-      "FloatFieldNanNotQuoted", RECOMMENDED,
-      R"({"optionalFloat": NaN})");
-  ExpectParseFailureForJson(
-      "FloatFieldInfinityNotQuoted", RECOMMENDED,
-      R"({"optionalFloat": Infinity})");
-  ExpectParseFailureForJson(
-      "FloatFieldNegativeInfinityNotQuoted", RECOMMENDED,
-      R"({"optionalFloat": -Infinity})");
-  // Parsers should reject out-of-bound values.
-  ExpectParseFailureForJson(
-      "FloatFieldTooSmall", REQUIRED,
-      R"({"optionalFloat": -3.502823e+38})");
-  ExpectParseFailureForJson(
-      "FloatFieldTooLarge", REQUIRED,
-      R"({"optionalFloat": 3.502823e+38})");
-
-  // Double fields.
-  RunValidJsonTest(
-      "DoubleFieldMinPositiveValue", REQUIRED,
-      R"({"optionalDouble": 2.22507e-308})",
-      "optional_double: 2.22507e-308");
-  RunValidJsonTest(
-      "DoubleFieldMaxNegativeValue", REQUIRED,
-      R"({"optionalDouble": -2.22507e-308})",
-      "optional_double: -2.22507e-308");
-  RunValidJsonTest(
-      "DoubleFieldMaxPositiveValue", REQUIRED,
-      R"({"optionalDouble": 1.79769e+308})",
-      "optional_double: 1.79769e+308");
-  RunValidJsonTest(
-      "DoubleFieldMinNegativeValue", REQUIRED,
-      R"({"optionalDouble": -1.79769e+308})",
-      "optional_double: -1.79769e+308");
-  // Values can be quoted.
-  RunValidJsonTest(
-      "DoubleFieldQuotedValue", REQUIRED,
-      R"({"optionalDouble": "1"})",
-      "optional_double: 1");
-  // Speical values.
-  RunValidJsonTest(
-      "DoubleFieldNan", REQUIRED,
-      R"({"optionalDouble": "NaN"})",
-      "optional_double: nan");
-  RunValidJsonTest(
-      "DoubleFieldInfinity", REQUIRED,
-      R"({"optionalDouble": "Infinity"})",
-      "optional_double: inf");
-  RunValidJsonTest(
-      "DoubleFieldNegativeInfinity", REQUIRED,
-      R"({"optionalDouble": "-Infinity"})",
-      "optional_double: -inf");
-  // Non-cannonical Nan will be correctly normalized.
-  {
-    TestAllTypesProto3 message;
-    message.set_optional_double(
-        WireFormatLite::DecodeDouble(0x7FFA123456789ABCLL));
-    RunValidJsonTestWithProtobufInput(
-        "DoubleFieldNormalizeQuietNan", REQUIRED, message,
-        "optional_double: nan");
-    message.set_optional_double(
-        WireFormatLite::DecodeDouble(0xFFFBCBA987654321LL));
-    RunValidJsonTestWithProtobufInput(
-        "DoubleFieldNormalizeSignalingNan", REQUIRED, message,
-        "optional_double: nan");
-  }
-
-  // Special values must be quoted.
-  ExpectParseFailureForJson(
-      "DoubleFieldNanNotQuoted", RECOMMENDED,
-      R"({"optionalDouble": NaN})");
-  ExpectParseFailureForJson(
-      "DoubleFieldInfinityNotQuoted", RECOMMENDED,
-      R"({"optionalDouble": Infinity})");
-  ExpectParseFailureForJson(
-      "DoubleFieldNegativeInfinityNotQuoted", RECOMMENDED,
-      R"({"optionalDouble": -Infinity})");
-
-  // Parsers should reject out-of-bound values.
-  ExpectParseFailureForJson(
-      "DoubleFieldTooSmall", REQUIRED,
-      R"({"optionalDouble": -1.89769e+308})");
-  ExpectParseFailureForJson(
-      "DoubleFieldTooLarge", REQUIRED,
-      R"({"optionalDouble": +1.89769e+308})");
-
-  // Enum fields.
-  RunValidJsonTest(
-      "EnumField", REQUIRED,
-      R"({"optionalNestedEnum": "FOO"})",
-      "optional_nested_enum: FOO");
-  // Enum values must be represented as strings.
-  ExpectParseFailureForJson(
-      "EnumFieldNotQuoted", REQUIRED,
-      R"({"optionalNestedEnum": FOO})");
-  // Numeric values are allowed.
-  RunValidJsonTest(
-      "EnumFieldNumericValueZero", REQUIRED,
-      R"({"optionalNestedEnum": 0})",
-      "optional_nested_enum: FOO");
-  RunValidJsonTest(
-      "EnumFieldNumericValueNonZero", REQUIRED,
-      R"({"optionalNestedEnum": 1})",
-      "optional_nested_enum: BAR");
-  // Unknown enum values are represented as numeric values.
-  RunValidJsonTestWithValidator(
-      "EnumFieldUnknownValue", REQUIRED,
-      R"({"optionalNestedEnum": 123})",
-      [](const Json::Value& value) {
-        return value["optionalNestedEnum"].type() == Json::intValue &&
-            value["optionalNestedEnum"].asInt() == 123;
-      });
-
-  // String fields.
-  RunValidJsonTest(
-      "StringField", REQUIRED,
-      R"({"optionalString": "Hello world!"})",
-      "optional_string: \"Hello world!\"");
-  RunValidJsonTest(
-      "StringFieldUnicode", REQUIRED,
-      // Google in Chinese.
-      R"({"optionalString": "谷歌"})",
-      R"(optional_string: "谷歌")");
-  RunValidJsonTest(
-      "StringFieldEscape", REQUIRED,
-      R"({"optionalString": "\"\\\/\b\f\n\r\t"})",
-      R"(optional_string: "\"\\/\b\f\n\r\t")");
-  RunValidJsonTest(
-      "StringFieldUnicodeEscape", REQUIRED,
-      R"({"optionalString": "\u8C37\u6B4C"})",
-      R"(optional_string: "谷歌")");
-  RunValidJsonTest(
-      "StringFieldUnicodeEscapeWithLowercaseHexLetters", REQUIRED,
-      R"({"optionalString": "\u8c37\u6b4c"})",
-      R"(optional_string: "谷歌")");
-  RunValidJsonTest(
-      "StringFieldSurrogatePair", REQUIRED,
-      // The character is an emoji: grinning face with smiling eyes. 😁
-      R"({"optionalString": "\uD83D\uDE01"})",
-      R"(optional_string: "\xF0\x9F\x98\x81")");
-
-  // Unicode escapes must start with "\u" (lowercase u).
-  ExpectParseFailureForJson(
-      "StringFieldUppercaseEscapeLetter", RECOMMENDED,
-      R"({"optionalString": "\U8C37\U6b4C"})");
-  ExpectParseFailureForJson(
-      "StringFieldInvalidEscape", RECOMMENDED,
-      R"({"optionalString": "\uXXXX\u6B4C"})");
-  ExpectParseFailureForJson(
-      "StringFieldUnterminatedEscape", RECOMMENDED,
-      R"({"optionalString": "\u8C3"})");
-  ExpectParseFailureForJson(
-      "StringFieldUnpairedHighSurrogate", RECOMMENDED,
-      R"({"optionalString": "\uD800"})");
-  ExpectParseFailureForJson(
-      "StringFieldUnpairedLowSurrogate", RECOMMENDED,
-      R"({"optionalString": "\uDC00"})");
-  ExpectParseFailureForJson(
-      "StringFieldSurrogateInWrongOrder", RECOMMENDED,
-      R"({"optionalString": "\uDE01\uD83D"})");
-  ExpectParseFailureForJson(
-      "StringFieldNotAString", REQUIRED,
-      R"({"optionalString": 12345})");
-
-  // Bytes fields.
-  RunValidJsonTest(
-      "BytesField", REQUIRED,
-      R"({"optionalBytes": "AQI="})",
-      R"(optional_bytes: "\x01\x02")");
-  RunValidJsonTest(
-      "BytesFieldBase64Url", RECOMMENDED,
-      R"({"optionalBytes": "-_"})",
-      R"(optional_bytes: "\xfb")");
-
-  // Message fields.
-  RunValidJsonTest(
-      "MessageField", REQUIRED,
-      R"({"optionalNestedMessage": {"a": 1234}})",
-      "optional_nested_message: {a: 1234}");
-
-  // Oneof fields.
-  ExpectParseFailureForJson(
-      "OneofFieldDuplicate", REQUIRED,
-      R"({"oneofUint32": 1, "oneofString": "test"})");
-  // Ensure zero values for oneof make it out/backs.
-  TestAllTypesProto3 messageProto3;
-  TestAllTypesProto2 messageProto2;
-  TestOneofMessage(messageProto3, true);
-  TestOneofMessage(messageProto2, false);
-  RunValidJsonTest(
-      "OneofZeroUint32", RECOMMENDED,
-      R"({"oneofUint32": 0})", "oneof_uint32: 0");
-  RunValidJsonTest(
-      "OneofZeroMessage", RECOMMENDED,
-      R"({"oneofNestedMessage": {}})", "oneof_nested_message: {}");
-  RunValidJsonTest(
-      "OneofZeroString", RECOMMENDED,
-      R"({"oneofString": ""})", "oneof_string: \"\"");
-  RunValidJsonTest(
-      "OneofZeroBytes", RECOMMENDED,
-      R"({"oneofBytes": ""})", "oneof_bytes: \"\"");
-  RunValidJsonTest(
-      "OneofZeroBool", RECOMMENDED,
-      R"({"oneofBool": false})", "oneof_bool: false");
-  RunValidJsonTest(
-      "OneofZeroUint64", RECOMMENDED,
-      R"({"oneofUint64": 0})", "oneof_uint64: 0");
-  RunValidJsonTest(
-      "OneofZeroFloat", RECOMMENDED,
-      R"({"oneofFloat": 0.0})", "oneof_float: 0");
-  RunValidJsonTest(
-      "OneofZeroDouble", RECOMMENDED,
-      R"({"oneofDouble": 0.0})", "oneof_double: 0");
-  RunValidJsonTest(
-      "OneofZeroEnum", RECOMMENDED,
-      R"({"oneofEnum":"FOO"})", "oneof_enum: FOO");
-
-  // Repeated fields.
-  RunValidJsonTest(
-      "PrimitiveRepeatedField", REQUIRED,
-      R"({"repeatedInt32": [1, 2, 3, 4]})",
-      "repeated_int32: [1, 2, 3, 4]");
-  RunValidJsonTest(
-      "EnumRepeatedField", REQUIRED,
-      R"({"repeatedNestedEnum": ["FOO", "BAR", "BAZ"]})",
-      "repeated_nested_enum: [FOO, BAR, BAZ]");
-  RunValidJsonTest(
-      "StringRepeatedField", REQUIRED,
-      R"({"repeatedString": ["Hello", "world"]})",
-      R"(repeated_string: ["Hello", "world"])");
-  RunValidJsonTest(
-      "BytesRepeatedField", REQUIRED,
-      R"({"repeatedBytes": ["AAEC", "AQI="]})",
-      R"(repeated_bytes: ["\x00\x01\x02", "\x01\x02"])");
-  RunValidJsonTest(
-      "MessageRepeatedField", REQUIRED,
-      R"({"repeatedNestedMessage": [{"a": 1234}, {"a": 5678}]})",
-      "repeated_nested_message: {a: 1234}"
-      "repeated_nested_message: {a: 5678}");
-
-  // Repeated field elements are of incorrect type.
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingIntegersGotBool", REQUIRED,
-      R"({"repeatedInt32": [1, false, 3, 4]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingIntegersGotString", REQUIRED,
-      R"({"repeatedInt32": [1, 2, "name", 4]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingIntegersGotMessage", REQUIRED,
-      R"({"repeatedInt32": [1, 2, 3, {"a": 4}]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingStringsGotInt", REQUIRED,
-      R"({"repeatedString": ["1", 2, "3", "4"]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingStringsGotBool", REQUIRED,
-      R"({"repeatedString": ["1", "2", false, "4"]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingStringsGotMessage", REQUIRED,
-      R"({"repeatedString": ["1", 2, "3", {"a": 4}]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingMessagesGotInt", REQUIRED,
-      R"({"repeatedNestedMessage": [{"a": 1}, 2]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingMessagesGotBool", REQUIRED,
-      R"({"repeatedNestedMessage": [{"a": 1}, false]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldWrongElementTypeExpectingMessagesGotString", REQUIRED,
-      R"({"repeatedNestedMessage": [{"a": 1}, "2"]})");
-  // Trailing comma in the repeated field is not allowed.
-  ExpectParseFailureForJson(
-      "RepeatedFieldTrailingComma", RECOMMENDED,
-      R"({"repeatedInt32": [1, 2, 3, 4,]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldTrailingCommaWithSpace", RECOMMENDED,
-      "{\"repeatedInt32\": [1, 2, 3, 4 ,]}");
-  ExpectParseFailureForJson(
-      "RepeatedFieldTrailingCommaWithSpaceCommaSpace", RECOMMENDED,
-      "{\"repeatedInt32\": [1, 2, 3, 4 , ]}");
-  ExpectParseFailureForJson(
-      "RepeatedFieldTrailingCommaWithNewlines", RECOMMENDED,
-      "{\"repeatedInt32\": [\n  1,\n  2,\n  3,\n  4,\n]}");
-
-  // Map fields.
-  RunValidJsonTest(
-      "Int32MapField", REQUIRED,
-      R"({"mapInt32Int32": {"1": 2, "3": 4}})",
-      "map_int32_int32: {key: 1 value: 2}"
-      "map_int32_int32: {key: 3 value: 4}");
-  ExpectParseFailureForJson(
-      "Int32MapFieldKeyNotQuoted", RECOMMENDED,
-      R"({"mapInt32Int32": {1: 2, 3: 4}})");
-  RunValidJsonTest(
-      "Uint32MapField", REQUIRED,
-      R"({"mapUint32Uint32": {"1": 2, "3": 4}})",
-      "map_uint32_uint32: {key: 1 value: 2}"
-      "map_uint32_uint32: {key: 3 value: 4}");
-  ExpectParseFailureForJson(
-      "Uint32MapFieldKeyNotQuoted", RECOMMENDED,
-      R"({"mapUint32Uint32": {1: 2, 3: 4}})");
-  RunValidJsonTest(
-      "Int64MapField", REQUIRED,
-      R"({"mapInt64Int64": {"1": 2, "3": 4}})",
-      "map_int64_int64: {key: 1 value: 2}"
-      "map_int64_int64: {key: 3 value: 4}");
-  ExpectParseFailureForJson(
-      "Int64MapFieldKeyNotQuoted", RECOMMENDED,
-      R"({"mapInt64Int64": {1: 2, 3: 4}})");
-  RunValidJsonTest(
-      "Uint64MapField", REQUIRED,
-      R"({"mapUint64Uint64": {"1": 2, "3": 4}})",
-      "map_uint64_uint64: {key: 1 value: 2}"
-      "map_uint64_uint64: {key: 3 value: 4}");
-  ExpectParseFailureForJson(
-      "Uint64MapFieldKeyNotQuoted", RECOMMENDED,
-      R"({"mapUint64Uint64": {1: 2, 3: 4}})");
-  RunValidJsonTest(
-      "BoolMapField", REQUIRED,
-      R"({"mapBoolBool": {"true": true, "false": false}})",
-      "map_bool_bool: {key: true value: true}"
-      "map_bool_bool: {key: false value: false}");
-  ExpectParseFailureForJson(
-      "BoolMapFieldKeyNotQuoted", RECOMMENDED,
-      R"({"mapBoolBool": {true: true, false: false}})");
-  RunValidJsonTest(
-      "MessageMapField", REQUIRED,
-      R"({
-        "mapStringNestedMessage": {
-          "hello": {"a": 1234},
-          "world": {"a": 5678}
-        }
-      })",
-      R"(
-        map_string_nested_message: {
-          key: "hello"
-          value: {a: 1234}
-        }
-        map_string_nested_message: {
-          key: "world"
-          value: {a: 5678}
-        }
-      )");
-  // Since Map keys are represented as JSON strings, escaping should be allowed.
-  RunValidJsonTest(
-      "Int32MapEscapedKey", REQUIRED,
-      R"({"mapInt32Int32": {"\u0031": 2}})",
-      "map_int32_int32: {key: 1 value: 2}");
-  RunValidJsonTest(
-      "Int64MapEscapedKey", REQUIRED,
-      R"({"mapInt64Int64": {"\u0031": 2}})",
-      "map_int64_int64: {key: 1 value: 2}");
-  RunValidJsonTest(
-      "BoolMapEscapedKey", REQUIRED,
-      R"({"mapBoolBool": {"tr\u0075e": true}})",
-      "map_bool_bool: {key: true value: true}");
-
-  // "null" is accepted for all fields types.
-  RunValidJsonTest(
-      "AllFieldAcceptNull", REQUIRED,
-      R"({
-        "optionalInt32": null,
-        "optionalInt64": null,
-        "optionalUint32": null,
-        "optionalUint64": null,
-        "optionalSint32": null,
-        "optionalSint64": null,
-        "optionalFixed32": null,
-        "optionalFixed64": null,
-        "optionalSfixed32": null,
-        "optionalSfixed64": null,
-        "optionalFloat": null,
-        "optionalDouble": null,
-        "optionalBool": null,
-        "optionalString": null,
-        "optionalBytes": null,
-        "optionalNestedEnum": null,
-        "optionalNestedMessage": null,
-        "repeatedInt32": null,
-        "repeatedInt64": null,
-        "repeatedUint32": null,
-        "repeatedUint64": null,
-        "repeatedSint32": null,
-        "repeatedSint64": null,
-        "repeatedFixed32": null,
-        "repeatedFixed64": null,
-        "repeatedSfixed32": null,
-        "repeatedSfixed64": null,
-        "repeatedFloat": null,
-        "repeatedDouble": null,
-        "repeatedBool": null,
-        "repeatedString": null,
-        "repeatedBytes": null,
-        "repeatedNestedEnum": null,
-        "repeatedNestedMessage": null,
-        "mapInt32Int32": null,
-        "mapBoolBool": null,
-        "mapStringNestedMessage": null
-      })",
-      "");
-
-  // Repeated field elements cannot be null.
-  ExpectParseFailureForJson(
-      "RepeatedFieldPrimitiveElementIsNull", RECOMMENDED,
-      R"({"repeatedInt32": [1, null, 2]})");
-  ExpectParseFailureForJson(
-      "RepeatedFieldMessageElementIsNull", RECOMMENDED,
-      R"({"repeatedNestedMessage": [{"a":1}, null, {"a":2}]})");
-  // Map field keys cannot be null.
-  ExpectParseFailureForJson(
-      "MapFieldKeyIsNull", RECOMMENDED,
-      R"({"mapInt32Int32": {null: 1}})");
-  // Map field values cannot be null.
-  ExpectParseFailureForJson(
-      "MapFieldValueIsNull", RECOMMENDED,
-      R"({"mapInt32Int32": {"0": null}})");
-
-  // http://www.rfc-editor.org/rfc/rfc7159.txt says strings have to use double
-  // quotes.
-  ExpectParseFailureForJson(
-      "StringFieldSingleQuoteKey", RECOMMENDED,
-      R"({'optionalString': "Hello world!"})");
-  ExpectParseFailureForJson(
-      "StringFieldSingleQuoteValue", RECOMMENDED,
-      R"({"optionalString": 'Hello world!'})");
-  ExpectParseFailureForJson(
-      "StringFieldSingleQuoteBoth", RECOMMENDED,
-      R"({'optionalString': 'Hello world!'})");
-
-  // Unknown fields.
-  {
-    TestAllTypesProto3 messageProto3;
-    TestAllTypesProto2 messageProto2;
-    //TODO(yilunchong): update this behavior when unknown field's behavior
-    // changed in open source. Also delete
-    // Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
-    // from failure list of python_cpp python java
-    TestUnknownMessage(messageProto3, true);
-    TestUnknownMessage(messageProto2, false);
-  }
-
-  // Wrapper types.
-  RunValidJsonTest(
-      "OptionalBoolWrapper", REQUIRED,
-      R"({"optionalBoolWrapper": false})",
-      "optional_bool_wrapper: {value: false}");
-  RunValidJsonTest(
-      "OptionalInt32Wrapper", REQUIRED,
-      R"({"optionalInt32Wrapper": 0})",
-      "optional_int32_wrapper: {value: 0}");
-  RunValidJsonTest(
-      "OptionalUint32Wrapper", REQUIRED,
-      R"({"optionalUint32Wrapper": 0})",
-      "optional_uint32_wrapper: {value: 0}");
-  RunValidJsonTest(
-      "OptionalInt64Wrapper", REQUIRED,
-      R"({"optionalInt64Wrapper": 0})",
-      "optional_int64_wrapper: {value: 0}");
-  RunValidJsonTest(
-      "OptionalUint64Wrapper", REQUIRED,
-      R"({"optionalUint64Wrapper": 0})",
-      "optional_uint64_wrapper: {value: 0}");
-  RunValidJsonTest(
-      "OptionalFloatWrapper", REQUIRED,
-      R"({"optionalFloatWrapper": 0})",
-      "optional_float_wrapper: {value: 0}");
-  RunValidJsonTest(
-      "OptionalDoubleWrapper", REQUIRED,
-      R"({"optionalDoubleWrapper": 0})",
-      "optional_double_wrapper: {value: 0}");
-  RunValidJsonTest(
-      "OptionalStringWrapper", REQUIRED,
-      R"({"optionalStringWrapper": ""})",
-      R"(optional_string_wrapper: {value: ""})");
-  RunValidJsonTest(
-      "OptionalBytesWrapper", REQUIRED,
-      R"({"optionalBytesWrapper": ""})",
-      R"(optional_bytes_wrapper: {value: ""})");
-  RunValidJsonTest(
-      "OptionalWrapperTypesWithNonDefaultValue", REQUIRED,
-      R"({
-        "optionalBoolWrapper": true,
-        "optionalInt32Wrapper": 1,
-        "optionalUint32Wrapper": 1,
-        "optionalInt64Wrapper": "1",
-        "optionalUint64Wrapper": "1",
-        "optionalFloatWrapper": 1,
-        "optionalDoubleWrapper": 1,
-        "optionalStringWrapper": "1",
-        "optionalBytesWrapper": "AQI="
-      })",
-      R"(
-        optional_bool_wrapper: {value: true}
-        optional_int32_wrapper: {value: 1}
-        optional_uint32_wrapper: {value: 1}
-        optional_int64_wrapper: {value: 1}
-        optional_uint64_wrapper: {value: 1}
-        optional_float_wrapper: {value: 1}
-        optional_double_wrapper: {value: 1}
-        optional_string_wrapper: {value: "1"}
-        optional_bytes_wrapper: {value: "\x01\x02"}
-      )");
-  RunValidJsonTest(
-      "RepeatedBoolWrapper", REQUIRED,
-      R"({"repeatedBoolWrapper": [true, false]})",
-      "repeated_bool_wrapper: {value: true}"
-      "repeated_bool_wrapper: {value: false}");
-  RunValidJsonTest(
-      "RepeatedInt32Wrapper", REQUIRED,
-      R"({"repeatedInt32Wrapper": [0, 1]})",
-      "repeated_int32_wrapper: {value: 0}"
-      "repeated_int32_wrapper: {value: 1}");
-  RunValidJsonTest(
-      "RepeatedUint32Wrapper", REQUIRED,
-      R"({"repeatedUint32Wrapper": [0, 1]})",
-      "repeated_uint32_wrapper: {value: 0}"
-      "repeated_uint32_wrapper: {value: 1}");
-  RunValidJsonTest(
-      "RepeatedInt64Wrapper", REQUIRED,
-      R"({"repeatedInt64Wrapper": [0, 1]})",
-      "repeated_int64_wrapper: {value: 0}"
-      "repeated_int64_wrapper: {value: 1}");
-  RunValidJsonTest(
-      "RepeatedUint64Wrapper", REQUIRED,
-      R"({"repeatedUint64Wrapper": [0, 1]})",
-      "repeated_uint64_wrapper: {value: 0}"
-      "repeated_uint64_wrapper: {value: 1}");
-  RunValidJsonTest(
-      "RepeatedFloatWrapper", REQUIRED,
-      R"({"repeatedFloatWrapper": [0, 1]})",
-      "repeated_float_wrapper: {value: 0}"
-      "repeated_float_wrapper: {value: 1}");
-  RunValidJsonTest(
-      "RepeatedDoubleWrapper", REQUIRED,
-      R"({"repeatedDoubleWrapper": [0, 1]})",
-      "repeated_double_wrapper: {value: 0}"
-      "repeated_double_wrapper: {value: 1}");
-  RunValidJsonTest(
-      "RepeatedStringWrapper", REQUIRED,
-      R"({"repeatedStringWrapper": ["", "AQI="]})",
-      R"(
-        repeated_string_wrapper: {value: ""}
-        repeated_string_wrapper: {value: "AQI="}
-      )");
-  RunValidJsonTest(
-      "RepeatedBytesWrapper", REQUIRED,
-      R"({"repeatedBytesWrapper": ["", "AQI="]})",
-      R"(
-        repeated_bytes_wrapper: {value: ""}
-        repeated_bytes_wrapper: {value: "\x01\x02"}
-      )");
-  RunValidJsonTest(
-      "WrapperTypesWithNullValue", REQUIRED,
-      R"({
-        "optionalBoolWrapper": null,
-        "optionalInt32Wrapper": null,
-        "optionalUint32Wrapper": null,
-        "optionalInt64Wrapper": null,
-        "optionalUint64Wrapper": null,
-        "optionalFloatWrapper": null,
-        "optionalDoubleWrapper": null,
-        "optionalStringWrapper": null,
-        "optionalBytesWrapper": null,
-        "repeatedBoolWrapper": null,
-        "repeatedInt32Wrapper": null,
-        "repeatedUint32Wrapper": null,
-        "repeatedInt64Wrapper": null,
-        "repeatedUint64Wrapper": null,
-        "repeatedFloatWrapper": null,
-        "repeatedDoubleWrapper": null,
-        "repeatedStringWrapper": null,
-        "repeatedBytesWrapper": null
-      })",
-      "");
-
-  // Duration
-  RunValidJsonTest(
-      "DurationMinValue", REQUIRED,
-      R"({"optionalDuration": "-315576000000.999999999s"})",
-      "optional_duration: {seconds: -315576000000 nanos: -999999999}");
-  RunValidJsonTest(
-      "DurationMaxValue", REQUIRED,
-      R"({"optionalDuration": "315576000000.999999999s"})",
-      "optional_duration: {seconds: 315576000000 nanos: 999999999}");
-  RunValidJsonTest(
-      "DurationRepeatedValue", REQUIRED,
-      R"({"repeatedDuration": ["1.5s", "-1.5s"]})",
-      "repeated_duration: {seconds: 1 nanos: 500000000}"
-      "repeated_duration: {seconds: -1 nanos: -500000000}");
-  RunValidJsonTest(
-      "DurationNull", REQUIRED,
-      R"({"optionalDuration": null})",
-      "");
-
-  ExpectParseFailureForJson(
-      "DurationMissingS", REQUIRED,
-      R"({"optionalDuration": "1"})");
-  ExpectParseFailureForJson(
-      "DurationJsonInputTooSmall", REQUIRED,
-      R"({"optionalDuration": "-315576000001.000000000s"})");
-  ExpectParseFailureForJson(
-      "DurationJsonInputTooLarge", REQUIRED,
-      R"({"optionalDuration": "315576000001.000000000s"})");
-  ExpectSerializeFailureForJson(
-      "DurationProtoInputTooSmall", REQUIRED,
-      "optional_duration: {seconds: -315576000001 nanos: 0}");
-  ExpectSerializeFailureForJson(
-      "DurationProtoInputTooLarge", REQUIRED,
-      "optional_duration: {seconds: 315576000001 nanos: 0}");
-
-  RunValidJsonTestWithValidator(
-      "DurationHasZeroFractionalDigit", RECOMMENDED,
-      R"({"optionalDuration": "1.000000000s"})",
-      [](const Json::Value& value) {
-        return value["optionalDuration"].asString() == "1s";
-      });
-  RunValidJsonTestWithValidator(
-      "DurationHas3FractionalDigits", RECOMMENDED,
-      R"({"optionalDuration": "1.010000000s"})",
-      [](const Json::Value& value) {
-        return value["optionalDuration"].asString() == "1.010s";
-      });
-  RunValidJsonTestWithValidator(
-      "DurationHas6FractionalDigits", RECOMMENDED,
-      R"({"optionalDuration": "1.000010000s"})",
-      [](const Json::Value& value) {
-        return value["optionalDuration"].asString() == "1.000010s";
-      });
-  RunValidJsonTestWithValidator(
-      "DurationHas9FractionalDigits", RECOMMENDED,
-      R"({"optionalDuration": "1.000000010s"})",
-      [](const Json::Value& value) {
-        return value["optionalDuration"].asString() == "1.000000010s";
-      });
-
-  // Timestamp
-  RunValidJsonTest(
-      "TimestampMinValue", REQUIRED,
-      R"({"optionalTimestamp": "0001-01-01T00:00:00Z"})",
-      "optional_timestamp: {seconds: -62135596800}");
-  RunValidJsonTest(
-      "TimestampMaxValue", REQUIRED,
-      R"({"optionalTimestamp": "9999-12-31T23:59:59.999999999Z"})",
-      "optional_timestamp: {seconds: 253402300799 nanos: 999999999}");
-  RunValidJsonTest(
-      "TimestampRepeatedValue", REQUIRED,
-      R"({
-        "repeatedTimestamp": [
-          "0001-01-01T00:00:00Z",
-          "9999-12-31T23:59:59.999999999Z"
-        ]
-      })",
-      "repeated_timestamp: {seconds: -62135596800}"
-      "repeated_timestamp: {seconds: 253402300799 nanos: 999999999}");
-  RunValidJsonTest(
-      "TimestampWithPositiveOffset", REQUIRED,
-      R"({"optionalTimestamp": "1970-01-01T08:00:00+08:00"})",
-      "optional_timestamp: {seconds: 0}");
-  RunValidJsonTest(
-      "TimestampWithNegativeOffset", REQUIRED,
-      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
-      "optional_timestamp: {seconds: 0}");
-  RunValidJsonTest(
-      "TimestampNull", REQUIRED,
-      R"({"optionalTimestamp": null})",
-      "");
-
-  ExpectParseFailureForJson(
-      "TimestampJsonInputTooSmall", REQUIRED,
-      R"({"optionalTimestamp": "0000-01-01T00:00:00Z"})");
-  ExpectParseFailureForJson(
-      "TimestampJsonInputTooLarge", REQUIRED,
-      R"({"optionalTimestamp": "10000-01-01T00:00:00Z"})");
-  ExpectParseFailureForJson(
-      "TimestampJsonInputMissingZ", REQUIRED,
-      R"({"optionalTimestamp": "0001-01-01T00:00:00"})");
-  ExpectParseFailureForJson(
-      "TimestampJsonInputMissingT", REQUIRED,
-      R"({"optionalTimestamp": "0001-01-01 00:00:00Z"})");
-  ExpectParseFailureForJson(
-      "TimestampJsonInputLowercaseZ", REQUIRED,
-      R"({"optionalTimestamp": "0001-01-01T00:00:00z"})");
-  ExpectParseFailureForJson(
-      "TimestampJsonInputLowercaseT", REQUIRED,
-      R"({"optionalTimestamp": "0001-01-01t00:00:00Z"})");
-  ExpectSerializeFailureForJson(
-      "TimestampProtoInputTooSmall", REQUIRED,
-      "optional_timestamp: {seconds: -62135596801}");
-  ExpectSerializeFailureForJson(
-      "TimestampProtoInputTooLarge", REQUIRED,
-      "optional_timestamp: {seconds: 253402300800}");
-  RunValidJsonTestWithValidator(
-      "TimestampZeroNormalized", RECOMMENDED,
-      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
-      [](const Json::Value& value) {
-        return value["optionalTimestamp"].asString() ==
-            "1970-01-01T00:00:00Z";
-      });
-  RunValidJsonTestWithValidator(
-      "TimestampHasZeroFractionalDigit", RECOMMENDED,
-      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000000Z"})",
-      [](const Json::Value& value) {
-        return value["optionalTimestamp"].asString() ==
-            "1970-01-01T00:00:00Z";
-      });
-  RunValidJsonTestWithValidator(
-      "TimestampHas3FractionalDigits", RECOMMENDED,
-      R"({"optionalTimestamp": "1970-01-01T00:00:00.010000000Z"})",
-      [](const Json::Value& value) {
-        return value["optionalTimestamp"].asString() ==
-            "1970-01-01T00:00:00.010Z";
-      });
-  RunValidJsonTestWithValidator(
-      "TimestampHas6FractionalDigits", RECOMMENDED,
-      R"({"optionalTimestamp": "1970-01-01T00:00:00.000010000Z"})",
-      [](const Json::Value& value) {
-        return value["optionalTimestamp"].asString() ==
-            "1970-01-01T00:00:00.000010Z";
-      });
-  RunValidJsonTestWithValidator(
-      "TimestampHas9FractionalDigits", RECOMMENDED,
-      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000010Z"})",
-      [](const Json::Value& value) {
-        return value["optionalTimestamp"].asString() ==
-            "1970-01-01T00:00:00.000000010Z";
-      });
-
-  // FieldMask
-  RunValidJsonTest(
-      "FieldMask", REQUIRED,
-      R"({"optionalFieldMask": "foo,barBaz"})",
-      R"(optional_field_mask: {paths: "foo" paths: "bar_baz"})");
-  ExpectParseFailureForJson(
-      "FieldMaskInvalidCharacter", RECOMMENDED,
-      R"({"optionalFieldMask": "foo,bar_bar"})");
-  ExpectSerializeFailureForJson(
-      "FieldMaskPathsDontRoundTrip", RECOMMENDED,
-      R"(optional_field_mask: {paths: "fooBar"})");
-  ExpectSerializeFailureForJson(
-      "FieldMaskNumbersDontRoundTrip", RECOMMENDED,
-      R"(optional_field_mask: {paths: "foo_3_bar"})");
-  ExpectSerializeFailureForJson(
-      "FieldMaskTooManyUnderscore", RECOMMENDED,
-      R"(optional_field_mask: {paths: "foo__bar"})");
-
-  // Struct
-  RunValidJsonTest(
-      "Struct", REQUIRED,
-      R"({
-        "optionalStruct": {
-          "nullValue": null,
-          "intValue": 1234,
-          "boolValue": true,
-          "doubleValue": 1234.5678,
-          "stringValue": "Hello world!",
-          "listValue": [1234, "5678"],
-          "objectValue": {
-            "value": 0
-          }
-        }
-      })",
-      R"(
-        optional_struct: {
-          fields: {
-            key: "nullValue"
-            value: {null_value: NULL_VALUE}
-          }
-          fields: {
-            key: "intValue"
-            value: {number_value: 1234}
-          }
-          fields: {
-            key: "boolValue"
-            value: {bool_value: true}
-          }
-          fields: {
-            key: "doubleValue"
-            value: {number_value: 1234.5678}
-          }
-          fields: {
-            key: "stringValue"
-            value: {string_value: "Hello world!"}
-          }
-          fields: {
-            key: "listValue"
-            value: {
-              list_value: {
-                values: {
-                  number_value: 1234
-                }
-                values: {
-                  string_value: "5678"
-                }
-              }
-            }
-          }
-          fields: {
-            key: "objectValue"
-            value: {
-              struct_value: {
-                fields: {
-                  key: "value"
-                  value: {
-                    number_value: 0
-                  }
-                }
-              }
-            }
-          }
-        }
-      )");
-  // Value
-  RunValidJsonTest(
-      "ValueAcceptInteger", REQUIRED,
-      R"({"optionalValue": 1})",
-      "optional_value: { number_value: 1}");
-  RunValidJsonTest(
-      "ValueAcceptFloat", REQUIRED,
-      R"({"optionalValue": 1.5})",
-      "optional_value: { number_value: 1.5}");
-  RunValidJsonTest(
-      "ValueAcceptBool", REQUIRED,
-      R"({"optionalValue": false})",
-      "optional_value: { bool_value: false}");
-  RunValidJsonTest(
-      "ValueAcceptNull", REQUIRED,
-      R"({"optionalValue": null})",
-      "optional_value: { null_value: NULL_VALUE}");
-  RunValidJsonTest(
-      "ValueAcceptString", REQUIRED,
-      R"({"optionalValue": "hello"})",
-      R"(optional_value: { string_value: "hello"})");
-  RunValidJsonTest(
-      "ValueAcceptList", REQUIRED,
-      R"({"optionalValue": [0, "hello"]})",
-      R"(
-        optional_value: {
-          list_value: {
-            values: {
-              number_value: 0
-            }
-            values: {
-              string_value: "hello"
-            }
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "ValueAcceptListWithNull", REQUIRED,
-      R"({"optionalValue": ["x", null, "y"]})",
-      R"(
-        optional_value: {
-          list_value: {
-            values: {
-              string_value: "x"
-            }
-            values: {
-              null_value: NULL_VALUE
-            }
-            values: {
-              string_value: "y"
-            }
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "ValueAcceptObject", REQUIRED,
-      R"({"optionalValue": {"value": 1}})",
-      R"(
-        optional_value: {
-          struct_value: {
-            fields: {
-              key: "value"
-              value: {
-                number_value: 1
-              }
-            }
-          }
-        }
-      )");
-
-  // Any
-  RunValidJsonTest(
-      "Any", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3",
-          "optionalInt32": 12345
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
-            optional_int32: 12345
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyNested", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Any",
-          "value": {
-            "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3",
-            "optionalInt32": 12345
-          }
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Any] {
-            [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
-              optional_int32: 12345
-            }
-          }
-        }
-      )");
-  // The special "@type" tag is not required to appear first.
-  RunValidJsonTest(
-      "AnyUnorderedTypeTag", REQUIRED,
-      R"({
-        "optionalAny": {
-          "optionalInt32": 12345,
-          "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
-            optional_int32: 12345
-          }
-        }
-      )");
-  // Well-known types in Any.
-  RunValidJsonTest(
-      "AnyWithInt32ValueWrapper", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Int32Value",
-          "value": 12345
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Int32Value] {
-            value: 12345
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyWithDuration", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Duration",
-          "value": "1.5s"
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Duration] {
-            seconds: 1
-            nanos: 500000000
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyWithTimestamp", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Timestamp",
-          "value": "1970-01-01T00:00:00Z"
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Timestamp] {
-            seconds: 0
-            nanos: 0
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyWithFieldMask", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.FieldMask",
-          "value": "foo,barBaz"
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.FieldMask] {
-            paths: ["foo", "bar_baz"]
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyWithStruct", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Struct",
-          "value": {
-            "foo": 1
-          }
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Struct] {
-            fields: {
-              key: "foo"
-              value: {
-                number_value: 1
-              }
-            }
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyWithValueForJsonObject", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Value",
-          "value": {
-            "foo": 1
-          }
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Value] {
-            struct_value: {
-              fields: {
-                key: "foo"
-                value: {
-                  number_value: 1
-                }
-              }
-            }
-          }
-        }
-      )");
-  RunValidJsonTest(
-      "AnyWithValueForInteger", REQUIRED,
-      R"({
-        "optionalAny": {
-          "@type": "type.googleapis.com/google.protobuf.Value",
-          "value": 1
-        }
-      })",
-      R"(
-        optional_any: {
-          [type.googleapis.com/google.protobuf.Value] {
-            number_value: 1
-          }
-        }
-      )");
-
-  RunValidJsonIgnoreUnknownTest(
-      "IgnoreUnknownJsonNumber", REQUIRED,
-      R"({
-        "unknown": 1
-      })",
-      "");
-  RunValidJsonIgnoreUnknownTest(
-      "IgnoreUnknownJsonString", REQUIRED,
-      R"({
-        "unknown": "a"
-      })",
-      "");
-  RunValidJsonIgnoreUnknownTest(
-      "IgnoreUnknownJsonTrue", REQUIRED,
-      R"({
-        "unknown": true
-      })",
-      "");
-  RunValidJsonIgnoreUnknownTest(
-      "IgnoreUnknownJsonFalse", REQUIRED,
-      R"({
-        "unknown": false
-      })",
-      "");
-  RunValidJsonIgnoreUnknownTest(
-      "IgnoreUnknownJsonNull", REQUIRED,
-      R"({
-        "unknown": null
-      })",
-      "");
-  RunValidJsonIgnoreUnknownTest(
-      "IgnoreUnknownJsonObject", REQUIRED,
-      R"({
-        "unknown": {"a": 1}
-      })",
-      "");
+  RunSuiteImpl();
 
 
   bool ok = true;
   bool ok = true;
   if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt",
   if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt",

+ 64 - 91
conformance/conformance_test.h

@@ -40,12 +40,13 @@
 
 
 #include <functional>
 #include <functional>
 #include <string>
 #include <string>
+
+#include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/wire_format_lite.h>
 
 
 #include "conformance.pb.h"
 #include "conformance.pb.h"
-#include "third_party/jsoncpp/json.h"
 
 
 namespace conformance {
 namespace conformance {
 class ConformanceRequest;
 class ConformanceRequest;
@@ -78,7 +79,23 @@ class ConformanceTestRunner {
 };
 };
 
 
 // Class representing the test suite itself.  To run it, implement your own
 // Class representing the test suite itself.  To run it, implement your own
-// class derived from ConformanceTestRunner and then write code like:
+// class derived from ConformanceTestRunner, class derived from
+// ConformanceTestSuite and then write code like:
+//
+//    class MyConformanceTestSuite : public ConformanceTestSuite {
+//     public:
+//      void RunSuiteImpl() {
+//        // INSERT ACTURAL TESTS.
+//      }
+//    };
+//
+//    // Force MyConformanceTestSuite to be added at dynamic initialization
+//    // time.
+//    struct StaticTestSuiteInitializer {
+//      StaticTestSuiteInitializer() {
+//        AddTestSuite(new MyConformanceTestSuite());
+//      }
+//    } static_test_suite_initializer;
 //
 //
 //    class MyConformanceTestRunner : public ConformanceTestRunner {
 //    class MyConformanceTestRunner : public ConformanceTestRunner {
 //     public:
 //     public:
@@ -89,15 +106,17 @@ class ConformanceTestRunner {
 //
 //
 //    int main() {
 //    int main() {
 //      MyConformanceTestRunner runner;
 //      MyConformanceTestRunner runner;
-//      google::protobuf::ConformanceTestSuite suite;
-//
-//      std::string output;
-//      suite.RunSuite(&runner, &output);
+//      const std::set<ConformanceTestSuite*>& test_suite_set =
+//          ::google::protobuf::GetTestSuiteSet();
+//      for (auto suite : test_suite_set) {
+//        suite->RunSuite(&runner, &output);
+//      }
 //    }
 //    }
 //
 //
 class ConformanceTestSuite {
 class ConformanceTestSuite {
  public:
  public:
   ConformanceTestSuite() : verbose_(false), enforce_recommended_(false) {}
   ConformanceTestSuite() : verbose_(false), enforce_recommended_(false) {}
+  virtual ~ConformanceTestSuite() {}
 
 
   void SetVerbose(bool verbose) { verbose_ = verbose; }
   void SetVerbose(bool verbose) { verbose_ = verbose; }
 
 
@@ -130,7 +149,7 @@ class ConformanceTestSuite {
   // tests passed.
   // tests passed.
   bool RunSuite(ConformanceTestRunner* runner, std::string* output);
   bool RunSuite(ConformanceTestRunner* runner, std::string* output);
 
 
- private:
+ protected:
   // Test cases are classified into a few categories:
   // Test cases are classified into a few categories:
   //   REQUIRED: the test case must be passed for an implementation to be
   //   REQUIRED: the test case must be passed for an implementation to be
   //             interoperable with other implementations. For example, a
   //             interoperable with other implementations. For example, a
@@ -151,38 +170,43 @@ class ConformanceTestSuite {
   class ConformanceRequestSetting {
   class ConformanceRequestSetting {
    public:
    public:
     ConformanceRequestSetting(
     ConformanceRequestSetting(
-        ConformanceLevel level, conformance::WireFormat input_format,
-        conformance::WireFormat output_format, bool is_proto3,
+        ConformanceLevel level,
+        conformance::WireFormat input_format,
+        conformance::WireFormat output_format,
+        conformance::TestCategory test_category,
+        const Message& prototype_message,
         const string& test_name, const string& input);
         const string& test_name, const string& input);
+    virtual ~ConformanceRequestSetting() {}
+
+    Message* GetTestMessage() const;
 
 
-   Message* GetTestMessage() const;
+    string GetTestName() const;
 
 
-   const string& GetTestName() const {
-     return test_name_;
-   }
+    const conformance::ConformanceRequest& GetRequest() const {
+      return request_;
+    }
 
 
-   const conformance::ConformanceRequest& GetRequest() const {
-     return request_;
-   }
+    const ConformanceLevel GetLevel() const {
+      return level_;
+    }
 
 
-   const ConformanceLevel GetLevel() const {
-     return level_;
-   }
+    string ConformanceLevelToString(ConformanceLevel level) const;
+
+   protected:
+    virtual string InputFormatString(conformance::WireFormat format) const;
+    virtual string OutputFormatString(conformance::WireFormat format) const;
 
 
-   void SetIgnoreUnknownJson(bool ignore_unknown_json) {
-     request_.set_ignore_unknown_json(ignore_unknown_json);
-   }
-  
    private:
    private:
     ConformanceLevel level_;
     ConformanceLevel level_;
-    conformance::WireFormat input_format_;
-    conformance::WireFormat output_format_;
-    bool is_proto3_;
+    ::conformance::WireFormat input_format_;
+    ::conformance::WireFormat output_format_;
+    const Message& prototype_message_;
     string test_name_;
     string test_name_;
     conformance::ConformanceRequest request_;
     conformance::ConformanceRequest request_;
   };
   };
 
 
-  static string ConformanceLevelToString(ConformanceLevel level);
+  bool CheckSetEmpty(const std::set<string>& set_to_check,
+                     const std::string& write_to_file, const std::string& msg);
 
 
   void ReportSuccess(const std::string& test_name);
   void ReportSuccess(const std::string& test_name);
   void ReportFailure(const string& test_name,
   void ReportFailure(const string& test_name,
@@ -193,73 +217,18 @@ class ConformanceTestSuite {
   void ReportSkip(const string& test_name,
   void ReportSkip(const string& test_name,
                   const conformance::ConformanceRequest& request,
                   const conformance::ConformanceRequest& request,
                   const conformance::ConformanceResponse& response);
                   const conformance::ConformanceResponse& response);
-  void RunTest(const std::string& test_name,
-               const conformance::ConformanceRequest& request,
-               conformance::ConformanceResponse* response);
+
   void RunValidInputTest(const ConformanceRequestSetting& setting,
   void RunValidInputTest(const ConformanceRequestSetting& setting,
                          const string& equivalent_text_format);
                          const string& equivalent_text_format);
   void RunValidBinaryInputTest(const ConformanceRequestSetting& setting,
   void RunValidBinaryInputTest(const ConformanceRequestSetting& setting,
                                const string& equivalent_wire_format);
                                const string& equivalent_wire_format);
-  void RunValidJsonTest(const string& test_name,
-                        ConformanceLevel level,
-                        const string& input_json,
-                        const string& equivalent_text_format);
-  void RunValidJsonIgnoreUnknownTest(
-      const string& test_name, ConformanceLevel level, const string& input_json,
-      const string& equivalent_text_format);
-  void RunValidJsonTestWithProtobufInput(
-      const string& test_name,
-      ConformanceLevel level,
-      const protobuf_test_messages::proto3::TestAllTypesProto3& input,
-      const string& equivalent_text_format);
-  void RunValidProtobufTest(const string& test_name, ConformanceLevel level,
-                            const string& input_protobuf,
-                            const string& equivalent_text_format,
-                            bool isProto3);
-  void RunValidBinaryProtobufTest(const string& test_name,
-                                  ConformanceLevel level,
-                                  const string& input_protobuf,
-                                  bool isProto3);
-  void RunValidProtobufTestWithMessage(
-      const string& test_name, ConformanceLevel level,
-      const Message *input,
-      const string& equivalent_text_format,
-      bool isProto3);
-
-  typedef std::function<bool(const Json::Value&)> Validator;
-  void RunValidJsonTestWithValidator(const string& test_name,
-                                     ConformanceLevel level,
-                                     const string& input_json,
-                                     const Validator& validator);
-  void ExpectParseFailureForJson(const string& test_name,
-                                 ConformanceLevel level,
-                                 const string& input_json);
-  void ExpectSerializeFailureForJson(const string& test_name,
-                                     ConformanceLevel level,
-                                     const string& text_format);
-  void ExpectParseFailureForProtoWithProtoVersion (const string& proto,
-                                                   const string& test_name,
-                                                   ConformanceLevel level,
-                                                   bool isProto3);
-  void ExpectParseFailureForProto(const std::string& proto,
-                                  const std::string& test_name,
-                                  ConformanceLevel level);
-  void ExpectHardParseFailureForProto(const std::string& proto,
-                                      const std::string& test_name,
-                                      ConformanceLevel level);
-  void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
-  void TestIllegalTags();
-  template <class MessageType>
-  void TestOneofMessage (MessageType &message,
-                         bool isProto3);
-  template <class MessageType>
-  void TestUnknownMessage (MessageType &message,
-                           bool isProto3);
-  void TestValidDataForType(
-      google::protobuf::FieldDescriptor::Type,
-      std::vector<std::pair<std::string, std::string>> values);
-  bool CheckSetEmpty(const std::set<string>& set_to_check,
-                     const std::string& write_to_file, const std::string& msg);
+
+  void RunTest(const std::string& test_name,
+               const conformance::ConformanceRequest& request,
+               conformance::ConformanceResponse* response);
+
+  virtual void RunSuiteImpl() = 0;
+
   ConformanceTestRunner* runner_;
   ConformanceTestRunner* runner_;
   int successes_;
   int successes_;
   int expected_failures_;
   int expected_failures_;
@@ -285,10 +254,14 @@ class ConformanceTestSuite {
   // The set of tests that the testee opted out of;
   // The set of tests that the testee opted out of;
   std::set<std::string> skipped_;
   std::set<std::string> skipped_;
 
 
-  std::unique_ptr<google::protobuf::util::TypeResolver> type_resolver_;
+  std::unique_ptr<google::protobuf::util::TypeResolver>
+      type_resolver_;
   std::string type_url_;
   std::string type_url_;
 };
 };
 
 
+void AddTestSuite(ConformanceTestSuite* suite);
+const std::set<ConformanceTestSuite*>& GetTestSuiteSet();
+
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
 
 

+ 2368 - 0
conformance/conformance_test_impl.cc

@@ -0,0 +1,2368 @@
+// 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.
+
+#include "conformance_test.h"
+#include "third_party/jsoncpp/json.h"
+
+#include <google/protobuf/test_messages_proto3.pb.h>
+#include <google/protobuf/test_messages_proto2.pb.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/type_resolver_util.h>
+#include <google/protobuf/wire_format_lite.h>
+
+using conformance::ConformanceRequest;
+using conformance::ConformanceResponse;
+using google::protobuf::Descriptor;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::Message;
+using google::protobuf::internal::WireFormatLite;
+using google::protobuf::TextFormat;
+using google::protobuf::util::NewTypeResolverForDescriptorPool;
+using protobuf_test_messages::proto3::TestAllTypesProto3;
+using protobuf_test_messages::proto2::TestAllTypesProto2;
+using std::string;
+
+namespace {
+
+static const char kTypeUrlPrefix[] = "type.googleapis.com";
+
+static string GetTypeUrl(const Descriptor* message) {
+  return string(kTypeUrlPrefix) + "/" + message->full_name();
+}
+
+/* Routines for building arbitrary protos *************************************/
+
+// We would use CodedOutputStream except that we want more freedom to build
+// arbitrary protos (even invalid ones).
+
+const string empty;
+
+string cat(const string& a, const string& b,
+           const string& c = empty,
+           const string& d = empty,
+           const string& e = empty,
+           const string& f = empty,
+           const string& g = empty,
+           const string& h = empty,
+           const string& i = empty,
+           const string& j = empty,
+           const string& k = empty,
+           const string& l = empty) {
+  string ret;
+  ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() +
+              g.size() + h.size() + i.size() + j.size() + k.size() + l.size());
+  ret.append(a);
+  ret.append(b);
+  ret.append(c);
+  ret.append(d);
+  ret.append(e);
+  ret.append(f);
+  ret.append(g);
+  ret.append(h);
+  ret.append(i);
+  ret.append(j);
+  ret.append(k);
+  ret.append(l);
+  return ret;
+}
+
+// The maximum number of bytes that it takes to encode a 64-bit varint.
+#define VARINT_MAX_LEN 10
+
+size_t vencode64(uint64_t val, int over_encoded_bytes, char *buf) {
+  if (val == 0) { buf[0] = 0; return 1; }
+  size_t i = 0;
+  while (val) {
+    uint8_t byte = val & 0x7fU;
+    val >>= 7;
+    if (val || over_encoded_bytes) byte |= 0x80U;
+    buf[i++] = byte;
+  }
+  while (over_encoded_bytes--) {
+    assert(i < 10);
+    uint8_t byte = over_encoded_bytes ? 0x80 : 0;
+    buf[i++] = byte;
+  }
+  return i;
+}
+
+string varint(uint64_t x) {
+  char buf[VARINT_MAX_LEN];
+  size_t len = vencode64(x, 0, buf);
+  return string(buf, len);
+}
+
+// Encodes a varint that is |extra| bytes longer than it needs to be, but still
+// valid.
+string longvarint(uint64_t x, int extra) {
+  char buf[VARINT_MAX_LEN];
+  size_t len = vencode64(x, extra, buf);
+  return string(buf, len);
+}
+
+// TODO: proper byte-swapping for big-endian machines.
+string fixed32(void *data) { return string(static_cast<char*>(data), 4); }
+string fixed64(void *data) { return string(static_cast<char*>(data), 8); }
+
+string delim(const string& buf) { return cat(varint(buf.size()), buf); }
+string u32(uint32_t u32) { return fixed32(&u32); }
+string u64(uint64_t u64) { return fixed64(&u64); }
+string flt(float f) { return fixed32(&f); }
+string dbl(double d) { return fixed64(&d); }
+string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); }
+string zz64(int64_t x) { return varint(WireFormatLite::ZigZagEncode64(x)); }
+
+string tag(uint32_t fieldnum, char wire_type) {
+  return varint((fieldnum << 3) | wire_type);
+}
+
+string submsg(uint32_t fn, const string& buf) {
+  return cat( tag(fn, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), delim(buf) );
+}
+
+#define UNKNOWN_FIELD 666
+
+const FieldDescriptor* GetFieldForType(FieldDescriptor::Type type,
+                                       bool repeated, bool is_proto3) {
+
+  const Descriptor* d = is_proto3 ?
+      TestAllTypesProto3().GetDescriptor() : TestAllTypesProto2().GetDescriptor();
+  for (int i = 0; i < d->field_count(); i++) {
+    const FieldDescriptor* f = d->field(i);
+    if (f->type() == type && f->is_repeated() == repeated) {
+      return f;
+    }
+  }
+  GOOGLE_LOG(FATAL) << "Couldn't find field with type " << (int)type;
+  return nullptr;
+}
+
+string UpperCase(string str) {
+  for (int i = 0; i < str.size(); i++) {
+    str[i] = toupper(str[i]);
+  }
+  return str;
+}
+
+std::unique_ptr<Message> NewTestMessage(bool is_proto3) {
+  std::unique_ptr<Message> prototype;
+  if (is_proto3) {
+    prototype.reset(new TestAllTypesProto3());
+  } else {
+    prototype.reset(new TestAllTypesProto2());
+  }
+  return prototype;
+}
+
+}  // anonymous namespace
+
+namespace google {
+namespace protobuf {
+
+class ConformanceTestSuiteImpl : public ConformanceTestSuite {
+ public:
+  ConformanceTestSuiteImpl() {}
+
+ private:
+  void RunSuiteImpl();
+  void RunValidJsonTest(const string& test_name,
+                        ConformanceLevel level,
+                        const string& input_json,
+                        const string& equivalent_text_format);
+  void RunValidJsonTestWithProtobufInput(
+      const string& test_name,
+      ConformanceLevel level,
+      const protobuf_test_messages::proto3::TestAllTypesProto3& input,
+      const string& equivalent_text_format);
+  void RunValidJsonIgnoreUnknownTest(
+      const string& test_name, ConformanceLevel level, const string& input_json,
+      const string& equivalent_text_format);
+  void RunValidProtobufTest(const string& test_name, ConformanceLevel level,
+                            const string& input_protobuf,
+                            const string& equivalent_text_format,
+                            bool is_proto3);
+  void RunValidBinaryProtobufTest(const string& test_name,
+                                  ConformanceLevel level,
+                                  const string& input_protobuf,
+                                  bool is_proto3);
+  void RunValidProtobufTestWithMessage(
+      const string& test_name, ConformanceLevel level,
+      const Message *input,
+      const string& equivalent_text_format,
+      bool is_proto3);
+
+  typedef std::function<bool(const Json::Value&)> Validator;
+  void RunValidJsonTestWithValidator(const string& test_name,
+                                     ConformanceLevel level,
+                                     const string& input_json,
+                                     const Validator& validator);
+  void ExpectParseFailureForJson(const string& test_name,
+                                 ConformanceLevel level,
+                                 const string& input_json);
+  void ExpectSerializeFailureForJson(const string& test_name,
+                                     ConformanceLevel level,
+                                     const string& text_format);
+  void ExpectParseFailureForProtoWithProtoVersion (const string& proto,
+                                                   const string& test_name,
+                                                   ConformanceLevel level,
+                                                   bool is_proto3);
+  void ExpectParseFailureForProto(const std::string& proto,
+                                  const std::string& test_name,
+                                  ConformanceLevel level);
+  void ExpectHardParseFailureForProto(const std::string& proto,
+                                      const std::string& test_name,
+                                      ConformanceLevel level);
+  void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
+  void TestIllegalTags();
+  template <class MessageType>
+  void TestOneofMessage (MessageType &message,
+                         bool is_proto3);
+  template <class MessageType>
+  void TestUnknownMessage (MessageType &message,
+                           bool is_proto3);
+  void TestValidDataForType(
+      google::protobuf::FieldDescriptor::Type,
+      std::vector<std::pair<std::string, std::string>> values);
+};
+
+void ConformanceTestSuiteImpl::ExpectParseFailureForProtoWithProtoVersion (
+    const string& proto, const string& test_name, ConformanceLevel level,
+    bool is_proto3) {
+  std::unique_ptr<Message> prototype = NewTestMessage(is_proto3);
+  // We don't expect output, but if the program erroneously accepts the protobuf
+  // we let it send its response as this.  We must not leave it unspecified.
+  ConformanceRequestSetting setting(
+      level, conformance::PROTOBUF, conformance::PROTOBUF,
+      conformance::BINARY_TEST,
+      *prototype, test_name, proto);
+
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  string effective_test_name =
+      StrCat(setting.ConformanceLevelToString(level),
+             (is_proto3 ? ".Proto3" : ".Proto2"),
+             ".ProtobufInput.", test_name);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, level, request, response,
+                  "Should have failed to parse, but didn't.");
+  }
+}
+
+// Expect that this precise protobuf will cause a parse error.
+void ConformanceTestSuiteImpl::ExpectParseFailureForProto(
+    const string& proto, const string& test_name, ConformanceLevel level) {
+  ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, true);
+  ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, false);
+}
+
+// Expect that this protobuf will cause a parse error, even if it is followed
+// by valid protobuf data.  We can try running this twice: once with this
+// data verbatim and once with this data followed by some valid data.
+//
+// TODO(haberman): implement the second of these.
+void ConformanceTestSuiteImpl::ExpectHardParseFailureForProto(
+    const string& proto, const string& test_name, ConformanceLevel level) {
+  return ExpectParseFailureForProto(proto, test_name, level);
+}
+
+void ConformanceTestSuiteImpl::RunValidJsonTest(
+    const string& test_name, ConformanceLevel level, const string& input_json,
+    const string& equivalent_text_format) {
+  TestAllTypesProto3 prototype;
+  ConformanceRequestSetting setting1(
+      level, conformance::JSON, conformance::PROTOBUF,
+      conformance::JSON_TEST,
+      prototype, test_name, input_json);
+  RunValidInputTest(setting1, equivalent_text_format);
+  ConformanceRequestSetting setting2(
+      level, conformance::JSON, conformance::JSON,
+      conformance::JSON_TEST,
+      prototype, test_name, input_json);
+  RunValidInputTest(setting2, equivalent_text_format);
+}
+
+void ConformanceTestSuiteImpl::RunValidJsonTestWithProtobufInput(
+    const string& test_name, ConformanceLevel level, const TestAllTypesProto3& input,
+    const string& equivalent_text_format) {
+  ConformanceRequestSetting setting(
+      level, conformance::PROTOBUF, conformance::JSON,
+      conformance::JSON_TEST,
+      input, test_name, input.SerializeAsString());
+  RunValidInputTest(setting, equivalent_text_format);
+}
+
+void ConformanceTestSuiteImpl::RunValidJsonIgnoreUnknownTest(
+    const string& test_name, ConformanceLevel level, const string& input_json,
+    const string& equivalent_text_format) {
+  TestAllTypesProto3 prototype;
+  ConformanceRequestSetting setting(
+      level, conformance::JSON, conformance::PROTOBUF,
+      conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST,
+      prototype, test_name, input_json);
+  RunValidInputTest(setting, equivalent_text_format);
+}
+
+void ConformanceTestSuiteImpl::RunValidProtobufTest(
+    const string& test_name, ConformanceLevel level,
+    const string& input_protobuf, const string& equivalent_text_format,
+    bool is_proto3) {
+  std::unique_ptr<Message> prototype = NewTestMessage(is_proto3);
+
+  ConformanceRequestSetting setting1(
+      level, conformance::PROTOBUF, conformance::PROTOBUF,
+      conformance::BINARY_TEST,
+      *prototype, test_name, input_protobuf);
+  RunValidInputTest(setting1, equivalent_text_format);
+
+  if (is_proto3) {
+    ConformanceRequestSetting setting2(
+        level, conformance::PROTOBUF, conformance::JSON,
+        conformance::BINARY_TEST,
+        *prototype, test_name, input_protobuf);
+    RunValidInputTest(setting2, equivalent_text_format);
+  }
+}
+
+void ConformanceTestSuiteImpl::RunValidBinaryProtobufTest(
+    const string& test_name, ConformanceLevel level,
+    const string& input_protobuf, bool is_proto3) {
+  std::unique_ptr<Message> prototype = NewTestMessage(is_proto3);
+  ConformanceRequestSetting setting(
+      level, conformance::PROTOBUF, conformance::PROTOBUF,
+      conformance::BINARY_TEST,
+      *prototype, test_name, input_protobuf);
+  RunValidBinaryInputTest(setting, input_protobuf);
+}
+
+void ConformanceTestSuiteImpl::RunValidProtobufTestWithMessage(
+    const string& test_name, ConformanceLevel level, const Message *input,
+    const string& equivalent_text_format, bool is_proto3) {
+  RunValidProtobufTest(test_name, level, input->SerializeAsString(),
+                       equivalent_text_format, is_proto3);
+}
+
+// According to proto3 JSON specification, JSON serializers follow more strict
+// rules than parsers (e.g., a serializer must serialize int32 values as JSON
+// numbers while the parser is allowed to accept them as JSON strings). This
+// method allows strict checking on a proto3 JSON serializer by inspecting
+// the JSON output directly.
+void ConformanceTestSuiteImpl::RunValidJsonTestWithValidator(
+    const string& test_name, ConformanceLevel level, const string& input_json,
+    const Validator& validator) {
+  TestAllTypesProto3 prototype;
+  ConformanceRequestSetting setting(
+      level, conformance::JSON, conformance::JSON,
+      conformance::JSON_TEST,
+      prototype, test_name, input_json);
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  string effective_test_name =
+      StrCat(setting.ConformanceLevelToString(level),
+             ".Proto3.JsonInput.",
+             test_name, ".Validator");
+
+  RunTest(effective_test_name, request, &response);
+
+  if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+    return;
+  }
+
+  if (response.result_case() != ConformanceResponse::kJsonPayload) {
+    ReportFailure(effective_test_name, level, request, response,
+                  "Expected JSON payload but got type %d.",
+                  response.result_case());
+    return;
+  }
+  Json::Reader reader;
+  Json::Value value;
+  if (!reader.parse(response.json_payload(), value)) {
+    ReportFailure(effective_test_name, level, request, response,
+                  "JSON payload cannot be parsed as valid JSON: %s",
+                  reader.getFormattedErrorMessages().c_str());
+    return;
+  }
+  if (!validator(value)) {
+    ReportFailure(effective_test_name, level, request, response,
+                  "JSON payload validation failed.");
+    return;
+  }
+  ReportSuccess(effective_test_name);
+}
+
+void ConformanceTestSuiteImpl::ExpectParseFailureForJson(
+    const string& test_name, ConformanceLevel level, const string& input_json) {
+  TestAllTypesProto3 prototype;
+  // We don't expect output, but if the program erroneously accepts the protobuf
+  // we let it send its response as this.  We must not leave it unspecified.
+  ConformanceRequestSetting setting(
+      level, conformance::JSON, conformance::JSON,
+      conformance::JSON_TEST,
+      prototype, test_name, input_json);
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  string effective_test_name =
+      StrCat(setting.ConformanceLevelToString(level),
+             ".Proto3.JsonInput.", test_name);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, level, request, response,
+                  "Should have failed to parse, but didn't.");
+  }
+}
+
+void ConformanceTestSuiteImpl::ExpectSerializeFailureForJson(
+    const string& test_name, ConformanceLevel level, const string& text_format) {
+  TestAllTypesProto3 payload_message;
+  GOOGLE_CHECK(
+      TextFormat::ParseFromString(text_format, &payload_message))
+          << "Failed to parse: " << text_format;
+
+  TestAllTypesProto3 prototype;
+  ConformanceRequestSetting setting(
+      level, conformance::PROTOBUF, conformance::JSON,
+      conformance::JSON_TEST,
+      prototype, test_name, payload_message.SerializeAsString());
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  string effective_test_name =
+      StrCat(setting.ConformanceLevelToString(level),
+             ".", test_name, ".JsonOutput");
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kSerializeError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, level, request, response,
+                  "Should have failed to serialize, but didn't.");
+  }
+}
+
+//TODO: proto2?
+void ConformanceTestSuiteImpl::TestPrematureEOFForType(
+    FieldDescriptor::Type type) {
+  // Incomplete values for each wire type.
+  static const string incompletes[6] = {
+    string("\x80"),     // VARINT
+    string("abcdefg"),  // 64BIT
+    string("\x80"),     // DELIMITED (partial length)
+    string(),           // START_GROUP (no value required)
+    string(),           // END_GROUP (no value required)
+    string("abc")       // 32BIT
+  };
+
+  const FieldDescriptor* field = GetFieldForType(type, false, true);
+  const FieldDescriptor* rep_field = GetFieldForType(type, true, true);
+  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(type));
+  const string& incomplete = incompletes[wire_type];
+  const string type_name =
+      UpperCase(string(".") + FieldDescriptor::TypeName(type));
+
+  ExpectParseFailureForProto(
+      tag(field->number(), wire_type),
+      "PrematureEofBeforeKnownNonRepeatedValue" + type_name, REQUIRED);
+
+  ExpectParseFailureForProto(
+      tag(rep_field->number(), wire_type),
+      "PrematureEofBeforeKnownRepeatedValue" + type_name, REQUIRED);
+
+  ExpectParseFailureForProto(
+      tag(UNKNOWN_FIELD, wire_type),
+      "PrematureEofBeforeUnknownValue" + type_name, REQUIRED);
+
+  ExpectParseFailureForProto(
+      cat( tag(field->number(), wire_type), incomplete ),
+      "PrematureEofInsideKnownNonRepeatedValue" + type_name, REQUIRED);
+
+  ExpectParseFailureForProto(
+      cat( tag(rep_field->number(), wire_type), incomplete ),
+      "PrematureEofInsideKnownRepeatedValue" + type_name, REQUIRED);
+
+  ExpectParseFailureForProto(
+      cat( tag(UNKNOWN_FIELD, wire_type), incomplete ),
+      "PrematureEofInsideUnknownValue" + type_name, REQUIRED);
+
+  if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    ExpectParseFailureForProto(
+        cat( tag(field->number(), wire_type), varint(1) ),
+        "PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name,
+        REQUIRED);
+
+    ExpectParseFailureForProto(
+        cat( tag(rep_field->number(), wire_type), varint(1) ),
+        "PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name,
+        REQUIRED);
+
+    // EOF in the middle of delimited data for unknown value.
+    ExpectParseFailureForProto(
+        cat( tag(UNKNOWN_FIELD, wire_type), varint(1) ),
+        "PrematureEofInDelimitedDataForUnknownValue" + type_name, REQUIRED);
+
+    if (type == FieldDescriptor::TYPE_MESSAGE) {
+      // Submessage ends in the middle of a value.
+      string incomplete_submsg =
+          cat( tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT),
+                incompletes[WireFormatLite::WIRETYPE_VARINT] );
+      ExpectHardParseFailureForProto(
+          cat( tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+               varint(incomplete_submsg.size()),
+               incomplete_submsg ),
+          "PrematureEofInSubmessageValue" + type_name, REQUIRED);
+    }
+  } else if (type != FieldDescriptor::TYPE_GROUP) {
+    // Non-delimited, non-group: eligible for packing.
+
+    // Packed region ends in the middle of a value.
+    ExpectHardParseFailureForProto(
+        cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+            varint(incomplete.size()), incomplete),
+        "PrematureEofInPackedFieldValue" + type_name, REQUIRED);
+
+    // EOF in the middle of packed region.
+    ExpectParseFailureForProto(
+        cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
+            varint(1)),
+        "PrematureEofInPackedField" + type_name, REQUIRED);
+  }
+}
+
+void ConformanceTestSuiteImpl::TestValidDataForType(
+    FieldDescriptor::Type type,
+    std::vector<std::pair<std::string, std::string>> values) {
+  for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
+    const string type_name =
+        UpperCase(string(".") + FieldDescriptor::TypeName(type));
+    WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+        static_cast<WireFormatLite::FieldType>(type));
+    const FieldDescriptor* field = GetFieldForType(type, false, is_proto3);
+    const FieldDescriptor* rep_field = GetFieldForType(type, true, is_proto3);
+
+    RunValidProtobufTest("ValidDataScalar" + type_name, REQUIRED,
+                         cat(tag(field->number(), wire_type), values[0].first),
+                         field->name() + ": " + values[0].second, is_proto3);
+
+    string proto;
+    string text = field->name() + ": " + values.back().second;
+    for (size_t i = 0; i < values.size(); i++) {
+      proto += cat(tag(field->number(), wire_type), values[i].first);
+    }
+    RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED,
+                         proto, text, is_proto3);
+
+    proto.clear();
+    text.clear();
+
+    for (size_t i = 0; i < values.size(); i++) {
+      proto += cat(tag(rep_field->number(), wire_type), values[i].first);
+      text += rep_field->name() + ": " + values[i].second + " ";
+    }
+    RunValidProtobufTest("ValidDataRepeated" + type_name, REQUIRED,
+                         proto, text, is_proto3);
+  }
+}
+
+// TODO: proto2?
+void ConformanceTestSuiteImpl::TestIllegalTags() {
+  // field num 0 is illegal
+  string nullfield[] = {
+    "\1DEADBEEF",
+    "\2\1\1",
+    "\3\4",
+    "\5DEAD"
+  };
+  for (int i = 0; i < 4; i++) {
+    string name = "IllegalZeroFieldNum_Case_0";
+    name.back() += i;
+    ExpectParseFailureForProto(nullfield[i], name, REQUIRED);
+  }
+}
+template <class MessageType>
+void ConformanceTestSuiteImpl::TestOneofMessage (
+    MessageType &message, bool is_proto3) {
+  message.set_oneof_uint32(0);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroUint32", RECOMMENDED, &message, "oneof_uint32: 0", is_proto3);
+  message.mutable_oneof_nested_message()->set_a(0);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroMessage", RECOMMENDED, &message,
+      is_proto3 ? "oneof_nested_message: {}" : "oneof_nested_message: {a: 0}",
+      is_proto3);
+  message.mutable_oneof_nested_message()->set_a(1);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroMessageSetTwice", RECOMMENDED, &message,
+      "oneof_nested_message: {a: 1}",
+      is_proto3);
+  message.set_oneof_string("");
+  RunValidProtobufTestWithMessage(
+      "OneofZeroString", RECOMMENDED, &message, "oneof_string: \"\"", is_proto3);
+  message.set_oneof_bytes("");
+  RunValidProtobufTestWithMessage(
+      "OneofZeroBytes", RECOMMENDED, &message, "oneof_bytes: \"\"", is_proto3);
+  message.set_oneof_bool(false);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroBool", RECOMMENDED, &message, "oneof_bool: false", is_proto3);
+  message.set_oneof_uint64(0);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroUint64", RECOMMENDED, &message, "oneof_uint64: 0", is_proto3);
+  message.set_oneof_float(0.0f);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroFloat", RECOMMENDED, &message, "oneof_float: 0", is_proto3);
+  message.set_oneof_double(0.0);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroDouble", RECOMMENDED, &message, "oneof_double: 0", is_proto3);
+  message.set_oneof_enum(MessageType::FOO);
+  RunValidProtobufTestWithMessage(
+      "OneofZeroEnum", RECOMMENDED, &message, "oneof_enum: FOO", is_proto3);
+}
+
+template <class MessageType>
+void ConformanceTestSuiteImpl::TestUnknownMessage(
+    MessageType& message, bool is_proto3) {
+  message.ParseFromString("\xA8\x1F\x01");
+  RunValidBinaryProtobufTest("UnknownVarint", REQUIRED,
+                             message.SerializeAsString(), is_proto3);
+}
+
+void ConformanceTestSuiteImpl::RunSuiteImpl() {
+  type_resolver_.reset(NewTypeResolverForDescriptorPool(
+      kTypeUrlPrefix, DescriptorPool::generated_pool()));
+  type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor());
+
+  for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) {
+    if (i == FieldDescriptor::TYPE_GROUP) continue;
+    TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
+  }
+
+  TestIllegalTags();
+
+  int64 kInt64Min = -9223372036854775808ULL;
+  int64 kInt64Max = 9223372036854775807ULL;
+  uint64 kUint64Max = 18446744073709551615ULL;
+  int32 kInt32Max = 2147483647;
+  int32 kInt32Min = -2147483648;
+  uint32 kUint32Max = 4294967295UL;
+
+  TestValidDataForType(FieldDescriptor::TYPE_DOUBLE, {
+    {dbl(0.1), "0.1"},
+    {dbl(1.7976931348623157e+308), "1.7976931348623157e+308"},
+    {dbl(2.22507385850720138309e-308), "2.22507385850720138309e-308"}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_FLOAT, {
+    {flt(0.1), "0.1"},
+    {flt(1.00000075e-36), "1.00000075e-36"},
+    {flt(3.402823e+38), "3.402823e+38"},  // 3.40282347e+38
+    {flt(1.17549435e-38f), "1.17549435e-38"}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_INT64, {
+    {varint(12345), "12345"},
+    {varint(kInt64Max), std::to_string(kInt64Max)},
+    {varint(kInt64Min), std::to_string(kInt64Min)}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_UINT64, {
+    {varint(12345), "12345"},
+    {varint(kUint64Max), std::to_string(kUint64Max)},
+    {varint(0), "0"}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_INT32, {
+    {varint(12345), "12345"},
+    {longvarint(12345, 2), "12345"},
+    {longvarint(12345, 7), "12345"},
+    {varint(kInt32Max), std::to_string(kInt32Max)},
+    {varint(kInt32Min), std::to_string(kInt32Min)},
+    {varint(1LL << 33), std::to_string(static_cast<int32>(1LL << 33))},
+    {varint((1LL << 33) - 1),
+     std::to_string(static_cast<int32>((1LL << 33) - 1))},
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_UINT32, {
+    {varint(12345), "12345"},
+    {longvarint(12345, 2), "12345"},
+    {longvarint(12345, 7), "12345"},
+    {varint(kUint32Max), std::to_string(kUint32Max)},  // UINT32_MAX
+    {varint(0), "0"},
+    {varint(1LL << 33), std::to_string(static_cast<uint32>(1LL << 33))},
+    {varint((1LL << 33) - 1),
+     std::to_string(static_cast<uint32>((1LL << 33) - 1))},
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_FIXED64, {
+    {u64(12345), "12345"},
+    {u64(kUint64Max), std::to_string(kUint64Max)},
+    {u64(0), "0"}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_FIXED32, {
+    {u32(12345), "12345"},
+    {u32(kUint32Max), std::to_string(kUint32Max)},  // UINT32_MAX
+    {u32(0), "0"}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, {
+    {u64(12345), "12345"},
+    {u64(kInt64Max), std::to_string(kInt64Max)},
+    {u64(kInt64Min), std::to_string(kInt64Min)}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, {
+    {u32(12345), "12345"},
+    {u32(kInt32Max), std::to_string(kInt32Max)},
+    {u32(kInt32Min), std::to_string(kInt32Min)}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_BOOL, {
+    {varint(1), "true"},
+    {varint(0), "false"},
+    {varint(12345678), "true"}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_SINT32, {
+    {zz32(12345), "12345"},
+    {zz32(kInt32Max), std::to_string(kInt32Max)},
+    {zz32(kInt32Min), std::to_string(kInt32Min)}
+  });
+  TestValidDataForType(FieldDescriptor::TYPE_SINT64, {
+    {zz64(12345), "12345"},
+    {zz64(kInt64Max), std::to_string(kInt64Max)},
+    {zz64(kInt64Min), std::to_string(kInt64Min)}
+  });
+
+  // TODO(haberman):
+  // TestValidDataForType(FieldDescriptor::TYPE_STRING
+  // TestValidDataForType(FieldDescriptor::TYPE_GROUP
+  // TestValidDataForType(FieldDescriptor::TYPE_MESSAGE
+  // TestValidDataForType(FieldDescriptor::TYPE_BYTES
+  // TestValidDataForType(FieldDescriptor::TYPE_ENUM
+
+  RunValidJsonTest("HelloWorld", REQUIRED,
+                   "{\"optionalString\":\"Hello, World!\"}",
+                   "optional_string: 'Hello, World!'");
+
+  // NOTE: The spec for JSON support is still being sorted out, these may not
+  // all be correct.
+  // Test field name conventions.
+  RunValidJsonTest(
+      "FieldNameInSnakeCase", REQUIRED,
+      R"({
+        "fieldname1": 1,
+        "fieldName2": 2,
+        "FieldName3": 3,
+        "fieldName4": 4
+      })",
+      R"(
+        fieldname1: 1
+        field_name2: 2
+        _field_name3: 3
+        field__name4_: 4
+      )");
+  RunValidJsonTest(
+      "FieldNameWithNumbers", REQUIRED,
+      R"({
+        "field0name5": 5,
+        "field0Name6": 6
+      })",
+      R"(
+        field0name5: 5
+        field_0_name6: 6
+      )");
+  RunValidJsonTest(
+      "FieldNameWithMixedCases", REQUIRED,
+      R"({
+        "fieldName7": 7,
+        "FieldName8": 8,
+        "fieldName9": 9,
+        "FieldName10": 10,
+        "FIELDNAME11": 11,
+        "FIELDName12": 12
+      })",
+      R"(
+        fieldName7: 7
+        FieldName8: 8
+        field_Name9: 9
+        Field_Name10: 10
+        FIELD_NAME11: 11
+        FIELD_name12: 12
+      )");
+  RunValidJsonTest(
+      "FieldNameWithDoubleUnderscores", RECOMMENDED,
+      R"({
+        "FieldName13": 13,
+        "FieldName14": 14,
+        "fieldName15": 15,
+        "fieldName16": 16,
+        "fieldName17": 17,
+        "FieldName18": 18
+      })",
+      R"(
+        __field_name13: 13
+        __Field_name14: 14
+        field__name15: 15
+        field__Name16: 16
+        field_name17__: 17
+        Field_name18__: 18
+      )");
+  // Using the original proto field name in JSON is also allowed.
+  RunValidJsonTest(
+      "OriginalProtoFieldName", REQUIRED,
+      R"({
+        "fieldname1": 1,
+        "field_name2": 2,
+        "_field_name3": 3,
+        "field__name4_": 4,
+        "field0name5": 5,
+        "field_0_name6": 6,
+        "fieldName7": 7,
+        "FieldName8": 8,
+        "field_Name9": 9,
+        "Field_Name10": 10,
+        "FIELD_NAME11": 11,
+        "FIELD_name12": 12,
+        "__field_name13": 13,
+        "__Field_name14": 14,
+        "field__name15": 15,
+        "field__Name16": 16,
+        "field_name17__": 17,
+        "Field_name18__": 18
+      })",
+      R"(
+        fieldname1: 1
+        field_name2: 2
+        _field_name3: 3
+        field__name4_: 4
+        field0name5: 5
+        field_0_name6: 6
+        fieldName7: 7
+        FieldName8: 8
+        field_Name9: 9
+        Field_Name10: 10
+        FIELD_NAME11: 11
+        FIELD_name12: 12
+        __field_name13: 13
+        __Field_name14: 14
+        field__name15: 15
+        field__Name16: 16
+        field_name17__: 17
+        Field_name18__: 18
+      )");
+  // Field names can be escaped.
+  RunValidJsonTest(
+      "FieldNameEscaped", REQUIRED,
+      R"({"fieldn\u0061me1": 1})",
+      "fieldname1: 1");
+  // String ends with escape character.
+  ExpectParseFailureForJson(
+      "StringEndsWithEscapeChar", RECOMMENDED,
+      "{\"optionalString\": \"abc\\");
+  // Field names must be quoted (or it's not valid JSON).
+  ExpectParseFailureForJson(
+      "FieldNameNotQuoted", RECOMMENDED,
+      "{fieldname1: 1}");
+  // Trailing comma is not allowed (not valid JSON).
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObject", RECOMMENDED,
+      R"({"fieldname1":1,})");
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObjectWithSpace", RECOMMENDED,
+      R"({"fieldname1":1 ,})");
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObjectWithSpaceCommaSpace", RECOMMENDED,
+      R"({"fieldname1":1 , })");
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObjectWithNewlines", RECOMMENDED,
+      R"({
+        "fieldname1":1,
+      })");
+  // JSON doesn't support comments.
+  ExpectParseFailureForJson(
+      "JsonWithComments", RECOMMENDED,
+      R"({
+        // This is a comment.
+        "fieldname1": 1
+      })");
+  // JSON spec says whitespace doesn't matter, so try a few spacings to be sure.
+  RunValidJsonTest(
+      "OneLineNoSpaces", RECOMMENDED,
+      "{\"optionalInt32\":1,\"optionalInt64\":2}",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  RunValidJsonTest(
+      "OneLineWithSpaces", RECOMMENDED,
+      "{ \"optionalInt32\" : 1 , \"optionalInt64\" : 2 }",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  RunValidJsonTest(
+      "MultilineNoSpaces", RECOMMENDED,
+      "{\n\"optionalInt32\"\n:\n1\n,\n\"optionalInt64\"\n:\n2\n}",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  RunValidJsonTest(
+      "MultilineWithSpaces", RECOMMENDED,
+      "{\n  \"optionalInt32\"  :  1\n  ,\n  \"optionalInt64\"  :  2\n}\n",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  // Missing comma between key/value pairs.
+  ExpectParseFailureForJson(
+      "MissingCommaOneLine", RECOMMENDED,
+      "{ \"optionalInt32\": 1 \"optionalInt64\": 2 }");
+  ExpectParseFailureForJson(
+      "MissingCommaMultiline", RECOMMENDED,
+      "{\n  \"optionalInt32\": 1\n  \"optionalInt64\": 2\n}");
+  // Duplicated field names are not allowed.
+  ExpectParseFailureForJson(
+      "FieldNameDuplicate", RECOMMENDED,
+      R"({
+        "optionalNestedMessage": {a: 1},
+        "optionalNestedMessage": {}
+      })");
+  ExpectParseFailureForJson(
+      "FieldNameDuplicateDifferentCasing1", RECOMMENDED,
+      R"({
+        "optional_nested_message": {a: 1},
+        "optionalNestedMessage": {}
+      })");
+  ExpectParseFailureForJson(
+      "FieldNameDuplicateDifferentCasing2", RECOMMENDED,
+      R"({
+        "optionalNestedMessage": {a: 1},
+        "optional_nested_message": {}
+      })");
+  // Serializers should use lowerCamelCase by default.
+  RunValidJsonTestWithValidator(
+      "FieldNameInLowerCamelCase", REQUIRED,
+      R"({
+        "fieldname1": 1,
+        "fieldName2": 2,
+        "FieldName3": 3,
+        "fieldName4": 4
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldname1") &&
+            value.isMember("fieldName2") &&
+            value.isMember("FieldName3") &&
+            value.isMember("fieldName4");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithNumbers", REQUIRED,
+      R"({
+        "field0name5": 5,
+        "field0Name6": 6
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("field0name5") &&
+            value.isMember("field0Name6");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithMixedCases", REQUIRED,
+      R"({
+        "fieldName7": 7,
+        "FieldName8": 8,
+        "fieldName9": 9,
+        "FieldName10": 10,
+        "FIELDNAME11": 11,
+        "FIELDName12": 12
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldName7") &&
+            value.isMember("FieldName8") &&
+            value.isMember("fieldName9") &&
+            value.isMember("FieldName10") &&
+            value.isMember("FIELDNAME11") &&
+            value.isMember("FIELDName12");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithDoubleUnderscores", RECOMMENDED,
+      R"({
+        "FieldName13": 13,
+        "FieldName14": 14,
+        "fieldName15": 15,
+        "fieldName16": 16,
+        "fieldName17": 17,
+        "FieldName18": 18
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("FieldName13") &&
+            value.isMember("FieldName14") &&
+            value.isMember("fieldName15") &&
+            value.isMember("fieldName16") &&
+            value.isMember("fieldName17") &&
+            value.isMember("FieldName18");
+      });
+
+  // Integer fields.
+  RunValidJsonTest(
+      "Int32FieldMaxValue", REQUIRED,
+      R"({"optionalInt32": 2147483647})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldMinValue", REQUIRED,
+      R"({"optionalInt32": -2147483648})",
+      "optional_int32: -2147483648");
+  RunValidJsonTest(
+      "Uint32FieldMaxValue", REQUIRED,
+      R"({"optionalUint32": 4294967295})",
+      "optional_uint32: 4294967295");
+  RunValidJsonTest(
+      "Int64FieldMaxValue", REQUIRED,
+      R"({"optionalInt64": "9223372036854775807"})",
+      "optional_int64: 9223372036854775807");
+  RunValidJsonTest(
+      "Int64FieldMinValue", REQUIRED,
+      R"({"optionalInt64": "-9223372036854775808"})",
+      "optional_int64: -9223372036854775808");
+  RunValidJsonTest(
+      "Uint64FieldMaxValue", REQUIRED,
+      R"({"optionalUint64": "18446744073709551615"})",
+      "optional_uint64: 18446744073709551615");
+  // While not the largest Int64, this is the largest
+  // Int64 which can be exactly represented within an
+  // IEEE-754 64-bit float, which is the expected level
+  // of interoperability guarantee. Larger values may
+  // work in some implementations, but should not be
+  // relied upon.
+  RunValidJsonTest(
+      "Int64FieldMaxValueNotQuoted", REQUIRED,
+      R"({"optionalInt64": 9223372036854774784})",
+      "optional_int64: 9223372036854774784");
+  RunValidJsonTest(
+      "Int64FieldMinValueNotQuoted", REQUIRED,
+      R"({"optionalInt64": -9223372036854775808})",
+      "optional_int64: -9223372036854775808");
+  // Largest interoperable Uint64; see comment above
+  // for Int64FieldMaxValueNotQuoted.
+  RunValidJsonTest(
+      "Uint64FieldMaxValueNotQuoted", REQUIRED,
+      R"({"optionalUint64": 18446744073709549568})",
+      "optional_uint64: 18446744073709549568");
+  // Values can be represented as JSON strings.
+  RunValidJsonTest(
+      "Int32FieldStringValue", REQUIRED,
+      R"({"optionalInt32": "2147483647"})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldStringValueEscaped", REQUIRED,
+      R"({"optionalInt32": "2\u003147483647"})",
+      "optional_int32: 2147483647");
+
+  // Parsers reject out-of-bound integer values.
+  ExpectParseFailureForJson(
+      "Int32FieldTooLarge", REQUIRED,
+      R"({"optionalInt32": 2147483648})");
+  ExpectParseFailureForJson(
+      "Int32FieldTooSmall", REQUIRED,
+      R"({"optionalInt32": -2147483649})");
+  ExpectParseFailureForJson(
+      "Uint32FieldTooLarge", REQUIRED,
+      R"({"optionalUint32": 4294967296})");
+  ExpectParseFailureForJson(
+      "Int64FieldTooLarge", REQUIRED,
+      R"({"optionalInt64": "9223372036854775808"})");
+  ExpectParseFailureForJson(
+      "Int64FieldTooSmall", REQUIRED,
+      R"({"optionalInt64": "-9223372036854775809"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldTooLarge", REQUIRED,
+      R"({"optionalUint64": "18446744073709551616"})");
+  // Parser reject non-integer numeric values as well.
+  ExpectParseFailureForJson(
+      "Int32FieldNotInteger", REQUIRED,
+      R"({"optionalInt32": 0.5})");
+  ExpectParseFailureForJson(
+      "Uint32FieldNotInteger", REQUIRED,
+      R"({"optionalUint32": 0.5})");
+  ExpectParseFailureForJson(
+      "Int64FieldNotInteger", REQUIRED,
+      R"({"optionalInt64": "0.5"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldNotInteger", REQUIRED,
+      R"({"optionalUint64": "0.5"})");
+
+  // Integers but represented as float values are accepted.
+  RunValidJsonTest(
+      "Int32FieldFloatTrailingZero", REQUIRED,
+      R"({"optionalInt32": 100000.000})",
+      "optional_int32: 100000");
+  RunValidJsonTest(
+      "Int32FieldExponentialFormat", REQUIRED,
+      R"({"optionalInt32": 1e5})",
+      "optional_int32: 100000");
+  RunValidJsonTest(
+      "Int32FieldMaxFloatValue", REQUIRED,
+      R"({"optionalInt32": 2.147483647e9})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldMinFloatValue", REQUIRED,
+      R"({"optionalInt32": -2.147483648e9})",
+      "optional_int32: -2147483648");
+  RunValidJsonTest(
+      "Uint32FieldMaxFloatValue", REQUIRED,
+      R"({"optionalUint32": 4.294967295e9})",
+      "optional_uint32: 4294967295");
+
+  // Parser reject non-numeric values.
+  ExpectParseFailureForJson(
+      "Int32FieldNotNumber", REQUIRED,
+      R"({"optionalInt32": "3x3"})");
+  ExpectParseFailureForJson(
+      "Uint32FieldNotNumber", REQUIRED,
+      R"({"optionalUint32": "3x3"})");
+  ExpectParseFailureForJson(
+      "Int64FieldNotNumber", REQUIRED,
+      R"({"optionalInt64": "3x3"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldNotNumber", REQUIRED,
+      R"({"optionalUint64": "3x3"})");
+  // JSON does not allow "+" on numric values.
+  ExpectParseFailureForJson(
+      "Int32FieldPlusSign", REQUIRED,
+      R"({"optionalInt32": +1})");
+  // JSON doesn't allow leading 0s.
+  ExpectParseFailureForJson(
+      "Int32FieldLeadingZero", REQUIRED,
+      R"({"optionalInt32": 01})");
+  ExpectParseFailureForJson(
+      "Int32FieldNegativeWithLeadingZero", REQUIRED,
+      R"({"optionalInt32": -01})");
+  // String values must follow the same syntax rule. Specifically leading
+  // or trailing spaces are not allowed.
+  ExpectParseFailureForJson(
+      "Int32FieldLeadingSpace", REQUIRED,
+      R"({"optionalInt32": " 1"})");
+  ExpectParseFailureForJson(
+      "Int32FieldTrailingSpace", REQUIRED,
+      R"({"optionalInt32": "1 "})");
+
+  // 64-bit values are serialized as strings.
+  RunValidJsonTestWithValidator(
+      "Int64FieldBeString", RECOMMENDED,
+      R"({"optionalInt64": 1})",
+      [](const Json::Value& value) {
+        return value["optionalInt64"].type() == Json::stringValue &&
+            value["optionalInt64"].asString() == "1";
+      });
+  RunValidJsonTestWithValidator(
+      "Uint64FieldBeString", RECOMMENDED,
+      R"({"optionalUint64": 1})",
+      [](const Json::Value& value) {
+        return value["optionalUint64"].type() == Json::stringValue &&
+            value["optionalUint64"].asString() == "1";
+      });
+
+  // Bool fields.
+  RunValidJsonTest(
+      "BoolFieldTrue", REQUIRED,
+      R"({"optionalBool":true})",
+      "optional_bool: true");
+  RunValidJsonTest(
+      "BoolFieldFalse", REQUIRED,
+      R"({"optionalBool":false})",
+      "optional_bool: false");
+
+  // Other forms are not allowed.
+  ExpectParseFailureForJson(
+      "BoolFieldIntegerZero", RECOMMENDED,
+      R"({"optionalBool":0})");
+  ExpectParseFailureForJson(
+      "BoolFieldIntegerOne", RECOMMENDED,
+      R"({"optionalBool":1})");
+  ExpectParseFailureForJson(
+      "BoolFieldCamelCaseTrue", RECOMMENDED,
+      R"({"optionalBool":True})");
+  ExpectParseFailureForJson(
+      "BoolFieldCamelCaseFalse", RECOMMENDED,
+      R"({"optionalBool":False})");
+  ExpectParseFailureForJson(
+      "BoolFieldAllCapitalTrue", RECOMMENDED,
+      R"({"optionalBool":TRUE})");
+  ExpectParseFailureForJson(
+      "BoolFieldAllCapitalFalse", RECOMMENDED,
+      R"({"optionalBool":FALSE})");
+  ExpectParseFailureForJson(
+      "BoolFieldDoubleQuotedTrue", RECOMMENDED,
+      R"({"optionalBool":"true"})");
+  ExpectParseFailureForJson(
+      "BoolFieldDoubleQuotedFalse", RECOMMENDED,
+      R"({"optionalBool":"false"})");
+
+  // Float fields.
+  RunValidJsonTest(
+      "FloatFieldMinPositiveValue", REQUIRED,
+      R"({"optionalFloat": 1.175494e-38})",
+      "optional_float: 1.175494e-38");
+  RunValidJsonTest(
+      "FloatFieldMaxNegativeValue", REQUIRED,
+      R"({"optionalFloat": -1.175494e-38})",
+      "optional_float: -1.175494e-38");
+  RunValidJsonTest(
+      "FloatFieldMaxPositiveValue", REQUIRED,
+      R"({"optionalFloat": 3.402823e+38})",
+      "optional_float: 3.402823e+38");
+  RunValidJsonTest(
+      "FloatFieldMinNegativeValue", REQUIRED,
+      R"({"optionalFloat": 3.402823e+38})",
+      "optional_float: 3.402823e+38");
+  // Values can be quoted.
+  RunValidJsonTest(
+      "FloatFieldQuotedValue", REQUIRED,
+      R"({"optionalFloat": "1"})",
+      "optional_float: 1");
+  // Special values.
+  RunValidJsonTest(
+      "FloatFieldNan", REQUIRED,
+      R"({"optionalFloat": "NaN"})",
+      "optional_float: nan");
+  RunValidJsonTest(
+      "FloatFieldInfinity", REQUIRED,
+      R"({"optionalFloat": "Infinity"})",
+      "optional_float: inf");
+  RunValidJsonTest(
+      "FloatFieldNegativeInfinity", REQUIRED,
+      R"({"optionalFloat": "-Infinity"})",
+      "optional_float: -inf");
+  // Non-cannonical Nan will be correctly normalized.
+  {
+    TestAllTypesProto3 message;
+    // IEEE floating-point standard 32-bit quiet NaN:
+    //   0111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
+    message.set_optional_float(
+        WireFormatLite::DecodeFloat(0x7FA12345));
+    RunValidJsonTestWithProtobufInput(
+        "FloatFieldNormalizeQuietNan", REQUIRED, message,
+        "optional_float: nan");
+    // IEEE floating-point standard 64-bit signaling NaN:
+    //   1111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
+    message.set_optional_float(
+        WireFormatLite::DecodeFloat(0xFFB54321));
+    RunValidJsonTestWithProtobufInput(
+        "FloatFieldNormalizeSignalingNan", REQUIRED, message,
+        "optional_float: nan");
+  }
+
+  // Special values must be quoted.
+  ExpectParseFailureForJson(
+      "FloatFieldNanNotQuoted", RECOMMENDED,
+      R"({"optionalFloat": NaN})");
+  ExpectParseFailureForJson(
+      "FloatFieldInfinityNotQuoted", RECOMMENDED,
+      R"({"optionalFloat": Infinity})");
+  ExpectParseFailureForJson(
+      "FloatFieldNegativeInfinityNotQuoted", RECOMMENDED,
+      R"({"optionalFloat": -Infinity})");
+  // Parsers should reject out-of-bound values.
+  ExpectParseFailureForJson(
+      "FloatFieldTooSmall", REQUIRED,
+      R"({"optionalFloat": -3.502823e+38})");
+  ExpectParseFailureForJson(
+      "FloatFieldTooLarge", REQUIRED,
+      R"({"optionalFloat": 3.502823e+38})");
+
+  // Double fields.
+  RunValidJsonTest(
+      "DoubleFieldMinPositiveValue", REQUIRED,
+      R"({"optionalDouble": 2.22507e-308})",
+      "optional_double: 2.22507e-308");
+  RunValidJsonTest(
+      "DoubleFieldMaxNegativeValue", REQUIRED,
+      R"({"optionalDouble": -2.22507e-308})",
+      "optional_double: -2.22507e-308");
+  RunValidJsonTest(
+      "DoubleFieldMaxPositiveValue", REQUIRED,
+      R"({"optionalDouble": 1.79769e+308})",
+      "optional_double: 1.79769e+308");
+  RunValidJsonTest(
+      "DoubleFieldMinNegativeValue", REQUIRED,
+      R"({"optionalDouble": -1.79769e+308})",
+      "optional_double: -1.79769e+308");
+  // Values can be quoted.
+  RunValidJsonTest(
+      "DoubleFieldQuotedValue", REQUIRED,
+      R"({"optionalDouble": "1"})",
+      "optional_double: 1");
+  // Speical values.
+  RunValidJsonTest(
+      "DoubleFieldNan", REQUIRED,
+      R"({"optionalDouble": "NaN"})",
+      "optional_double: nan");
+  RunValidJsonTest(
+      "DoubleFieldInfinity", REQUIRED,
+      R"({"optionalDouble": "Infinity"})",
+      "optional_double: inf");
+  RunValidJsonTest(
+      "DoubleFieldNegativeInfinity", REQUIRED,
+      R"({"optionalDouble": "-Infinity"})",
+      "optional_double: -inf");
+  // Non-cannonical Nan will be correctly normalized.
+  {
+    TestAllTypesProto3 message;
+    message.set_optional_double(
+        WireFormatLite::DecodeDouble(0x7FFA123456789ABCLL));
+    RunValidJsonTestWithProtobufInput(
+        "DoubleFieldNormalizeQuietNan", REQUIRED, message,
+        "optional_double: nan");
+    message.set_optional_double(
+        WireFormatLite::DecodeDouble(0xFFFBCBA987654321LL));
+    RunValidJsonTestWithProtobufInput(
+        "DoubleFieldNormalizeSignalingNan", REQUIRED, message,
+        "optional_double: nan");
+  }
+
+  // Special values must be quoted.
+  ExpectParseFailureForJson(
+      "DoubleFieldNanNotQuoted", RECOMMENDED,
+      R"({"optionalDouble": NaN})");
+  ExpectParseFailureForJson(
+      "DoubleFieldInfinityNotQuoted", RECOMMENDED,
+      R"({"optionalDouble": Infinity})");
+  ExpectParseFailureForJson(
+      "DoubleFieldNegativeInfinityNotQuoted", RECOMMENDED,
+      R"({"optionalDouble": -Infinity})");
+
+  // Parsers should reject out-of-bound values.
+  ExpectParseFailureForJson(
+      "DoubleFieldTooSmall", REQUIRED,
+      R"({"optionalDouble": -1.89769e+308})");
+  ExpectParseFailureForJson(
+      "DoubleFieldTooLarge", REQUIRED,
+      R"({"optionalDouble": +1.89769e+308})");
+
+  // Enum fields.
+  RunValidJsonTest(
+      "EnumField", REQUIRED,
+      R"({"optionalNestedEnum": "FOO"})",
+      "optional_nested_enum: FOO");
+  // Enum values must be represented as strings.
+  ExpectParseFailureForJson(
+      "EnumFieldNotQuoted", REQUIRED,
+      R"({"optionalNestedEnum": FOO})");
+  // Numeric values are allowed.
+  RunValidJsonTest(
+      "EnumFieldNumericValueZero", REQUIRED,
+      R"({"optionalNestedEnum": 0})",
+      "optional_nested_enum: FOO");
+  RunValidJsonTest(
+      "EnumFieldNumericValueNonZero", REQUIRED,
+      R"({"optionalNestedEnum": 1})",
+      "optional_nested_enum: BAR");
+  // Unknown enum values are represented as numeric values.
+  RunValidJsonTestWithValidator(
+      "EnumFieldUnknownValue", REQUIRED,
+      R"({"optionalNestedEnum": 123})",
+      [](const Json::Value& value) {
+        return value["optionalNestedEnum"].type() == Json::intValue &&
+            value["optionalNestedEnum"].asInt() == 123;
+      });
+
+  // String fields.
+  RunValidJsonTest(
+      "StringField", REQUIRED,
+      R"({"optionalString": "Hello world!"})",
+      "optional_string: \"Hello world!\"");
+  RunValidJsonTest(
+      "StringFieldUnicode", REQUIRED,
+      // Google in Chinese.
+      R"({"optionalString": "谷歌"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldEscape", REQUIRED,
+      R"({"optionalString": "\"\\\/\b\f\n\r\t"})",
+      R"(optional_string: "\"\\/\b\f\n\r\t")");
+  RunValidJsonTest(
+      "StringFieldUnicodeEscape", REQUIRED,
+      R"({"optionalString": "\u8C37\u6B4C"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldUnicodeEscapeWithLowercaseHexLetters", REQUIRED,
+      R"({"optionalString": "\u8c37\u6b4c"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldSurrogatePair", REQUIRED,
+      // The character is an emoji: grinning face with smiling eyes. 😁
+      R"({"optionalString": "\uD83D\uDE01"})",
+      R"(optional_string: "\xF0\x9F\x98\x81")");
+
+  // Unicode escapes must start with "\u" (lowercase u).
+  ExpectParseFailureForJson(
+      "StringFieldUppercaseEscapeLetter", RECOMMENDED,
+      R"({"optionalString": "\U8C37\U6b4C"})");
+  ExpectParseFailureForJson(
+      "StringFieldInvalidEscape", RECOMMENDED,
+      R"({"optionalString": "\uXXXX\u6B4C"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnterminatedEscape", RECOMMENDED,
+      R"({"optionalString": "\u8C3"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnpairedHighSurrogate", RECOMMENDED,
+      R"({"optionalString": "\uD800"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnpairedLowSurrogate", RECOMMENDED,
+      R"({"optionalString": "\uDC00"})");
+  ExpectParseFailureForJson(
+      "StringFieldSurrogateInWrongOrder", RECOMMENDED,
+      R"({"optionalString": "\uDE01\uD83D"})");
+  ExpectParseFailureForJson(
+      "StringFieldNotAString", REQUIRED,
+      R"({"optionalString": 12345})");
+
+  // Bytes fields.
+  RunValidJsonTest(
+      "BytesField", REQUIRED,
+      R"({"optionalBytes": "AQI="})",
+      R"(optional_bytes: "\x01\x02")");
+  RunValidJsonTest(
+      "BytesFieldBase64Url", RECOMMENDED,
+      R"({"optionalBytes": "-_"})",
+      R"(optional_bytes: "\xfb")");
+
+  // Message fields.
+  RunValidJsonTest(
+      "MessageField", REQUIRED,
+      R"({"optionalNestedMessage": {"a": 1234}})",
+      "optional_nested_message: {a: 1234}");
+
+  // Oneof fields.
+  ExpectParseFailureForJson(
+      "OneofFieldDuplicate", REQUIRED,
+      R"({"oneofUint32": 1, "oneofString": "test"})");
+  // Ensure zero values for oneof make it out/backs.
+  TestAllTypesProto3 messageProto3;
+  TestAllTypesProto2 messageProto2;
+  TestOneofMessage(messageProto3, true);
+  TestOneofMessage(messageProto2, false);
+  RunValidJsonTest(
+      "OneofZeroUint32", RECOMMENDED,
+      R"({"oneofUint32": 0})", "oneof_uint32: 0");
+  RunValidJsonTest(
+      "OneofZeroMessage", RECOMMENDED,
+      R"({"oneofNestedMessage": {}})", "oneof_nested_message: {}");
+  RunValidJsonTest(
+      "OneofZeroString", RECOMMENDED,
+      R"({"oneofString": ""})", "oneof_string: \"\"");
+  RunValidJsonTest(
+      "OneofZeroBytes", RECOMMENDED,
+      R"({"oneofBytes": ""})", "oneof_bytes: \"\"");
+  RunValidJsonTest(
+      "OneofZeroBool", RECOMMENDED,
+      R"({"oneofBool": false})", "oneof_bool: false");
+  RunValidJsonTest(
+      "OneofZeroUint64", RECOMMENDED,
+      R"({"oneofUint64": 0})", "oneof_uint64: 0");
+  RunValidJsonTest(
+      "OneofZeroFloat", RECOMMENDED,
+      R"({"oneofFloat": 0.0})", "oneof_float: 0");
+  RunValidJsonTest(
+      "OneofZeroDouble", RECOMMENDED,
+      R"({"oneofDouble": 0.0})", "oneof_double: 0");
+  RunValidJsonTest(
+      "OneofZeroEnum", RECOMMENDED,
+      R"({"oneofEnum":"FOO"})", "oneof_enum: FOO");
+
+  // Repeated fields.
+  RunValidJsonTest(
+      "PrimitiveRepeatedField", REQUIRED,
+      R"({"repeatedInt32": [1, 2, 3, 4]})",
+      "repeated_int32: [1, 2, 3, 4]");
+  RunValidJsonTest(
+      "EnumRepeatedField", REQUIRED,
+      R"({"repeatedNestedEnum": ["FOO", "BAR", "BAZ"]})",
+      "repeated_nested_enum: [FOO, BAR, BAZ]");
+  RunValidJsonTest(
+      "StringRepeatedField", REQUIRED,
+      R"({"repeatedString": ["Hello", "world"]})",
+      R"(repeated_string: ["Hello", "world"])");
+  RunValidJsonTest(
+      "BytesRepeatedField", REQUIRED,
+      R"({"repeatedBytes": ["AAEC", "AQI="]})",
+      R"(repeated_bytes: ["\x00\x01\x02", "\x01\x02"])");
+  RunValidJsonTest(
+      "MessageRepeatedField", REQUIRED,
+      R"({"repeatedNestedMessage": [{"a": 1234}, {"a": 5678}]})",
+      "repeated_nested_message: {a: 1234}"
+      "repeated_nested_message: {a: 5678}");
+
+  // Repeated field elements are of incorrect type.
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotBool", REQUIRED,
+      R"({"repeatedInt32": [1, false, 3, 4]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotString", REQUIRED,
+      R"({"repeatedInt32": [1, 2, "name", 4]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotMessage", REQUIRED,
+      R"({"repeatedInt32": [1, 2, 3, {"a": 4}]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotInt", REQUIRED,
+      R"({"repeatedString": ["1", 2, "3", "4"]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotBool", REQUIRED,
+      R"({"repeatedString": ["1", "2", false, "4"]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotMessage", REQUIRED,
+      R"({"repeatedString": ["1", 2, "3", {"a": 4}]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotInt", REQUIRED,
+      R"({"repeatedNestedMessage": [{"a": 1}, 2]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotBool", REQUIRED,
+      R"({"repeatedNestedMessage": [{"a": 1}, false]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotString", REQUIRED,
+      R"({"repeatedNestedMessage": [{"a": 1}, "2"]})");
+  // Trailing comma in the repeated field is not allowed.
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingComma", RECOMMENDED,
+      R"({"repeatedInt32": [1, 2, 3, 4,]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingCommaWithSpace", RECOMMENDED,
+      "{\"repeatedInt32\": [1, 2, 3, 4 ,]}");
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingCommaWithSpaceCommaSpace", RECOMMENDED,
+      "{\"repeatedInt32\": [1, 2, 3, 4 , ]}");
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingCommaWithNewlines", RECOMMENDED,
+      "{\"repeatedInt32\": [\n  1,\n  2,\n  3,\n  4,\n]}");
+
+  // Map fields.
+  RunValidJsonTest(
+      "Int32MapField", REQUIRED,
+      R"({"mapInt32Int32": {"1": 2, "3": 4}})",
+      "map_int32_int32: {key: 1 value: 2}"
+      "map_int32_int32: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Int32MapFieldKeyNotQuoted", RECOMMENDED,
+      R"({"mapInt32Int32": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Uint32MapField", REQUIRED,
+      R"({"mapUint32Uint32": {"1": 2, "3": 4}})",
+      "map_uint32_uint32: {key: 1 value: 2}"
+      "map_uint32_uint32: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Uint32MapFieldKeyNotQuoted", RECOMMENDED,
+      R"({"mapUint32Uint32": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Int64MapField", REQUIRED,
+      R"({"mapInt64Int64": {"1": 2, "3": 4}})",
+      "map_int64_int64: {key: 1 value: 2}"
+      "map_int64_int64: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Int64MapFieldKeyNotQuoted", RECOMMENDED,
+      R"({"mapInt64Int64": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Uint64MapField", REQUIRED,
+      R"({"mapUint64Uint64": {"1": 2, "3": 4}})",
+      "map_uint64_uint64: {key: 1 value: 2}"
+      "map_uint64_uint64: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Uint64MapFieldKeyNotQuoted", RECOMMENDED,
+      R"({"mapUint64Uint64": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "BoolMapField", REQUIRED,
+      R"({"mapBoolBool": {"true": true, "false": false}})",
+      "map_bool_bool: {key: true value: true}"
+      "map_bool_bool: {key: false value: false}");
+  ExpectParseFailureForJson(
+      "BoolMapFieldKeyNotQuoted", RECOMMENDED,
+      R"({"mapBoolBool": {true: true, false: false}})");
+  RunValidJsonTest(
+      "MessageMapField", REQUIRED,
+      R"({
+        "mapStringNestedMessage": {
+          "hello": {"a": 1234},
+          "world": {"a": 5678}
+        }
+      })",
+      R"(
+        map_string_nested_message: {
+          key: "hello"
+          value: {a: 1234}
+        }
+        map_string_nested_message: {
+          key: "world"
+          value: {a: 5678}
+        }
+      )");
+  // Since Map keys are represented as JSON strings, escaping should be allowed.
+  RunValidJsonTest(
+      "Int32MapEscapedKey", REQUIRED,
+      R"({"mapInt32Int32": {"\u0031": 2}})",
+      "map_int32_int32: {key: 1 value: 2}");
+  RunValidJsonTest(
+      "Int64MapEscapedKey", REQUIRED,
+      R"({"mapInt64Int64": {"\u0031": 2}})",
+      "map_int64_int64: {key: 1 value: 2}");
+  RunValidJsonTest(
+      "BoolMapEscapedKey", REQUIRED,
+      R"({"mapBoolBool": {"tr\u0075e": true}})",
+      "map_bool_bool: {key: true value: true}");
+
+  // "null" is accepted for all fields types.
+  RunValidJsonTest(
+      "AllFieldAcceptNull", REQUIRED,
+      R"({
+        "optionalInt32": null,
+        "optionalInt64": null,
+        "optionalUint32": null,
+        "optionalUint64": null,
+        "optionalSint32": null,
+        "optionalSint64": null,
+        "optionalFixed32": null,
+        "optionalFixed64": null,
+        "optionalSfixed32": null,
+        "optionalSfixed64": null,
+        "optionalFloat": null,
+        "optionalDouble": null,
+        "optionalBool": null,
+        "optionalString": null,
+        "optionalBytes": null,
+        "optionalNestedEnum": null,
+        "optionalNestedMessage": null,
+        "repeatedInt32": null,
+        "repeatedInt64": null,
+        "repeatedUint32": null,
+        "repeatedUint64": null,
+        "repeatedSint32": null,
+        "repeatedSint64": null,
+        "repeatedFixed32": null,
+        "repeatedFixed64": null,
+        "repeatedSfixed32": null,
+        "repeatedSfixed64": null,
+        "repeatedFloat": null,
+        "repeatedDouble": null,
+        "repeatedBool": null,
+        "repeatedString": null,
+        "repeatedBytes": null,
+        "repeatedNestedEnum": null,
+        "repeatedNestedMessage": null,
+        "mapInt32Int32": null,
+        "mapBoolBool": null,
+        "mapStringNestedMessage": null
+      })",
+      "");
+
+  // Repeated field elements cannot be null.
+  ExpectParseFailureForJson(
+      "RepeatedFieldPrimitiveElementIsNull", RECOMMENDED,
+      R"({"repeatedInt32": [1, null, 2]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldMessageElementIsNull", RECOMMENDED,
+      R"({"repeatedNestedMessage": [{"a":1}, null, {"a":2}]})");
+  // Map field keys cannot be null.
+  ExpectParseFailureForJson(
+      "MapFieldKeyIsNull", RECOMMENDED,
+      R"({"mapInt32Int32": {null: 1}})");
+  // Map field values cannot be null.
+  ExpectParseFailureForJson(
+      "MapFieldValueIsNull", RECOMMENDED,
+      R"({"mapInt32Int32": {"0": null}})");
+
+  // http://www.rfc-editor.org/rfc/rfc7159.txt says strings have to use double
+  // quotes.
+  ExpectParseFailureForJson(
+      "StringFieldSingleQuoteKey", RECOMMENDED,
+      R"({'optionalString': "Hello world!"})");
+  ExpectParseFailureForJson(
+      "StringFieldSingleQuoteValue", RECOMMENDED,
+      R"({"optionalString": 'Hello world!'})");
+  ExpectParseFailureForJson(
+      "StringFieldSingleQuoteBoth", RECOMMENDED,
+      R"({'optionalString': 'Hello world!'})");
+
+  // Unknown fields.
+  {
+    TestAllTypesProto3 messageProto3;
+    TestAllTypesProto2 messageProto2;
+    //TODO(yilunchong): update this behavior when unknown field's behavior
+    // changed in open source. Also delete
+    // Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
+    // from failure list of python_cpp python java
+    TestUnknownMessage(messageProto3, true);
+    TestUnknownMessage(messageProto2, false);
+  }
+
+  // Wrapper types.
+  RunValidJsonTest(
+      "OptionalBoolWrapper", REQUIRED,
+      R"({"optionalBoolWrapper": false})",
+      "optional_bool_wrapper: {value: false}");
+  RunValidJsonTest(
+      "OptionalInt32Wrapper", REQUIRED,
+      R"({"optionalInt32Wrapper": 0})",
+      "optional_int32_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalUint32Wrapper", REQUIRED,
+      R"({"optionalUint32Wrapper": 0})",
+      "optional_uint32_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalInt64Wrapper", REQUIRED,
+      R"({"optionalInt64Wrapper": 0})",
+      "optional_int64_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalUint64Wrapper", REQUIRED,
+      R"({"optionalUint64Wrapper": 0})",
+      "optional_uint64_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalFloatWrapper", REQUIRED,
+      R"({"optionalFloatWrapper": 0})",
+      "optional_float_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalDoubleWrapper", REQUIRED,
+      R"({"optionalDoubleWrapper": 0})",
+      "optional_double_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalStringWrapper", REQUIRED,
+      R"({"optionalStringWrapper": ""})",
+      R"(optional_string_wrapper: {value: ""})");
+  RunValidJsonTest(
+      "OptionalBytesWrapper", REQUIRED,
+      R"({"optionalBytesWrapper": ""})",
+      R"(optional_bytes_wrapper: {value: ""})");
+  RunValidJsonTest(
+      "OptionalWrapperTypesWithNonDefaultValue", REQUIRED,
+      R"({
+        "optionalBoolWrapper": true,
+        "optionalInt32Wrapper": 1,
+        "optionalUint32Wrapper": 1,
+        "optionalInt64Wrapper": "1",
+        "optionalUint64Wrapper": "1",
+        "optionalFloatWrapper": 1,
+        "optionalDoubleWrapper": 1,
+        "optionalStringWrapper": "1",
+        "optionalBytesWrapper": "AQI="
+      })",
+      R"(
+        optional_bool_wrapper: {value: true}
+        optional_int32_wrapper: {value: 1}
+        optional_uint32_wrapper: {value: 1}
+        optional_int64_wrapper: {value: 1}
+        optional_uint64_wrapper: {value: 1}
+        optional_float_wrapper: {value: 1}
+        optional_double_wrapper: {value: 1}
+        optional_string_wrapper: {value: "1"}
+        optional_bytes_wrapper: {value: "\x01\x02"}
+      )");
+  RunValidJsonTest(
+      "RepeatedBoolWrapper", REQUIRED,
+      R"({"repeatedBoolWrapper": [true, false]})",
+      "repeated_bool_wrapper: {value: true}"
+      "repeated_bool_wrapper: {value: false}");
+  RunValidJsonTest(
+      "RepeatedInt32Wrapper", REQUIRED,
+      R"({"repeatedInt32Wrapper": [0, 1]})",
+      "repeated_int32_wrapper: {value: 0}"
+      "repeated_int32_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedUint32Wrapper", REQUIRED,
+      R"({"repeatedUint32Wrapper": [0, 1]})",
+      "repeated_uint32_wrapper: {value: 0}"
+      "repeated_uint32_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedInt64Wrapper", REQUIRED,
+      R"({"repeatedInt64Wrapper": [0, 1]})",
+      "repeated_int64_wrapper: {value: 0}"
+      "repeated_int64_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedUint64Wrapper", REQUIRED,
+      R"({"repeatedUint64Wrapper": [0, 1]})",
+      "repeated_uint64_wrapper: {value: 0}"
+      "repeated_uint64_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedFloatWrapper", REQUIRED,
+      R"({"repeatedFloatWrapper": [0, 1]})",
+      "repeated_float_wrapper: {value: 0}"
+      "repeated_float_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedDoubleWrapper", REQUIRED,
+      R"({"repeatedDoubleWrapper": [0, 1]})",
+      "repeated_double_wrapper: {value: 0}"
+      "repeated_double_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedStringWrapper", REQUIRED,
+      R"({"repeatedStringWrapper": ["", "AQI="]})",
+      R"(
+        repeated_string_wrapper: {value: ""}
+        repeated_string_wrapper: {value: "AQI="}
+      )");
+  RunValidJsonTest(
+      "RepeatedBytesWrapper", REQUIRED,
+      R"({"repeatedBytesWrapper": ["", "AQI="]})",
+      R"(
+        repeated_bytes_wrapper: {value: ""}
+        repeated_bytes_wrapper: {value: "\x01\x02"}
+      )");
+  RunValidJsonTest(
+      "WrapperTypesWithNullValue", REQUIRED,
+      R"({
+        "optionalBoolWrapper": null,
+        "optionalInt32Wrapper": null,
+        "optionalUint32Wrapper": null,
+        "optionalInt64Wrapper": null,
+        "optionalUint64Wrapper": null,
+        "optionalFloatWrapper": null,
+        "optionalDoubleWrapper": null,
+        "optionalStringWrapper": null,
+        "optionalBytesWrapper": null,
+        "repeatedBoolWrapper": null,
+        "repeatedInt32Wrapper": null,
+        "repeatedUint32Wrapper": null,
+        "repeatedInt64Wrapper": null,
+        "repeatedUint64Wrapper": null,
+        "repeatedFloatWrapper": null,
+        "repeatedDoubleWrapper": null,
+        "repeatedStringWrapper": null,
+        "repeatedBytesWrapper": null
+      })",
+      "");
+
+  // Duration
+  RunValidJsonTest(
+      "DurationMinValue", REQUIRED,
+      R"({"optionalDuration": "-315576000000.999999999s"})",
+      "optional_duration: {seconds: -315576000000 nanos: -999999999}");
+  RunValidJsonTest(
+      "DurationMaxValue", REQUIRED,
+      R"({"optionalDuration": "315576000000.999999999s"})",
+      "optional_duration: {seconds: 315576000000 nanos: 999999999}");
+  RunValidJsonTest(
+      "DurationRepeatedValue", REQUIRED,
+      R"({"repeatedDuration": ["1.5s", "-1.5s"]})",
+      "repeated_duration: {seconds: 1 nanos: 500000000}"
+      "repeated_duration: {seconds: -1 nanos: -500000000}");
+  RunValidJsonTest(
+      "DurationNull", REQUIRED,
+      R"({"optionalDuration": null})",
+      "");
+
+  ExpectParseFailureForJson(
+      "DurationMissingS", REQUIRED,
+      R"({"optionalDuration": "1"})");
+  ExpectParseFailureForJson(
+      "DurationJsonInputTooSmall", REQUIRED,
+      R"({"optionalDuration": "-315576000001.000000000s"})");
+  ExpectParseFailureForJson(
+      "DurationJsonInputTooLarge", REQUIRED,
+      R"({"optionalDuration": "315576000001.000000000s"})");
+  ExpectSerializeFailureForJson(
+      "DurationProtoInputTooSmall", REQUIRED,
+      "optional_duration: {seconds: -315576000001 nanos: 0}");
+  ExpectSerializeFailureForJson(
+      "DurationProtoInputTooLarge", REQUIRED,
+      "optional_duration: {seconds: 315576000001 nanos: 0}");
+
+  RunValidJsonTestWithValidator(
+      "DurationHasZeroFractionalDigit", RECOMMENDED,
+      R"({"optionalDuration": "1.000000000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas3FractionalDigits", RECOMMENDED,
+      R"({"optionalDuration": "1.010000000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.010s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas6FractionalDigits", RECOMMENDED,
+      R"({"optionalDuration": "1.000010000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.000010s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas9FractionalDigits", RECOMMENDED,
+      R"({"optionalDuration": "1.000000010s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.000000010s";
+      });
+
+  // Timestamp
+  RunValidJsonTest(
+      "TimestampMinValue", REQUIRED,
+      R"({"optionalTimestamp": "0001-01-01T00:00:00Z"})",
+      "optional_timestamp: {seconds: -62135596800}");
+  RunValidJsonTest(
+      "TimestampMaxValue", REQUIRED,
+      R"({"optionalTimestamp": "9999-12-31T23:59:59.999999999Z"})",
+      "optional_timestamp: {seconds: 253402300799 nanos: 999999999}");
+  RunValidJsonTest(
+      "TimestampRepeatedValue", REQUIRED,
+      R"({
+        "repeatedTimestamp": [
+          "0001-01-01T00:00:00Z",
+          "9999-12-31T23:59:59.999999999Z"
+        ]
+      })",
+      "repeated_timestamp: {seconds: -62135596800}"
+      "repeated_timestamp: {seconds: 253402300799 nanos: 999999999}");
+  RunValidJsonTest(
+      "TimestampWithPositiveOffset", REQUIRED,
+      R"({"optionalTimestamp": "1970-01-01T08:00:00+08:00"})",
+      "optional_timestamp: {seconds: 0}");
+  RunValidJsonTest(
+      "TimestampWithNegativeOffset", REQUIRED,
+      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
+      "optional_timestamp: {seconds: 0}");
+  RunValidJsonTest(
+      "TimestampNull", REQUIRED,
+      R"({"optionalTimestamp": null})",
+      "");
+
+  ExpectParseFailureForJson(
+      "TimestampJsonInputTooSmall", REQUIRED,
+      R"({"optionalTimestamp": "0000-01-01T00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputTooLarge", REQUIRED,
+      R"({"optionalTimestamp": "10000-01-01T00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputMissingZ", REQUIRED,
+      R"({"optionalTimestamp": "0001-01-01T00:00:00"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputMissingT", REQUIRED,
+      R"({"optionalTimestamp": "0001-01-01 00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputLowercaseZ", REQUIRED,
+      R"({"optionalTimestamp": "0001-01-01T00:00:00z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputLowercaseT", REQUIRED,
+      R"({"optionalTimestamp": "0001-01-01t00:00:00Z"})");
+  ExpectSerializeFailureForJson(
+      "TimestampProtoInputTooSmall", REQUIRED,
+      "optional_timestamp: {seconds: -62135596801}");
+  ExpectSerializeFailureForJson(
+      "TimestampProtoInputTooLarge", REQUIRED,
+      "optional_timestamp: {seconds: 253402300800}");
+  RunValidJsonTestWithValidator(
+      "TimestampZeroNormalized", RECOMMENDED,
+      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHasZeroFractionalDigit", RECOMMENDED,
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas3FractionalDigits", RECOMMENDED,
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.010000000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.010Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas6FractionalDigits", RECOMMENDED,
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000010000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.000010Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas9FractionalDigits", RECOMMENDED,
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000010Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.000000010Z";
+      });
+
+  // FieldMask
+  RunValidJsonTest(
+      "FieldMask", REQUIRED,
+      R"({"optionalFieldMask": "foo,barBaz"})",
+      R"(optional_field_mask: {paths: "foo" paths: "bar_baz"})");
+  ExpectParseFailureForJson(
+      "FieldMaskInvalidCharacter", RECOMMENDED,
+      R"({"optionalFieldMask": "foo,bar_bar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskPathsDontRoundTrip", RECOMMENDED,
+      R"(optional_field_mask: {paths: "fooBar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskNumbersDontRoundTrip", RECOMMENDED,
+      R"(optional_field_mask: {paths: "foo_3_bar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskTooManyUnderscore", RECOMMENDED,
+      R"(optional_field_mask: {paths: "foo__bar"})");
+
+  // Struct
+  RunValidJsonTest(
+      "Struct", REQUIRED,
+      R"({
+        "optionalStruct": {
+          "nullValue": null,
+          "intValue": 1234,
+          "boolValue": true,
+          "doubleValue": 1234.5678,
+          "stringValue": "Hello world!",
+          "listValue": [1234, "5678"],
+          "objectValue": {
+            "value": 0
+          }
+        }
+      })",
+      R"(
+        optional_struct: {
+          fields: {
+            key: "nullValue"
+            value: {null_value: NULL_VALUE}
+          }
+          fields: {
+            key: "intValue"
+            value: {number_value: 1234}
+          }
+          fields: {
+            key: "boolValue"
+            value: {bool_value: true}
+          }
+          fields: {
+            key: "doubleValue"
+            value: {number_value: 1234.5678}
+          }
+          fields: {
+            key: "stringValue"
+            value: {string_value: "Hello world!"}
+          }
+          fields: {
+            key: "listValue"
+            value: {
+              list_value: {
+                values: {
+                  number_value: 1234
+                }
+                values: {
+                  string_value: "5678"
+                }
+              }
+            }
+          }
+          fields: {
+            key: "objectValue"
+            value: {
+              struct_value: {
+                fields: {
+                  key: "value"
+                  value: {
+                    number_value: 0
+                  }
+                }
+              }
+            }
+          }
+        }
+      )");
+  // Value
+  RunValidJsonTest(
+      "ValueAcceptInteger", REQUIRED,
+      R"({"optionalValue": 1})",
+      "optional_value: { number_value: 1}");
+  RunValidJsonTest(
+      "ValueAcceptFloat", REQUIRED,
+      R"({"optionalValue": 1.5})",
+      "optional_value: { number_value: 1.5}");
+  RunValidJsonTest(
+      "ValueAcceptBool", REQUIRED,
+      R"({"optionalValue": false})",
+      "optional_value: { bool_value: false}");
+  RunValidJsonTest(
+      "ValueAcceptNull", REQUIRED,
+      R"({"optionalValue": null})",
+      "optional_value: { null_value: NULL_VALUE}");
+  RunValidJsonTest(
+      "ValueAcceptString", REQUIRED,
+      R"({"optionalValue": "hello"})",
+      R"(optional_value: { string_value: "hello"})");
+  RunValidJsonTest(
+      "ValueAcceptList", REQUIRED,
+      R"({"optionalValue": [0, "hello"]})",
+      R"(
+        optional_value: {
+          list_value: {
+            values: {
+              number_value: 0
+            }
+            values: {
+              string_value: "hello"
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "ValueAcceptObject", REQUIRED,
+      R"({"optionalValue": {"value": 1}})",
+      R"(
+        optional_value: {
+          struct_value: {
+            fields: {
+              key: "value"
+              value: {
+                number_value: 1
+              }
+            }
+          }
+        }
+      )");
+
+  // Any
+  RunValidJsonTest(
+      "Any", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3",
+          "optionalInt32": 12345
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
+            optional_int32: 12345
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyNested", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Any",
+          "value": {
+            "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3",
+            "optionalInt32": 12345
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Any] {
+            [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
+              optional_int32: 12345
+            }
+          }
+        }
+      )");
+  // The special "@type" tag is not required to appear first.
+  RunValidJsonTest(
+      "AnyUnorderedTypeTag", REQUIRED,
+      R"({
+        "optionalAny": {
+          "optionalInt32": 12345,
+          "@type": "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
+            optional_int32: 12345
+          }
+        }
+      )");
+  // Well-known types in Any.
+  RunValidJsonTest(
+      "AnyWithInt32ValueWrapper", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Int32Value",
+          "value": 12345
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Int32Value] {
+            value: 12345
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithDuration", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Duration",
+          "value": "1.5s"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Duration] {
+            seconds: 1
+            nanos: 500000000
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithTimestamp", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Timestamp",
+          "value": "1970-01-01T00:00:00Z"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Timestamp] {
+            seconds: 0
+            nanos: 0
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithFieldMask", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.FieldMask",
+          "value": "foo,barBaz"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.FieldMask] {
+            paths: ["foo", "bar_baz"]
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithStruct", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Struct",
+          "value": {
+            "foo": 1
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Struct] {
+            fields: {
+              key: "foo"
+              value: {
+                number_value: 1
+              }
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithValueForJsonObject", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Value",
+          "value": {
+            "foo": 1
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Value] {
+            struct_value: {
+              fields: {
+                key: "foo"
+                value: {
+                  number_value: 1
+                }
+              }
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithValueForInteger", REQUIRED,
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Value",
+          "value": 1
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Value] {
+            number_value: 1
+          }
+        }
+      )");
+
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonNumber", REQUIRED,
+      R"({
+        "unknown": 1
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonString", REQUIRED,
+      R"({
+        "unknown": "a"
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonTrue", REQUIRED,
+      R"({
+        "unknown": true
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonFalse", REQUIRED,
+      R"({
+        "unknown": false
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonNull", REQUIRED,
+      R"({
+        "unknown": null
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonObject", REQUIRED,
+      R"({
+        "unknown": {"a": 1}
+      })",
+      "");
+}
+
+struct StaticTestSuiteInitializer {
+  StaticTestSuiteInitializer() {
+    AddTestSuite(new ConformanceTestSuiteImpl());
+  }
+} static_test_suite_initializer;
+
+}  // namespace protobuf
+}  // namespace google

+ 16 - 6
conformance/conformance_test_runner.cc

@@ -66,9 +66,9 @@
 #include "conformance.pb.h"
 #include "conformance.pb.h"
 #include "conformance_test.h"
 #include "conformance_test.h"
 
 
-using conformance::ConformanceRequest;
 using conformance::ConformanceResponse;
 using conformance::ConformanceResponse;
 using google::protobuf::StringAppendF;
 using google::protobuf::StringAppendF;
+using google::protobuf::ConformanceTestSuite;
 using std::string;
 using std::string;
 using std::vector;
 using std::vector;
 
 
@@ -287,7 +287,8 @@ void ParseFailureList(const char *filename, std::vector<string>* failure_list) {
 
 
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
   char *program;
   char *program;
-  google::protobuf::ConformanceTestSuite suite;
+  const std::set<ConformanceTestSuite*>& test_suite_set =
+      ::google::protobuf::GetTestSuiteSet();
 
 
   string failure_list_filename;
   string failure_list_filename;
   std::vector<string> failure_list;
   std::vector<string> failure_list;
@@ -298,9 +299,13 @@ int main(int argc, char *argv[]) {
       failure_list_filename = argv[arg];
       failure_list_filename = argv[arg];
       ParseFailureList(argv[arg], &failure_list);
       ParseFailureList(argv[arg], &failure_list);
     } else if (strcmp(argv[arg], "--verbose") == 0) {
     } else if (strcmp(argv[arg], "--verbose") == 0) {
-      suite.SetVerbose(true);
+      for (auto *suite : test_suite_set) {
+        suite->SetVerbose(true);
+      }
     } else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
     } else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
-      suite.SetEnforceRecommended(true);
+      for (auto suite : test_suite_set) {
+        suite->SetEnforceRecommended(true);
+      }
     } else if (argv[arg][0] == '-') {
     } else if (argv[arg][0] == '-') {
       fprintf(stderr, "Unknown option: %s\n", argv[arg]);
       fprintf(stderr, "Unknown option: %s\n", argv[arg]);
       UsageError();
       UsageError();
@@ -313,11 +318,16 @@ int main(int argc, char *argv[]) {
     }
     }
   }
   }
 
 
-  suite.SetFailureList(failure_list_filename, failure_list);
+  for (auto suite : test_suite_set) {
+    suite->SetFailureList(failure_list_filename, failure_list);
+  }
   ForkPipeRunner runner(program);
   ForkPipeRunner runner(program);
 
 
   std::string output;
   std::string output;
-  bool ok = suite.RunSuite(&runner, &output);
+  bool ok = true;
+  for (auto suite : test_suite_set) {
+    ok &= suite->RunSuite(&runner, &output);
+  }
 
 
   fwrite(output.c_str(), 1, output.size(), stderr);
   fwrite(output.c_str(), 1, output.size(), stderr);
 
 

+ 0 - 6
conformance/failure_list_cpp.txt

@@ -54,9 +54,3 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 0 - 6
conformance/failure_list_csharp.txt

@@ -1,8 +1,2 @@
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 0 - 6
conformance/failure_list_java.txt

@@ -45,9 +45,3 @@ Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValu
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 20 - 0
conformance/failure_list_php_c.txt

@@ -1,6 +1,8 @@
 Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
 Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
 Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
 Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
 Recommended.FieldMaskTooManyUnderscore.JsonOutput
 Recommended.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
+Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
@@ -14,6 +16,11 @@ Recommended.Proto3.JsonInput.StringEndsWithEscapeChar
 Recommended.Proto3.JsonInput.StringFieldSurrogateInWrongOrder
 Recommended.Proto3.JsonInput.StringFieldSurrogateInWrongOrder
 Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
+Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
+Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
+Recommended.Proto3.JsonInput.TimestampHas9FractionalDigits.Validator
+Recommended.Proto3.JsonInput.TimestampHasZeroFractionalDigit.Validator
+Recommended.Proto3.JsonInput.TimestampZeroNormalized.Validator
 Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
 Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
 Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
 Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooLarge.JsonOutput
@@ -55,6 +62,7 @@ Required.Proto3.JsonInput.FieldMask.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
+Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
@@ -103,6 +111,16 @@ Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOu
 Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
 Required.Proto3.JsonInput.Struct.JsonOutput
 Required.Proto3.JsonInput.Struct.JsonOutput
 Required.Proto3.JsonInput.Struct.ProtobufOutput
 Required.Proto3.JsonInput.Struct.ProtobufOutput
+Required.Proto3.JsonInput.TimestampMaxValue.JsonOutput
+Required.Proto3.JsonInput.TimestampMaxValue.ProtobufOutput
+Required.Proto3.JsonInput.TimestampMinValue.JsonOutput
+Required.Proto3.JsonInput.TimestampMinValue.ProtobufOutput
+Required.Proto3.JsonInput.TimestampRepeatedValue.JsonOutput
+Required.Proto3.JsonInput.TimestampRepeatedValue.ProtobufOutput
+Required.Proto3.JsonInput.TimestampWithNegativeOffset.JsonOutput
+Required.Proto3.JsonInput.TimestampWithNegativeOffset.ProtobufOutput
+Required.Proto3.JsonInput.TimestampWithPositiveOffset.JsonOutput
+Required.Proto3.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptBool.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptBool.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptBool.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptBool.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput
@@ -111,6 +129,8 @@ Required.Proto3.JsonInput.ValueAcceptInteger.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
+Required.Proto3.JsonInput.ValueAcceptListWithNull.JsonOutput
+Required.Proto3.JsonInput.ValueAcceptListWithNull.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput

+ 0 - 6
conformance/failure_list_python-post26.txt

@@ -1,8 +1,2 @@
 JsonInput.StringFieldSurrogateInWrongOrder
 JsonInput.StringFieldSurrogateInWrongOrder
 JsonInput.StringFieldUnpairedHighSurrogate
 JsonInput.StringFieldUnpairedHighSurrogate
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 0 - 6
conformance/failure_list_python.txt

@@ -19,9 +19,3 @@ Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_0
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 0 - 6
conformance/failure_list_python_cpp.txt

@@ -52,9 +52,3 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 0 - 8
conformance/failure_list_ruby.txt

@@ -120,8 +120,6 @@ Required.Proto3.JsonInput.ValueAcceptInteger.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptListWithNull.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptListWithNull.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
@@ -135,9 +133,3 @@ Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
 Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
-Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 1 - 5
java/core/src/main/java/com/google/protobuf/AbstractMessage.java

@@ -32,7 +32,6 @@ package com.google.protobuf;
 
 
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.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;
@@ -446,10 +445,7 @@ 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();
+      boolean discardUnknown = input.shouldDiscardUnknownFields();
       final UnknownFieldSet.Builder unknownFields =
       final UnknownFieldSet.Builder unknownFields =
           discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields());
           discardUnknown ? null : UnknownFieldSet.newBuilder(getUnknownFields());
       while (true) {
       while (true) {

+ 2 - 1
java/core/src/main/java/com/google/protobuf/BooleanArrayList.java

@@ -42,7 +42,8 @@ import java.util.RandomAccess;
  *
  *
  * @author dweis@google.com (Daniel Weis)
  * @author dweis@google.com (Daniel Weis)
  */
  */
-final class BooleanArrayList extends AbstractProtobufList<Boolean>
+final class BooleanArrayList
+    extends AbstractProtobufList<Boolean>
     implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
     implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
 
 
   private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
   private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();

+ 83 - 7
java/core/src/main/java/com/google/protobuf/ByteString.java

@@ -46,6 +46,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.NoSuchElementException;
@@ -221,6 +222,67 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
     return size() == 0;
     return size() == 0;
   }
   }
 
 
+  // =================================================================
+  // Comparison
+
+  private static final int UNSIGNED_BYTE_MASK = 0xFF;
+
+  /**
+   * Returns the value of the given byte as an integer, interpreting the byte as an unsigned value.
+   * That is, returns {@code value + 256} if {@code value} is negative; {@code value} itself
+   * otherwise.
+   *
+   * <p>Note: This code was copied from {@link com.google.common.primitives.UnsignedBytes#toInt}, as
+   * Guava libraries cannot be used in the {@code com.google.protobuf} package.
+   */
+  private static int toInt(byte value) {
+    return value & UNSIGNED_BYTE_MASK;
+  }
+
+  /**
+   * Compares two {@link ByteString}s lexicographically, treating their contents as unsigned byte
+   * values between 0 and 255 (inclusive).
+   *
+   * <p>For example, {@code (byte) -1} is considered to be greater than {@code (byte) 1} because
+   * it is interpreted as an unsigned value, {@code 255}.
+   */
+  private static final Comparator<ByteString> UNSIGNED_LEXICOGRAPHICAL_COMPARATOR =
+      new Comparator<ByteString>() {
+        @Override
+        public int compare(ByteString former, ByteString latter) {
+          ByteIterator formerBytes = former.iterator();
+          ByteIterator latterBytes = latter.iterator();
+
+          while (formerBytes.hasNext() && latterBytes.hasNext()) {
+            // Note: This code was copied from com.google.common.primitives.UnsignedBytes#compare,
+            // as Guava libraries cannot be used in the {@code com.google.protobuf} package.
+            int result =
+                Integer.compare(toInt(formerBytes.nextByte()), toInt(latterBytes.nextByte()));
+            if (result != 0) {
+              return result;
+            }
+          }
+
+          return Integer.compare(former.size(), latter.size());
+        }
+      };
+
+  /**
+   * Returns a {@link Comparator<ByteString>} which compares {@link ByteString}-s lexicographically
+   * as sequences of unsigned bytes (i.e. values between 0 and 255, inclusive).
+   *
+   * <p>For example, {@code (byte) -1} is considered to be greater than {@code (byte) 1} because
+   * it is interpreted as an unsigned value, {@code 255}:
+   *
+   * <ul>
+   * <li>{@code `-1` -> 0b11111111 (two's complement) -> 255}
+   * <li>{@code `1` -> 0b00000001 -> 1}
+   * </ul>
+   */
+  public static Comparator<ByteString> unsignedLexicographicalComparator() {
+    return UNSIGNED_LEXICOGRAPHICAL_COMPARATOR;
+  }
+
   // =================================================================
   // =================================================================
   // ByteString -> substring
   // ByteString -> substring
 
 
@@ -287,8 +349,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    * @param offset offset in source array
    * @param offset offset in source array
    * @param size number of bytes to copy
    * @param size number of bytes to copy
    * @return new {@code ByteString}
    * @return new {@code ByteString}
+   * @throws IndexOutOfBoundsException if {@code offset} or {@code size} are out of bounds
    */
    */
   public static ByteString copyFrom(byte[] bytes, int offset, int size) {
   public static ByteString copyFrom(byte[] bytes, int offset, int size) {
+    checkRange(offset, offset + size, bytes.length);
     return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size));
     return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size));
   }
   }
 
 
@@ -339,8 +403,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    * @param bytes source buffer
    * @param bytes source buffer
    * @param size number of bytes to copy
    * @param size number of bytes to copy
    * @return new {@code ByteString}
    * @return new {@code ByteString}
+   * @throws IndexOutOfBoundsException if {@code size > bytes.remaining()}
    */
    */
   public static ByteString copyFrom(ByteBuffer bytes, int size) {
   public static ByteString copyFrom(ByteBuffer bytes, int size) {
+    checkRange(0, size, bytes.remaining());
     byte[] copy = new byte[size];
     byte[] copy = new byte[size];
     bytes.get(copy);
     bytes.get(copy);
     return new LiteralByteString(copy);
     return new LiteralByteString(copy);
@@ -578,6 +644,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
   /**
   /**
    * Copies bytes into a buffer at the given offset.
    * Copies bytes into a buffer at the given offset.
    *
    *
+   * <p>To copy a subset of bytes, you call this method on the return value of {@link
+   * #substring(int, int)}. Example: {@code byteString.substring(start, end).copyTo(target, offset)}
+   *
    * @param target buffer to copy into
    * @param target buffer to copy into
    * @param offset in the target buffer
    * @param offset in the target buffer
    * @throws IndexOutOfBoundsException if the offset is negative or too large
    * @throws IndexOutOfBoundsException if the offset is negative or too large
@@ -589,15 +658,16 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
   /**
   /**
    * Copies bytes into a buffer.
    * Copies bytes into a buffer.
    *
    *
-   * @param target       buffer to copy into
+   * @param target buffer to copy into
    * @param sourceOffset offset within these bytes
    * @param sourceOffset offset within these bytes
    * @param targetOffset offset within the target buffer
    * @param targetOffset offset within the target buffer
    * @param numberToCopy number of bytes to copy
    * @param numberToCopy number of bytes to copy
-   * @throws IndexOutOfBoundsException if an offset or size is negative or too
-   *     large
+   * @throws IndexOutOfBoundsException if an offset or size is negative or too large
+   * @deprecation Instead, call {@code byteString.substring(sourceOffset, sourceOffset +
+   *     numberToCopy).copyTo(target, targetOffset)}
    */
    */
-  public final void copyTo(byte[] target, int sourceOffset, int targetOffset,
-      int numberToCopy) {
+  @Deprecated
+  public final void copyTo(byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
     checkRange(sourceOffset, sourceOffset + numberToCopy, size());
     checkRange(sourceOffset, sourceOffset + numberToCopy, size());
     checkRange(targetOffset, targetOffset + numberToCopy, target.length);
     checkRange(targetOffset, targetOffset + numberToCopy, target.length);
     if (numberToCopy > 0) {
     if (numberToCopy > 0) {
@@ -617,10 +687,13 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
   /**
   /**
    * Copies bytes into a ByteBuffer.
    * Copies bytes into a ByteBuffer.
    *
    *
+   * <p>To copy a subset of bytes, you call this method on the return value of {@link
+   * #substring(int, int)}. Example: {@code byteString.substring(start, end).copyTo(target)}
+   *
    * @param target ByteBuffer to copy into.
    * @param target ByteBuffer to copy into.
    * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only
    * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only
-   * @throws java.nio.BufferOverflowException if the {@code target}'s
-   *     remaining() space is not large enough to hold the data.
+   * @throws java.nio.BufferOverflowException if the {@code target}'s remaining() space is not large
+   *     enough to hold the data.
    */
    */
   public abstract void copyTo(ByteBuffer target);
   public abstract void copyTo(ByteBuffer target);
 
 
@@ -1258,6 +1331,9 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
      * @param bytes array to wrap
      * @param bytes array to wrap
      */
      */
     LiteralByteString(byte[] bytes) {
     LiteralByteString(byte[] bytes) {
+      if (bytes == null) {
+        throw new NullPointerException();
+      }
       this.bytes = bytes;
       this.bytes = bytes;
     }
     }
 
 

+ 17 - 101
java/core/src/main/java/com/google/protobuf/CodedInputStream.java

@@ -64,12 +64,6 @@ public abstract class CodedInputStream {
   // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h
   // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h
   private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE;
   private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE;
 
 
-  /**
-   * Whether to enable our custom UTF-8 decode codepath which does not use {@link StringCoding}.
-   * Currently disabled.
-   */
-  private static final boolean ENABLE_CUSTOM_UTF8_DECODE = false;
-
   /** Visible for subclasses. See setRecursionLimit() */
   /** Visible for subclasses. See setRecursionLimit() */
   int recursionDepth;
   int recursionDepth;
 
 
@@ -417,21 +411,7 @@ public abstract class CodedInputStream {
   }
   }
 
 
 
 
-  private boolean explicitDiscardUnknownFields = false;
-
-  private static volatile boolean proto3DiscardUnknownFieldsDefault = false;
-
-  static void setProto3DiscardUnknownsByDefaultForTest() {
-    proto3DiscardUnknownFieldsDefault = true;
-  }
-
-  static void setProto3KeepUnknownsByDefaultForTest() {
-    proto3DiscardUnknownFieldsDefault = false;
-  }
-
-  static boolean getProto3DiscardUnknownFieldsDefault() {
-    return proto3DiscardUnknownFieldsDefault;
-  }
+  private boolean shouldDiscardUnknownFields = false;
 
 
   /**
   /**
    * Sets this {@code CodedInputStream} to discard unknown fields. Only applies to full runtime
    * Sets this {@code CodedInputStream} to discard unknown fields. Only applies to full runtime
@@ -442,7 +422,7 @@ public abstract class CodedInputStream {
    * runtime.
    * runtime.
    */
    */
   final void discardUnknownFields() {
   final void discardUnknownFields() {
-    explicitDiscardUnknownFields = true;
+    shouldDiscardUnknownFields = true;
   }
   }
 
 
   /**
   /**
@@ -450,7 +430,7 @@ public abstract class CodedInputStream {
    * default.
    * default.
    */
    */
   final void unsetDiscardUnknownFields() {
   final void unsetDiscardUnknownFields() {
-    explicitDiscardUnknownFields = false;
+    shouldDiscardUnknownFields = false;
   }
   }
 
 
   /**
   /**
@@ -458,19 +438,7 @@ public abstract class CodedInputStream {
    * runtime messages.
    * runtime messages.
    */
    */
   final boolean shouldDiscardUnknownFields() {
   final boolean shouldDiscardUnknownFields() {
-    return explicitDiscardUnknownFields;
-  }
-
-  /**
-   * Whether unknown fields in this input stream should be discarded during parsing for proto3 full
-   * runtime messages.
-   *
-   * <p>This function was temporarily introduced before proto3 unknown fields behavior is changed.
-   * TODO(liujisi): remove this and related code in GeneratedMessage after proto3 unknown
-   * fields migration is done.
-   */
-  final boolean shouldDiscardUnknownFieldsProto3() {
-    return explicitDiscardUnknownFields ? true : proto3DiscardUnknownFieldsDefault;
+    return shouldDiscardUnknownFields;
   }
   }
 
 
   /**
   /**
@@ -831,19 +799,9 @@ public abstract class CodedInputStream {
     public String readStringRequireUtf8() throws IOException {
     public String readStringRequireUtf8() throws IOException {
       final int size = readRawVarint32();
       final int size = readRawVarint32();
       if (size > 0 && size <= (limit - pos)) {
       if (size > 0 && size <= (limit - pos)) {
-        if (ENABLE_CUSTOM_UTF8_DECODE) {
-          String result = Utf8.decodeUtf8(buffer, pos, size);
-          pos += size;
-          return result;
-        } else {
-          // TODO(martinrb): We could save a pass by validating while decoding.
-          if (!Utf8.isValidUtf8(buffer, pos, pos + size)) {
-            throw InvalidProtocolBufferException.invalidUtf8();
-          }
-          final int tempPos = pos;
-          pos += size;
-          return new String(buffer, tempPos, size, UTF_8);
-        }
+        String result = Utf8.decodeUtf8(buffer, pos, size);
+        pos += size;
+        return result;
       }
       }
 
 
       if (size == 0) {
       if (size == 0) {
@@ -1559,25 +1517,10 @@ public abstract class CodedInputStream {
     public String readStringRequireUtf8() throws IOException {
     public String readStringRequireUtf8() throws IOException {
       final int size = readRawVarint32();
       final int size = readRawVarint32();
       if (size > 0 && size <= remaining()) {
       if (size > 0 && size <= remaining()) {
-        if (ENABLE_CUSTOM_UTF8_DECODE) {
-          final int bufferPos = bufferPos(pos);
-          String result = Utf8.decodeUtf8(buffer, bufferPos, size);
-          pos += size;
-          return result;
-        } else {
-          // TODO(nathanmittler): Is there a way to avoid this copy?
-          // The same as readBytes' logic
-          byte[] bytes = new byte[size];
-          UnsafeUtil.copyMemory(pos, bytes, 0, size);
-          // TODO(martinrb): We could save a pass by validating while decoding.
-          if (!Utf8.isValidUtf8(bytes)) {
-            throw InvalidProtocolBufferException.invalidUtf8();
-          }
-
-          String result = new String(bytes, UTF_8);
-          pos += size;
-          return result;
-        }
+        final int bufferPos = bufferPos(pos);
+        String result = Utf8.decodeUtf8(buffer, bufferPos, size);
+        pos += size;
+        return result;
       }
       }
 
 
       if (size == 0) {
       if (size == 0) {
@@ -2345,15 +2288,7 @@ public abstract class CodedInputStream {
         bytes = readRawBytesSlowPath(size);
         bytes = readRawBytesSlowPath(size);
         tempPos = 0;
         tempPos = 0;
       }
       }
-      if (ENABLE_CUSTOM_UTF8_DECODE) {
-        return Utf8.decodeUtf8(bytes, tempPos, size);
-      } else {
-        // TODO(martinrb): We could save a pass by validating while decoding.
-        if (!Utf8.isValidUtf8(bytes, tempPos, tempPos + size)) {
-          throw InvalidProtocolBufferException.invalidUtf8();
-        }
-        return new String(bytes, tempPos, size, UTF_8);
-      }
+      return Utf8.decodeUtf8(bytes, tempPos, size);
     }
     }
 
 
     @Override
     @Override
@@ -3373,34 +3308,15 @@ public abstract class CodedInputStream {
     public String readStringRequireUtf8() throws IOException {
     public String readStringRequireUtf8() throws IOException {
       final int size = readRawVarint32();
       final int size = readRawVarint32();
       if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
       if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
-        if (ENABLE_CUSTOM_UTF8_DECODE) {
-          final int bufferPos = (int) (currentByteBufferPos - currentByteBufferStartPos);
-          String result = Utf8.decodeUtf8(currentByteBuffer, bufferPos, size);
-          currentByteBufferPos += size;
-          return result;
-        } else {
-          byte[] bytes = new byte[size];
-          UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
-          if (!Utf8.isValidUtf8(bytes)) {
-            throw InvalidProtocolBufferException.invalidUtf8();
-          }
-          String result = new String(bytes, UTF_8);
-          currentByteBufferPos += size;
-          return result;
-        }
+        final int bufferPos = (int) (currentByteBufferPos - currentByteBufferStartPos);
+        String result = Utf8.decodeUtf8(currentByteBuffer, bufferPos, size);
+        currentByteBufferPos += size;
+        return result;
       }
       }
       if (size >= 0 && size <= remaining()) {
       if (size >= 0 && size <= remaining()) {
         byte[] bytes = new byte[size];
         byte[] bytes = new byte[size];
         readRawBytesTo(bytes, 0, size);
         readRawBytesTo(bytes, 0, size);
-        if (ENABLE_CUSTOM_UTF8_DECODE) {
-          return Utf8.decodeUtf8(bytes, 0, size);
-        } else {
-          if (!Utf8.isValidUtf8(bytes)) {
-            throw InvalidProtocolBufferException.invalidUtf8();
-          }
-          String result = new String(bytes, UTF_8);
-          return result;
-        }
+        return Utf8.decodeUtf8(bytes, 0, size);
       }
       }
 
 
       if (size == 0) {
       if (size == 0) {

+ 2 - 1
java/core/src/main/java/com/google/protobuf/DoubleArrayList.java

@@ -42,7 +42,8 @@ import java.util.RandomAccess;
  *
  *
  * @author dweis@google.com (Daniel Weis)
  * @author dweis@google.com (Daniel Weis)
  */
  */
-final class DoubleArrayList extends AbstractProtobufList<Double>
+final class DoubleArrayList
+    extends AbstractProtobufList<Double>
     implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
     implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
 
 
   private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
   private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();

+ 0 - 8
java/core/src/main/java/com/google/protobuf/DynamicMessage.java

@@ -608,20 +608,12 @@ public final class DynamicMessage extends AbstractMessage {
 
 
     @Override
     @Override
     public Builder setUnknownFields(UnknownFieldSet unknownFields) {
     public Builder setUnknownFields(UnknownFieldSet unknownFields) {
-      if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
-          && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
-        return this;
-      }
       this.unknownFields = unknownFields;
       this.unknownFields = unknownFields;
       return this;
       return this;
     }
     }
 
 
     @Override
     @Override
     public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
     public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
-      if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3
-          && CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
-        return this;
-      }
       this.unknownFields =
       this.unknownFields =
         UnknownFieldSet.newBuilder(this.unknownFields)
         UnknownFieldSet.newBuilder(this.unknownFields)
                        .mergeFrom(unknownFields)
                        .mergeFrom(unknownFields)

+ 2 - 1
java/core/src/main/java/com/google/protobuf/FloatArrayList.java

@@ -42,7 +42,8 @@ import java.util.RandomAccess;
  *
  *
  * @author dweis@google.com (Daniel Weis)
  * @author dweis@google.com (Daniel Weis)
  */
  */
-final class FloatArrayList extends AbstractProtobufList<Float>
+final class FloatArrayList
+    extends AbstractProtobufList<Float>
     implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
     implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
 
 
   private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
   private static final FloatArrayList EMPTY_LIST = new FloatArrayList();

+ 1 - 2
java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -33,7 +33,6 @@ package com.google.protobuf;
 import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
 import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
 import com.google.protobuf.Internal.BooleanList;
 import com.google.protobuf.Internal.BooleanList;
 import com.google.protobuf.Internal.DoubleList;
 import com.google.protobuf.Internal.DoubleList;
-import com.google.protobuf.Internal.EnumLiteMap;
 import com.google.protobuf.Internal.FloatList;
 import com.google.protobuf.Internal.FloatList;
 import com.google.protobuf.Internal.IntList;
 import com.google.protobuf.Internal.IntList;
 import com.google.protobuf.Internal.LongList;
 import com.google.protobuf.Internal.LongList;
@@ -1600,7 +1599,7 @@ public abstract class GeneratedMessageLite<
   protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>>
   protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>>
       extends AbstractParser<T> {
       extends AbstractParser<T> {
 
 
-    private T defaultInstance;
+    private final T defaultInstance;
 
 
     public DefaultInstanceBasedParser(T defaultInstance) {
     public DefaultInstanceBasedParser(T defaultInstance) {
       this.defaultInstance = defaultInstance;
       this.defaultInstance = defaultInstance;

+ 90 - 17
java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java

@@ -38,6 +38,11 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
+import com.google.protobuf.Internal.BooleanList;
+import com.google.protobuf.Internal.DoubleList;
+import com.google.protobuf.Internal.FloatList;
+import com.google.protobuf.Internal.IntList;
+import com.google.protobuf.Internal.LongList;
 // In opensource protobuf, we have versioned this GeneratedMessageV3 class to GeneratedMessageV3V3 and
 // In opensource protobuf, we have versioned this GeneratedMessageV3 class to GeneratedMessageV3V3 and
 // in the future may have GeneratedMessageV3V4 etc. This allows us to change some aspects of this
 // in the future may have GeneratedMessageV3V4 etc. This allows us to change some aspects of this
 // class without breaking binary compatibility with old generated code that still subclasses
 // class without breaking binary compatibility with old generated code that still subclasses
@@ -293,16 +298,17 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     return unknownFields.mergeFieldFrom(tag, input);
     return unknownFields.mergeFieldFrom(tag, input);
   }
   }
 
 
+  /**
+   * Delegates to parseUnknownField. This method is obsolete, but we must retain it for
+   * compatibility with older generated code.
+   */
   protected boolean parseUnknownFieldProto3(
   protected boolean parseUnknownFieldProto3(
       CodedInputStream input,
       CodedInputStream input,
       UnknownFieldSet.Builder unknownFields,
       UnknownFieldSet.Builder unknownFields,
       ExtensionRegistryLite extensionRegistry,
       ExtensionRegistryLite extensionRegistry,
       int tag)
       int tag)
       throws IOException {
       throws IOException {
-    if (input.shouldDiscardUnknownFieldsProto3()) {
-      return input.skipField(tag);
-    }
-    return unknownFields.mergeFieldFrom(tag, input);
+    return parseUnknownField(input, unknownFields, extensionRegistry, tag);
   }
   }
 
 
   protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input)
   protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input)
@@ -363,6 +369,76 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
     return UnsafeUtil.hasUnsafeArrayOperations() && UnsafeUtil.hasUnsafeByteBufferOperations();
     return UnsafeUtil.hasUnsafeArrayOperations() && UnsafeUtil.hasUnsafeByteBufferOperations();
   }
   }
 
 
+  protected static IntList emptyIntList() {
+    return IntArrayList.emptyList();
+  }
+
+  protected static IntList newIntList() {
+    return new IntArrayList();
+  }
+
+  protected static IntList mutableCopy(IntList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static LongList emptyLongList() {
+    return LongArrayList.emptyList();
+  }
+
+  protected static LongList newLongList() {
+    return new LongArrayList();
+  }
+
+  protected static LongList mutableCopy(LongList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static FloatList emptyFloatList() {
+    return FloatArrayList.emptyList();
+  }
+
+  protected static FloatList newFloatList() {
+    return new FloatArrayList();
+  }
+
+  protected static FloatList mutableCopy(FloatList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static DoubleList emptyDoubleList() {
+    return DoubleArrayList.emptyList();
+  }
+
+  protected static DoubleList newDoubleList() {
+    return new DoubleArrayList();
+  }
+
+  protected static DoubleList mutableCopy(DoubleList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
+  protected static BooleanList emptyBooleanList() {
+    return BooleanArrayList.emptyList();
+  }
+
+  protected static BooleanList newBooleanList() {
+    return new BooleanArrayList();
+  }
+
+  protected static BooleanList mutableCopy(BooleanList list) {
+    int size = list.size();
+    return list.mutableCopyWithCapacity(
+        size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
+  }
+
   @Override
   @Override
   public void writeTo(final CodedOutputStream output) throws IOException {
   public void writeTo(final CodedOutputStream output) throws IOException {
     MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
     MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
@@ -641,13 +717,12 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       return (BuilderType) this;
       return (BuilderType) this;
     }
     }
 
 
+    /**
+     * Delegates to setUnknownFields. This method is obsolete, but we must retain it for
+     * compatibility with older generated code.
+     */
     protected BuilderType setUnknownFieldsProto3(final UnknownFieldSet unknownFields) {
     protected BuilderType setUnknownFieldsProto3(final UnknownFieldSet unknownFields) {
-      if (CodedInputStream.getProto3DiscardUnknownFieldsDefault()) {
-        return (BuilderType) this;
-      }
-      this.unknownFields = unknownFields;
-      onChanged();
-      return (BuilderType) this;
+      return setUnknownFields(unknownFields);
     }
     }
 
 
     @Override
     @Override
@@ -1009,19 +1084,17 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
           getDescriptorForType(), new MessageReflection.ExtensionAdapter(extensions), tag);
           getDescriptorForType(), new MessageReflection.ExtensionAdapter(extensions), tag);
     }
     }
 
 
+    /**
+     * Delegates to parseUnknownField. This method is obsolete, but we must retain it for
+     * compatibility with older generated code.
+     */
     @Override
     @Override
     protected boolean parseUnknownFieldProto3(
     protected boolean parseUnknownFieldProto3(
         CodedInputStream input,
         CodedInputStream input,
         UnknownFieldSet.Builder unknownFields,
         UnknownFieldSet.Builder unknownFields,
         ExtensionRegistryLite extensionRegistry,
         ExtensionRegistryLite extensionRegistry,
         int tag) throws IOException {
         int tag) throws IOException {
-      return MessageReflection.mergeFieldFrom(
-          input,
-          input.shouldDiscardUnknownFieldsProto3() ? null : unknownFields,
-          extensionRegistry,
-          getDescriptorForType(),
-          new MessageReflection.ExtensionAdapter(extensions),
-          tag);
+      return parseUnknownField(input, unknownFields, extensionRegistry, tag);
     }
     }
 
 
 
 

+ 2 - 1
java/core/src/main/java/com/google/protobuf/IntArrayList.java

@@ -42,7 +42,8 @@ import java.util.RandomAccess;
  *
  *
  * @author dweis@google.com (Daniel Weis)
  * @author dweis@google.com (Daniel Weis)
  */
  */
-final class IntArrayList extends AbstractProtobufList<Integer>
+final class IntArrayList
+    extends AbstractProtobufList<Integer>
     implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
     implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
 
 
   private static final IntArrayList EMPTY_LIST = new IntArrayList();
   private static final IntArrayList EMPTY_LIST = new IntArrayList();

+ 5 - 0
java/core/src/main/java/com/google/protobuf/Internal.java

@@ -234,6 +234,11 @@ public final class Internal {
     T findValueByNumber(int number);
     T findValueByNumber(int number);
   }
   }
 
 
+  /** Interface for an object which verifies integers are in range. */
+  public interface EnumVerifier {
+    boolean isInRange(int number);
+  }
+
   /**
   /**
    * Helper method for implementing {@link Message#hashCode()} for longs.
    * Helper method for implementing {@link Message#hashCode()} for longs.
    * @see Long#hashCode()
    * @see Long#hashCode()

+ 16 - 16
java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java

@@ -69,7 +69,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
   static {
   static {
     EMPTY_LIST.makeImmutable();
     EMPTY_LIST.makeImmutable();
   }
   }
-  
+
   static LazyStringArrayList emptyList() {
   static LazyStringArrayList emptyList() {
     return EMPTY_LIST;
     return EMPTY_LIST;
   }
   }
@@ -83,8 +83,8 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
     this(DEFAULT_CAPACITY);
     this(DEFAULT_CAPACITY);
   }
   }
 
 
-  public LazyStringArrayList(int intialCapacity) {
-    this(new ArrayList<Object>(intialCapacity));
+  public LazyStringArrayList(int initialCapacity) {
+    this(new ArrayList<Object>(initialCapacity));
   }
   }
 
 
   public LazyStringArrayList(LazyStringList from) {
   public LazyStringArrayList(LazyStringList from) {
@@ -95,7 +95,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
   public LazyStringArrayList(List<String> from) {
   public LazyStringArrayList(List<String> from) {
     this(new ArrayList<Object>(from));
     this(new ArrayList<Object>(from));
   }
   }
-  
+
   private LazyStringArrayList(ArrayList<Object> list) {
   private LazyStringArrayList(ArrayList<Object> list) {
     this.list = list;
     this.list = list;
   }
   }
@@ -150,13 +150,13 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
     list.add(index, element);
     list.add(index, element);
     modCount++;
     modCount++;
   }
   }
-  
+
   private void add(int index, ByteString element) {
   private void add(int index, ByteString element) {
     ensureIsMutable();
     ensureIsMutable();
     list.add(index, element);
     list.add(index, element);
     modCount++;
     modCount++;
   }
   }
-  
+
   private void add(int index, byte[] element) {
   private void add(int index, byte[] element) {
     ensureIsMutable();
     ensureIsMutable();
     list.add(index, element);
     list.add(index, element);
@@ -221,7 +221,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
     list.add(element);
     list.add(element);
     modCount++;
     modCount++;
   }
   }
-  
+
   @Override
   @Override
   public void add(byte[] element) {
   public void add(byte[] element) {
     ensureIsMutable();
     ensureIsMutable();
@@ -233,7 +233,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
   public Object getRaw(int index) {
   public Object getRaw(int index) {
     return list.get(index);
     return list.get(index);
   }
   }
-  
+
   @Override
   @Override
   public ByteString getByteString(int index) {
   public ByteString getByteString(int index) {
     Object o = list.get(index);
     Object o = list.get(index);
@@ -243,7 +243,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
     }
     }
     return b;
     return b;
   }
   }
-  
+
   @Override
   @Override
   public byte[] getByteArray(int index) {
   public byte[] getByteArray(int index) {
     Object o = list.get(index);
     Object o = list.get(index);
@@ -258,7 +258,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
   public void set(int index, ByteString s) {
   public void set(int index, ByteString s) {
     setAndReturn(index, s);
     setAndReturn(index, s);
   }
   }
-  
+
   private Object setAndReturn(int index, ByteString s) {
   private Object setAndReturn(int index, ByteString s) {
     ensureIsMutable();
     ensureIsMutable();
     return list.set(index, s);
     return list.set(index, s);
@@ -268,7 +268,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
   public void set(int index, byte[] s) {
   public void set(int index, byte[] s) {
     setAndReturn(index, s);
     setAndReturn(index, s);
   }
   }
-  
+
   private Object setAndReturn(int index, byte[] s) {
   private Object setAndReturn(int index, byte[] s) {
     ensureIsMutable();
     ensureIsMutable();
     return list.set(index, s);
     return list.set(index, s);
@@ -283,7 +283,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
       return Internal.toStringUtf8((byte[]) o);
       return Internal.toStringUtf8((byte[]) o);
     }
     }
   }
   }
-  
+
   private static ByteString asByteString(Object o) {
   private static ByteString asByteString(Object o) {
     if (o instanceof ByteString) {
     if (o instanceof ByteString) {
       return (ByteString) o;
       return (ByteString) o;
@@ -293,7 +293,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
       return ByteString.copyFrom((byte[]) o);
       return ByteString.copyFrom((byte[]) o);
     }
     }
   }
   }
-  
+
   private static byte[] asByteArray(Object o) {
   private static byte[] asByteArray(Object o) {
     if (o instanceof byte[]) {
     if (o instanceof byte[]) {
       return (byte[]) o;
       return (byte[]) o;
@@ -327,11 +327,11 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
   private static class ByteArrayListView extends AbstractList<byte[]>
   private static class ByteArrayListView extends AbstractList<byte[]>
       implements RandomAccess {
       implements RandomAccess {
     private final LazyStringArrayList list;
     private final LazyStringArrayList list;
-    
+
     ByteArrayListView(LazyStringArrayList list) {
     ByteArrayListView(LazyStringArrayList list) {
       this.list = list;
       this.list = list;
     }
     }
-    
+
     @Override
     @Override
     public byte[] get(int index) {
     public byte[] get(int index) {
       return list.getByteArray(index);
       return list.getByteArray(index);
@@ -362,7 +362,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
       return asByteArray(o);
       return asByteArray(o);
     }
     }
   }
   }
-  
+
   @Override
   @Override
   public List<byte[]> asByteArrayList() {
   public List<byte[]> asByteArrayList() {
     return new ByteArrayListView(this);
     return new ByteArrayListView(this);

+ 2 - 1
java/core/src/main/java/com/google/protobuf/LongArrayList.java

@@ -42,7 +42,8 @@ import java.util.RandomAccess;
  *
  *
  * @author dweis@google.com (Daniel Weis)
  * @author dweis@google.com (Daniel Weis)
  */
  */
-final class LongArrayList extends AbstractProtobufList<Long>
+final class LongArrayList
+    extends AbstractProtobufList<Long>
     implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
     implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
 
 
   private static final LongArrayList EMPTY_LIST = new LongArrayList();
   private static final LongArrayList EMPTY_LIST = new LongArrayList();

+ 6 - 12
java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java

@@ -30,6 +30,8 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import static com.google.protobuf.Internal.checkNotNull;
+
 import java.util.AbstractList;
 import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
@@ -290,9 +292,7 @@ public class RepeatedFieldBuilder
    */
    */
   public RepeatedFieldBuilder<MType, BType, IType> setMessage(
   public RepeatedFieldBuilder<MType, BType, IType> setMessage(
       int index, MType message) {
       int index, MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
+    checkNotNull(message);
     ensureMutableMessageList();
     ensureMutableMessageList();
     messages.set(index, message);
     messages.set(index, message);
     if (builders != null) {
     if (builders != null) {
@@ -315,9 +315,7 @@ public class RepeatedFieldBuilder
    */
    */
   public RepeatedFieldBuilder<MType, BType, IType> addMessage(
   public RepeatedFieldBuilder<MType, BType, IType> addMessage(
       MType message) {
       MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
+    checkNotNull(message);
     ensureMutableMessageList();
     ensureMutableMessageList();
     messages.add(message);
     messages.add(message);
     if (builders != null) {
     if (builders != null) {
@@ -339,9 +337,7 @@ public class RepeatedFieldBuilder
    */
    */
   public RepeatedFieldBuilder<MType, BType, IType> addMessage(
   public RepeatedFieldBuilder<MType, BType, IType> addMessage(
       int index, MType message) {
       int index, MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
+    checkNotNull(message);
     ensureMutableMessageList();
     ensureMutableMessageList();
     messages.add(index, message);
     messages.add(index, message);
     if (builders != null) {
     if (builders != null) {
@@ -363,9 +359,7 @@ public class RepeatedFieldBuilder
   public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
   public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
       Iterable<? extends MType> values) {
       Iterable<? extends MType> values) {
     for (final MType value : values) {
     for (final MType value : values) {
-      if (value == null) {
-        throw new NullPointerException();
-      }
+      checkNotNull(value);
     }
     }
 
 
     // If we can inspect the size, we can more efficiently add messages.
     // If we can inspect the size, we can more efficiently add messages.

+ 4 - 8
java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java

@@ -30,6 +30,8 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import static com.google.protobuf.Internal.checkNotNull;
+
 /**
 /**
  * {@code SingleFieldBuilder} implements a structure that a protocol
  * {@code SingleFieldBuilder} implements a structure that a protocol
  * message uses to hold a single field of another protocol message. It supports
  * message uses to hold a single field of another protocol message. It supports
@@ -84,10 +86,7 @@ public class SingleFieldBuilder
       MType message,
       MType message,
       GeneratedMessage.BuilderParent parent,
       GeneratedMessage.BuilderParent parent,
       boolean isClean) {
       boolean isClean) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    this.message = message;
+    this.message = checkNotNull(message);
     this.parent = parent;
     this.parent = parent;
     this.isClean = isClean;
     this.isClean = isClean;
   }
   }
@@ -169,10 +168,7 @@ public class SingleFieldBuilder
    */
    */
   public SingleFieldBuilder<MType, BType, IType> setMessage(
   public SingleFieldBuilder<MType, BType, IType> setMessage(
       MType message) {
       MType message) {
-    if (message == null) {
-      throw new NullPointerException();
-    }
-    this.message = message;
+    this.message = checkNotNull(message);
     if (builder != null) {
     if (builder != null) {
       builder.dispose();
       builder.dispose();
       builder = null;
       builder = null;

+ 2 - 2
java/core/src/main/java/com/google/protobuf/TextFormat.java

@@ -1444,8 +1444,8 @@ public final class TextFormat {
           logger.warning(msg.toString());
           logger.warning(msg.toString());
       } else {
       } else {
         String[] lineColumn = unknownFields.get(0).split(":");
         String[] lineColumn = unknownFields.get(0).split(":");
-        throw new ParseException(Integer.valueOf(lineColumn[0]),
-            Integer.valueOf(lineColumn[1]), msg.toString());
+        throw new ParseException(
+            Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString());
       }
       }
     }
     }
 
 

+ 17 - 0
java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java

@@ -785,6 +785,23 @@ public final class UnknownFieldSet implements MessageLite {
           group};
           group};
     }
     }
 
 
+    /**
+     * Serializes the message to a {@code ByteString} and returns it. This is just a trivial wrapper
+     * around {@link #writeTo(int, CodedOutputStream)}.
+     */
+    public ByteString toByteString(int fieldNumber) {
+      try {
+        // TODO(lukes): consider caching serialized size in a volatile long
+        final ByteString.CodedBuilder out =
+            ByteString.newCodedBuilder(getSerializedSize(fieldNumber));
+        writeTo(fieldNumber, out.getCodedOutput());
+        return out.build();
+      } catch (IOException e) {
+        throw new RuntimeException(
+            "Serializing to a ByteString should never fail with an IOException", e);
+      }
+    }
+
     /**
     /**
      * Serializes the field, including field number, and writes it to
      * Serializes the field, including field number, and writes it to
      * {@code output}.
      * {@code output}.

+ 5 - 6
java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

@@ -33,6 +33,7 @@ package com.google.protobuf;
 import java.lang.reflect.Field;
 import java.lang.reflect.Field;
 import java.nio.Buffer;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.security.AccessController;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedExceptionAction;
 import java.util.logging.Level;
 import java.util.logging.Level;
@@ -146,6 +147,10 @@ final class UnsafeUtil {
     return MEMORY_ACCESSOR.getObject(target, offset);
     return MEMORY_ACCESSOR.getObject(target, offset);
   }
   }
 
 
+  static void putObject(Object target, long offset, Object value) {
+    MEMORY_ACCESSOR.putObject(target, offset, value);
+  }
+
   static byte getByte(byte[] target, long index) {
   static byte getByte(byte[] target, long index) {
     return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index);
     return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index);
   }
   }
@@ -370,12 +375,6 @@ final class UnsafeUtil {
     return field != null && field.getType() == long.class ? field : null;
     return field != null && field.getType() == long.class ? field : null;
   }
   }
 
 
-  /** Finds the value field within a {@link String}. */
-  private static Field stringValueField() {
-    Field field = field(String.class, "value");
-    return field != null && field.getType() == char[].class ? field : null;
-  }
-
   /**
   /**
    * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
    * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
    * available.
    * available.

+ 3 - 2
java/core/src/main/java/com/google/protobuf/Utf8.java

@@ -42,7 +42,6 @@ import static java.lang.Character.isSurrogatePair;
 import static java.lang.Character.toCodePoint;
 import static java.lang.Character.toCodePoint;
 
 
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
-import java.util.Arrays;
 
 
 /**
 /**
  * A set of low-level, high-performance static utility methods related
  * A set of low-level, high-performance static utility methods related
@@ -87,7 +86,9 @@ final class Utf8 {
    * delegate for which all methods are delegated directly to.
    * delegate for which all methods are delegated directly to.
    */
    */
   private static final Processor processor =
   private static final Processor processor =
-      UnsafeProcessor.isAvailable() ? new UnsafeProcessor() : new SafeProcessor();
+      (UnsafeProcessor.isAvailable() && !Android.isOnAndroidDevice())
+          ? new UnsafeProcessor()
+          : new SafeProcessor();
 
 
   /**
   /**
    * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII
    * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII

+ 2 - 2
java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java

@@ -210,8 +210,8 @@ public class AbstractMessageTest extends TestCase {
     new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
     new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
 
 
   TestUtil.ReflectionTester extensionsReflectionTester =
   TestUtil.ReflectionTester extensionsReflectionTester =
-    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
-                                  TestUtil.getExtensionRegistry());
+      new TestUtil.ReflectionTester(
+          TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry());
 
 
   public void testClear() throws Exception {
   public void testClear() throws Exception {
     AbstractMessageWrapper message =
     AbstractMessageWrapper message =

+ 5 - 3
java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java

@@ -299,20 +299,22 @@ public class BooleanArrayListTest extends TestCase {
   }
   }
 
 
   public void testRemoveEndOfCapacity() {
   public void testRemoveEndOfCapacity() {
-    BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
+    BooleanList toRemove =
+        BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addBoolean(true);
     toRemove.addBoolean(true);
     toRemove.remove(0);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
   public void testSublistRemoveEndOfCapacity() {
   public void testSublistRemoveEndOfCapacity() {
-    BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
+    BooleanList toRemove =
+        BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addBoolean(true);
     toRemove.addBoolean(true);
     toRemove.subList(0, 1).clear();
     toRemove.subList(0, 1).clear();
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
-  private void assertImmutable(BooleanArrayList list) {
+  private void assertImmutable(BooleanList list) {
 
 
     try {
     try {
       list.add(true);
       list.add(true);

+ 66 - 0
java/core/src/test/java/com/google/protobuf/ByteStringTest.java

@@ -41,6 +41,7 @@ import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.NoSuchElementException;
@@ -86,6 +87,40 @@ public class ByteStringTest extends TestCase {
     return left.length == right.length && isArrayRange(left, right, 0, left.length);
     return left.length == right.length && isArrayRange(left, right, 0, left.length);
   }
   }
 
 
+  public void testCompare_equalByteStrings_compareEqual() throws Exception {
+    byte[] referenceBytes = getTestBytes();
+    ByteString string1 = ByteString.copyFrom(referenceBytes);
+    ByteString string2 = ByteString.copyFrom(referenceBytes);
+
+    assertEquals(
+        "ByteString instances containing the same data must compare equal.",
+        0,
+        ByteString.unsignedLexicographicalComparator().compare(string1, string2));
+  }
+
+  public void testCompare_byteStringsSortLexicographically() throws Exception {
+    ByteString app = ByteString.copyFromUtf8("app");
+    ByteString apple = ByteString.copyFromUtf8("apple");
+    ByteString banana = ByteString.copyFromUtf8("banana");
+
+    Comparator<ByteString> comparator = ByteString.unsignedLexicographicalComparator();
+
+    assertTrue("ByteString(app) < ByteString(apple)", comparator.compare(app, apple) < 0);
+    assertTrue("ByteString(app) < ByteString(banana)", comparator.compare(app, banana) < 0);
+    assertTrue("ByteString(apple) < ByteString(banana)", comparator.compare(apple, banana) < 0);
+  }
+
+  public void testCompare_interpretsByteValuesAsUnsigned() throws Exception {
+    // Two's compliment of `-1` == 0b11111111 == 255
+    ByteString twoHundredFiftyFive = ByteString.copyFrom(new byte[] {-1});
+    // 0b00000001 == 1
+    ByteString one = ByteString.copyFrom(new byte[] {1});
+
+    assertTrue(
+        "ByteString comparison treats bytes as unsigned values",
+        ByteString.unsignedLexicographicalComparator().compare(one, twoHundredFiftyFive) < 0);
+  }
+
   public void testSubstring_BeginIndex() {
   public void testSubstring_BeginIndex() {
     byte[] bytes = getTestBytes();
     byte[] bytes = getTestBytes();
     ByteString substring = ByteString.copyFrom(bytes).substring(500);
     ByteString substring = ByteString.copyFrom(bytes).substring(500);
@@ -161,6 +196,34 @@ public class ByteStringTest extends TestCase {
         byteString, byteStringAlt);
         byteString, byteStringAlt);
   }
   }
 
 
+  public void testCopyFrom_LengthTooBig() {
+    byte[] testBytes = getTestBytes(100);
+    try {
+      ByteString.copyFrom(testBytes, 0, 200);
+      fail("Should throw");
+    } catch (IndexOutOfBoundsException expected) {
+    }
+
+    try {
+      ByteString.copyFrom(testBytes, 99, 2);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+
+    ByteBuffer buf = ByteBuffer.wrap(testBytes);
+    try {
+      ByteString.copyFrom(buf, 101);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+
+    try {
+      ByteString.copyFrom(testBytes, -1, 10);
+      fail("Should throw");
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
   public void testCopyTo_TargetOffset() {
   public void testCopyTo_TargetOffset() {
     byte[] bytes = getTestBytes();
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes);
     ByteString byteString = ByteString.copyFrom(bytes);
@@ -761,6 +824,9 @@ public class ByteStringTest extends TestCase {
    * Tests ByteString uses Arrays based byte copier when running under Hotstop VM.
    * Tests ByteString uses Arrays based byte copier when running under Hotstop VM.
    */
    */
   public void testByteArrayCopier() throws Exception {
   public void testByteArrayCopier() throws Exception {
+    if (Android.isOnAndroidDevice()) {
+      return;
+    }
     Field field = ByteString.class.getDeclaredField("byteArrayCopier");
     Field field = ByteString.class.getDeclaredField("byteArrayCopier");
     field.setAccessible(true);
     field.setAccessible(true);
     Object byteArrayCopier = field.get(null);
     Object byteArrayCopier = field.get(null);

+ 3 - 20
java/core/src/test/java/com/google/protobuf/DiscardUnknownFieldsTest.java

@@ -62,22 +62,17 @@ public class DiscardUnknownFieldsTest {
   }
   }
 
 
   private static void testProto2Message(Message message) throws Exception {
   private static void testProto2Message(Message message) throws Exception {
-    assertUnknownFieldsDefaultPreserved(message);
+    assertUnknownFieldsPreserved(message);
     assertUnknownFieldsExplicitlyDiscarded(message);
     assertUnknownFieldsExplicitlyDiscarded(message);
     assertReuseCodedInputStreamPreserve(message);
     assertReuseCodedInputStreamPreserve(message);
     assertUnknownFieldsInUnknownFieldSetArePreserve(message);
     assertUnknownFieldsInUnknownFieldSetArePreserve(message);
   }
   }
 
 
   private static void testProto3Message(Message message) throws Exception {
   private static void testProto3Message(Message message) throws Exception {
-    CodedInputStream.setProto3KeepUnknownsByDefaultForTest();
-    assertUnknownFieldsDefaultPreserved(message);
+    assertUnknownFieldsPreserved(message);
     assertUnknownFieldsExplicitlyDiscarded(message);
     assertUnknownFieldsExplicitlyDiscarded(message);
     assertReuseCodedInputStreamPreserve(message);
     assertReuseCodedInputStreamPreserve(message);
     assertUnknownFieldsInUnknownFieldSetArePreserve(message);
     assertUnknownFieldsInUnknownFieldSetArePreserve(message);
-    CodedInputStream.setProto3DiscardUnknownsByDefaultForTest();
-    assertUnknownFieldsDefaultDiscarded(message);
-    assertUnknownFieldsExplicitlyDiscarded(message);
-    assertUnknownFieldsInUnknownFieldSetAreDiscarded(message);
   }
   }
 
 
   private static void assertReuseCodedInputStreamPreserve(Message message) throws Exception {
   private static void assertReuseCodedInputStreamPreserve(Message message) throws Exception {
@@ -122,7 +117,7 @@ public class DiscardUnknownFieldsTest {
     assertEquals(message.getClass().getName(), 0, built.getSerializedSize());
     assertEquals(message.getClass().getName(), 0, built.getSerializedSize());
   }
   }
 
 
-  private static void assertUnknownFieldsDefaultPreserved(MessageLite message) throws Exception {
+  private static void assertUnknownFieldsPreserved(MessageLite message) throws Exception {
     {
     {
       MessageLite parsed = message.getParserForType().parseFrom(payload);
       MessageLite parsed = message.getParserForType().parseFrom(payload);
       assertEquals(message.getClass().getName(), payload, parsed.toByteString());
       assertEquals(message.getClass().getName(), payload, parsed.toByteString());
@@ -134,18 +129,6 @@ public class DiscardUnknownFieldsTest {
     }
     }
   }
   }
 
 
-  private static void assertUnknownFieldsDefaultDiscarded(MessageLite message) throws Exception {
-    {
-      MessageLite parsed = message.getParserForType().parseFrom(payload);
-      assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
-    }
-
-    {
-      MessageLite parsed = message.newBuilderForType().mergeFrom(payload).build();
-      assertEquals(message.getClass().getName(), 0, parsed.getSerializedSize());
-    }
-  }
-
   private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception {
   private static void assertUnknownFieldsExplicitlyDiscarded(Message message) throws Exception {
     Message parsed =
     Message parsed =
         DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);
         DiscardUnknownFieldsParser.wrap(message.getParserForType()).parseFrom(payload);

+ 26 - 24
java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java

@@ -78,10 +78,10 @@ public class DoubleArrayListTest extends TestCase {
     list.addAll(asList(1D, 2D, 3D, 4D));
     list.addAll(asList(1D, 2D, 3D, 4D));
     Iterator<Double> iterator = list.iterator();
     Iterator<Double> iterator = list.iterator();
     assertEquals(4, list.size());
     assertEquals(4, list.size());
-    assertEquals(1D, (double) list.get(0));
-    assertEquals(1D, (double) iterator.next());
+    assertEquals(1D, (double) list.get(0), 0.0);
+    assertEquals(1D, (double) iterator.next(), 0.0);
     list.set(0, 1D);
     list.set(0, 1D);
-    assertEquals(2D, (double) iterator.next());
+    assertEquals(2D, (double) iterator.next(), 0.0);
 
 
     list.remove(0);
     list.remove(0);
     try {
     try {
@@ -102,9 +102,9 @@ public class DoubleArrayListTest extends TestCase {
   }
   }
 
 
   public void testGet() {
   public void testGet() {
-    assertEquals(1D, (double) TERTIARY_LIST.get(0));
-    assertEquals(2D, (double) TERTIARY_LIST.get(1));
-    assertEquals(3D, (double) TERTIARY_LIST.get(2));
+    assertEquals(1D, (double) TERTIARY_LIST.get(0), 0.0);
+    assertEquals(2D, (double) TERTIARY_LIST.get(1), 0.0);
+    assertEquals(3D, (double) TERTIARY_LIST.get(2), 0.0);
 
 
     try {
     try {
       TERTIARY_LIST.get(-1);
       TERTIARY_LIST.get(-1);
@@ -122,9 +122,9 @@ public class DoubleArrayListTest extends TestCase {
   }
   }
 
 
   public void testGetDouble() {
   public void testGetDouble() {
-    assertEquals(1D, TERTIARY_LIST.getDouble(0));
-    assertEquals(2D, TERTIARY_LIST.getDouble(1));
-    assertEquals(3D, TERTIARY_LIST.getDouble(2));
+    assertEquals(1D, TERTIARY_LIST.getDouble(0), 0.0);
+    assertEquals(2D, TERTIARY_LIST.getDouble(1), 0.0);
+    assertEquals(3D, TERTIARY_LIST.getDouble(2), 0.0);
 
 
     try {
     try {
       TERTIARY_LIST.get(-1);
       TERTIARY_LIST.get(-1);
@@ -163,11 +163,11 @@ public class DoubleArrayListTest extends TestCase {
     list.addDouble(2);
     list.addDouble(2);
     list.addDouble(4);
     list.addDouble(4);
 
 
-    assertEquals(2D, (double) list.set(0, 3D));
-    assertEquals(3D, list.getDouble(0));
+    assertEquals(2D, (double) list.set(0, 3D), 0.0);
+    assertEquals(3D, list.getDouble(0), 0.0);
 
 
-    assertEquals(4D, (double) list.set(1, 0D));
-    assertEquals(0D, list.getDouble(1));
+    assertEquals(4D, (double) list.set(1, 0D), 0.0);
+    assertEquals(0D, list.getDouble(1), 0.0);
 
 
     try {
     try {
       list.set(-1, 0D);
       list.set(-1, 0D);
@@ -188,11 +188,11 @@ public class DoubleArrayListTest extends TestCase {
     list.addDouble(1);
     list.addDouble(1);
     list.addDouble(3);
     list.addDouble(3);
 
 
-    assertEquals(1D, list.setDouble(0, 0));
-    assertEquals(0D, list.getDouble(0));
+    assertEquals(1D, list.setDouble(0, 0), 0.0);
+    assertEquals(0D, list.getDouble(0), 0.0);
 
 
-    assertEquals(3D, list.setDouble(1, 0));
-    assertEquals(0D, list.getDouble(1));
+    assertEquals(3D, list.setDouble(1, 0), 0.0);
+    assertEquals(0D, list.getDouble(1), 0.0);
 
 
     try {
     try {
       list.setDouble(-1, 0);
       list.setDouble(-1, 0);
@@ -257,8 +257,8 @@ public class DoubleArrayListTest extends TestCase {
 
 
     assertTrue(list.addAll(Collections.singleton(1D)));
     assertTrue(list.addAll(Collections.singleton(1D)));
     assertEquals(1, list.size());
     assertEquals(1, list.size());
-    assertEquals(1D, (double) list.get(0));
-    assertEquals(1D, list.getDouble(0));
+    assertEquals(1D, (double) list.get(0), 0.0);
+    assertEquals(1D, list.getDouble(0), 0.0);
 
 
     assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
     assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
     assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
     assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
@@ -272,7 +272,7 @@ public class DoubleArrayListTest extends TestCase {
 
 
   public void testRemove() {
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     list.addAll(TERTIARY_LIST);
-    assertEquals(1D, (double) list.remove(0));
+    assertEquals(1D, (double) list.remove(0), 0.0);
     assertEquals(asList(2D, 3D), list);
     assertEquals(asList(2D, 3D), list);
 
 
     assertTrue(list.remove(Double.valueOf(3)));
     assertTrue(list.remove(Double.valueOf(3)));
@@ -281,7 +281,7 @@ public class DoubleArrayListTest extends TestCase {
     assertFalse(list.remove(Double.valueOf(3)));
     assertFalse(list.remove(Double.valueOf(3)));
     assertEquals(asList(2D), list);
     assertEquals(asList(2D), list);
 
 
-    assertEquals(2D, (double) list.remove(0));
+    assertEquals(2D, (double) list.remove(0), 0.0);
     assertEquals(asList(), list);
     assertEquals(asList(), list);
 
 
     try {
     try {
@@ -299,20 +299,22 @@ public class DoubleArrayListTest extends TestCase {
   }
   }
 
 
   public void testRemoveEndOfCapacity() {
   public void testRemoveEndOfCapacity() {
-    DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
+    DoubleList toRemove =
+        DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addDouble(3);
     toRemove.addDouble(3);
     toRemove.remove(0);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
   public void testSublistRemoveEndOfCapacity() {
   public void testSublistRemoveEndOfCapacity() {
-    DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
+    DoubleList toRemove =
+        DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addDouble(3);
     toRemove.addDouble(3);
     toRemove.subList(0, 1).clear();
     toRemove.subList(0, 1).clear();
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
-  private void assertImmutable(DoubleArrayList list) {
+  private void assertImmutable(DoubleList list) {
     if (list.contains(1D)) {
     if (list.contains(1D)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     }

+ 5 - 5
java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java

@@ -51,8 +51,8 @@ public class DynamicMessageTest extends TestCase {
     new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
     new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
 
 
   TestUtil.ReflectionTester extensionsReflectionTester =
   TestUtil.ReflectionTester extensionsReflectionTester =
-    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
-                                  TestUtil.getExtensionRegistry());
+      new TestUtil.ReflectionTester(
+          TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry());
   TestUtil.ReflectionTester packedReflectionTester =
   TestUtil.ReflectionTester packedReflectionTester =
     new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
     new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
 
 
@@ -194,9 +194,9 @@ public class DynamicMessageTest extends TestCase {
 
 
   public void testDynamicMessageExtensionParsing() throws Exception {
   public void testDynamicMessageExtensionParsing() throws Exception {
     ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
     ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
-    Message message = DynamicMessage.parseFrom(
-        TestAllExtensions.getDescriptor(), rawBytes,
-        TestUtil.getExtensionRegistry());
+    Message message =
+        DynamicMessage.parseFrom(
+            TestAllExtensions.getDescriptor(), rawBytes, TestUtil.getFullExtensionRegistry());
     extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
     extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
 
 
     // Test Parser interface.
     // Test Parser interface.

+ 26 - 24
java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java

@@ -78,10 +78,10 @@ public class FloatArrayListTest extends TestCase {
     list.addAll(asList(1F, 2F, 3F, 4F));
     list.addAll(asList(1F, 2F, 3F, 4F));
     Iterator<Float> iterator = list.iterator();
     Iterator<Float> iterator = list.iterator();
     assertEquals(4, list.size());
     assertEquals(4, list.size());
-    assertEquals(1F, (float) list.get(0));
-    assertEquals(1F, (float) iterator.next());
+    assertEquals(1F, (float) list.get(0), 0.0f);
+    assertEquals(1F, (float) iterator.next(), 0.0f);
     list.set(0, 1F);
     list.set(0, 1F);
-    assertEquals(2F, (float) iterator.next());
+    assertEquals(2F, (float) iterator.next(), 0.0f);
 
 
     list.remove(0);
     list.remove(0);
     try {
     try {
@@ -102,9 +102,9 @@ public class FloatArrayListTest extends TestCase {
   }
   }
 
 
   public void testGet() {
   public void testGet() {
-    assertEquals(1F, (float) TERTIARY_LIST.get(0));
-    assertEquals(2F, (float) TERTIARY_LIST.get(1));
-    assertEquals(3F, (float) TERTIARY_LIST.get(2));
+    assertEquals(1F, (float) TERTIARY_LIST.get(0), 0.0f);
+    assertEquals(2F, (float) TERTIARY_LIST.get(1), 0.0f);
+    assertEquals(3F, (float) TERTIARY_LIST.get(2), 0.0f);
 
 
     try {
     try {
       TERTIARY_LIST.get(-1);
       TERTIARY_LIST.get(-1);
@@ -122,9 +122,9 @@ public class FloatArrayListTest extends TestCase {
   }
   }
 
 
   public void testGetFloat() {
   public void testGetFloat() {
-    assertEquals(1F, TERTIARY_LIST.getFloat(0));
-    assertEquals(2F, TERTIARY_LIST.getFloat(1));
-    assertEquals(3F, TERTIARY_LIST.getFloat(2));
+    assertEquals(1F, TERTIARY_LIST.getFloat(0), 0.0f);
+    assertEquals(2F, TERTIARY_LIST.getFloat(1), 0.0f);
+    assertEquals(3F, TERTIARY_LIST.getFloat(2), 0.0f);
 
 
     try {
     try {
       TERTIARY_LIST.get(-1);
       TERTIARY_LIST.get(-1);
@@ -163,11 +163,11 @@ public class FloatArrayListTest extends TestCase {
     list.addFloat(2);
     list.addFloat(2);
     list.addFloat(4);
     list.addFloat(4);
 
 
-    assertEquals(2F, (float) list.set(0, 3F));
-    assertEquals(3F, list.getFloat(0));
+    assertEquals(2F, (float) list.set(0, 3F), 0.0f);
+    assertEquals(3F, list.getFloat(0), 0.0f);
 
 
-    assertEquals(4F, (float) list.set(1, 0F));
-    assertEquals(0F, list.getFloat(1));
+    assertEquals(4F, (float) list.set(1, 0F), 0.0f);
+    assertEquals(0F, list.getFloat(1), 0.0f);
 
 
     try {
     try {
       list.set(-1, 0F);
       list.set(-1, 0F);
@@ -188,11 +188,11 @@ public class FloatArrayListTest extends TestCase {
     list.addFloat(1);
     list.addFloat(1);
     list.addFloat(3);
     list.addFloat(3);
 
 
-    assertEquals(1F, list.setFloat(0, 0));
-    assertEquals(0F, list.getFloat(0));
+    assertEquals(1F, list.setFloat(0, 0), 0.0f);
+    assertEquals(0F, list.getFloat(0), 0.0f);
 
 
-    assertEquals(3F, list.setFloat(1, 0));
-    assertEquals(0F, list.getFloat(1));
+    assertEquals(3F, list.setFloat(1, 0), 0.0f);
+    assertEquals(0F, list.getFloat(1), 0.0f);
 
 
     try {
     try {
       list.setFloat(-1, 0);
       list.setFloat(-1, 0);
@@ -257,8 +257,8 @@ public class FloatArrayListTest extends TestCase {
 
 
     assertTrue(list.addAll(Collections.singleton(1F)));
     assertTrue(list.addAll(Collections.singleton(1F)));
     assertEquals(1, list.size());
     assertEquals(1, list.size());
-    assertEquals(1F, (float) list.get(0));
-    assertEquals(1F, list.getFloat(0));
+    assertEquals(1F, (float) list.get(0), 0.0f);
+    assertEquals(1F, list.getFloat(0), 0.0f);
 
 
     assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
     assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
     assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
     assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
@@ -272,7 +272,7 @@ public class FloatArrayListTest extends TestCase {
 
 
   public void testRemove() {
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     list.addAll(TERTIARY_LIST);
-    assertEquals(1F, (float) list.remove(0));
+    assertEquals(1F, (float) list.remove(0), 0.0f);
     assertEquals(asList(2F, 3F), list);
     assertEquals(asList(2F, 3F), list);
 
 
     assertTrue(list.remove(Float.valueOf(3)));
     assertTrue(list.remove(Float.valueOf(3)));
@@ -281,7 +281,7 @@ public class FloatArrayListTest extends TestCase {
     assertFalse(list.remove(Float.valueOf(3)));
     assertFalse(list.remove(Float.valueOf(3)));
     assertEquals(asList(2F), list);
     assertEquals(asList(2F), list);
 
 
-    assertEquals(2F, (float) list.remove(0));
+    assertEquals(2F, (float) list.remove(0), 0.0f);
     assertEquals(asList(), list);
     assertEquals(asList(), list);
 
 
     try {
     try {
@@ -299,20 +299,22 @@ public class FloatArrayListTest extends TestCase {
   }
   }
 
 
   public void testRemoveEndOfCapacity() {
   public void testRemoveEndOfCapacity() {
-    FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
+    FloatList toRemove =
+        FloatArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addFloat(3);
     toRemove.addFloat(3);
     toRemove.remove(0);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
   public void testSublistRemoveEndOfCapacity() {
   public void testSublistRemoveEndOfCapacity() {
-    FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
+    FloatList toRemove =
+        FloatArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addFloat(3);
     toRemove.addFloat(3);
     toRemove.subList(0, 1).clear();
     toRemove.subList(0, 1).clear();
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
-  private void assertImmutable(FloatArrayList list) {
+  private void assertImmutable(FloatList list) {
     if (list.contains(1F)) {
     if (list.contains(1F)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     }

+ 2 - 2
java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -590,8 +590,8 @@ public class GeneratedMessageTest extends TestCase {
   // Extensions.
   // Extensions.
 
 
   TestUtil.ReflectionTester extensionsReflectionTester =
   TestUtil.ReflectionTester extensionsReflectionTester =
-    new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
-                                  TestUtil.getExtensionRegistry());
+      new TestUtil.ReflectionTester(
+          TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry());
 
 
   public void testExtensionMessageOrBuilder() throws Exception {
   public void testExtensionMessageOrBuilder() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();

+ 5 - 3
java/core/src/test/java/com/google/protobuf/IntArrayListTest.java

@@ -299,20 +299,22 @@ public class IntArrayListTest extends TestCase {
   }
   }
 
 
   public void testRemoveEndOfCapacity() {
   public void testRemoveEndOfCapacity() {
-    IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
+    IntList toRemove =
+        IntArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addInt(3);
     toRemove.addInt(3);
     toRemove.remove(0);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
   public void testSublistRemoveEndOfCapacity() {
   public void testSublistRemoveEndOfCapacity() {
-    IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
+    IntList toRemove =
+        IntArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addInt(3);
     toRemove.addInt(3);
     toRemove.subList(0, 1).clear();
     toRemove.subList(0, 1).clear();
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
-  private void assertImmutable(IntArrayList list) {
+  private void assertImmutable(IntList list) {
     if (list.contains(1)) {
     if (list.contains(1)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     }

+ 61 - 0
java/core/src/test/java/com/google/protobuf/LiteTest.java

@@ -57,6 +57,8 @@ import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Field;
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.ArrayList;
@@ -2378,4 +2380,63 @@ public class LiteTest extends TestCase {
     } catch (NullPointerException expected) {
     } catch (NullPointerException expected) {
     }
     }
   }
   }
+
+  public void testSerializeToOutputStreamThrowsIOException() {
+    try {
+      TestAllTypesLite.newBuilder()
+          .setOptionalBytes(ByteString.copyFromUtf8("hello"))
+          .build()
+          .writeTo(
+              new OutputStream() {
+
+                @Override
+                public void write(int b) throws IOException {
+                  throw new IOException();
+                }
+              });
+      fail();
+    } catch (IOException expected) {
+    }
+  }
+
+  public void testUnpairedSurrogatesReplacedByQuestionMark() throws InvalidProtocolBufferException {
+    String testString = "foo \ud83d bar";
+    String expectedString = "foo ? bar";
+
+    TestAllTypesLite testMessage =
+        TestAllTypesLite.newBuilder().setOptionalString(testString).build();
+    ByteString serializedMessage = testMessage.toByteString();
+
+    // Behavior is compatible with String.getBytes("UTF-8"), which replaces
+    // unpaired surrogates with a question mark.
+    TestAllTypesLite parsedMessage = TestAllTypesLite.parseFrom(serializedMessage);
+    assertEquals(expectedString, parsedMessage.getOptionalString());
+
+    // Conversion happens during serialization.
+    ByteString expectedBytes = ByteString.copyFromUtf8(expectedString);
+    assertTrue(
+        String.format(
+            "Expected serializedMessage (%s) to contain \"%s\" (%s).",
+            encodeHex(serializedMessage), expectedString, encodeHex(expectedBytes)),
+        contains(serializedMessage, expectedBytes));
+  }
+
+  private String encodeHex(ByteString bytes) {
+    String hexDigits = "0123456789abcdef";
+    StringBuilder stringBuilder = new StringBuilder(bytes.size() * 2);
+    for (byte b : bytes) {
+      stringBuilder.append(hexDigits.charAt((b & 0xf0) >> 4));
+      stringBuilder.append(hexDigits.charAt(b & 0x0f));
+    }
+    return stringBuilder.toString();
+  }
+
+  private boolean contains(ByteString a, ByteString b) {
+    for (int i = 0; i <= a.size() - b.size(); ++i) {
+      if (a.substring(i, i + b.size()).equals(b)) {
+        return true;
+      }
+    }
+    return false;
+  }
 }
 }

+ 5 - 3
java/core/src/test/java/com/google/protobuf/LongArrayListTest.java

@@ -299,20 +299,22 @@ public class LongArrayListTest extends TestCase {
   }
   }
 
 
   public void testRemoveEndOfCapacity() {
   public void testRemoveEndOfCapacity() {
-    LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
+    LongList toRemove =
+        LongArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addLong(3);
     toRemove.addLong(3);
     toRemove.remove(0);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
   public void testSublistRemoveEndOfCapacity() {
   public void testSublistRemoveEndOfCapacity() {
-    LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
+    LongList toRemove =
+        LongArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addLong(3);
     toRemove.addLong(3);
     toRemove.subList(0, 1).clear();
     toRemove.subList(0, 1).clear();
     assertEquals(0, toRemove.size());
     assertEquals(0, toRemove.size());
   }
   }
 
 
-  private void assertImmutable(LongArrayList list) {
+  private void assertImmutable(LongList list) {
     if (list.contains(1L)) {
     if (list.contains(1L)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     }

+ 155 - 49
java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java

@@ -42,33 +42,33 @@ import junit.framework.TestCase;
  * Tests for {@link ProtobufArrayList}.
  * Tests for {@link ProtobufArrayList}.
  */
  */
 public class ProtobufArrayListTest extends TestCase {
 public class ProtobufArrayListTest extends TestCase {
-  
+
   private static final ProtobufArrayList<Integer> UNARY_LIST = newImmutableProtoArrayList(1);
   private static final ProtobufArrayList<Integer> UNARY_LIST = newImmutableProtoArrayList(1);
   private static final ProtobufArrayList<Integer> TERTIARY_LIST =
   private static final ProtobufArrayList<Integer> TERTIARY_LIST =
       newImmutableProtoArrayList(1, 2, 3);
       newImmutableProtoArrayList(1, 2, 3);
-  
+
   private ProtobufArrayList<Integer> list;
   private ProtobufArrayList<Integer> list;
-  
+
   @Override
   @Override
   protected void setUp() throws Exception {
   protected void setUp() throws Exception {
     list = new ProtobufArrayList<Integer>();
     list = new ProtobufArrayList<Integer>();
   }
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
   public void testEmptyListReturnsSameInstance() {
     assertSame(ProtobufArrayList.emptyList(), ProtobufArrayList.emptyList());
     assertSame(ProtobufArrayList.emptyList(), ProtobufArrayList.emptyList());
   }
   }
-  
+
   public void testEmptyListIsImmutable() {
   public void testEmptyListIsImmutable() {
     assertImmutable(ProtobufArrayList.<Integer>emptyList());
     assertImmutable(ProtobufArrayList.<Integer>emptyList());
   }
   }
-  
+
   public void testModificationWithIteration() {
   public void testModificationWithIteration() {
     list.addAll(asList(1, 2, 3, 4));
     list.addAll(asList(1, 2, 3, 4));
     Iterator<Integer> iterator = list.iterator();
     Iterator<Integer> iterator = list.iterator();
     assertEquals(4, list.size());
     assertEquals(4, list.size());
     assertEquals(1, (int) list.get(0));
     assertEquals(1, (int) list.get(0));
     assertEquals(1, (int) iterator.next());
     assertEquals(1, (int) iterator.next());
-    
+
     list.remove(0);
     list.remove(0);
     try {
     try {
       iterator.next();
       iterator.next();
@@ -76,7 +76,7 @@ public class ProtobufArrayListTest extends TestCase {
     } catch (ConcurrentModificationException e) {
     } catch (ConcurrentModificationException e) {
       // expected
       // expected
     }
     }
-    
+
     iterator = list.iterator();
     iterator = list.iterator();
     list.set(0, 1);
     list.set(0, 1);
     try {
     try {
@@ -85,7 +85,7 @@ public class ProtobufArrayListTest extends TestCase {
     } catch (ConcurrentModificationException e) {
     } catch (ConcurrentModificationException e) {
       // expected
       // expected
     }
     }
-    
+
     iterator = list.iterator();
     iterator = list.iterator();
     list.add(0, 0);
     list.add(0, 0);
     try {
     try {
@@ -95,7 +95,7 @@ public class ProtobufArrayListTest extends TestCase {
       // expected
       // expected
     }
     }
   }
   }
-  
+
   public void testMakeImmutable() {
   public void testMakeImmutable() {
     list.add(2);
     list.add(2);
     list.add(4);
     list.add(4);
@@ -104,107 +104,213 @@ public class ProtobufArrayListTest extends TestCase {
     list.makeImmutable();
     list.makeImmutable();
     assertImmutable(list);
     assertImmutable(list);
   }
   }
-  
+
   public void testRemove() {
   public void testRemove() {
-    list.add(2);
-    list.add(4);
-    list.add(6);
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1, (int) list.remove(0));
+    assertEquals(asList(2, 3), list);
 
 
-    list.remove(1);
-    assertEquals(asList(2, 6), list);
+    assertTrue(list.remove(Integer.valueOf(3)));
+    assertEquals(asList(2), list);
 
 
-    list.remove(1);
+    assertFalse(list.remove(Integer.valueOf(3)));
     assertEquals(asList(2), list);
     assertEquals(asList(2), list);
 
 
-    list.remove(0);
+    assertEquals(2, (int) list.remove(0));
     assertEquals(asList(), list);
     assertEquals(asList(), list);
+
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
   }
   }
-  
+
   public void testGet() {
   public void testGet() {
-    list.add(2);
-    list.add(6);
-    
-    assertEquals(2, (int) list.get(0));
-    assertEquals(6, (int) list.get(1));
+    assertEquals(1, (int) TERTIARY_LIST.get(0));
+    assertEquals(2, (int) TERTIARY_LIST.get(1));
+    assertEquals(3, (int) TERTIARY_LIST.get(2));
+
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
   }
   }
-  
+
   public void testSet() {
   public void testSet() {
     list.add(2);
     list.add(2);
-    list.add(6);
-    
-    list.set(0, 1);
+    list.add(4);
+
+    assertEquals(2, (int) list.set(0, 3));
+    assertEquals(3, (int) list.get(0));
+
+    assertEquals(4, (int) list.set(1, 0));
+    assertEquals(0, (int) list.get(1));
+
+    try {
+      list.set(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2));
+    assertEquals(asList(2), list);
+
+    assertTrue(list.add(3));
+    list.add(0, 4);
+    assertEquals(asList(4, 2, 3), list);
+
+    list.add(0, 1);
+    list.add(0, 0);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Integer.valueOf(5 + i));
+    }
+    assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
+
+    try {
+      list.add(-1, 5);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.add(4, 5);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1)));
+    assertEquals(1, list.size());
     assertEquals(1, (int) list.get(0));
     assertEquals(1, (int) list.get(0));
-    list.set(1, 2);
-    assertEquals(2, (int) list.get(1));
+
+    assertTrue(list.addAll(asList(2, 3, 4, 5, 6)));
+    assertEquals(asList(1, 2, 3, 4, 5, 6), list);
+
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list);
+
+    assertFalse(list.addAll(Collections.<Integer>emptyList()));
+    assertFalse(list.addAll(IntArrayList.emptyList()));
+  }
+
+  public void testSize() {
+    assertEquals(0, ProtobufArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.add(3);
+    list.add(4);
+    list.add(6);
+    list.add(8);
+    assertEquals(4, list.size());
+
+    list.remove(0);
+    assertEquals(3, list.size());
+
+    list.add(17);
+    assertEquals(4, list.size());
   }
   }
 
 
   private void assertImmutable(List<Integer> list) {
   private void assertImmutable(List<Integer> list) {
     if (list.contains(1)) {
     if (list.contains(1)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     }
-    
+
     try {
     try {
       list.add(1);
       list.add(1);
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.add(0, 1);
       list.add(0, 1);
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(Collections.<Integer>emptyList());
       list.addAll(Collections.<Integer>emptyList());
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(Collections.singletonList(1));
       list.addAll(Collections.singletonList(1));
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(new ProtobufArrayList<Integer>());
       list.addAll(new ProtobufArrayList<Integer>());
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(UNARY_LIST);
       list.addAll(UNARY_LIST);
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(0, Collections.singleton(1));
       list.addAll(0, Collections.singleton(1));
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(0, UNARY_LIST);
       list.addAll(0, UNARY_LIST);
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.addAll(0, Collections.<Integer>emptyList());
       list.addAll(0, Collections.<Integer>emptyList());
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
-    } 
+    }
 
 
     try {
     try {
       list.clear();
       list.clear();
@@ -219,56 +325,56 @@ public class ProtobufArrayListTest extends TestCase {
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.remove(new Object());
       list.remove(new Object());
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.removeAll(Collections.emptyList());
       list.removeAll(Collections.emptyList());
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.removeAll(Collections.singleton(1));
       list.removeAll(Collections.singleton(1));
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.removeAll(UNARY_LIST);
       list.removeAll(UNARY_LIST);
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.retainAll(Collections.emptyList());
       list.retainAll(Collections.emptyList());
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.retainAll(Collections.singleton(1));
       list.retainAll(Collections.singleton(1));
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.retainAll(UNARY_LIST);
       list.retainAll(UNARY_LIST);
       fail();
       fail();
     } catch (UnsupportedOperationException e) {
     } catch (UnsupportedOperationException e) {
       // expected
       // expected
     }
     }
-    
+
     try {
     try {
       list.set(0, 0);
       list.set(0, 0);
       fail();
       fail();
@@ -276,7 +382,7 @@ public class ProtobufArrayListTest extends TestCase {
       // expected
       // expected
     }
     }
   }
   }
-  
+
   private static ProtobufArrayList<Integer> newImmutableProtoArrayList(int... elements) {
   private static ProtobufArrayList<Integer> newImmutableProtoArrayList(int... elements) {
     ProtobufArrayList<Integer> list = new ProtobufArrayList<Integer>();
     ProtobufArrayList<Integer> list = new ProtobufArrayList<Integer>();
     for (int element : elements) {
     for (int element : elements) {

+ 31 - 6
java/core/src/test/java/com/google/protobuf/TestUtil.java

@@ -130,8 +130,6 @@ import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
 import static protobuf_unittest.UnittestProto.defaultFloatExtension;
 import static protobuf_unittest.UnittestProto.defaultFloatExtension;
 import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
-// The static imports are to avoid 100+ char lines.  The following is roughly equivalent to
-// import static protobuf_unittest.UnittestProto.*;
 import static protobuf_unittest.UnittestProto.defaultInt32Extension;
 import static protobuf_unittest.UnittestProto.defaultInt32Extension;
 import static protobuf_unittest.UnittestProto.defaultInt64Extension;
 import static protobuf_unittest.UnittestProto.defaultInt64Extension;
 import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
 import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
@@ -263,12 +261,14 @@ public final class TestUtil {
     return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
     return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
   }
   }
 
 
+  // BEGIN FULL-RUNTIME
   /**
   /**
    * Dirties the message by resetting the momoized serialized size.
    * Dirties the message by resetting the momoized serialized size.
    */
    */
   public static void resetMemoizedSize(AbstractMessage message) {
   public static void resetMemoizedSize(AbstractMessage message) {
     message.memoizedSize = -1;
     message.memoizedSize = -1;
   }
   }
+  // END FULL-RUNTIME
 
 
   /**
   /**
    * Get a {@code TestAllTypes} with all fields set as they would be by
    * Get a {@code TestAllTypes} with all fields set as they would be by
@@ -1201,17 +1201,29 @@ public final class TestUtil {
    * Get an unmodifiable {@link ExtensionRegistry} containing all the
    * Get an unmodifiable {@link ExtensionRegistry} containing all the
    * extensions of {@code TestAllExtensions}.
    * extensions of {@code TestAllExtensions}.
    */
    */
-  public static ExtensionRegistry getExtensionRegistry() {
+  public static ExtensionRegistryLite getExtensionRegistry() {
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    registerAllExtensions(registry);
+    return registry.getUnmodifiable();
+  }
+
+  // BEGIN FULL-RUNTIME
+  /**
+   * Get an unmodifiable {@link ExtensionRegistry} containing all the
+   * extensions of {@code TestAllExtensions}.
+   */
+  public static ExtensionRegistry getFullExtensionRegistry() {
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     registerAllExtensions(registry);
     registerAllExtensions(registry);
     return registry.getUnmodifiable();
     return registry.getUnmodifiable();
   }
   }
+  // END FULL-RUNTIME
 
 
   /**
   /**
    * Register all of {@code TestAllExtensions}'s extensions with the
    * Register all of {@code TestAllExtensions}'s extensions with the
    * given {@link ExtensionRegistry}.
    * given {@link ExtensionRegistry}.
    */
    */
-  public static void registerAllExtensions(ExtensionRegistry registry) {
+  public static void registerAllExtensions(ExtensionRegistryLite registry) {
     UnittestProto.registerAllExtensions(registry);
     UnittestProto.registerAllExtensions(registry);
     TestUtilLite.registerAllExtensionsLite(registry);
     TestUtilLite.registerAllExtensionsLite(registry);
   }
   }
@@ -2634,6 +2646,7 @@ public final class TestUtil {
   }
   }
 
 
   // =================================================================
   // =================================================================
+  // BEGIN FULL-RUNTIME
 
 
   /**
   /**
    * Performs the same things that the methods of {@code TestUtil} do, but
    * Performs the same things that the methods of {@code TestUtil} do, but
@@ -3819,6 +3832,16 @@ public final class TestUtil {
         "Couldn't read file: " + fullPath.getPath(), e);
         "Couldn't read file: " + fullPath.getPath(), e);
     }
     }
   }
   }
+  // END FULL-RUNTIME
+
+  private static ByteString readBytesFromResource(String name) {
+    try {
+      return ByteString.copyFrom(
+          com.google.common.io.ByteStreams.toByteArray(TestUtil.class.getResourceAsStream(name)));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
 
 
   /**
   /**
    * Get the bytes of the "golden message".  This is a serialized TestAllTypes
    * Get the bytes of the "golden message".  This is a serialized TestAllTypes
@@ -3829,7 +3852,7 @@ public final class TestUtil {
    */
    */
   public static ByteString getGoldenMessage() {
   public static ByteString getGoldenMessage() {
     if (goldenMessage == null) {
     if (goldenMessage == null) {
-      goldenMessage = readBytesFromFile("golden_message_oneof_implemented");
+      goldenMessage = readBytesFromResource("/google/protobuf/testdata/golden_message_oneof_implemented");
     }
     }
     return goldenMessage;
     return goldenMessage;
   }
   }
@@ -3846,12 +3869,13 @@ public final class TestUtil {
   public static ByteString getGoldenPackedFieldsMessage() {
   public static ByteString getGoldenPackedFieldsMessage() {
     if (goldenPackedFieldsMessage == null) {
     if (goldenPackedFieldsMessage == null) {
       goldenPackedFieldsMessage =
       goldenPackedFieldsMessage =
-          readBytesFromFile("golden_packed_fields_message");
+          readBytesFromResource("/google/protobuf/testdata/golden_packed_fields_message");
     }
     }
     return goldenPackedFieldsMessage;
     return goldenPackedFieldsMessage;
   }
   }
   private static ByteString goldenPackedFieldsMessage = null;
   private static ByteString goldenPackedFieldsMessage = null;
 
 
+  // BEGIN FULL-RUNTIME
   /**
   /**
    * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing.
    * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing.
    *
    *
@@ -3871,4 +3895,5 @@ public final class TestUtil {
       return invalidations;
       return invalidations;
     }
     }
   }
   }
+  // END FULL-RUNTIME
 }
 }

+ 9 - 16
java/core/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -382,17 +382,14 @@ public class TextFormatTest extends TestCase {
 
 
   public void testMergeExtensions() throws Exception {
   public void testMergeExtensions() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
-    TextFormat.merge(allExtensionsSetText,
-                     TestUtil.getExtensionRegistry(),
-                     builder);
+    TextFormat.merge(allExtensionsSetText, TestUtil.getFullExtensionRegistry(), builder);
     TestUtil.assertAllExtensionsSet(builder.build());
     TestUtil.assertAllExtensionsSet(builder.build());
   }
   }
 
 
   public void testParseExtensions() throws Exception {
   public void testParseExtensions() throws Exception {
     TestUtil.assertAllExtensionsSet(
     TestUtil.assertAllExtensionsSet(
-        TextFormat.parse(allExtensionsSetText,
-                         TestUtil.getExtensionRegistry(),
-                         TestAllExtensions.class));
+        TextFormat.parse(
+            allExtensionsSetText, TestUtil.getFullExtensionRegistry(), TestAllExtensions.class));
   }
   }
 
 
   public void testMergeAndParseCompatibility() throws Exception {
   public void testMergeAndParseCompatibility() throws Exception {
@@ -523,7 +520,7 @@ public class TextFormatTest extends TestCase {
     // Test merge().
     // Test merge().
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
     try {
-      TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
+      TextFormat.merge(text, TestUtil.getFullExtensionRegistry(), builder);
       fail("Expected parse exception.");
       fail("Expected parse exception.");
     } catch (TextFormat.ParseException e) {
     } catch (TextFormat.ParseException e) {
       assertEquals(error, e.getMessage());
       assertEquals(error, e.getMessage());
@@ -531,8 +528,7 @@ public class TextFormatTest extends TestCase {
 
 
     // Test parse().
     // Test parse().
     try {
     try {
-      TextFormat.parse(
-          text, TestUtil.getExtensionRegistry(), TestAllTypes.class);
+      TextFormat.parse(text, TestUtil.getFullExtensionRegistry(), TestAllTypes.class);
       fail("Expected parse exception.");
       fail("Expected parse exception.");
     } catch (TextFormat.ParseException e) {
     } catch (TextFormat.ParseException e) {
       assertEquals(error, e.getMessage());
       assertEquals(error, e.getMessage());
@@ -544,8 +540,7 @@ public class TextFormatTest extends TestCase {
       String text) {
       String text) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
     try {
-      parserWithOverwriteForbidden.merge(
-          text, TestUtil.getExtensionRegistry(), builder);
+      parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder);
       fail("Expected parse exception.");
       fail("Expected parse exception.");
     } catch (TextFormat.ParseException e) {
     } catch (TextFormat.ParseException e) {
       assertEquals(error, e.getMessage());
       assertEquals(error, e.getMessage());
@@ -555,8 +550,7 @@ public class TextFormatTest extends TestCase {
   private TestAllTypes assertParseSuccessWithOverwriteForbidden(
   private TestAllTypes assertParseSuccessWithOverwriteForbidden(
       String text) throws TextFormat.ParseException {
       String text) throws TextFormat.ParseException {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-    parserWithOverwriteForbidden.merge(
-        text, TestUtil.getExtensionRegistry(), builder);
+    parserWithOverwriteForbidden.merge(text, TestUtil.getFullExtensionRegistry(), builder);
     return builder.build();
     return builder.build();
   }
   }
 
 
@@ -1118,8 +1112,7 @@ public class TextFormatTest extends TestCase {
     String input = "foo_string: \"stringvalue\" foo_int: 123";
     String input = "foo_string: \"stringvalue\" foo_int: 123";
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     try {
     try {
-      parserWithOverwriteForbidden.merge(
-          input, TestUtil.getExtensionRegistry(), builder);
+      parserWithOverwriteForbidden.merge(input, TestUtil.getFullExtensionRegistry(), builder);
       fail("Expected parse exception.");
       fail("Expected parse exception.");
     } catch (TextFormat.ParseException e) {
     } catch (TextFormat.ParseException e) {
       assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
       assertEquals("1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
@@ -1131,7 +1124,7 @@ public class TextFormatTest extends TestCase {
   public void testOneofOverwriteAllowed() throws Exception {
   public void testOneofOverwriteAllowed() throws Exception {
     String input = "foo_string: \"stringvalue\" foo_int: 123";
     String input = "foo_string: \"stringvalue\" foo_int: 123";
     TestOneof2.Builder builder = TestOneof2.newBuilder();
     TestOneof2.Builder builder = TestOneof2.newBuilder();
-    defaultParser.merge(input, TestUtil.getExtensionRegistry(), builder);
+    defaultParser.merge(input, TestUtil.getFullExtensionRegistry(), builder);
     // Only the last value sticks.
     // Only the last value sticks.
     TestOneof2 oneof = builder.build();
     TestOneof2 oneof = builder.build();
     assertFalse(oneof.hasFooString());
     assertFalse(oneof.hasFooString());

+ 2 - 2
java/core/src/test/java/com/google/protobuf/WireFormatTest.java

@@ -132,7 +132,7 @@ public class WireFormatTest extends TestCase {
     TestAllTypes message = TestUtil.getAllSet();
     TestAllTypes message = TestUtil.getAllSet();
     ByteString rawBytes = message.toByteString();
     ByteString rawBytes = message.toByteString();
 
 
-    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+    ExtensionRegistryLite registry = TestUtil.getExtensionRegistry();
 
 
     TestAllExtensions message2 =
     TestAllExtensions message2 =
       TestAllExtensions.parseFrom(rawBytes, registry);
       TestAllExtensions.parseFrom(rawBytes, registry);
@@ -145,7 +145,7 @@ public class WireFormatTest extends TestCase {
     TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
     TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
     ByteString rawBytes = message.toByteString();
     ByteString rawBytes = message.toByteString();
 
 
-    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+    ExtensionRegistryLite registry = TestUtil.getExtensionRegistry();
 
 
     TestPackedExtensions message2 =
     TestPackedExtensions message2 =
         TestPackedExtensions.parseFrom(rawBytes, registry);
         TestPackedExtensions.parseFrom(rawBytes, registry);

+ 0 - 2
java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto

@@ -36,8 +36,6 @@ syntax = "proto2";
 
 
 package protobuf_unittest;
 package protobuf_unittest;
 
 
-option optimize_for = LITE_RUNTIME;
-
 message LazyMessageLite {
 message LazyMessageLite {
   optional int32 num = 1;
   optional int32 num = 1;
   optional int32 num_with_default = 2 [default = 421];
   optional int32 num_with_default = 2 [default = 421];

+ 0 - 1
java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto

@@ -34,7 +34,6 @@ syntax = "proto2";
 
 
 package protobuf_unittest.lite_equals_and_hash;
 package protobuf_unittest.lite_equals_and_hash;
 
 
-option optimize_for = LITE_RUNTIME;
 
 
 message TestOneofEquals {
 message TestOneofEquals {
   oneof oneof_field {
   oneof oneof_field {

+ 2 - 3
java/core/src/test/proto/com/google/protobuf/map_lite_test.proto

@@ -30,10 +30,9 @@
 
 
 syntax = "proto3";
 syntax = "proto3";
 
 
-package map_lite_test;
+package map_test;
 
 
-option optimize_for = LITE_RUNTIME;
-option java_package = "map_lite_test";
+option java_package = "map_test";
 option java_outer_classname = "MapTestProto";
 option java_outer_classname = "MapTestProto";
 
 
 message TestMap {
 message TestMap {

+ 0 - 1
java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto

@@ -38,7 +38,6 @@ syntax = "proto2";
 
 
 package protobuf_unittest;
 package protobuf_unittest;
 
 
-option optimize_for = LITE_RUNTIME;
 
 
 import "com/google/protobuf/non_nested_extension_lite.proto";
 import "com/google/protobuf/non_nested_extension_lite.proto";
 
 

+ 0 - 1
java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto

@@ -36,7 +36,6 @@ syntax = "proto2";
 
 
 package protobuf_unittest;
 package protobuf_unittest;
 
 
-option optimize_for = LITE_RUNTIME;
 
 
 message MessageLiteToBeExtended {
 message MessageLiteToBeExtended {
   extensions 1 to max;
   extensions 1 to max;

+ 3 - 0
java/util/src/main/java/com/google/protobuf/util/Durations.java

@@ -61,6 +61,9 @@ public final class Durations {
   public static final Duration MAX_VALUE =
   public static final Duration MAX_VALUE =
       Duration.newBuilder().setSeconds(DURATION_SECONDS_MAX).setNanos(999999999).build();
       Duration.newBuilder().setSeconds(DURATION_SECONDS_MAX).setNanos(999999999).build();
 
 
+  /** A constant holding the duration of zero. */
+  public static final Duration ZERO = Duration.newBuilder().setSeconds(0L).setNanos(0).build();
+
   private Durations() {}
   private Durations() {}
 
 
   private static final Comparator<Duration> COMPARATOR =
   private static final Comparator<Duration> COMPARATOR =

+ 9 - 7
java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java

@@ -249,12 +249,9 @@ final class FieldMaskTree {
           continue;
           continue;
         }
         }
         String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
         String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
-        merge(
-            entry.getValue(),
-            childPath,
-            (Message) source.getField(field),
-            destination.getFieldBuilder(field),
-            options);
+        Message.Builder childBuilder = ((Message) destination.getField(field)).toBuilder();
+        merge(entry.getValue(), childPath, (Message) source.getField(field), childBuilder, options);
+        destination.setField(field, childBuilder.buildPartial());
         continue;
         continue;
       }
       }
       if (field.isRepeated()) {
       if (field.isRepeated()) {
@@ -275,7 +272,12 @@ final class FieldMaskTree {
             }
             }
           } else {
           } else {
             if (source.hasField(field)) {
             if (source.hasField(field)) {
-              destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field));
+              destination.setField(
+                  field,
+                  ((Message) destination.getField(field))
+                      .toBuilder()
+                      .mergeFrom((Message) source.getField(field))
+                      .build());
             }
             }
           }
           }
         } else {
         } else {

+ 1 - 1
java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java

@@ -235,7 +235,7 @@ public class FieldMaskUtil {
   /**
   /**
    * Converts a FieldMask to its canonical form. In the canonical form of a
    * Converts a FieldMask to its canonical form. In the canonical form of a
    * FieldMask, all field paths are sorted alphabetically and redundant field
    * FieldMask, all field paths are sorted alphabetically and redundant field
-   * paths are moved.
+   * paths are removed.
    */
    */
   public static FieldMask normalize(FieldMask mask) {
   public static FieldMask normalize(FieldMask mask) {
     return new FieldMaskTree(mask).toFieldMask();
     return new FieldMaskTree(mask).toFieldMask();

+ 1 - 1
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

@@ -610,7 +610,7 @@ public class JsonFormat {
     private final CharSequence blankOrNewLine;
     private final CharSequence blankOrNewLine;
 
 
     private static class GsonHolder {
     private static class GsonHolder {
-      private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
+      private static final Gson DEFAULT_GSON = new GsonBuilder().create();
     }
     }
 
 
     PrinterImpl(
     PrinterImpl(

+ 110 - 40
java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java

@@ -30,9 +30,14 @@
 
 
 package com.google.protobuf.util;
 package com.google.protobuf.util;
 
 
+import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.Message;
+import com.google.protobuf.UninitializedMessageException;
 import protobuf_unittest.UnittestProto.NestedTestAllTypes;
 import protobuf_unittest.UnittestProto.NestedTestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredMessage;
 import junit.framework.TestCase;
 import junit.framework.TestCase;
 
 
 public class FieldMaskTreeTest extends TestCase {
 public class FieldMaskTreeTest extends TestCase {
@@ -90,8 +95,68 @@ public class FieldMaskTreeTest extends TestCase {
     tree.intersectFieldPath("bar", result);
     tree.intersectFieldPath("bar", result);
     assertEquals("bar.baz,bar.quz,foo", result.toString());
     assertEquals("bar.baz,bar.quz,foo", result.toString());
   }
   }
-
+  
   public void testMerge() throws Exception {
   public void testMerge() throws Exception {
+    testMergeImpl(true);
+    testMergeImpl(false);
+    testMergeRequire(false);
+    testMergeRequire(true);
+  }
+
+  private void merge(
+      FieldMaskTree tree,
+      Message source,
+      Message.Builder builder,
+      FieldMaskUtil.MergeOptions options,
+      boolean useDynamicMessage)
+      throws Exception {
+    if (useDynamicMessage) {
+      Message.Builder newBuilder =
+          DynamicMessage.newBuilder(source.getDescriptorForType())
+              .mergeFrom(builder.buildPartial().toByteArray());
+      tree.merge(
+          DynamicMessage.newBuilder(source.getDescriptorForType())
+              .mergeFrom(source.toByteArray())
+              .build(),
+          newBuilder,
+          options);
+      builder.clear();
+      builder.mergeFrom(newBuilder.buildPartial());
+    } else {
+      tree.merge(source, builder, options);
+    }
+  }
+
+  private void testMergeRequire(boolean useDynamicMessage) throws Exception {
+    TestRequired value = TestRequired.newBuilder().setA(4321).setB(8765).setC(233333).build();
+    TestRequiredMessage source = TestRequiredMessage.newBuilder().setRequiredMessage(value).build();
+
+    FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions();
+    TestRequiredMessage.Builder builder = TestRequiredMessage.newBuilder();
+    merge(
+        new FieldMaskTree().addFieldPath("required_message.a"),
+        source,
+        builder,
+        options,
+        useDynamicMessage);
+    assertTrue(builder.hasRequiredMessage());
+    assertTrue(builder.getRequiredMessage().hasA());
+    assertFalse(builder.getRequiredMessage().hasB());
+    assertFalse(builder.getRequiredMessage().hasC());
+    merge(
+        new FieldMaskTree().addFieldPath("required_message.b").addFieldPath("required_message.c"),
+        source,
+        builder,
+        options,
+        useDynamicMessage);
+    try {
+      assertEquals(builder.build(), source);
+    } catch (UninitializedMessageException e) {
+      throw new AssertionError("required field isn't set", e);
+    }
+  }
+
+  private void testMergeImpl(boolean useDynamicMessage) throws Exception {
     TestAllTypes value =
     TestAllTypes value =
         TestAllTypes.newBuilder()
         TestAllTypes.newBuilder()
             .setOptionalInt32(1234)
             .setOptionalInt32(1234)
@@ -119,45 +184,51 @@ public class FieldMaskTreeTest extends TestCase {
 
 
     // Test merging each individual field.
     // Test merging each individual field.
     NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
     NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload.optional_int32").merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
+        source, builder, options, useDynamicMessage);
     NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
     NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().setOptionalInt32(1234);
     expected.getPayloadBuilder().setOptionalInt32(1234);
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("payload.optional_nested_message")
-        .merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.optional_nested_message"),
+        source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
     expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678));
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"),
+        source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().addRepeatedInt32(4321);
     expected.getPayloadBuilder().addRepeatedInt32(4321);
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("payload.repeated_nested_message")
-        .merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.repeated_nested_message"),
+        source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
     expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765));
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("child.payload.optional_int32")
-        .merge(source, builder, options);
+    merge(
+        new FieldMaskTree().addFieldPath("child.payload.optional_int32"),
+        source,
+        builder,
+        options,
+        useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234);
     expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234);
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("child.payload.optional_nested_message")
-        .merge(source, builder, options);
+    merge(
+        new FieldMaskTree().addFieldPath("child.payload.optional_nested_message"),
+        source,
+        builder,
+        options,
+        useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected
     expected
         .getChildBuilder()
         .getChildBuilder()
@@ -166,17 +237,15 @@ public class FieldMaskTreeTest extends TestCase {
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("child.payload.repeated_int32")
-        .merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("child.payload.repeated_int32"),
+        source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321);
     expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321);
     assertEquals(expected.build(), builder.build());
     assertEquals(expected.build(), builder.build());
 
 
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("child.payload.repeated_nested_message")
-        .merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("child.payload.repeated_nested_message"),
+        source, builder, options, useDynamicMessage);
     expected = NestedTestAllTypes.newBuilder();
     expected = NestedTestAllTypes.newBuilder();
     expected
     expected
         .getChildBuilder()
         .getChildBuilder()
@@ -186,23 +255,23 @@ public class FieldMaskTreeTest extends TestCase {
 
 
     // Test merging all fields.
     // Test merging all fields.
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("child")
-        .addFieldPath("payload")
-        .merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("child").addFieldPath("payload"),
+        source, builder, options, useDynamicMessage);
     assertEquals(source, builder.build());
     assertEquals(source, builder.build());
 
 
     // Test repeated options.
     // Test repeated options.
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().addRepeatedInt32(1000);
     builder.getPayloadBuilder().addRepeatedInt32(1000);
-    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"),
+        source, builder, options, useDynamicMessage);
     // Default behavior is to append repeated fields.
     // Default behavior is to append repeated fields.
     assertEquals(2, builder.getPayload().getRepeatedInt32Count());
     assertEquals(2, builder.getPayload().getRepeatedInt32Count());
     assertEquals(1000, builder.getPayload().getRepeatedInt32(0));
     assertEquals(1000, builder.getPayload().getRepeatedInt32(0));
     assertEquals(4321, builder.getPayload().getRepeatedInt32(1));
     assertEquals(4321, builder.getPayload().getRepeatedInt32(1));
     // Change to replace repeated fields.
     // Change to replace repeated fields.
     options.setReplaceRepeatedFields(true);
     options.setReplaceRepeatedFields(true);
-    new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.repeated_int32"),
+        source, builder, options, useDynamicMessage);
     assertEquals(1, builder.getPayload().getRepeatedInt32Count());
     assertEquals(1, builder.getPayload().getRepeatedInt32Count());
     assertEquals(4321, builder.getPayload().getRepeatedInt32(0));
     assertEquals(4321, builder.getPayload().getRepeatedInt32(0));
 
 
@@ -210,7 +279,8 @@ public class FieldMaskTreeTest extends TestCase {
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
-    new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload"),
+        source, builder, options, useDynamicMessage);
     // Default behavior is to merge message fields.
     // Default behavior is to merge message fields.
     assertEquals(1234, builder.getPayload().getOptionalInt32());
     assertEquals(1234, builder.getPayload().getOptionalInt32());
     assertEquals(2000, builder.getPayload().getOptionalUint32());
     assertEquals(2000, builder.getPayload().getOptionalUint32());
@@ -218,14 +288,14 @@ public class FieldMaskTreeTest extends TestCase {
     // Test merging unset message fields.
     // Test merging unset message fields.
     NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build();
     NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build();
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload"),
+        clearedSource, builder, options, useDynamicMessage);
     assertEquals(false, builder.hasPayload());
     assertEquals(false, builder.hasPayload());
 
 
     // Skip a message field if they are unset in both source and target.
     // Skip a message field if they are unset in both source and target.
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
-    new FieldMaskTree()
-        .addFieldPath("payload.optional_int32")
-        .merge(clearedSource, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
+        clearedSource, builder, options, useDynamicMessage);
     assertEquals(false, builder.hasPayload());
     assertEquals(false, builder.hasPayload());
 
 
     // Change to replace message fields.
     // Change to replace message fields.
@@ -233,7 +303,8 @@ public class FieldMaskTreeTest extends TestCase {
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
-    new FieldMaskTree().addFieldPath("payload").merge(source, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload"),
+        source, builder, options, useDynamicMessage);
     assertEquals(1234, builder.getPayload().getOptionalInt32());
     assertEquals(1234, builder.getPayload().getOptionalInt32());
     assertEquals(0, builder.getPayload().getOptionalUint32());
     assertEquals(0, builder.getPayload().getOptionalUint32());
 
 
@@ -241,7 +312,8 @@ public class FieldMaskTreeTest extends TestCase {
     builder = NestedTestAllTypes.newBuilder();
     builder = NestedTestAllTypes.newBuilder();
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalInt32(1000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
     builder.getPayloadBuilder().setOptionalUint32(2000);
-    new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload"),
+        clearedSource, builder, options, useDynamicMessage);
     assertEquals(false, builder.hasPayload());
     assertEquals(false, builder.hasPayload());
 
 
     // Test merging unset primitive fields.
     // Test merging unset primitive fields.
@@ -249,18 +321,16 @@ public class FieldMaskTreeTest extends TestCase {
     builder.getPayloadBuilder().clearOptionalInt32();
     builder.getPayloadBuilder().clearOptionalInt32();
     NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build();
     NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build();
     builder = source.toBuilder();
     builder = source.toBuilder();
-    new FieldMaskTree()
-        .addFieldPath("payload.optional_int32")
-        .merge(sourceWithPayloadInt32Unset, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
+        sourceWithPayloadInt32Unset, builder, options, useDynamicMessage);
     assertEquals(true, builder.getPayload().hasOptionalInt32());
     assertEquals(true, builder.getPayload().hasOptionalInt32());
     assertEquals(0, builder.getPayload().getOptionalInt32());
     assertEquals(0, builder.getPayload().getOptionalInt32());
 
 
     // Change to clear unset primitive fields.
     // Change to clear unset primitive fields.
     options.setReplacePrimitiveFields(true);
     options.setReplacePrimitiveFields(true);
     builder = source.toBuilder();
     builder = source.toBuilder();
-    new FieldMaskTree()
-        .addFieldPath("payload.optional_int32")
-        .merge(sourceWithPayloadInt32Unset, builder, options);
+    merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
+        sourceWithPayloadInt32Unset, builder, options, useDynamicMessage);
     assertEquals(true, builder.hasPayload());
     assertEquals(true, builder.hasPayload());
     assertEquals(false, builder.getPayload().hasOptionalInt32());
     assertEquals(false, builder.getPayload().hasOptionalInt32());
   }
   }

+ 8 - 5
java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java

@@ -70,7 +70,6 @@ import java.io.StringReader;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.BigInteger;
 import java.util.Collections;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Set;
 import java.util.Set;
@@ -1188,10 +1187,14 @@ public class JsonFormatTest extends TestCase {
     assertRoundTripEquals(message);
     assertRoundTripEquals(message);
   }
   }
 
 
-  public void testDefaultGsonDoesNotHtmlEscape() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build();
-    assertEquals(
-        "{\n" + "  \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message));
+  // Regression test for b/73832901. Make sure html tags are escaped.
+  public void testHtmlEscape() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("</script>").build();
+    assertEquals("{\n  \"optionalString\": \"\\u003c/script\\u003e\"\n}", toJsonString(message));
+
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    JsonFormat.parser().merge(toJsonString(message), builder);
+    assertEquals(message.getOptionalString(), builder.getOptionalString());
   }
   }
 
 
   public void testIncludingDefaultValueFields() throws Exception {
   public void testIncludingDefaultValueFields() throws Exception {

+ 1 - 1
js/binary/constants.js

@@ -174,7 +174,7 @@ jspb.PrunerFunction;
 
 
 /**
 /**
  * A comparer function returns true if two protos are equal.
  * A comparer function returns true if two protos are equal.
- * @typedef {!function(?jspb.ConstBinaryMessage,
+ * @typedef {function(?jspb.ConstBinaryMessage,
  *                     ?jspb.ConstBinaryMessage):boolean}
  *                     ?jspb.ConstBinaryMessage):boolean}
  */
  */
 jspb.ComparerFunction;
 jspb.ComparerFunction;

+ 8 - 9
js/binary/reader.js

@@ -290,7 +290,9 @@ jspb.BinaryReader.prototype.nextField = function() {
       nextWireType != jspb.BinaryConstants.WireType.DELIMITED &&
       nextWireType != jspb.BinaryConstants.WireType.DELIMITED &&
       nextWireType != jspb.BinaryConstants.WireType.START_GROUP &&
       nextWireType != jspb.BinaryConstants.WireType.START_GROUP &&
       nextWireType != jspb.BinaryConstants.WireType.END_GROUP) {
       nextWireType != jspb.BinaryConstants.WireType.END_GROUP) {
-    goog.asserts.fail('Invalid wire type');
+    goog.asserts.fail(
+        'Invalid wire type: %s (at position %s)', nextWireType,
+        this.fieldCursor_);
     this.error_ = true;
     this.error_ = true;
     return false;
     return false;
   }
   }
@@ -388,8 +390,7 @@ jspb.BinaryReader.prototype.skipFixed64Field = function() {
  * Skips over the next group field in the binary stream.
  * Skips over the next group field in the binary stream.
  */
  */
 jspb.BinaryReader.prototype.skipGroup = function() {
 jspb.BinaryReader.prototype.skipGroup = function() {
-  // Keep a stack of start-group tags that must be matched by end-group tags.
-  var nestedGroups = [this.nextField_];
+  var previousField = this.nextField_;
   do {
   do {
     if (!this.nextField()) {
     if (!this.nextField()) {
       goog.asserts.fail('Unmatched start-group tag: stream EOF');
       goog.asserts.fail('Unmatched start-group tag: stream EOF');
@@ -397,19 +398,17 @@ jspb.BinaryReader.prototype.skipGroup = function() {
       return;
       return;
     }
     }
     if (this.nextWireType_ ==
     if (this.nextWireType_ ==
-        jspb.BinaryConstants.WireType.START_GROUP) {
-      // Nested group start.
-      nestedGroups.push(this.nextField_);
-    } else if (this.nextWireType_ ==
                jspb.BinaryConstants.WireType.END_GROUP) {
                jspb.BinaryConstants.WireType.END_GROUP) {
       // Group end: check that it matches top-of-stack.
       // Group end: check that it matches top-of-stack.
-      if (this.nextField_ != nestedGroups.pop()) {
+      if (this.nextField_ != previousField) {
         goog.asserts.fail('Unmatched end-group tag');
         goog.asserts.fail('Unmatched end-group tag');
         this.error_ = true;
         this.error_ = true;
         return;
         return;
       }
       }
+      return;
     }
     }
-  } while (nestedGroups.length > 0);
+    this.skipField();
+  } while (true);
 };
 };
 
 
 
 

+ 15 - 0
js/binary/reader_test.js

@@ -679,9 +679,24 @@ describe('binaryReaderTest', function() {
     writer.writeInt32(5, sentinel);
     writer.writeInt32(5, sentinel);
     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
     writer.writeGroup(5, dummyMessage, function() {
     writer.writeGroup(5, dummyMessage, function() {
+      // Previously the skipGroup implementation was wrong, which only consume
+      // the decoder by nextField. This case is for making the previous
+      // implementation failed in skipGroup by an early end group tag.
+      // The reason is 44 = 5 * 8 + 4, this will be translated in to a field
+      // with number 5 and with type 4 (end group)
+      writer.writeInt64(44, 44);
+      // This will make previous implementation failed by invalid tag (7).
+      writer.writeInt64(42, 47);
       writer.writeInt64(42, 42);
       writer.writeInt64(42, 42);
+      // This is for making the previous implementation failed by an invalid
+      // varint. The bytes have at least 9 consecutive minus byte, which will
+      // fail in this.nextField for previous implementation.
+      writer.writeBytes(43, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
       writer.writeGroup(6, dummyMessage, function() {
       writer.writeGroup(6, dummyMessage, function() {
         writer.writeInt64(84, 42);
         writer.writeInt64(84, 42);
+        writer.writeInt64(84, 44);
+        writer.writeBytes(
+          43, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
       });
       });
     });
     });
 
 

+ 3 - 2
js/binary/utils.js

@@ -971,8 +971,9 @@ 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 (typeof Buffer != 'undefined' && data.constructor === Buffer) {
+    return /** @type {!Uint8Array} */ (
+        new Uint8Array(/** @type {?} */ (data)));
   }
   }
 
 
   if (data.constructor === Array) {
   if (data.constructor === Array) {

+ 7 - 7
js/map.js

@@ -136,7 +136,7 @@ jspb.Map.prototype.toArray = function() {
  *
  *
  * @param {boolean=} includeInstance Whether to include the JSPB instance for
  * @param {boolean=} includeInstance Whether to include the JSPB instance for
  *    transitional soy proto support: http://goto/soy-param-migration
  *    transitional soy proto support: http://goto/soy-param-migration
- * @param {!function((boolean|undefined),V):!Object=} valueToObject
+ * @param {function((boolean|undefined),V):!Object=} valueToObject
  *    The static toObject() method, if V is a message type.
  *    The static toObject() method, if V is a message type.
  * @return {!Array<!Array<!Object>>}
  * @return {!Array<!Array<!Object>>}
  */
  */
@@ -165,9 +165,9 @@ jspb.Map.prototype.toObject = function(includeInstance, valueToObject) {
  *
  *
  * @template K, V
  * @template K, V
  * @param {!Array<!Array<!Object>>} entries
  * @param {!Array<!Array<!Object>>} entries
- * @param {!function(new:V,?=)} valueCtor
+ * @param {function(new:V,?=)} valueCtor
  *    The constructor for type V.
  *    The constructor for type V.
- * @param {!function(!Object):V} valueFromObject
+ * @param {function(!Object):V} valueFromObject
  *    The fromObject function for type V.
  *    The fromObject function for type V.
  * @return {!jspb.Map<K, V>}
  * @return {!jspb.Map<K, V>}
  */
  */
@@ -410,9 +410,9 @@ jspb.Map.prototype.has = function(key) {
  * number.
  * number.
  * @param {number} fieldNumber
  * @param {number} fieldNumber
  * @param {!jspb.BinaryWriter} writer
  * @param {!jspb.BinaryWriter} writer
- * @param {!function(this:jspb.BinaryWriter,number,K)} keyWriterFn
+ * @param {function(this:jspb.BinaryWriter,number,K)} keyWriterFn
  *     The method on BinaryWriter that writes type K to the stream.
  *     The method on BinaryWriter that writes type K to the stream.
- * @param {!function(this:jspb.BinaryWriter,number,V,?=)|
+ * @param {function(this:jspb.BinaryWriter,number,V,?=)|
  *          function(this:jspb.BinaryWriter,number,V,?)} valueWriterFn
  *          function(this:jspb.BinaryWriter,number,V,?)} valueWriterFn
  *     The method on BinaryWriter that writes type V to the stream.  May be
  *     The method on BinaryWriter that writes type V to the stream.  May be
  *     writeMessage, in which case the second callback arg form is used.
  *     writeMessage, in which case the second callback arg form is used.
@@ -448,10 +448,10 @@ jspb.Map.prototype.serializeBinary = function(
  * @template K, V
  * @template K, V
  * @param {!jspb.Map} map
  * @param {!jspb.Map} map
  * @param {!jspb.BinaryReader} reader
  * @param {!jspb.BinaryReader} reader
- * @param {!function(this:jspb.BinaryReader):K} keyReaderFn
+ * @param {function(this:jspb.BinaryReader):K} keyReaderFn
  *     The method on BinaryReader that reads type K from the stream.
  *     The method on BinaryReader that reads type K from the stream.
  *
  *
- * @param {!function(this:jspb.BinaryReader):V|
+ * @param {function(this:jspb.BinaryReader):V|
  *          function(this:jspb.BinaryReader,V,
  *          function(this:jspb.BinaryReader,V,
  *                  function(V,!jspb.BinaryReader))} valueReaderFn
  *                  function(V,!jspb.BinaryReader))} valueReaderFn
  *    The method on BinaryReader that reads type V from the stream. May be
  *    The method on BinaryReader that reads type V from the stream. May be

+ 31 - 19
js/message.js

@@ -439,9 +439,19 @@ jspb.Message.isArray_ = function(o) {
  * @private
  * @private
  */
  */
 jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
 jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
-  if (msg.array.length) {
-    var foundIndex = msg.array.length - 1;
-    var obj = msg.array[foundIndex];
+  // There are 3 variants that need to be dealt with which are the
+  // combination of whether there exists an extension object (EO) and
+  // whether there is a suggested pivot (SP).
+  //
+  // EO,    ?    : pivot is the index of the EO
+  // no-EO, no-SP: pivot is MAX_INT
+  // no-EO, SP   : pivot is the max(lastindex + 1, SP)
+
+  var msgLength = msg.array.length;
+  var lastIndex = -1;
+  if (msgLength) {
+    lastIndex = msgLength - 1;
+    var obj = msg.array[lastIndex];
     // Normal fields are never objects, so we can be sure that if we find an
     // Normal fields are never objects, so we can be sure that if we find an
     // object here, then it's the extension object. However, we must ensure that
     // object here, then it's the extension object. However, we must ensure that
     // the object is not an array, since arrays are valid field values.
     // the object is not an array, since arrays are valid field values.
@@ -449,14 +459,17 @@ jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
     // in Safari on iOS 8. See the description of CL/86511464 for details.
     // in Safari on iOS 8. See the description of CL/86511464 for details.
     if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
     if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
         !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
         !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
-      msg.pivot_ = jspb.Message.getFieldNumber_(msg, foundIndex);
+      msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex);
       msg.extensionObject_ = obj;
       msg.extensionObject_ = obj;
       return;
       return;
     }
     }
   }
   }
 
 
   if (suggestedPivot > -1) {
   if (suggestedPivot > -1) {
-    msg.pivot_ = suggestedPivot;
+    // If a extension object is not present, set the pivot value as being
+    // after the last value in the array to avoid overwriting values, etc.
+    msg.pivot_ = Math.max(
+        suggestedPivot, jspb.Message.getFieldNumber_(msg, lastIndex + 1));
     // Avoid changing the shape of the proto with an empty extension object by
     // Avoid changing the shape of the proto with an empty extension object by
     // deferring the materialization of the extension object until the first
     // deferring the materialization of the extension object until the first
     // time a field set into it (may be due to getting a repeated proto field
     // time a field set into it (may be due to getting a repeated proto field
@@ -922,17 +935,6 @@ jspb.Message.setProto3IntField = function(msg, fieldNumber, value) {
 };
 };
 
 
 
 
-/**
- * Sets the value of a non-extension integer, handled as string, field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
- * @param {number} fieldNumber The field number.
- * @param {number} value New value
- * @protected
- */
-jspb.Message.setProto3StringIntField = function(msg, fieldNumber, value) {
-  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '0');
-};
-
 /**
 /**
  * Sets the value of a non-extension floating point field of a proto3
  * Sets the value of a non-extension floating point field of a proto3
  * @param {!jspb.Message} msg A jspb proto.
  * @param {!jspb.Message} msg A jspb proto.
@@ -993,12 +995,22 @@ jspb.Message.setProto3EnumField = function(msg, fieldNumber, value) {
 };
 };
 
 
 
 
+/**
+ * Sets the value of a non-extension int field of a proto3 that has jstype set
+ * to String.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {string} value New value
+ * @protected
+ */
+jspb.Message.setProto3StringIntField = function(msg, fieldNumber, value) {
+  jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "0");
+};
 
 
 /**
 /**
  * Sets the value of a non-extension primitive field, with proto3 (non-nullable
  * Sets the value of a non-extension primitive field, with proto3 (non-nullable
  * primitives) semantics of ignoring values that are equal to the type's
  * primitives) semantics of ignoring values that are equal to the type's
  * default.
  * default.
- * @template T
  * @param {!jspb.Message} msg A jspb proto.
  * @param {!jspb.Message} msg A jspb proto.
  * @param {number} fieldNumber The field number.
  * @param {number} fieldNumber The field number.
  * @param {!Uint8Array|string|number|boolean|undefined} value New value
  * @param {!Uint8Array|string|number|boolean|undefined} value New value
@@ -1007,7 +1019,7 @@ jspb.Message.setProto3EnumField = function(msg, fieldNumber, value) {
  */
  */
 jspb.Message.setFieldIgnoringDefault_ = function(
 jspb.Message.setFieldIgnoringDefault_ = function(
     msg, fieldNumber, value, defaultValue) {
     msg, fieldNumber, value, defaultValue) {
-  if (value != defaultValue) {
+  if (value !== defaultValue) {
     jspb.Message.setField(msg, fieldNumber, value);
     jspb.Message.setField(msg, fieldNumber, value);
   } else {
   } else {
     msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = null;
     msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = null;
@@ -1127,7 +1139,7 @@ jspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) {
  * @param {!jspb.Message} msg A jspb proto.
  * @param {!jspb.Message} msg A jspb proto.
  * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
  * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
  * @param {number} fieldNumber The field number.
  * @param {number} fieldNumber The field number.
- * @return {Array<!jspb.Message>} The repeated field as an array of protos.
+ * @return {!Array<!jspb.Message>} The repeated field as an array of protos.
  * @protected
  * @protected
  */
  */
 jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
 jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {

+ 1 - 0
js/message_test.js

@@ -73,6 +73,7 @@ goog.require('proto.jspb.test.Simple1');
 goog.require('proto.jspb.test.Simple2');
 goog.require('proto.jspb.test.Simple2');
 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.TestCloneExtension');
 goog.require('proto.jspb.test.TestEndsWithBytes');
 goog.require('proto.jspb.test.TestEndsWithBytes');
 goog.require('proto.jspb.test.TestGroup');
 goog.require('proto.jspb.test.TestGroup');
 goog.require('proto.jspb.test.TestGroup1');
 goog.require('proto.jspb.test.TestGroup1');

+ 7 - 0
js/test.proto

@@ -165,6 +165,13 @@ message TestClone {
   extensions 10 to max;
   extensions 10 to max;
 }
 }
 
 
+message TestCloneExtension {
+  extend TestClone {
+    optional TestCloneExtension low_ext = 11;
+  }
+  optional int32 f = 1;
+}
+
 message CloneExtension {
 message CloneExtension {
   extend TestClone {
   extend TestClone {
     optional CloneExtension ext_field = 100;
     optional CloneExtension ext_field = 100;

+ 6 - 3
python/compatibility_tests/v2.5.0/tests/google/protobuf/internal/text_format_test.py

@@ -410,7 +410,8 @@ class TextFormatTest(unittest.TestCase):
     text = 'optional_nested_enum: BARR'
     text = 'optional_nested_enum: BARR'
     self.assertRaisesWithMessage(
     self.assertRaisesWithMessage(
         text_format.ParseError,
         text_format.ParseError,
-        ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
+        ('1:23 : \'optional_nested_enum: BARR\': '
+         'Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
          'has no value named BARR.'),
          'has no value named BARR.'),
         text_format.Merge, text, message)
         text_format.Merge, text, message)
 
 
@@ -418,7 +419,8 @@ class TextFormatTest(unittest.TestCase):
     text = 'optional_nested_enum: 100'
     text = 'optional_nested_enum: 100'
     self.assertRaisesWithMessage(
     self.assertRaisesWithMessage(
         text_format.ParseError,
         text_format.ParseError,
-        ('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
+        ('1:23 : \'optional_nested_enum: 100\': '
+         'Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
          'has no value with number 100.'),
          'has no value with number 100.'),
         text_format.Merge, text, message)
         text_format.Merge, text, message)
 
 
@@ -427,7 +429,8 @@ class TextFormatTest(unittest.TestCase):
     text = 'optional_int32: bork'
     text = 'optional_int32: bork'
     self.assertRaisesWithMessage(
     self.assertRaisesWithMessage(
         text_format.ParseError,
         text_format.ParseError,
-        ('1:17 : Couldn\'t parse integer: bork'),
+        ('1:17 : \'optional_int32: bork\': '
+         'Couldn\'t parse integer: bork'),
         text_format.Merge, text, message)
         text_format.Merge, text, message)
 
 
   def testMergeStringFieldUnescape(self):
   def testMergeStringFieldUnescape(self):

+ 11 - 0
python/google/protobuf/descriptor_database.py

@@ -76,6 +76,9 @@ class DescriptorDatabase(object):
         self._AddSymbol(name, file_desc_proto)
         self._AddSymbol(name, file_desc_proto)
     for enum in file_desc_proto.enum_type:
     for enum in file_desc_proto.enum_type:
       self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto)
       self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto)
+      for enum_value in enum.value:
+        self._file_desc_protos_by_symbol[
+            '.'.join((package, enum_value.name))] = file_desc_proto
     for extension in file_desc_proto.extension:
     for extension in file_desc_proto.extension:
       self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto)
       self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto)
     for service in file_desc_proto.service:
     for service in file_desc_proto.service:
@@ -133,6 +136,14 @@ class DescriptorDatabase(object):
       top_level, _, _ = symbol.rpartition('.')
       top_level, _, _ = symbol.rpartition('.')
       return self._file_desc_protos_by_symbol[top_level]
       return self._file_desc_protos_by_symbol[top_level]
 
 
+  def FindFileContainingExtension(self, extendee_name, extension_number):
+    # TODO(jieluo): implement this API.
+    return None
+
+  def FindAllExtensionNumbers(self, extendee_name):
+    # TODO(jieluo): implement this API.
+    return []
+
   def _AddSymbol(self, name, file_desc_proto):
   def _AddSymbol(self, name, file_desc_proto):
     if name in self._file_desc_protos_by_symbol:
     if name in self._file_desc_protos_by_symbol:
       warn_msg = ('Conflict register for file "' + file_desc_proto.name +
       warn_msg = ('Conflict register for file "' + file_desc_proto.name +

+ 170 - 26
python/google/protobuf/descriptor_pool.py

@@ -131,33 +131,46 @@ class DescriptorPool(object):
     # TODO(jieluo): Remove _file_desc_by_toplevel_extension after
     # TODO(jieluo): Remove _file_desc_by_toplevel_extension after
     # maybe year 2020 for compatibility issue (with 3.4.1 only).
     # maybe year 2020 for compatibility issue (with 3.4.1 only).
     self._file_desc_by_toplevel_extension = {}
     self._file_desc_by_toplevel_extension = {}
+    self._top_enum_values = {}
     # We store extensions in two two-level mappings: The first key is the
     # We store extensions in two two-level mappings: The first key is the
     # descriptor of the message being extended, the second key is the extension
     # descriptor of the message being extended, the second key is the extension
     # full name or its tag number.
     # full name or its tag number.
     self._extensions_by_name = collections.defaultdict(dict)
     self._extensions_by_name = collections.defaultdict(dict)
     self._extensions_by_number = collections.defaultdict(dict)
     self._extensions_by_number = collections.defaultdict(dict)
 
 
-  def _CheckConflictRegister(self, desc):
+  def _CheckConflictRegister(self, desc, desc_name, file_name):
     """Check if the descriptor name conflicts with another of the same name.
     """Check if the descriptor name conflicts with another of the same name.
 
 
     Args:
     Args:
-      desc: Descriptor of a message, enum, service or extension.
+      desc: Descriptor of a message, enum, service, extension or enum value.
+      desc_name: the full name of desc.
+      file_name: The file name of descriptor.
     """
     """
-    desc_name = desc.full_name
     for register, descriptor_type in [
     for register, descriptor_type in [
         (self._descriptors, descriptor.Descriptor),
         (self._descriptors, descriptor.Descriptor),
         (self._enum_descriptors, descriptor.EnumDescriptor),
         (self._enum_descriptors, descriptor.EnumDescriptor),
         (self._service_descriptors, descriptor.ServiceDescriptor),
         (self._service_descriptors, descriptor.ServiceDescriptor),
-        (self._toplevel_extensions, descriptor.FieldDescriptor)]:
+        (self._toplevel_extensions, descriptor.FieldDescriptor),
+        (self._top_enum_values, descriptor.EnumValueDescriptor)]:
       if desc_name in register:
       if desc_name in register:
-        file_name = register[desc_name].file.name
+        old_desc = register[desc_name]
+        if isinstance(old_desc, descriptor.EnumValueDescriptor):
+          old_file = old_desc.type.file.name
+        else:
+          old_file = old_desc.file.name
+
         if not isinstance(desc, descriptor_type) or (
         if not isinstance(desc, descriptor_type) or (
-            file_name != desc.file.name):
-          warn_msg = ('Conflict register for file "' + desc.file.name +
+            old_file != file_name):
+          warn_msg = ('Conflict register for file "' + file_name +
                       '": ' + desc_name +
                       '": ' + desc_name +
                       ' is already defined in file "' +
                       ' is already defined in file "' +
-                      file_name + '"')
+                      old_file + '"')
+          if isinstance(desc, descriptor.EnumValueDescriptor):
+            warn_msg += ('\nNote: enum values appear as '
+                         'siblings of the enum type instead of '
+                         'children of it.')
           warnings.warn(warn_msg, RuntimeWarning)
           warnings.warn(warn_msg, RuntimeWarning)
+
         return
         return
 
 
   def Add(self, file_desc_proto):
   def Add(self, file_desc_proto):
@@ -196,7 +209,7 @@ class DescriptorPool(object):
     if not isinstance(desc, descriptor.Descriptor):
     if not isinstance(desc, descriptor.Descriptor):
       raise TypeError('Expected instance of descriptor.Descriptor.')
       raise TypeError('Expected instance of descriptor.Descriptor.')
 
 
-    self._CheckConflictRegister(desc)
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
 
 
     self._descriptors[desc.full_name] = desc
     self._descriptors[desc.full_name] = desc
     self._AddFileDescriptor(desc.file)
     self._AddFileDescriptor(desc.file)
@@ -213,8 +226,26 @@ class DescriptorPool(object):
     if not isinstance(enum_desc, descriptor.EnumDescriptor):
     if not isinstance(enum_desc, descriptor.EnumDescriptor):
       raise TypeError('Expected instance of descriptor.EnumDescriptor.')
       raise TypeError('Expected instance of descriptor.EnumDescriptor.')
 
 
-    self._CheckConflictRegister(enum_desc)
+    file_name = enum_desc.file.name
+    self._CheckConflictRegister(enum_desc, enum_desc.full_name, file_name)
     self._enum_descriptors[enum_desc.full_name] = enum_desc
     self._enum_descriptors[enum_desc.full_name] = enum_desc
+
+    # Top enum values need to be indexed.
+    # Count the number of dots to see whether the enum is toplevel or nested
+    # in a message. We cannot use enum_desc.containing_type at this stage.
+    if enum_desc.file.package:
+      top_level = (enum_desc.full_name.count('.')
+                   - enum_desc.file.package.count('.') == 1)
+    else:
+      top_level = enum_desc.full_name.count('.') == 0
+    if top_level:
+      file_name = enum_desc.file.name
+      package = enum_desc.file.package
+      for enum_value in enum_desc.values:
+        full_name = _NormalizeFullyQualifiedName(
+            '.'.join((package, enum_value.name)))
+        self._CheckConflictRegister(enum_value, full_name, file_name)
+        self._top_enum_values[full_name] = enum_value
     self._AddFileDescriptor(enum_desc.file)
     self._AddFileDescriptor(enum_desc.file)
 
 
   def AddServiceDescriptor(self, service_desc):
   def AddServiceDescriptor(self, service_desc):
@@ -227,7 +258,8 @@ class DescriptorPool(object):
     if not isinstance(service_desc, descriptor.ServiceDescriptor):
     if not isinstance(service_desc, descriptor.ServiceDescriptor):
       raise TypeError('Expected instance of descriptor.ServiceDescriptor.')
       raise TypeError('Expected instance of descriptor.ServiceDescriptor.')
 
 
-    self._CheckConflictRegister(service_desc)
+    self._CheckConflictRegister(service_desc, service_desc.full_name,
+                                service_desc.file.name)
     self._service_descriptors[service_desc.full_name] = service_desc
     self._service_descriptors[service_desc.full_name] = service_desc
 
 
   def AddExtensionDescriptor(self, extension):
   def AddExtensionDescriptor(self, extension):
@@ -247,7 +279,6 @@ class DescriptorPool(object):
       raise TypeError('Expected an extension descriptor.')
       raise TypeError('Expected an extension descriptor.')
 
 
     if extension.extension_scope is None:
     if extension.extension_scope is None:
-      self._CheckConflictRegister(extension)
       self._toplevel_extensions[extension.full_name] = extension
       self._toplevel_extensions[extension.full_name] = extension
 
 
     try:
     try:
@@ -348,6 +379,30 @@ class DescriptorPool(object):
     """
     """
 
 
     symbol = _NormalizeFullyQualifiedName(symbol)
     symbol = _NormalizeFullyQualifiedName(symbol)
+    try:
+      return self._InternalFindFileContainingSymbol(symbol)
+    except KeyError:
+      pass
+
+    try:
+      # Try fallback database. Build and find again if possible.
+      self._FindFileContainingSymbolInDb(symbol)
+      return self._InternalFindFileContainingSymbol(symbol)
+    except KeyError:
+      raise KeyError('Cannot find a file containing %s' % symbol)
+
+  def _InternalFindFileContainingSymbol(self, symbol):
+    """Gets the already built FileDescriptor containing the specified symbol.
+
+    Args:
+      symbol: The name of the symbol to search for.
+
+    Returns:
+      A FileDescriptor that contains the specified symbol.
+
+    Raises:
+      KeyError: if the file cannot be found in the pool.
+    """
     try:
     try:
       return self._descriptors[symbol].file
       return self._descriptors[symbol].file
     except KeyError:
     except KeyError:
@@ -364,7 +419,7 @@ class DescriptorPool(object):
       pass
       pass
 
 
     try:
     try:
-      return self._FindFileContainingSymbolInDb(symbol)
+      return self._top_enum_values[symbol].type.file
     except KeyError:
     except KeyError:
       pass
       pass
 
 
@@ -373,13 +428,15 @@ class DescriptorPool(object):
     except KeyError:
     except KeyError:
       pass
       pass
 
 
-    # Try nested extensions inside a message.
-    message_name, _, extension_name = symbol.rpartition('.')
+    # Try fields, enum values and nested extensions inside a message.
+    top_name, _, sub_name = symbol.rpartition('.')
     try:
     try:
-      message = self.FindMessageTypeByName(message_name)
-      assert message.extensions_by_name[extension_name]
+      message = self.FindMessageTypeByName(top_name)
+      assert (sub_name in message.extensions_by_name or
+              sub_name in message.fields_by_name or
+              sub_name in message.enum_values_by_name)
       return message.file
       return message.file
-    except KeyError:
+    except (KeyError, AssertionError):
       raise KeyError('Cannot find a file containing %s' % symbol)
       raise KeyError('Cannot find a file containing %s' % symbol)
 
 
   def FindMessageTypeByName(self, full_name):
   def FindMessageTypeByName(self, full_name):
@@ -499,7 +556,11 @@ class DescriptorPool(object):
       KeyError: when no extension with the given number is known for the
       KeyError: when no extension with the given number is known for the
         specified message.
         specified message.
     """
     """
-    return self._extensions_by_number[message_descriptor][number]
+    try:
+      return self._extensions_by_number[message_descriptor][number]
+    except KeyError:
+      self._TryLoadExtensionFromDB(message_descriptor, number)
+      return self._extensions_by_number[message_descriptor][number]
 
 
   def FindAllExtensions(self, message_descriptor):
   def FindAllExtensions(self, message_descriptor):
     """Gets all the known extension of a given message.
     """Gets all the known extension of a given message.
@@ -513,8 +574,57 @@ class DescriptorPool(object):
     Returns:
     Returns:
       A list of FieldDescriptor describing the extensions.
       A list of FieldDescriptor describing the extensions.
     """
     """
+    # Fallback to descriptor db if FindAllExtensionNumbers is provided.
+    if self._descriptor_db and hasattr(
+        self._descriptor_db, 'FindAllExtensionNumbers'):
+      full_name = message_descriptor.full_name
+      all_numbers = self._descriptor_db.FindAllExtensionNumbers(full_name)
+      for number in all_numbers:
+        if number in self._extensions_by_number[message_descriptor]:
+          continue
+        self._TryLoadExtensionFromDB(message_descriptor, number)
+
     return list(self._extensions_by_number[message_descriptor].values())
     return list(self._extensions_by_number[message_descriptor].values())
 
 
+  def _TryLoadExtensionFromDB(self, message_descriptor, number):
+    """Try to Load extensions from decriptor db.
+
+    Args:
+      message_descriptor: descriptor of the extended message.
+      number: the extension number that needs to be loaded.
+    """
+    if not self._descriptor_db:
+      return
+    # Only supported when FindFileContainingExtension is provided.
+    if not hasattr(
+        self._descriptor_db, 'FindFileContainingExtension'):
+      return
+
+    full_name = message_descriptor.full_name
+    file_proto = self._descriptor_db.FindFileContainingExtension(
+        full_name, number)
+
+    if file_proto is None:
+      return
+
+    try:
+      file_desc = self._ConvertFileProtoToFileDescriptor(file_proto)
+      for extension in file_desc.extensions_by_name.values():
+        self._extensions_by_number[extension.containing_type][
+            extension.number] = extension
+        self._extensions_by_name[extension.containing_type][
+            extension.full_name] = extension
+      for message_type in file_desc.message_types_by_name.values():
+        for extension in message_type.extensions:
+          self._extensions_by_number[extension.containing_type][
+              extension.number] = extension
+          self._extensions_by_name[extension.containing_type][
+              extension.full_name] = extension
+    except:
+      warn_msg = ('Unable to load proto file %s for extension number %d.' %
+                  (file_proto.name, number))
+      warnings.warn(warn_msg, RuntimeWarning)
+
   def FindServiceByName(self, full_name):
   def FindServiceByName(self, full_name):
     """Loads the named service descriptor from the pool.
     """Loads the named service descriptor from the pool.
 
 
@@ -532,6 +642,23 @@ class DescriptorPool(object):
       self._FindFileContainingSymbolInDb(full_name)
       self._FindFileContainingSymbolInDb(full_name)
     return self._service_descriptors[full_name]
     return self._service_descriptors[full_name]
 
 
+  def FindMethodByName(self, full_name):
+    """Loads the named service method descriptor from the pool.
+
+    Args:
+      full_name: The full name of the method descriptor to load.
+
+    Returns:
+      The method descriptor for the service method.
+
+    Raises:
+      KeyError: if the method cannot be found in the pool.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    service_name, _, method_name = full_name.rpartition('.')
+    service_descriptor = self.FindServiceByName(service_name)
+    return service_descriptor.methods_by_name[method_name]
+
   def _FindFileContainingSymbolInDb(self, symbol):
   def _FindFileContainingSymbolInDb(self, symbol):
     """Finds the file in descriptor DB containing the specified symbol.
     """Finds the file in descriptor DB containing the specified symbol.
 
 
@@ -567,7 +694,6 @@ class DescriptorPool(object):
     Returns:
     Returns:
       A FileDescriptor matching the passed in proto.
       A FileDescriptor matching the passed in proto.
     """
     """
-
     if file_proto.name not in self._file_descriptors:
     if file_proto.name not in self._file_descriptors:
       built_deps = list(self._GetDeps(file_proto.dependency))
       built_deps = list(self._GetDeps(file_proto.dependency))
       direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
       direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
@@ -604,7 +730,7 @@ class DescriptorPool(object):
       for enum_type in file_proto.enum_type:
       for enum_type in file_proto.enum_type:
         file_descriptor.enum_types_by_name[enum_type.name] = (
         file_descriptor.enum_types_by_name[enum_type.name] = (
             self._ConvertEnumDescriptor(enum_type, file_proto.package,
             self._ConvertEnumDescriptor(enum_type, file_proto.package,
-                                        file_descriptor, None, scope))
+                                        file_descriptor, None, scope, True))
 
 
       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(
@@ -616,6 +742,8 @@ class DescriptorPool(object):
                            file_descriptor.package, scope)
                            file_descriptor.package, scope)
         file_descriptor.extensions_by_name[extension_desc.name] = (
         file_descriptor.extensions_by_name[extension_desc.name] = (
             extension_desc)
             extension_desc)
+        self._file_desc_by_toplevel_extension[extension_desc.full_name] = (
+            file_descriptor)
 
 
       for desc_proto in file_proto.message_type:
       for desc_proto in file_proto.message_type:
         self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
         self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
@@ -673,7 +801,8 @@ class DescriptorPool(object):
             nested, desc_name, file_desc, scope, syntax)
             nested, desc_name, file_desc, scope, syntax)
         for nested in desc_proto.nested_type]
         for nested in desc_proto.nested_type]
     enums = [
     enums = [
-        self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
+        self._ConvertEnumDescriptor(enum, desc_name, file_desc, None,
+                                    scope, False)
         for enum in desc_proto.enum_type]
         for enum in desc_proto.enum_type]
     fields = [self._MakeFieldDescriptor(field, desc_name, index, file_desc)
     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)]
@@ -718,12 +847,12 @@ class DescriptorPool(object):
         fields[field_index].containing_oneof = oneofs[oneof_index]
         fields[field_index].containing_oneof = oneofs[oneof_index]
 
 
     scope[_PrefixWithDot(desc_name)] = desc
     scope[_PrefixWithDot(desc_name)] = desc
-    self._CheckConflictRegister(desc)
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
     self._descriptors[desc_name] = desc
     self._descriptors[desc_name] = desc
     return desc
     return desc
 
 
   def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
   def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
-                             containing_type=None, scope=None):
+                             containing_type=None, scope=None, top_level=False):
     """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
     """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
 
 
     Args:
     Args:
@@ -732,6 +861,8 @@ class DescriptorPool(object):
       file_desc: The file containing the enum descriptor.
       file_desc: The file containing the enum descriptor.
       containing_type: The type containing this enum.
       containing_type: The type containing this enum.
       scope: Scope containing available types.
       scope: Scope containing available types.
+      top_level: If True, the enum is a top level symbol. If False, the enum
+          is defined inside a message.
 
 
     Returns:
     Returns:
       The added descriptor
       The added descriptor
@@ -757,8 +888,17 @@ class DescriptorPool(object):
                                      containing_type=containing_type,
                                      containing_type=containing_type,
                                      options=_OptionsOrNone(enum_proto))
                                      options=_OptionsOrNone(enum_proto))
     scope['.%s' % enum_name] = desc
     scope['.%s' % enum_name] = desc
-    self._CheckConflictRegister(desc)
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
     self._enum_descriptors[enum_name] = desc
     self._enum_descriptors[enum_name] = desc
+
+    # Add top level enum values.
+    if top_level:
+      for value in values:
+        full_name = _NormalizeFullyQualifiedName(
+            '.'.join((package, value.name)))
+        self._CheckConflictRegister(value, full_name, file_name)
+        self._top_enum_values[full_name] = value
+
     return desc
     return desc
 
 
   def _MakeFieldDescriptor(self, field_proto, message_name, index,
   def _MakeFieldDescriptor(self, field_proto, message_name, index,
@@ -885,6 +1025,8 @@ class DescriptorPool(object):
       elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
       elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
         field_desc.default_value = text_encoding.CUnescape(
         field_desc.default_value = text_encoding.CUnescape(
             field_proto.default_value)
             field_proto.default_value)
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE:
+        field_desc.default_value = None
       else:
       else:
         # All other types are of the "int" type.
         # All other types are of the "int" type.
         field_desc.default_value = int(field_proto.default_value)
         field_desc.default_value = int(field_proto.default_value)
@@ -901,6 +1043,8 @@ class DescriptorPool(object):
         field_desc.default_value = field_desc.enum_type.values[0].number
         field_desc.default_value = field_desc.enum_type.values[0].number
       elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
       elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
         field_desc.default_value = b''
         field_desc.default_value = b''
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE:
+        field_desc.default_value = None
       else:
       else:
         # All other types are of the "int" type.
         # All other types are of the "int" type.
         field_desc.default_value = 0
         field_desc.default_value = 0
@@ -954,7 +1098,7 @@ class DescriptorPool(object):
                                         methods=methods,
                                         methods=methods,
                                         options=_OptionsOrNone(service_proto),
                                         options=_OptionsOrNone(service_proto),
                                         file=file_desc)
                                         file=file_desc)
-    self._CheckConflictRegister(desc)
+    self._CheckConflictRegister(desc, desc.full_name, desc.file.name)
     self._service_descriptors[service_name] = desc
     self._service_descriptors[service_name] = desc
     return desc
     return desc
 
 

+ 30 - 0
python/google/protobuf/internal/__init__.py

@@ -0,0 +1,30 @@
+# 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.
+

+ 0 - 26
python/google/protobuf/internal/api_implementation.py

@@ -145,29 +145,3 @@ def Version():
 # For internal use only
 # For internal use only
 def IsPythonDefaultSerializationDeterministic():
 def IsPythonDefaultSerializationDeterministic():
   return _python_deterministic_proto_serialization
   return _python_deterministic_proto_serialization
-
-# DO NOT USE: For migration and testing only. Will be removed when Proto3
-# defaults to preserve unknowns.
-if _implementation_type == 'cpp':
-  try:
-    # pylint: disable=g-import-not-at-top
-    from google.protobuf.pyext import _message
-
-    def GetPythonProto3PreserveUnknownsDefault():
-      return _message.GetPythonProto3PreserveUnknownsDefault()
-
-    def SetPythonProto3PreserveUnknownsDefault(preserve):
-      _message.SetPythonProto3PreserveUnknownsDefault(preserve)
-  except ImportError:
-    # Unrecognized cpp implementation. Skipping the unknown fields APIs.
-    pass
-else:
-  _python_proto3_preserve_unknowns_default = True
-
-  def GetPythonProto3PreserveUnknownsDefault():
-    return _python_proto3_preserve_unknowns_default
-
-  def SetPythonProto3PreserveUnknownsDefault(preserve):
-    global _python_proto3_preserve_unknowns_default
-    _python_proto3_preserve_unknowns_default = preserve
-

+ 127 - 0
python/google/protobuf/internal/containers.py

@@ -628,3 +628,130 @@ class MessageMap(MutableMapping):
 
 
   def GetEntryClass(self):
   def GetEntryClass(self):
     return self._entry_descriptor._concrete_class
     return self._entry_descriptor._concrete_class
+
+
+class _UnknownField(object):
+
+  """A parsed unknown field."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_field_number', '_wire_type', '_data']
+
+  def __init__(self, field_number, wire_type, data):
+    self._field_number = field_number
+    self._wire_type = wire_type
+    self._data = data
+    return
+
+  def __lt__(self, other):
+    # pylint: disable=protected-access
+    return self._field_number < other._field_number
+
+  def __eq__(self, other):
+    if self is other:
+      return True
+    # pylint: disable=protected-access
+    return (self._field_number == other._field_number and
+            self._wire_type == other._wire_type and
+            self._data == other._data)
+
+
+class UnknownFieldRef(object):
+
+  def __init__(self, parent, index):
+    self._parent = parent
+    self._index = index
+    return
+
+  def _check_valid(self):
+    if not self._parent:
+      raise ValueError('UnknownField does not exist. '
+                       'The parent message might be cleared.')
+    if self._index >= len(self._parent):
+      raise ValueError('UnknownField does not exist. '
+                       'The parent message might be cleared.')
+
+  @property
+  def field_number(self):
+    self._check_valid()
+    # pylint: disable=protected-access
+    return self._parent._internal_get(self._index)._field_number
+
+  @property
+  def wire_type(self):
+    self._check_valid()
+    # pylint: disable=protected-access
+    return self._parent._internal_get(self._index)._wire_type
+
+  @property
+  def data(self):
+    self._check_valid()
+    # pylint: disable=protected-access
+    return self._parent._internal_get(self._index)._data
+
+
+class UnknownFieldSet(object):
+
+  """UnknownField container"""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_values']
+
+  def __init__(self):
+    self._values = []
+
+  def __getitem__(self, index):
+    if self._values is None:
+      raise ValueError('UnknownFields does not exist. '
+                       'The parent message might be cleared.')
+    size = len(self._values)
+    if index < 0:
+      index += size
+    if index < 0 or index >= size:
+      raise IndexError('index %d out of range'.index)
+
+    return UnknownFieldRef(self, index)
+
+  def _internal_get(self, index):
+    return self._values[index]
+
+  def __len__(self):
+    if self._values is None:
+      raise ValueError('UnknownFields does not exist. '
+                       'The parent message might be cleared.')
+    return len(self._values)
+
+  def _add(self, field_number, wire_type, data):
+    unknown_field = _UnknownField(field_number, wire_type, data)
+    self._values.append(unknown_field)
+    return unknown_field
+
+  def __iter__(self):
+    for i in range(len(self)):
+      yield UnknownFieldRef(self, i)
+
+  def _extend(self, other):
+    if other is None:
+      return
+    # pylint: disable=protected-access
+    self._values.extend(other._values)
+
+  def __eq__(self, other):
+    if self is other:
+      return True
+    # Sort unknown fields because their order shouldn't
+    # affect equality test.
+    values = list(self._values)
+    if other is None:
+      return not values
+    values.sort()
+    # pylint: disable=protected-access
+    other_values = sorted(other._values)
+    return values == other_values
+
+  def _clear(self):
+    for value in self._values:
+      # pylint: disable=protected-access
+      if isinstance(value._data, UnknownFieldSet):
+        value._data._clear()  # pylint: disable=protected-access
+    self._values = None

+ 176 - 16
python/google/protobuf/internal/decoder.py

@@ -86,7 +86,11 @@ import six
 
 
 if six.PY3:
 if six.PY3:
   long = int
   long = int
+else:
+  import re    # pylint: disable=g-import-not-at-top
+  _SURROGATE_PATTERN = re.compile(six.u(r'[\ud800-\udfff]'))
 
 
+from google.protobuf.internal import containers
 from google.protobuf.internal import encoder
 from google.protobuf.internal import encoder
 from google.protobuf.internal import wire_format
 from google.protobuf.internal import wire_format
 from google.protobuf import message
 from google.protobuf import message
@@ -167,7 +171,7 @@ _DecodeSignedVarint32 = _SignedVarintDecoder(32, int)
 
 
 
 
 def ReadTag(buffer, pos):
 def ReadTag(buffer, pos):
-  """Read a tag from the buffer, and return a (tag_bytes, new_pos) tuple.
+  """Read a tag from the memoryview, and return a (tag_bytes, new_pos) tuple.
 
 
   We return the raw bytes of the tag rather than decoding them.  The raw
   We return the raw bytes of the tag rather than decoding them.  The raw
   bytes can then be used to look up the proper decoder.  This effectively allows
   bytes can then be used to look up the proper decoder.  This effectively allows
@@ -175,13 +179,21 @@ def ReadTag(buffer, pos):
   for work that is done in C (searching for a byte string in a hash table).
   for work that is done in C (searching for a byte string in a hash table).
   In a low-level language it would be much cheaper to decode the varint and
   In a low-level language it would be much cheaper to decode the varint and
   use that, but not in Python.
   use that, but not in Python.
-  """
 
 
+  Args:
+    buffer: memoryview object of the encoded bytes
+    pos: int of the current position to start from
+
+  Returns:
+    Tuple[bytes, int] of the tag data and new position.
+  """
   start = pos
   start = pos
   while six.indexbytes(buffer, pos) & 0x80:
   while six.indexbytes(buffer, pos) & 0x80:
     pos += 1
     pos += 1
   pos += 1
   pos += 1
-  return (six.binary_type(buffer[start:pos]), pos)
+
+  tag_bytes = buffer[start:pos].tobytes()
+  return tag_bytes, pos
 
 
 
 
 # --------------------------------------------------------------------
 # --------------------------------------------------------------------
@@ -295,10 +307,20 @@ def _FloatDecoder():
   local_unpack = struct.unpack
   local_unpack = struct.unpack
 
 
   def InnerDecode(buffer, pos):
   def InnerDecode(buffer, pos):
+    """Decode serialized float to a float and new position.
+
+    Args:
+      buffer: memoryview of the serialized bytes
+      pos: int, position in the memory view to start at.
+
+    Returns:
+      Tuple[float, int] of the deserialized float value and new position
+      in the serialized data.
+    """
     # We expect a 32-bit value in little-endian byte order.  Bit 1 is the sign
     # We expect a 32-bit value in little-endian byte order.  Bit 1 is the sign
     # bit, bits 2-9 represent the exponent, and bits 10-32 are the significand.
     # bit, bits 2-9 represent the exponent, and bits 10-32 are the significand.
     new_pos = pos + 4
     new_pos = pos + 4
-    float_bytes = buffer[pos:new_pos]
+    float_bytes = buffer[pos:new_pos].tobytes()
 
 
     # If this value has all its exponent bits set, then it's non-finite.
     # If this value has all its exponent bits set, then it's non-finite.
     # In Python 2.4, struct.unpack will convert it to a finite 64-bit value.
     # In Python 2.4, struct.unpack will convert it to a finite 64-bit value.
@@ -329,10 +351,20 @@ def _DoubleDecoder():
   local_unpack = struct.unpack
   local_unpack = struct.unpack
 
 
   def InnerDecode(buffer, pos):
   def InnerDecode(buffer, pos):
+    """Decode serialized double to a double and new position.
+
+    Args:
+      buffer: memoryview of the serialized bytes.
+      pos: int, position in the memory view to start at.
+
+    Returns:
+      Tuple[float, int] of the decoded double value and new position
+      in the serialized data.
+    """
     # We expect a 64-bit value in little-endian byte order.  Bit 1 is the sign
     # We expect a 64-bit value in little-endian byte order.  Bit 1 is the sign
     # bit, bits 2-12 represent the exponent, and bits 13-64 are the significand.
     # bit, bits 2-12 represent the exponent, and bits 13-64 are the significand.
     new_pos = pos + 8
     new_pos = pos + 8
-    double_bytes = buffer[pos:new_pos]
+    double_bytes = buffer[pos:new_pos].tobytes()
 
 
     # If this value has all its exponent bits set and at least one significand
     # If this value has all its exponent bits set and at least one significand
     # bit set, it's not a number.  In Python 2.4, struct.unpack will treat it
     # bit set, it's not a number.  In Python 2.4, struct.unpack will treat it
@@ -355,6 +387,18 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
   if is_packed:
   if is_packed:
     local_DecodeVarint = _DecodeVarint
     local_DecodeVarint = _DecodeVarint
     def DecodePackedField(buffer, pos, end, message, field_dict):
     def DecodePackedField(buffer, pos, end, message, field_dict):
+      """Decode serialized packed enum to its value and a new position.
+
+      Args:
+        buffer: memoryview of the serialized bytes.
+        pos: int, position in the memory view to start at.
+        end: int, end position of serialized data
+        message: Message object to store unknown fields in
+        field_dict: Map[Descriptor, Any] to store decoded values in.
+
+      Returns:
+        int, new position in serialized data.
+      """
       value = field_dict.get(key)
       value = field_dict.get(key)
       if value is None:
       if value is None:
         value = field_dict.setdefault(key, new_default(message))
         value = field_dict.setdefault(key, new_default(message))
@@ -365,6 +409,7 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
       while pos < endpoint:
       while pos < endpoint:
         value_start_pos = pos
         value_start_pos = pos
         (element, pos) = _DecodeSignedVarint32(buffer, pos)
         (element, pos) = _DecodeSignedVarint32(buffer, pos)
+        # pylint: disable=protected-access
         if element in enum_type.values_by_number:
         if element in enum_type.values_by_number:
           value.append(element)
           value.append(element)
         else:
         else:
@@ -372,8 +417,10 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
             message._unknown_fields = []
             message._unknown_fields = []
           tag_bytes = encoder.TagBytes(field_number,
           tag_bytes = encoder.TagBytes(field_number,
                                        wire_format.WIRETYPE_VARINT)
                                        wire_format.WIRETYPE_VARINT)
+
           message._unknown_fields.append(
           message._unknown_fields.append(
-              (tag_bytes, buffer[value_start_pos:pos]))
+              (tag_bytes, buffer[value_start_pos:pos].tobytes()))
+          # pylint: enable=protected-access
       if pos > endpoint:
       if pos > endpoint:
         if element in enum_type.values_by_number:
         if element in enum_type.values_by_number:
           del value[-1]   # Discard corrupt value.
           del value[-1]   # Discard corrupt value.
@@ -386,18 +433,32 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
     tag_bytes = encoder.TagBytes(field_number, wire_format.WIRETYPE_VARINT)
     tag_bytes = encoder.TagBytes(field_number, wire_format.WIRETYPE_VARINT)
     tag_len = len(tag_bytes)
     tag_len = len(tag_bytes)
     def DecodeRepeatedField(buffer, pos, end, message, field_dict):
     def DecodeRepeatedField(buffer, pos, end, message, field_dict):
+      """Decode serialized repeated enum to its value and a new position.
+
+      Args:
+        buffer: memoryview of the serialized bytes.
+        pos: int, position in the memory view to start at.
+        end: int, end position of serialized data
+        message: Message object to store unknown fields in
+        field_dict: Map[Descriptor, Any] to store decoded values in.
+
+      Returns:
+        int, new position in serialized data.
+      """
       value = field_dict.get(key)
       value = field_dict.get(key)
       if value is None:
       if value is None:
         value = field_dict.setdefault(key, new_default(message))
         value = field_dict.setdefault(key, new_default(message))
       while 1:
       while 1:
         (element, new_pos) = _DecodeSignedVarint32(buffer, pos)
         (element, new_pos) = _DecodeSignedVarint32(buffer, pos)
+        # pylint: disable=protected-access
         if element in enum_type.values_by_number:
         if element in enum_type.values_by_number:
           value.append(element)
           value.append(element)
         else:
         else:
           if not message._unknown_fields:
           if not message._unknown_fields:
             message._unknown_fields = []
             message._unknown_fields = []
           message._unknown_fields.append(
           message._unknown_fields.append(
-              (tag_bytes, buffer[pos:new_pos]))
+              (tag_bytes, buffer[pos:new_pos].tobytes()))
+          # pylint: enable=protected-access
         # Predict that the next tag is another copy of the same repeated
         # Predict that the next tag is another copy of the same repeated
         # field.
         # field.
         pos = new_pos + tag_len
         pos = new_pos + tag_len
@@ -409,10 +470,23 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
     return DecodeRepeatedField
     return DecodeRepeatedField
   else:
   else:
     def DecodeField(buffer, pos, end, message, field_dict):
     def DecodeField(buffer, pos, end, message, field_dict):
+      """Decode serialized repeated enum to its value and a new position.
+
+      Args:
+        buffer: memoryview of the serialized bytes.
+        pos: int, position in the memory view to start at.
+        end: int, end position of serialized data
+        message: Message object to store unknown fields in
+        field_dict: Map[Descriptor, Any] to store decoded values in.
+
+      Returns:
+        int, new position in serialized data.
+      """
       value_start_pos = pos
       value_start_pos = pos
       (enum_value, pos) = _DecodeSignedVarint32(buffer, pos)
       (enum_value, pos) = _DecodeSignedVarint32(buffer, pos)
       if pos > end:
       if pos > end:
         raise _DecodeError('Truncated message.')
         raise _DecodeError('Truncated message.')
+      # pylint: disable=protected-access
       if enum_value in enum_type.values_by_number:
       if enum_value in enum_type.values_by_number:
         field_dict[key] = enum_value
         field_dict[key] = enum_value
       else:
       else:
@@ -421,7 +495,8 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, new_default):
         tag_bytes = encoder.TagBytes(field_number,
         tag_bytes = encoder.TagBytes(field_number,
                                      wire_format.WIRETYPE_VARINT)
                                      wire_format.WIRETYPE_VARINT)
         message._unknown_fields.append(
         message._unknown_fields.append(
-          (tag_bytes, buffer[value_start_pos:pos]))
+            (tag_bytes, buffer[value_start_pos:pos].tobytes()))
+        # pylint: enable=protected-access
       return pos
       return pos
     return DecodeField
     return DecodeField
 
 
@@ -458,20 +533,33 @@ BoolDecoder = _ModifiedDecoder(
     wire_format.WIRETYPE_VARINT, _DecodeVarint, bool)
     wire_format.WIRETYPE_VARINT, _DecodeVarint, bool)
 
 
 
 
-def StringDecoder(field_number, is_repeated, is_packed, key, new_default):
+def StringDecoder(field_number, is_repeated, is_packed, key, new_default,
+                  is_strict_utf8=False):
   """Returns a decoder for a string field."""
   """Returns a decoder for a string field."""
 
 
   local_DecodeVarint = _DecodeVarint
   local_DecodeVarint = _DecodeVarint
   local_unicode = six.text_type
   local_unicode = six.text_type
 
 
-  def _ConvertToUnicode(byte_str):
+  def _ConvertToUnicode(memview):
+    """Convert byte to unicode."""
+    byte_str = memview.tobytes()
     try:
     try:
-      return local_unicode(byte_str, 'utf-8')
+      value = local_unicode(byte_str, 'utf-8')
     except UnicodeDecodeError as e:
     except UnicodeDecodeError as e:
       # add more information to the error message and re-raise it.
       # add more information to the error message and re-raise it.
       e.reason = '%s in field: %s' % (e, key.full_name)
       e.reason = '%s in field: %s' % (e, key.full_name)
       raise
       raise
 
 
+    if is_strict_utf8 and six.PY2:
+      if _SURROGATE_PATTERN.search(value):
+        reason = ('String field %s contains invalid UTF-8 data when parsing'
+                  'a protocol buffer: surrogates not allowed. Use'
+                  'the bytes type if you intend to send raw bytes.') % (
+                      key.full_name)
+        raise message.DecodeError(reason)
+
+    return value
+
   assert not is_packed
   assert not is_packed
   if is_repeated:
   if is_repeated:
     tag_bytes = encoder.TagBytes(field_number,
     tag_bytes = encoder.TagBytes(field_number,
@@ -523,7 +611,7 @@ def BytesDecoder(field_number, is_repeated, is_packed, key, new_default):
         new_pos = pos + size
         new_pos = pos + size
         if new_pos > end:
         if new_pos > end:
           raise _DecodeError('Truncated string.')
           raise _DecodeError('Truncated string.')
-        value.append(buffer[pos:new_pos])
+        value.append(buffer[pos:new_pos].tobytes())
         # Predict that the next tag is another copy of the same repeated field.
         # Predict that the next tag is another copy of the same repeated field.
         pos = new_pos + tag_len
         pos = new_pos + tag_len
         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
@@ -536,7 +624,7 @@ def BytesDecoder(field_number, is_repeated, is_packed, key, new_default):
       new_pos = pos + size
       new_pos = pos + size
       if new_pos > end:
       if new_pos > end:
         raise _DecodeError('Truncated string.')
         raise _DecodeError('Truncated string.')
-      field_dict[key] = buffer[pos:new_pos]
+      field_dict[key] = buffer[pos:new_pos].tobytes()
       return new_pos
       return new_pos
     return DecodeField
     return DecodeField
 
 
@@ -665,6 +753,18 @@ def MessageSetItemDecoder(descriptor):
   local_SkipField = SkipField
   local_SkipField = SkipField
 
 
   def DecodeItem(buffer, pos, end, message, field_dict):
   def DecodeItem(buffer, pos, end, message, field_dict):
+    """Decode serialized message set to its value and new position.
+
+    Args:
+      buffer: memoryview of the serialized bytes.
+      pos: int, position in the memory view to start at.
+      end: int, end position of serialized data
+      message: Message object to store unknown fields in
+      field_dict: Map[Descriptor, Any] to store decoded values in.
+
+    Returns:
+      int, new position in serialized data.
+    """
     message_set_item_start = pos
     message_set_item_start = pos
     type_id = -1
     type_id = -1
     message_start = -1
     message_start = -1
@@ -695,6 +795,7 @@ def MessageSetItemDecoder(descriptor):
       raise _DecodeError('MessageSet item missing message.')
       raise _DecodeError('MessageSet item missing message.')
 
 
     extension = message.Extensions._FindExtensionByNumber(type_id)
     extension = message.Extensions._FindExtensionByNumber(type_id)
+    # pylint: disable=protected-access
     if extension is not None:
     if extension is not None:
       value = field_dict.get(extension)
       value = field_dict.get(extension)
       if value is None:
       if value is None:
@@ -707,8 +808,9 @@ def MessageSetItemDecoder(descriptor):
     else:
     else:
       if not message._unknown_fields:
       if not message._unknown_fields:
         message._unknown_fields = []
         message._unknown_fields = []
-      message._unknown_fields.append((MESSAGE_SET_ITEM_TAG,
-                                      buffer[message_set_item_start:pos]))
+      message._unknown_fields.append(
+          (MESSAGE_SET_ITEM_TAG, buffer[message_set_item_start:pos].tobytes()))
+      # pylint: enable=protected-access
 
 
     return pos
     return pos
 
 
@@ -767,7 +869,7 @@ def _SkipVarint(buffer, pos, end):
   # Previously ord(buffer[pos]) raised IndexError when pos is out of range.
   # Previously ord(buffer[pos]) raised IndexError when pos is out of range.
   # With this code, ord(b'') raises TypeError.  Both are handled in
   # With this code, ord(b'') raises TypeError.  Both are handled in
   # python_message.py to generate a 'Truncated message' error.
   # python_message.py to generate a 'Truncated message' error.
-  while ord(buffer[pos:pos+1]) & 0x80:
+  while ord(buffer[pos:pos+1].tobytes()) & 0x80:
     pos += 1
     pos += 1
   pos += 1
   pos += 1
   if pos > end:
   if pos > end:
@@ -782,6 +884,13 @@ def _SkipFixed64(buffer, pos, end):
     raise _DecodeError('Truncated message.')
     raise _DecodeError('Truncated message.')
   return pos
   return pos
 
 
+
+def _DecodeFixed64(buffer, pos):
+  """Decode a fixed64."""
+  new_pos = pos + 8
+  return (struct.unpack('<Q', buffer[pos:new_pos])[0], new_pos)
+
+
 def _SkipLengthDelimited(buffer, pos, end):
 def _SkipLengthDelimited(buffer, pos, end):
   """Skip a length-delimited value.  Returns the new position."""
   """Skip a length-delimited value.  Returns the new position."""
 
 
@@ -791,6 +900,7 @@ def _SkipLengthDelimited(buffer, pos, end):
     raise _DecodeError('Truncated message.')
     raise _DecodeError('Truncated message.')
   return pos
   return pos
 
 
+
 def _SkipGroup(buffer, pos, end):
 def _SkipGroup(buffer, pos, end):
   """Skip sub-group.  Returns the new position."""
   """Skip sub-group.  Returns the new position."""
 
 
@@ -801,11 +911,53 @@ def _SkipGroup(buffer, pos, end):
       return pos
       return pos
     pos = new_pos
     pos = new_pos
 
 
+
+def _DecodeGroup(buffer, pos):
+  """Decode group.  Returns the UnknownFieldSet and new position."""
+
+  unknown_field_set = containers.UnknownFieldSet()
+  while 1:
+    (tag_bytes, pos) = ReadTag(buffer, pos)
+    (tag, _) = _DecodeVarint(tag_bytes, 0)
+    field_number, wire_type = wire_format.UnpackTag(tag)
+    if wire_type == wire_format.WIRETYPE_END_GROUP:
+      break
+    (data, pos) = _DecodeUnknownField(buffer, pos, wire_type)
+    # pylint: disable=protected-access
+    unknown_field_set._add(field_number, wire_type, data)
+
+  return (unknown_field_set, pos)
+
+
+def _DecodeUnknownField(buffer, pos, wire_type):
+  """Decode a unknown field.  Returns the UnknownField and new position."""
+
+  if wire_type == wire_format.WIRETYPE_VARINT:
+    (data, pos) = _DecodeVarint(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_FIXED64:
+    (data, pos) = _DecodeFixed64(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_FIXED32:
+    (data, pos) = _DecodeFixed32(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED:
+    (size, pos) = _DecodeVarint(buffer, pos)
+    data = buffer[pos:pos+size]
+    pos += size
+  elif wire_type == wire_format.WIRETYPE_START_GROUP:
+    (data, pos) = _DecodeGroup(buffer, pos)
+  elif wire_type == wire_format.WIRETYPE_END_GROUP:
+    return (0, -1)
+  else:
+    raise _DecodeError('Wrong wire type in tag.')
+
+  return (data, pos)
+
+
 def _EndGroup(buffer, pos, end):
 def _EndGroup(buffer, pos, end):
   """Skipping an END_GROUP tag returns -1 to tell the parent loop to break."""
   """Skipping an END_GROUP tag returns -1 to tell the parent loop to break."""
 
 
   return -1
   return -1
 
 
+
 def _SkipFixed32(buffer, pos, end):
 def _SkipFixed32(buffer, pos, end):
   """Skip a fixed32 value.  Returns the new position."""
   """Skip a fixed32 value.  Returns the new position."""
 
 
@@ -814,6 +966,14 @@ def _SkipFixed32(buffer, pos, end):
     raise _DecodeError('Truncated message.')
     raise _DecodeError('Truncated message.')
   return pos
   return pos
 
 
+
+def _DecodeFixed32(buffer, pos):
+  """Decode a fixed32."""
+
+  new_pos = pos + 4
+  return (struct.unpack('<I', buffer[pos:new_pos])[0], new_pos)
+
+
 def _RaiseInvalidWireType(buffer, pos, end):
 def _RaiseInvalidWireType(buffer, pos, end):
   """Skip function for unknown wire types.  Raises an exception."""
   """Skip function for unknown wire types.  Raises an exception."""
 
 

+ 8 - 0
python/google/protobuf/internal/descriptor_database_test.py

@@ -43,6 +43,7 @@ import warnings
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import factory_test2_pb2
 from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import no_package_pb2
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_database
 
 
 
 
@@ -52,7 +53,10 @@ class DescriptorDatabaseTest(unittest.TestCase):
     db = descriptor_database.DescriptorDatabase()
     db = descriptor_database.DescriptorDatabase()
     file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
     file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
         factory_test2_pb2.DESCRIPTOR.serialized_pb)
         factory_test2_pb2.DESCRIPTOR.serialized_pb)
+    file_desc_proto2 = descriptor_pb2.FileDescriptorProto.FromString(
+        no_package_pb2.DESCRIPTOR.serialized_pb)
     db.Add(file_desc_proto)
     db.Add(file_desc_proto)
+    db.Add(file_desc_proto2)
 
 
     self.assertEqual(file_desc_proto, db.FindFileByName(
     self.assertEqual(file_desc_proto, db.FindFileByName(
         'google/protobuf/internal/factory_test2.proto'))
         'google/protobuf/internal/factory_test2.proto'))
@@ -76,6 +80,10 @@ class DescriptorDatabaseTest(unittest.TestCase):
     # Can find enum value.
     # Can find enum value.
     self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
     self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
         'google.protobuf.python.internal.Factory2Enum.FACTORY_2_VALUE_0'))
         'google.protobuf.python.internal.Factory2Enum.FACTORY_2_VALUE_0'))
+    self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
+        'google.protobuf.python.internal.FACTORY_2_VALUE_0'))
+    self.assertEqual(file_desc_proto2, db.FindFileContainingSymbol(
+        '.NO_PACKAGE_VALUE_0'))
     # Can find top level extension.
     # Can find top level extension.
     self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
     self.assertEqual(file_desc_proto, db.FindFileContainingSymbol(
         'google.protobuf.python.internal.another_field'))
         'google.protobuf.python.internal.another_field'))

+ 39 - 24
python/google/protobuf/internal/descriptor_pool_test.py

@@ -36,7 +36,6 @@ __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 
 import copy
 import copy
 import os
 import os
-import sys
 import warnings
 import warnings
 
 
 try:
 try:
@@ -55,6 +54,7 @@ from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
 from google.protobuf.internal import factory_test2_pb2
 from google.protobuf.internal import file_options_test_pb2
 from google.protobuf.internal import file_options_test_pb2
 from google.protobuf.internal import more_messages_pb2
 from google.protobuf.internal import more_messages_pb2
+from google.protobuf.internal import no_package_pb2
 from google.protobuf import descriptor
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
 from google.protobuf import descriptor_pool
@@ -120,7 +120,6 @@ class DescriptorPoolTestBase(object):
     self.assertIsInstance(file_desc5, descriptor.FileDescriptor)
     self.assertIsInstance(file_desc5, descriptor.FileDescriptor)
     self.assertEqual('google/protobuf/unittest.proto',
     self.assertEqual('google/protobuf/unittest.proto',
                      file_desc5.name)
                      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')
@@ -129,6 +128,32 @@ class DescriptorPoolTestBase(object):
     assert descriptor_pool.Default().FindFileContainingSymbol(
     assert descriptor_pool.Default().FindFileContainingSymbol(
         'protobuf_unittest.TestService')
         'protobuf_unittest.TestService')
 
 
+    # Can find field.
+    file_desc6 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory1Message.list_value')
+    self.assertIsInstance(file_desc6, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/internal/factory_test1.proto',
+                     file_desc6.name)
+
+    # Can find top level Enum value.
+    file_desc7 = self.pool.FindFileContainingSymbol(
+        'google.protobuf.python.internal.FACTORY_1_VALUE_0')
+    self.assertIsInstance(file_desc7, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/internal/factory_test1.proto',
+                     file_desc7.name)
+
+    # Can find nested Enum value.
+    file_desc8 = self.pool.FindFileContainingSymbol(
+        'protobuf_unittest.TestAllTypes.FOO')
+    self.assertIsInstance(file_desc8, descriptor.FileDescriptor)
+    self.assertEqual('google/protobuf/unittest.proto',
+                     file_desc8.name)
+
+    # TODO(jieluo): Add tests for no package when b/13860351 is fixed.
+
+    self.assertRaises(KeyError, self.pool.FindFileContainingSymbol,
+                      'google.protobuf.python.internal.Factory1Message.none_field')
+
   def testFindFileContainingSymbolFailure(self):
   def testFindFileContainingSymbolFailure(self):
     with self.assertRaises(KeyError):
     with self.assertRaises(KeyError):
       self.pool.FindFileContainingSymbol('Does not exist')
       self.pool.FindFileContainingSymbol('Does not exist')
@@ -217,11 +242,10 @@ class DescriptorPoolTestBase(object):
 
 
   def testFindTypeErrors(self):
   def testFindTypeErrors(self):
     self.assertRaises(TypeError, self.pool.FindExtensionByNumber, '')
     self.assertRaises(TypeError, self.pool.FindExtensionByNumber, '')
+    self.assertRaises(KeyError, self.pool.FindMethodByName, '')
 
 
     # TODO(jieluo): Fix python to raise correct errors.
     # TODO(jieluo): Fix python to raise correct errors.
     if api_implementation.Type() == 'cpp':
     if api_implementation.Type() == 'cpp':
-      self.assertRaises(TypeError, self.pool.FindMethodByName, 0)
-      self.assertRaises(KeyError, self.pool.FindMethodByName, '')
       error_type = TypeError
       error_type = TypeError
     else:
     else:
       error_type = AttributeError
       error_type = AttributeError
@@ -231,6 +255,7 @@ class DescriptorPoolTestBase(object):
     self.assertRaises(error_type, self.pool.FindEnumTypeByName, 0)
     self.assertRaises(error_type, self.pool.FindEnumTypeByName, 0)
     self.assertRaises(error_type, self.pool.FindOneofByName, 0)
     self.assertRaises(error_type, self.pool.FindOneofByName, 0)
     self.assertRaises(error_type, self.pool.FindServiceByName, 0)
     self.assertRaises(error_type, self.pool.FindServiceByName, 0)
+    self.assertRaises(error_type, self.pool.FindMethodByName, 0)
     self.assertRaises(error_type, self.pool.FindFileContainingSymbol, 0)
     self.assertRaises(error_type, self.pool.FindFileContainingSymbol, 0)
     if api_implementation.Type() == 'python':
     if api_implementation.Type() == 'python':
       error_type = KeyError
       error_type = KeyError
@@ -275,11 +300,6 @@ class DescriptorPoolTestBase(object):
       self.pool.FindEnumTypeByName('Does not exist')
       self.pool.FindEnumTypeByName('Does not exist')
 
 
   def testFindFieldByName(self):
   def testFindFieldByName(self):
-    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
-      if api_implementation.Type() == 'cpp':
-        # TODO(jieluo): Fix cpp extension to find field correctly
-        # when descriptor pool is using an underlying database.
-        return
     field = self.pool.FindFieldByName(
     field = self.pool.FindFieldByName(
         'google.protobuf.python.internal.Factory1Message.list_value')
         'google.protobuf.python.internal.Factory1Message.list_value')
     self.assertEqual(field.name, 'list_value')
     self.assertEqual(field.name, 'list_value')
@@ -290,11 +310,6 @@ class DescriptorPoolTestBase(object):
       self.pool.FindFieldByName('Does not exist')
       self.pool.FindFieldByName('Does not exist')
 
 
   def testFindOneofByName(self):
   def testFindOneofByName(self):
-    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
-      if api_implementation.Type() == 'cpp':
-        # TODO(jieluo): Fix cpp extension to find oneof correctly
-        # when descriptor pool is using an underlying database.
-        return
     oneof = self.pool.FindOneofByName(
     oneof = self.pool.FindOneofByName(
         'google.protobuf.python.internal.Factory2Message.oneof_field')
         'google.protobuf.python.internal.Factory2Message.oneof_field')
     self.assertEqual(oneof.name, 'oneof_field')
     self.assertEqual(oneof.name, 'oneof_field')
@@ -302,11 +317,6 @@ class DescriptorPoolTestBase(object):
       self.pool.FindOneofByName('Does not exist')
       self.pool.FindOneofByName('Does not exist')
 
 
   def testFindExtensionByName(self):
   def testFindExtensionByName(self):
-    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
-      if api_implementation.Type() == 'cpp':
-        # TODO(jieluo): Fix cpp extension to find extension correctly
-        # when descriptor pool is using an underlying database.
-        return
     # An extension defined in a message.
     # An extension defined in a message.
     extension = self.pool.FindExtensionByName(
     extension = self.pool.FindExtensionByName(
         'google.protobuf.python.internal.Factory2Message.one_more_field')
         'google.protobuf.python.internal.Factory2Message.one_more_field')
@@ -382,6 +392,11 @@ class DescriptorPoolTestBase(object):
     with self.assertRaises(KeyError):
     with self.assertRaises(KeyError):
       self.pool.FindServiceByName('Does not exist')
       self.pool.FindServiceByName('Does not exist')
 
 
+    method = self.pool.FindMethodByName('protobuf_unittest.TestService.Foo')
+    self.assertIs(method.containing_service, service)
+    with self.assertRaises(KeyError):
+      self.pool.FindMethodByName('protobuf_unittest.TestService.Doesnotexist')
+
   def testUserDefinedDB(self):
   def testUserDefinedDB(self):
     db = descriptor_database.DescriptorDatabase()
     db = descriptor_database.DescriptorDatabase()
     self.pool = descriptor_pool.DescriptorPool(db)
     self.pool = descriptor_pool.DescriptorPool(db)
@@ -601,6 +616,8 @@ class CreateDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
         unittest_import_pb2.DESCRIPTOR.serialized_pb))
         unittest_import_pb2.DESCRIPTOR.serialized_pb))
     self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
     self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
         unittest_pb2.DESCRIPTOR.serialized_pb))
         unittest_pb2.DESCRIPTOR.serialized_pb))
+    self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        no_package_pb2.DESCRIPTOR.serialized_pb))
 
 
 
 
 class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
 class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
@@ -620,6 +637,8 @@ class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
         unittest_import_pb2.DESCRIPTOR.serialized_pb))
         unittest_import_pb2.DESCRIPTOR.serialized_pb))
     db.Add(descriptor_pb2.FileDescriptorProto.FromString(
     db.Add(descriptor_pb2.FileDescriptorProto.FromString(
         unittest_pb2.DESCRIPTOR.serialized_pb))
         unittest_pb2.DESCRIPTOR.serialized_pb))
+    db.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        no_package_pb2.DESCRIPTOR.serialized_pb))
     self.pool = descriptor_pool.DescriptorPool(descriptor_db=db)
     self.pool = descriptor_pool.DescriptorPool(descriptor_db=db)
 
 
 
 
@@ -746,11 +765,7 @@ class MessageField(object):
     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)
     test.assertEqual(file_desc, field_desc.file)
-    # TODO(jieluo): Fix python and cpp extension diff for message field
-    # default value.
-    if api_implementation.Type() == 'cpp':
-      test.assertRaises(
-          NotImplementedError, getattr, field_desc, 'default_value')
+    test.assertEqual(field_desc.default_value, None)
 
 
 
 
 class StringField(object):
 class StringField(object):

+ 11 - 0
python/google/protobuf/internal/descriptor_test.py

@@ -452,6 +452,17 @@ class DescriptorTest(unittest.TestCase):
     self.assertEqual('attribute is not writable: has_options',
     self.assertEqual('attribute is not writable: has_options',
                      str(e.exception))
                      str(e.exception))
 
 
+  def testDefault(self):
+    message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    field = message_descriptor.fields_by_name['repeated_int32']
+    self.assertEqual(field.default_value, [])
+    field = message_descriptor.fields_by_name['repeated_nested_message']
+    self.assertEqual(field.default_value, [])
+    field = message_descriptor.fields_by_name['optionalgroup']
+    self.assertEqual(field.default_value, None)
+    field = message_descriptor.fields_by_name['optional_nested_message']
+    self.assertEqual(field.default_value, None)
+
 
 
 class NewDescriptorTest(DescriptorTest):
 class NewDescriptorTest(DescriptorTest):
   """Redo the same tests as above, but with a separate DescriptorPool."""
   """Redo the same tests as above, but with a separate DescriptorPool."""

+ 14 - 0
python/google/protobuf/internal/factory_test1.proto

@@ -56,3 +56,17 @@ message Factory1Message {
 
 
   extensions 1000 to max;
   extensions 1000 to max;
 }
 }
+
+message Factory1MethodRequest {
+  optional string argument = 1;
+}
+
+message Factory1MethodResponse {
+  optional string result = 1;
+}
+
+service Factory1Service {
+  // Dummy method for this dummy service.
+  rpc Factory1Method(Factory1MethodRequest) returns (Factory1MethodResponse) {
+  }
+}

+ 1 - 3
python/google/protobuf/internal/message_factory_test.py

@@ -142,10 +142,8 @@ class MessageFactoryTest(unittest.TestCase):
       self.assertEqual('test2', msg1.Extensions[ext2])
       self.assertEqual('test2', msg1.Extensions[ext2])
       self.assertEqual(None,
       self.assertEqual(None,
                        msg1.Extensions._FindExtensionByNumber(12321))
                        msg1.Extensions._FindExtensionByNumber(12321))
+      self.assertRaises(TypeError, len, msg1.Extensions)
       if api_implementation.Type() == 'cpp':
       if api_implementation.Type() == 'cpp':
-        # TODO(jieluo): Fix len to return the correct value.
-        # self.assertEqual(2, len(msg1.Extensions))
-        self.assertEqual(len(msg1.Extensions), len(msg1.Extensions))
         self.assertRaises(TypeError,
         self.assertRaises(TypeError,
                           msg1.Extensions._FindExtensionByName, 0)
                           msg1.Extensions._FindExtensionByName, 0)
         self.assertRaises(TypeError,
         self.assertRaises(TypeError,

+ 244 - 18
python/google/protobuf/internal/message_test.py

@@ -1,4 +1,5 @@
 #! /usr/bin/env python
 #! /usr/bin/env python
+# -*- coding: utf-8 -*-
 #
 #
 # Protocol Buffers - Google's data interchange format
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -49,6 +50,7 @@ import copy
 import math
 import math
 import operator
 import operator
 import pickle
 import pickle
+import pydoc
 import six
 import six
 import sys
 import sys
 import warnings
 import warnings
@@ -72,6 +74,7 @@ from google.protobuf import message_factory
 from google.protobuf import text_format
 from google.protobuf import text_format
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import encoder
 from google.protobuf.internal import encoder
+from google.protobuf.internal import more_extensions_pb2
 from google.protobuf.internal import packed_field_test_pb2
 from google.protobuf.internal import packed_field_test_pb2
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf.internal import testing_refleaks
 from google.protobuf.internal import testing_refleaks
@@ -415,6 +418,37 @@ class MessageTest(BaseTestCase):
     empty.ParseFromString(populated.SerializeToString())
     empty.ParseFromString(populated.SerializeToString())
     self.assertEqual(str(empty), '')
     self.assertEqual(str(empty), '')
 
 
+  def testMergeFromRepeatedField(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.append(1)
+    msg.repeated_int32.append(3)
+    msg.repeated_nested_message.add(bb=1)
+    msg.repeated_nested_message.add(bb=2)
+    other_msg = message_module.TestAllTypes()
+    other_msg.repeated_nested_message.add(bb=3)
+    other_msg.repeated_nested_message.add(bb=4)
+    other_msg.repeated_int32.append(5)
+    other_msg.repeated_int32.append(7)
+
+    msg.repeated_int32.MergeFrom(other_msg.repeated_int32)
+    self.assertEqual(4, len(msg.repeated_int32))
+
+    msg.repeated_nested_message.MergeFrom(other_msg.repeated_nested_message)
+    self.assertEqual([1, 2, 3, 4],
+                     [m.bb for m in msg.repeated_nested_message])
+
+  def testAddWrongRepeatedNestedField(self, message_module):
+    msg = message_module.TestAllTypes()
+    try:
+      msg.repeated_nested_message.add('wrong')
+    except TypeError:
+      pass
+    try:
+      msg.repeated_nested_message.add(value_field='wrong')
+    except ValueError:
+      pass
+    self.assertEqual(len(msg.repeated_nested_message), 0)
+
   def testRepeatedNestedFieldIteration(self, message_module):
   def testRepeatedNestedFieldIteration(self, message_module):
     msg = message_module.TestAllTypes()
     msg = message_module.TestAllTypes()
     msg.repeated_nested_message.add(bb=1)
     msg.repeated_nested_message.add(bb=1)
@@ -645,6 +679,82 @@ class MessageTest(BaseTestCase):
     m.payload.repeated_int32.extend([])
     m.payload.repeated_int32.extend([])
     self.assertTrue(m.HasField('payload'))
     self.assertTrue(m.HasField('payload'))
 
 
+  def testMergeFrom(self, message_module):
+    m1 = message_module.TestAllTypes()
+    m2 = message_module.TestAllTypes()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(0, m1.optional_nested_message.bb)
+    m2.optional_nested_message.bb = 1
+    # Make sure cmessage pointing to a mutable message after merge instead of
+    # the lazily created message.
+    m1.MergeFrom(m2)
+    self.assertEqual(1, m1.optional_nested_message.bb)
+
+    # Test more nested sub message.
+    msg1 = message_module.NestedTestAllTypes()
+    msg2 = message_module.NestedTestAllTypes()
+    self.assertEqual(0, msg1.child.payload.optional_nested_message.bb)
+    msg2.child.payload.optional_nested_message.bb = 1
+    msg1.MergeFrom(msg2)
+    self.assertEqual(1, msg1.child.payload.optional_nested_message.bb)
+
+    # Test repeated field.
+    self.assertEqual(msg1.payload.repeated_nested_message,
+                     msg1.payload.repeated_nested_message)
+    msg2.payload.repeated_nested_message.add().bb = 1
+    msg1.MergeFrom(msg2)
+    self.assertEqual(1, len(msg1.payload.repeated_nested_message))
+    self.assertEqual(1, msg1.payload.repeated_nested_message[0].bb)
+
+  def testMergeFromString(self, message_module):
+    m1 = message_module.TestAllTypes()
+    m2 = message_module.TestAllTypes()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(0, m1.optional_nested_message.bb)
+    m2.optional_nested_message.bb = 1
+    # Make sure cmessage pointing to a mutable message after merge instead of
+    # the lazily created message.
+    m1.MergeFromString(m2.SerializeToString())
+    self.assertEqual(1, m1.optional_nested_message.bb)
+
+  @unittest.skipIf(six.PY2, 'memoryview objects are not supported on py2')
+  def testMergeFromStringUsingMemoryViewWorksInPy3(self, message_module):
+    m2 = message_module.TestAllTypes()
+    m2.optional_string = 'scalar string'
+    m2.repeated_string.append('repeated string')
+    m2.optional_bytes = b'scalar bytes'
+    m2.repeated_bytes.append(b'repeated bytes')
+
+    serialized = m2.SerializeToString()
+    memview = memoryview(serialized)
+    m1 = message_module.TestAllTypes.FromString(memview)
+
+    self.assertEqual(m1.optional_bytes, b'scalar bytes')
+    self.assertEqual(m1.repeated_bytes, [b'repeated bytes'])
+    self.assertEqual(m1.optional_string, 'scalar string')
+    self.assertEqual(m1.repeated_string, ['repeated string'])
+    # Make sure that the memoryview was correctly converted to bytes, and
+    # that a sub-sliced memoryview is not being used.
+    self.assertIsInstance(m1.optional_bytes, bytes)
+    self.assertIsInstance(m1.repeated_bytes[0], bytes)
+    self.assertIsInstance(m1.optional_string, six.text_type)
+    self.assertIsInstance(m1.repeated_string[0], six.text_type)
+
+  @unittest.skipIf(six.PY3, 'memoryview is supported by py3')
+  def testMergeFromStringUsingMemoryViewIsPy2Error(self, message_module):
+    memview = memoryview(b'')
+    with self.assertRaises(TypeError):
+      message_module.TestAllTypes.FromString(memview)
+
+  def testMergeFromEmpty(self, message_module):
+    m1 = message_module.TestAllTypes()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(0, m1.optional_nested_message.bb)
+    self.assertFalse(m1.HasField('optional_nested_message'))
+    # Make sure the sub message is still immutable after merge from empty.
+    m1.MergeFromString(b'')  # field state should not change
+    self.assertFalse(m1.HasField('optional_nested_message'))
+
   def ensureNestedMessageExists(self, msg, attribute):
   def ensureNestedMessageExists(self, msg, attribute):
     """Make sure that a nested message object exists.
     """Make sure that a nested message object exists.
 
 
@@ -1067,14 +1177,8 @@ class MessageTest(BaseTestCase):
     with self.assertRaises(AttributeError):
     with self.assertRaises(AttributeError):
       m.repeated_int32 = []
       m.repeated_int32 = []
     m.repeated_int32.append(1)
     m.repeated_int32.append(1)
-    if api_implementation.Type() == 'cpp':
-      # For test coverage: cpp has a different path if composite
-      # field is in cache
-      with self.assertRaises(TypeError):
-        m.repeated_int32 = []
-    else:
-      with self.assertRaises(AttributeError):
-        m.repeated_int32 = []
+    with self.assertRaises(AttributeError):
+      m.repeated_int32 = []
 
 
 
 
 # Class to test proto2-only features (required, extensions, etc.)
 # Class to test proto2-only features (required, extensions, etc.)
@@ -1169,6 +1273,21 @@ class Proto2Test(BaseTestCase):
     msg = unittest_pb2.TestAllTypes()
     msg = unittest_pb2.TestAllTypes()
     self.assertRaises(AttributeError, getattr, msg, 'Extensions')
     self.assertRaises(AttributeError, getattr, msg, 'Extensions')
 
 
+  def testMergeFromExtensions(self):
+    msg1 = more_extensions_pb2.TopLevelMessage()
+    msg2 = more_extensions_pb2.TopLevelMessage()
+    # Cpp extension will lazily create a sub message which is immutable.
+    self.assertEqual(0, msg1.submessage.Extensions[
+        more_extensions_pb2.optional_int_extension])
+    self.assertFalse(msg1.HasField('submessage'))
+    msg2.submessage.Extensions[
+        more_extensions_pb2.optional_int_extension] = 123
+    # Make sure cmessage and extensions pointing to a mutable message
+    # after merge instead of the lazily created message.
+    msg1.MergeFrom(msg2)
+    self.assertEqual(123, msg1.submessage.Extensions[
+        more_extensions_pb2.optional_int_extension])
+
   def testGoldenExtensions(self):
   def testGoldenExtensions(self):
     golden_data = test_util.GoldenFileData('golden_message')
     golden_data = test_util.GoldenFileData('golden_message')
     golden_message = unittest_pb2.TestAllExtensions()
     golden_message = unittest_pb2.TestAllExtensions()
@@ -1316,6 +1435,15 @@ class Proto2Test(BaseTestCase):
       unittest_pb2.TestAllTypes(repeated_nested_enum='FOO')
       unittest_pb2.TestAllTypes(repeated_nested_enum='FOO')
 
 
 
 
+  def test_documentation(self):
+    # Also used by the interactive help() function.
+    doc = pydoc.html.document(unittest_pb2.TestAllTypes, 'message')
+    self.assertIn('class TestAllTypes', doc)
+    self.assertIn('SerializePartialToString', doc)
+    self.assertIn('repeated_float', doc)
+    base = unittest_pb2.TestAllTypes.__bases__[0]
+    self.assertRaises(AttributeError, getattr, base, '_extensions_by_name')
+
 
 
 # Class to test proto3-only features/behavior (updated field presence & enums)
 # Class to test proto3-only features/behavior (updated field presence & enums)
 class Proto3Test(BaseTestCase):
 class Proto3Test(BaseTestCase):
@@ -1539,10 +1667,8 @@ class Proto3Test(BaseTestCase):
     self.assertEqual(True, msg2.map_bool_bool[True])
     self.assertEqual(True, msg2.map_bool_bool[True])
     self.assertEqual(2, msg2.map_int32_enum[888])
     self.assertEqual(2, msg2.map_int32_enum[888])
     self.assertEqual(456, msg2.map_int32_enum[123])
     self.assertEqual(456, msg2.map_int32_enum[123])
-    # TODO(jieluo): Add cpp extension support.
-    if api_implementation.Type() == 'python':
-      self.assertEqual('{-123: -456}',
-                       str(msg2.map_int32_int32))
+    self.assertEqual('{-123: -456}',
+                     str(msg2.map_int32_int32))
 
 
   def testMapEntryAlwaysSerialized(self):
   def testMapEntryAlwaysSerialized(self):
     msg = map_unittest_pb2.TestMap()
     msg = map_unittest_pb2.TestMap()
@@ -1603,11 +1729,10 @@ class Proto3Test(BaseTestCase):
     self.assertIn(123, msg2.map_int32_foreign_message)
     self.assertIn(123, msg2.map_int32_foreign_message)
     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))
+    msg2.map_int32_foreign_message[123].c = 1
     # TODO(jieluo): Fix text format for message map.
     # TODO(jieluo): Fix text format for message map.
-    # TODO(jieluo): Add cpp extension support.
-    if api_implementation.Type() == 'python':
-      self.assertEqual(15,
-                       len(str(msg2.map_int32_foreign_message)))
+    self.assertIn(str(msg2.map_int32_foreign_message),
+                  ('{-456: , 123: c: 1\n}', '{123: c: 1\n, -456: }'))
 
 
   def testNestedMessageMapItemDelete(self):
   def testNestedMessageMapItemDelete(self):
     msg = map_unittest_pb2.TestMap()
     msg = map_unittest_pb2.TestMap()
@@ -1721,6 +1846,15 @@ class Proto3Test(BaseTestCase):
     self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
     self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
     self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
     self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
 
 
+    # Test when cpp extension cache a map.
+    m1 = map_unittest_pb2.TestMap()
+    m2 = map_unittest_pb2.TestMap()
+    self.assertEqual(m1.map_int32_foreign_message,
+                     m1.map_int32_foreign_message)
+    m2.map_int32_foreign_message[123].c = 10
+    m1.MergeFrom(m2)
+    self.assertEqual(10, m2.map_int32_foreign_message[123].c)
+
   def testMergeFromBadType(self):
   def testMergeFromBadType(self):
     msg = map_unittest_pb2.TestMap()
     msg = map_unittest_pb2.TestMap()
     with self.assertRaisesRegexp(
     with self.assertRaisesRegexp(
@@ -1972,7 +2106,7 @@ class Proto3Test(BaseTestCase):
   def testMapValidAfterFieldCleared(self):
   def testMapValidAfterFieldCleared(self):
     # Map needs to work even if field is cleared.
     # Map needs to work even if field is cleared.
     # For the C++ implementation this tests the correctness of
     # For the C++ implementation this tests the correctness of
-    # ScalarMapContainer::Release()
+    # MapContainer::Release()
     msg = map_unittest_pb2.TestMap()
     msg = map_unittest_pb2.TestMap()
     int32_map = msg.map_int32_int32
     int32_map = msg.map_int32_int32
 
 
@@ -1988,7 +2122,7 @@ class Proto3Test(BaseTestCase):
   def testMessageMapValidAfterFieldCleared(self):
   def testMessageMapValidAfterFieldCleared(self):
     # Map needs to work even if field is cleared.
     # Map needs to work even if field is cleared.
     # For the C++ implementation this tests the correctness of
     # For the C++ implementation this tests the correctness of
-    # ScalarMapContainer::Release()
+    # MapContainer::Release()
     msg = map_unittest_pb2.TestMap()
     msg = map_unittest_pb2.TestMap()
     int32_foreign_message = msg.map_int32_foreign_message
     int32_foreign_message = msg.map_int32_foreign_message
 
 
@@ -1998,6 +2132,24 @@ class Proto3Test(BaseTestCase):
     self.assertEqual(b'', msg.SerializeToString())
     self.assertEqual(b'', msg.SerializeToString())
     self.assertTrue(2 in int32_foreign_message.keys())
     self.assertTrue(2 in int32_foreign_message.keys())
 
 
+  def testMessageMapItemValidAfterTopMessageCleared(self):
+    # Message map item needs to work even if it is cleared.
+    # For the C++ implementation this tests the correctness of
+    # MapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_all_types[2].optional_string = 'bar'
+
+    if api_implementation.Type() == 'cpp':
+      # Need to keep the map reference because of b/27942626.
+      # TODO(jieluo): Remove it.
+      unused_map = msg.map_int32_all_types  # pylint: disable=unused-variable
+    msg_value = msg.map_int32_all_types[2]
+    msg.Clear()
+
+    # Reset to trigger sync between repeated field and map in c++.
+    msg.map_int32_all_types[3].optional_string = 'foo'
+    self.assertEqual(msg_value.optional_string, 'bar')
+
   def testMapIterInvalidatedByClearField(self):
   def testMapIterInvalidatedByClearField(self):
     # Map iterator is invalidated when field is cleared.
     # Map iterator is invalidated when field is cleared.
     # But this case does need to not crash the interpreter.
     # But this case does need to not crash the interpreter.
@@ -2058,6 +2210,80 @@ class Proto3Test(BaseTestCase):
     msg.map_string_foreign_message['foo'].c = 5
     msg.map_string_foreign_message['foo'].c = 5
     self.assertEqual(0, len(msg.FindInitializationErrors()))
     self.assertEqual(0, len(msg.FindInitializationErrors()))
 
 
+  def testStrictUtf8Check(self):
+    # Test u'\ud801' is rejected at parser in both python2 and python3.
+    serialized = (b'r\x03\xed\xa0\x81')
+    msg = unittest_proto3_arena_pb2.TestAllTypes()
+    with self.assertRaises(Exception) as context:
+      msg.MergeFromString(serialized)
+    if api_implementation.Type() == 'python':
+      self.assertIn('optional_string', str(context.exception))
+    else:
+      self.assertIn('Error parsing message', str(context.exception))
+
+    # Test optional_string=u'😍' is accepted.
+    serialized = unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=u'😍').SerializeToString()
+    msg2 = unittest_proto3_arena_pb2.TestAllTypes()
+    msg2.MergeFromString(serialized)
+    self.assertEqual(msg2.optional_string, u'😍')
+
+    msg = unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=u'\ud001')
+    self.assertEqual(msg.optional_string, u'\ud001')
+
+  @unittest.skipIf(six.PY2, 'Surrogates are acceptable in python2')
+  def testSurrogatesInPython3(self):
+    # Surrogates like U+D83D is an invalid unicode character, it is
+    # supported by Python2 only because in some builds, unicode strings
+    # use 2-bytes code units. Since Python 3.3, we don't have this problem.
+    #
+    # Surrogates are utf16 code units, in a unicode string they are invalid
+    # characters even when they appear in pairs like u'\ud801\udc01'. Protobuf
+    # Python3 reject such cases at setters and parsers. Python2 accpect it
+    # to keep same features with the language itself. 'Unpaired pairs'
+    # like u'\ud801' are rejected at parsers when strict utf8 check is enabled
+    # in proto3 to keep same behavior with c extension.
+
+    # Surrogates are rejected at setters in Python3.
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(
+          optional_string=u'\ud801\udc01')
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(
+          optional_string=b'\xed\xa0\x81')
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(
+          optional_string=u'\ud801')
+    with self.assertRaises(ValueError):
+      unittest_proto3_arena_pb2.TestAllTypes(
+          optional_string=u'\ud801\ud801')
+
+  @unittest.skipIf(six.PY3, 'Surrogates are rejected at setters in Python3')
+  def testSurrogatesInPython2(self):
+    # Test optional_string=u'\ud801\udc01'.
+    # surrogate pair is acceptable in python2.
+    msg = unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=u'\ud801\udc01')
+    # TODO(jieluo): Change pure python to have same behavior with c extension.
+    # Some build in python2 consider u'\ud801\udc01' and u'\U00010401' are
+    # equal, some are not equal.
+    if api_implementation.Type() == 'python':
+      self.assertEqual(msg.optional_string, u'\ud801\udc01')
+    else:
+      self.assertEqual(msg.optional_string, u'\U00010401')
+    serialized = msg.SerializeToString()
+    msg2 = unittest_proto3_arena_pb2.TestAllTypes()
+    msg2.MergeFromString(serialized)
+    self.assertEqual(msg2.optional_string, u'\U00010401')
+
+    # Python2 does not reject surrogates at setters.
+    msg = unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=b'\xed\xa0\x81')
+    unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=u'\ud801')
+    unittest_proto3_arena_pb2.TestAllTypes(
+        optional_string=u'\ud801\ud801')
 
 
 
 
 class ValidTypeNamesTest(BaseTestCase):
 class ValidTypeNamesTest(BaseTestCase):

+ 30 - 0
python/google/protobuf/internal/no_package.proto

@@ -1,3 +1,33 @@
+// 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";
 syntax = "proto2";
 
 
 enum NoPackageEnum {
 enum NoPackageEnum {

+ 128 - 22
python/google/protobuf/internal/python_message.py

@@ -56,6 +56,7 @@ import sys
 import weakref
 import weakref
 
 
 import six
 import six
+from six.moves import range
 
 
 # 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 api_implementation
@@ -124,6 +125,21 @@ class GeneratedProtocolMessageType(type):
       Newly-allocated class.
       Newly-allocated class.
     """
     """
     descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
     descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+
+    # If a concrete class already exists for this descriptor, don't try to
+    # create another.  Doing so will break any messages that already exist with
+    # the existing class.
+    #
+    # The C++ implementation appears to have its own internal `PyMessageFactory`
+    # to achieve similar results.
+    #
+    # This most commonly happens in `text_format.py` when using descriptors from
+    # a custom pool; it calls symbol_database.Global().getPrototype() on a
+    # descriptor which already has an existing concrete class.
+    new_class = getattr(descriptor, '_concrete_class', None)
+    if new_class:
+      return new_class
+
     if descriptor.full_name in well_known_types.WKTBASES:
     if descriptor.full_name in well_known_types.WKTBASES:
       bases += (well_known_types.WKTBASES[descriptor.full_name],)
       bases += (well_known_types.WKTBASES[descriptor.full_name],)
     _AddClassAttributesForNestedExtensions(descriptor, dictionary)
     _AddClassAttributesForNestedExtensions(descriptor, dictionary)
@@ -151,6 +167,16 @@ class GeneratedProtocolMessageType(type):
         type.
         type.
     """
     """
     descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
     descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+
+    # If this is an _existing_ class looked up via `_concrete_class` in the
+    # __new__ method above, then we don't need to re-initialize anything.
+    existing_class = getattr(descriptor, '_concrete_class', None)
+    if existing_class:
+      assert existing_class is cls, (
+          'Duplicate `GeneratedProtocolMessageType` created for descriptor %r'
+          % (descriptor.full_name))
+      return
+
     cls._decoders_by_tag = {}
     cls._decoders_by_tag = {}
     if (descriptor.has_options and
     if (descriptor.has_options and
         descriptor.GetOptions().message_set_wire_format):
         descriptor.GetOptions().message_set_wire_format):
@@ -245,6 +271,7 @@ def _AddSlots(message_descriptor, dictionary):
                              '_cached_byte_size_dirty',
                              '_cached_byte_size_dirty',
                              '_fields',
                              '_fields',
                              '_unknown_fields',
                              '_unknown_fields',
+                             '_unknown_field_set',
                              '_is_present_in_parent',
                              '_is_present_in_parent',
                              '_listener',
                              '_listener',
                              '_listener_for_children',
                              '_listener_for_children',
@@ -271,6 +298,13 @@ def _IsMessageMapField(field):
   return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
   return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
 
 
 
 
+def _IsStrictUtf8Check(field):
+  if field.containing_type.syntax != 'proto3':
+    return False
+  enforce_utf8 = True
+  return enforce_utf8
+
+
 def _AttachFieldHelpers(cls, field_descriptor):
 def _AttachFieldHelpers(cls, field_descriptor):
   is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED)
   is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED)
   is_packable = (is_repeated and
   is_packable = (is_repeated and
@@ -322,10 +356,16 @@ def _AttachFieldHelpers(cls, field_descriptor):
       field_decoder = decoder.MapDecoder(
       field_decoder = decoder.MapDecoder(
           field_descriptor, _GetInitializeDefaultForMap(field_descriptor),
           field_descriptor, _GetInitializeDefaultForMap(field_descriptor),
           is_message_map)
           is_message_map)
+    elif decode_type == _FieldDescriptor.TYPE_STRING:
+      is_strict_utf8_check = _IsStrictUtf8Check(field_descriptor)
+      field_decoder = decoder.StringDecoder(
+          field_descriptor.number, is_repeated, is_packed,
+          field_descriptor, field_descriptor._default_constructor,
+          is_strict_utf8_check)
     else:
     else:
       field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
       field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
-              field_descriptor.number, is_repeated, is_packed,
-              field_descriptor, field_descriptor._default_constructor)
+          field_descriptor.number, is_repeated, is_packed,
+          field_descriptor, field_descriptor._default_constructor)
 
 
     cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor)
     cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor)
 
 
@@ -422,6 +462,9 @@ def _DefaultValueConstructorForField(field):
     # _concrete_class may not yet be initialized.
     # _concrete_class may not yet be initialized.
     message_type = field.message_type
     message_type = field.message_type
     def MakeSubMessageDefault(message):
     def MakeSubMessageDefault(message):
+      assert getattr(message_type, '_concrete_class', None), (
+          'Uninitialized concrete class found for field %r (message type %r)'
+          % (field.full_name, message_type.full_name))
       result = message_type._concrete_class()
       result = message_type._concrete_class()
       result._SetListener(
       result._SetListener(
           _OneofListener(message, field)
           _OneofListener(message, field)
@@ -477,6 +520,9 @@ def _AddInitMethod(message_descriptor, cls):
     # _unknown_fields is () when empty for efficiency, and will be turned into
     # _unknown_fields is () when empty for efficiency, and will be turned into
     # a list if fields are added.
     # a list if fields are added.
     self._unknown_fields = ()
     self._unknown_fields = ()
+    # _unknown_field_set is None when empty for efficiency, and will be
+    # turned into UnknownFieldSet struct if fields are added.
+    self._unknown_field_set = None      # pylint: disable=protected-access
     self._is_present_in_parent = False
     self._is_present_in_parent = False
     self._listener = message_listener_mod.NullMessageListener()
     self._listener = message_listener_mod.NullMessageListener()
     self._listener_for_children = _Listener(self)
     self._listener_for_children = _Listener(self)
@@ -584,6 +630,14 @@ def _AddPropertiesForField(field, cls):
     _AddPropertiesForNonRepeatedScalarField(field, cls)
     _AddPropertiesForNonRepeatedScalarField(field, cls)
 
 
 
 
+class _FieldProperty(property):
+  __slots__ = ('DESCRIPTOR',)
+
+  def __init__(self, descriptor, getter, setter, doc):
+    property.__init__(self, getter, setter, doc=doc)
+    self.DESCRIPTOR = descriptor
+
+
 def _AddPropertiesForRepeatedField(field, cls):
 def _AddPropertiesForRepeatedField(field, cls):
   """Adds a public property for a "repeated" protocol message field.  Clients
   """Adds a public property for a "repeated" protocol message field.  Clients
   can use this property to get the value of the field, which will be either a
   can use this property to get the value of the field, which will be either a
@@ -625,7 +679,7 @@ def _AddPropertiesForRepeatedField(field, cls):
                          '"%s" in protocol message object.' % proto_field_name)
                          '"%s" in protocol message object.' % proto_field_name)
 
 
   doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
   doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
-  setattr(cls, property_name, property(getter, setter, doc=doc))
+  setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc))
 
 
 
 
 def _AddPropertiesForNonRepeatedScalarField(field, cls):
 def _AddPropertiesForNonRepeatedScalarField(field, cls):
@@ -681,7 +735,7 @@ def _AddPropertiesForNonRepeatedScalarField(field, cls):
 
 
   # Add a property to encapsulate the getter/setter.
   # Add a property to encapsulate the getter/setter.
   doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
   doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
-  setattr(cls, property_name, property(getter, setter, doc=doc))
+  setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc))
 
 
 
 
 def _AddPropertiesForNonRepeatedCompositeField(field, cls):
 def _AddPropertiesForNonRepeatedCompositeField(field, cls):
@@ -725,7 +779,7 @@ def _AddPropertiesForNonRepeatedCompositeField(field, cls):
 
 
   # Add a property to encapsulate the getter.
   # Add a property to encapsulate the getter.
   doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
   doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
-  setattr(cls, property_name, property(getter, setter, doc=doc))
+  setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc))
 
 
 
 
 def _AddPropertiesForExtensions(descriptor, cls):
 def _AddPropertiesForExtensions(descriptor, cls):
@@ -949,13 +1003,8 @@ def _AddEqualsMethod(message_descriptor, cls):
     if not self.ListFields() == other.ListFields():
     if not self.ListFields() == other.ListFields():
       return False
       return False
 
 
-    # Sort unknown fields because their order shouldn't affect equality test.
-    unknown_fields = list(self._unknown_fields)
-    unknown_fields.sort()
-    other_unknown_fields = list(other._unknown_fields)
-    other_unknown_fields.sort()
-
-    return unknown_fields == other_unknown_fields
+    # pylint: disable=protected-access
+    return self._unknown_field_set == other._unknown_field_set
 
 
   cls.__eq__ = __eq__
   cls.__eq__ = __eq__
 
 
@@ -1078,6 +1127,13 @@ def _AddSerializePartialToStringMethod(message_descriptor, cls):
 def _AddMergeFromStringMethod(message_descriptor, cls):
 def _AddMergeFromStringMethod(message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
   """Helper for _AddMessageMethods()."""
   def MergeFromString(self, serialized):
   def MergeFromString(self, serialized):
+    if isinstance(serialized, memoryview) and six.PY2:
+      raise TypeError(
+          'memoryview not supported in Python 2 with the pure Python proto '
+          'implementation: this is to maintain compatibility with the C++ '
+          'implementation')
+
+    serialized = memoryview(serialized)
     length = len(serialized)
     length = len(serialized)
     try:
     try:
       if self._InternalParse(serialized, 0, length) != length:
       if self._InternalParse(serialized, 0, length) != length:
@@ -1095,26 +1151,54 @@ def _AddMergeFromStringMethod(message_descriptor, cls):
   local_ReadTag = decoder.ReadTag
   local_ReadTag = decoder.ReadTag
   local_SkipField = decoder.SkipField
   local_SkipField = decoder.SkipField
   decoders_by_tag = cls._decoders_by_tag
   decoders_by_tag = cls._decoders_by_tag
-  is_proto3 = message_descriptor.syntax == "proto3"
 
 
   def InternalParse(self, buffer, pos, end):
   def InternalParse(self, buffer, pos, end):
+    """Create a message from serialized bytes.
+
+    Args:
+      self: Message, instance of the proto message object.
+      buffer: memoryview of the serialized data.
+      pos: int, position to start in the serialized data.
+      end: int, end position of the serialized data.
+
+    Returns:
+      Message object.
+    """
+    # Guard against internal misuse, since this function is called internally
+    # quite extensively, and its easy to accidentally pass bytes.
+    assert isinstance(buffer, memoryview)
     self._Modified()
     self._Modified()
     field_dict = self._fields
     field_dict = self._fields
-    unknown_field_list = self._unknown_fields
+    # pylint: disable=protected-access
+    unknown_field_set = self._unknown_field_set
     while pos != end:
     while pos != end:
       (tag_bytes, new_pos) = local_ReadTag(buffer, pos)
       (tag_bytes, new_pos) = local_ReadTag(buffer, pos)
       field_decoder, field_desc = decoders_by_tag.get(tag_bytes, (None, None))
       field_decoder, field_desc = decoders_by_tag.get(tag_bytes, (None, None))
       if field_decoder is None:
       if field_decoder is None:
-        value_start_pos = new_pos
-        new_pos = local_SkipField(buffer, new_pos, end, tag_bytes)
+        if not self._unknown_fields:   # pylint: disable=protected-access
+          self._unknown_fields = []    # pylint: disable=protected-access
+        if unknown_field_set is None:
+          # pylint: disable=protected-access
+          self._unknown_field_set = containers.UnknownFieldSet()
+          # pylint: disable=protected-access
+          unknown_field_set = self._unknown_field_set
+        # pylint: disable=protected-access
+        (tag, _) = decoder._DecodeVarint(tag_bytes, 0)
+        field_number, wire_type = wire_format.UnpackTag(tag)
+        # TODO(jieluo): remove old_pos.
+        old_pos = new_pos
+        (data, new_pos) = decoder._DecodeUnknownField(
+            buffer, new_pos, wire_type)  # pylint: disable=protected-access
         if new_pos == -1:
         if new_pos == -1:
           return pos
           return pos
-        if (not is_proto3 or
-            api_implementation.GetPythonProto3PreserveUnknownsDefault()):
-          if not unknown_field_list:
-            unknown_field_list = self._unknown_fields = []
-          unknown_field_list.append(
-              (tag_bytes, buffer[value_start_pos:new_pos]))
+        # pylint: disable=protected-access
+        unknown_field_set._add(field_number, wire_type, data)
+        # TODO(jieluo): remove _unknown_fields.
+        new_pos = local_SkipField(buffer, old_pos, end, tag_bytes)
+        if new_pos == -1:
+          return pos
+        self._unknown_fields.append(
+            (tag_bytes, buffer[old_pos:new_pos].tobytes()))
         pos = new_pos
         pos = new_pos
       else:
       else:
         pos = field_decoder(buffer, new_pos, end, self, field_dict)
         pos = field_decoder(buffer, new_pos, end, self, field_dict)
@@ -1259,6 +1343,10 @@ def _AddMergeFromMethod(cls):
       if not self._unknown_fields:
       if not self._unknown_fields:
         self._unknown_fields = []
         self._unknown_fields = []
       self._unknown_fields.extend(msg._unknown_fields)
       self._unknown_fields.extend(msg._unknown_fields)
+      # pylint: disable=protected-access
+      if self._unknown_field_set is None:
+        self._unknown_field_set = containers.UnknownFieldSet()
+      self._unknown_field_set._extend(msg._unknown_field_set)
 
 
   cls.MergeFrom = MergeFrom
   cls.MergeFrom = MergeFrom
 
 
@@ -1291,12 +1379,25 @@ def _Clear(self):
   # Clear fields.
   # Clear fields.
   self._fields = {}
   self._fields = {}
   self._unknown_fields = ()
   self._unknown_fields = ()
+  # pylint: disable=protected-access
+  if self._unknown_field_set is not None:
+    self._unknown_field_set._clear()
+    self._unknown_field_set = None
+
   self._oneofs = {}
   self._oneofs = {}
   self._Modified()
   self._Modified()
 
 
 
 
+def _UnknownFields(self):
+  if self._unknown_field_set is None:  # pylint: disable=protected-access
+    # pylint: disable=protected-access
+    self._unknown_field_set = containers.UnknownFieldSet()
+  return self._unknown_field_set    # pylint: disable=protected-access
+
+
 def _DiscardUnknownFields(self):
 def _DiscardUnknownFields(self):
   self._unknown_fields = []
   self._unknown_fields = []
+  self._unknown_field_set = None      # pylint: disable=protected-access
   for field, value in self.ListFields():
   for field, value in self.ListFields():
     if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
     if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
       if field.label == _FieldDescriptor.LABEL_REPEATED:
       if field.label == _FieldDescriptor.LABEL_REPEATED:
@@ -1335,6 +1436,7 @@ def _AddMessageMethods(message_descriptor, cls):
   _AddReduceMethod(cls)
   _AddReduceMethod(cls)
   # Adds methods which do not depend on cls.
   # Adds methods which do not depend on cls.
   cls.Clear = _Clear
   cls.Clear = _Clear
+  cls.UnknownFields = _UnknownFields
   cls.DiscardUnknownFields = _DiscardUnknownFields
   cls.DiscardUnknownFields = _DiscardUnknownFields
   cls._SetListener = _SetListener
   cls._SetListener = _SetListener
 
 
@@ -1471,6 +1573,10 @@ class _ExtensionDict(object):
     if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
     if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
       result = extension_handle._default_constructor(self._extended_message)
       result = extension_handle._default_constructor(self._extended_message)
     elif extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
     elif extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
+      assert getattr(extension_handle.message_type, '_concrete_class', None), (
+          'Uninitialized concrete class found for field %r (message type %r)'
+          % (extension_handle.full_name,
+             extension_handle.message_type.full_name))
       result = extension_handle.message_type._concrete_class()
       result = extension_handle.message_type._concrete_class()
       try:
       try:
         result._SetListener(self._extended_message._listener_for_children)
         result._SetListener(self._extended_message._listener_for_children)

+ 43 - 10
python/google/protobuf/internal/reflection_test.py

@@ -64,6 +64,10 @@ from google.protobuf.internal import testing_refleaks
 from google.protobuf.internal import decoder
 from google.protobuf.internal import decoder
 
 
 
 
+if six.PY3:
+  long = int  # pylint: disable=redefined-builtin,invalid-name
+
+
 BaseTestCase = testing_refleaks.BaseTestCase
 BaseTestCase = testing_refleaks.BaseTestCase
 
 
 
 
@@ -647,10 +651,7 @@ class ReflectionTest(BaseTestCase):
     TestGetAndDeserialize('optional_int32', 1, int)
     TestGetAndDeserialize('optional_int32', 1, int)
     TestGetAndDeserialize('optional_int32', 1 << 30, int)
     TestGetAndDeserialize('optional_int32', 1 << 30, int)
     TestGetAndDeserialize('optional_uint32', 1 << 30, int)
     TestGetAndDeserialize('optional_uint32', 1 << 30, int)
-    try:
-      integer_64 = long
-    except NameError:  # Python3
-      integer_64 = int
+    integer_64 = long
     if struct.calcsize('L') == 4:
     if struct.calcsize('L') == 4:
       # Python only has signed ints, so 32-bit python can't fit an uint32
       # Python only has signed ints, so 32-bit python can't fit an uint32
       # in an int.
       # in an int.
@@ -1103,6 +1104,7 @@ class ReflectionTest(BaseTestCase):
     self.assertEqual(23, myproto_instance.foo_field)
     self.assertEqual(23, myproto_instance.foo_field)
     self.assertTrue(myproto_instance.HasField('foo_field'))
     self.assertTrue(myproto_instance.HasField('foo_field'))
 
 
+  @testing_refleaks.SkipReferenceLeakChecker('MakeDescriptor is not repeatable')
   def testDescriptorProtoSupport(self):
   def testDescriptorProtoSupport(self):
     # Hand written descriptors/reflection are only supported by the pure-Python
     # Hand written descriptors/reflection are only supported by the pure-Python
     # implementation of the API.
     # implementation of the API.
@@ -1141,7 +1143,8 @@ class ReflectionTest(BaseTestCase):
     self.assertTrue('price' in desc.fields_by_name)
     self.assertTrue('price' in desc.fields_by_name)
     self.assertTrue('owners' in desc.fields_by_name)
     self.assertTrue('owners' in desc.fields_by_name)
 
 
-    class CarMessage(six.with_metaclass(reflection.GeneratedProtocolMessageType, message.Message)):
+    class CarMessage(six.with_metaclass(reflection.GeneratedProtocolMessageType,
+                                        message.Message)):
       DESCRIPTOR = desc
       DESCRIPTOR = desc
 
 
     prius = CarMessage()
     prius = CarMessage()
@@ -2435,7 +2438,7 @@ class SerializationTest(BaseTestCase):
 
 
     first_proto = unittest_pb2.TestAllTypes()
     first_proto = unittest_pb2.TestAllTypes()
     test_util.SetAllFields(first_proto)
     test_util.SetAllFields(first_proto)
-    serialized = first_proto.SerializeToString()
+    serialized = memoryview(first_proto.SerializeToString())
 
 
     for truncation_point in range(len(serialized) + 1):
     for truncation_point in range(len(serialized) + 1):
       try:
       try:
@@ -2857,6 +2860,38 @@ class SerializationTest(BaseTestCase):
     self.assertEqual(unittest_pb2.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER,
     self.assertEqual(unittest_pb2.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER,
       51)
       51)
 
 
+  def testFieldProperties(self):
+    cls = unittest_pb2.TestAllTypes
+    self.assertIs(cls.optional_int32.DESCRIPTOR,
+                  cls.DESCRIPTOR.fields_by_name['optional_int32'])
+    self.assertEqual(cls.OPTIONAL_INT32_FIELD_NUMBER,
+                     cls.optional_int32.DESCRIPTOR.number)
+    self.assertIs(cls.optional_nested_message.DESCRIPTOR,
+                  cls.DESCRIPTOR.fields_by_name['optional_nested_message'])
+    self.assertEqual(cls.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER,
+                     cls.optional_nested_message.DESCRIPTOR.number)
+    self.assertIs(cls.repeated_int32.DESCRIPTOR,
+                  cls.DESCRIPTOR.fields_by_name['repeated_int32'])
+    self.assertEqual(cls.REPEATED_INT32_FIELD_NUMBER,
+                     cls.repeated_int32.DESCRIPTOR.number)
+
+  def testFieldDataDescriptor(self):
+    msg = unittest_pb2.TestAllTypes()
+    msg.optional_int32 = 42
+    self.assertEqual(unittest_pb2.TestAllTypes.optional_int32.__get__(msg), 42)
+    unittest_pb2.TestAllTypes.optional_int32.__set__(msg, 25)
+    self.assertEqual(msg.optional_int32, 25)
+    with self.assertRaises(AttributeError):
+      del msg.optional_int32
+    try:
+      unittest_pb2.ForeignMessage.c.__get__(msg)
+    except TypeError:
+      pass  # The cpp implementation cannot mix fields from other messages.
+            # This test exercises a specific check that avoids a crash.
+    else:
+      pass  # The python implementation allows fields from other messages.
+            # This is useless, but works.
+
   def testInitKwargs(self):
   def testInitKwargs(self):
     proto = unittest_pb2.TestAllTypes(
     proto = unittest_pb2.TestAllTypes(
         optional_int32=1,
         optional_int32=1,
@@ -2963,6 +2998,7 @@ class ClassAPITest(BaseTestCase):
   @unittest.skipIf(
   @unittest.skipIf(
       api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
       api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
       'C++ implementation requires a call to MakeDescriptor()')
       'C++ implementation requires a call to MakeDescriptor()')
+  @testing_refleaks.SkipReferenceLeakChecker('MakeClass is not repeatable')
   def testMakeClassWithNestedDescriptor(self):
   def testMakeClassWithNestedDescriptor(self):
     leaf_desc = descriptor.Descriptor('leaf', 'package.parent.child.leaf', '',
     leaf_desc = descriptor.Descriptor('leaf', 'package.parent.child.leaf', '',
                                       containing_type=None, fields=[],
                                       containing_type=None, fields=[],
@@ -2980,10 +3016,7 @@ class ClassAPITest(BaseTestCase):
                                         containing_type=None, fields=[],
                                         containing_type=None, fields=[],
                                         nested_types=[child_desc, sibling_desc],
                                         nested_types=[child_desc, sibling_desc],
                                         enum_types=[], extensions=[])
                                         enum_types=[], extensions=[])
-    message_class = reflection.MakeClass(parent_desc)
-    self.assertIn('child', message_class.__dict__)
-    self.assertIn('sibling', message_class.__dict__)
-    self.assertIn('leaf', message_class.child.__dict__)
+    reflection.MakeClass(parent_desc)
 
 
   def _GetSerializedFileDescriptor(self, name):
   def _GetSerializedFileDescriptor(self, name):
     """Get a serialized representation of a test FileDescriptorProto.
     """Get a serialized representation of a test FileDescriptorProto.

+ 256 - 42
python/google/protobuf/internal/text_format_test.py

@@ -33,20 +33,19 @@
 
 
 """Test for google.protobuf.text_format."""
 """Test for google.protobuf.text_format."""
 
 
-__author__ = 'kenton@google.com (Kenton Varda)'
-
-
+import io
 import math
 import math
 import re
 import re
-import six
 import string
 import string
+import textwrap
 
 
+import six
+
+# pylint: disable=g-import-not-at-top
 try:
 try:
-  import unittest2 as unittest  # PY26, pylint: disable=g-import-not-at-top
+  import unittest2 as unittest  # PY26
 except ImportError:
 except ImportError:
-  import unittest  # pylint: disable=g-import-not-at-top
-
-from google.protobuf.internal import _parameterized
+  import unittest
 
 
 from google.protobuf import any_pb2
 from google.protobuf import any_pb2
 from google.protobuf import any_test_pb2
 from google.protobuf import any_test_pb2
@@ -54,12 +53,13 @@ from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf import unittest_proto3_arena_pb2
-from google.protobuf.internal import api_implementation
 from google.protobuf.internal import any_test_pb2 as test_extend_any
 from google.protobuf.internal import any_test_pb2 as test_extend_any
 from google.protobuf.internal import message_set_extensions_pb2
 from google.protobuf.internal import message_set_extensions_pb2
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf import descriptor_pool
 from google.protobuf import descriptor_pool
 from google.protobuf import text_format
 from google.protobuf import text_format
+from google.protobuf.internal import _parameterized
+# pylint: enable=g-import-not-at-top
 
 
 
 
 # Low-level nuts-n-bolts tests.
 # Low-level nuts-n-bolts tests.
@@ -100,8 +100,8 @@ class TextFormatBase(unittest.TestCase):
     return text
     return text
 
 
 
 
-@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2))
-class TextFormatTest(TextFormatBase):
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatMessageToStringTests(TextFormatBase):
 
 
   def testPrintExotic(self, message_module):
   def testPrintExotic(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
@@ -154,6 +154,40 @@ class TextFormatTest(TextFormatBase):
         'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 '
         'repeated_int32: 1 repeated_int32: 1 repeated_int32: 3 '
         'repeated_string: "Google" repeated_string: "Zurich"')
         'repeated_string: "Google" repeated_string: "Zurich"')
 
 
+  def VerifyPrintShortFormatRepeatedFields(self, message_module, as_one_line):
+    message = message_module.TestAllTypes()
+    message.repeated_int32.append(1)
+    message.repeated_string.append('Google')
+    message.repeated_string.append('Hello,World')
+    message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_FOO)
+    message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAR)
+    message.repeated_foreign_enum.append(unittest_pb2.FOREIGN_BAZ)
+    message.optional_nested_message.bb = 3
+    for i in (21, 32):
+      msg = message.repeated_nested_message.add()
+      msg.bb = i
+    expected_ascii = (
+        'optional_nested_message {\n  bb: 3\n}\n'
+        'repeated_int32: [1]\n'
+        'repeated_string: "Google"\n'
+        'repeated_string: "Hello,World"\n'
+        'repeated_nested_message {\n  bb: 21\n}\n'
+        'repeated_nested_message {\n  bb: 32\n}\n'
+        'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n')
+    if as_one_line:
+      expected_ascii = expected_ascii.replace('\n ', '').replace('\n', '')
+    actual_ascii = text_format.MessageToString(
+        message, use_short_repeated_primitives=True,
+        as_one_line=as_one_line)
+    self.CompareToGoldenText(actual_ascii, expected_ascii)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(actual_ascii, parsed_message)
+    self.assertEqual(parsed_message, message)
+
+  def tesPrintShortFormatRepeatedFields(self, message_module, as_one_line):
+    self.VerifyPrintShortFormatRepeatedFields(message_module, False)
+    self.VerifyPrintShortFormatRepeatedFields(message_module, True)
+
   def testPrintNestedNewLineInStringAsOneLine(self, message_module):
   def testPrintNestedNewLineInStringAsOneLine(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
     message.optional_string = 'a\nnew\nline'
     message.optional_string = 'a\nnew\nline'
@@ -213,13 +247,18 @@ class TextFormatTest(TextFormatBase):
 
 
   def testPrintRawUtf8String(self, message_module):
   def testPrintRawUtf8String(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
-    message.repeated_string.append(u'\u00fc\ua71f')
+    message.repeated_string.append(u'\u00fc\t\ua71f')
     text = text_format.MessageToString(message, as_utf8=True)
     text = text_format.MessageToString(message, as_utf8=True)
-    self.CompareToGoldenText(text, 'repeated_string: "\303\274\352\234\237"\n')
+    golden_unicode = u'repeated_string: "\u00fc\\t\ua71f"\n'
+    golden_text = golden_unicode if six.PY3 else golden_unicode.encode('utf-8')
+    # MessageToString always returns a native str.
+    self.CompareToGoldenText(text, golden_text)
     parsed_message = message_module.TestAllTypes()
     parsed_message = message_module.TestAllTypes()
     text_format.Parse(text, parsed_message)
     text_format.Parse(text, parsed_message)
-    self.assertEqual(message, parsed_message,
-                     '\n%s != %s' % (message, parsed_message))
+    self.assertEqual(
+        message, parsed_message, '\n%s != %s  (%s != %s)' %
+        (message, parsed_message, message.repeated_string[0],
+         parsed_message.repeated_string[0]))
 
 
   def testPrintFloatFormat(self, message_module):
   def testPrintFloatFormat(self, message_module):
     # Check that float_format argument is passed to sub-message formatting.
     # Check that float_format argument is passed to sub-message formatting.
@@ -259,6 +298,36 @@ class TextFormatTest(TextFormatBase):
     message.c = 123
     message.c = 123
     self.assertEqual('c: 123\n', str(message))
     self.assertEqual('c: 123\n', str(message))
 
 
+  def testMessageToStringUnicode(self, message_module):
+    golden_unicode = u'Á short desçription and a 🍌.'
+    golden_bytes = golden_unicode.encode('utf-8')
+    message = message_module.TestAllTypes()
+    message.optional_string = golden_unicode
+    message.optional_bytes = golden_bytes
+    text = text_format.MessageToString(message, as_utf8=True)
+    golden_message = textwrap.dedent(
+        'optional_string: "Á short desçription and a 🍌."\n'
+        'optional_bytes: '
+        r'"\303\201 short des\303\247ription and a \360\237\215\214."'
+        '\n')
+    self.CompareToGoldenText(text, golden_message)
+
+  def testMessageToStringASCII(self, message_module):
+    golden_unicode = u'Á short desçription and a 🍌.'
+    golden_bytes = golden_unicode.encode('utf-8')
+    message = message_module.TestAllTypes()
+    message.optional_string = golden_unicode
+    message.optional_bytes = golden_bytes
+    text = text_format.MessageToString(message, as_utf8=False)  # ASCII
+    golden_message = (
+        'optional_string: '
+        r'"\303\201 short des\303\247ription and a \360\237\215\214."'
+        '\n'
+        'optional_bytes: '
+        r'"\303\201 short des\303\247ription and a \360\237\215\214."'
+        '\n')
+    self.CompareToGoldenText(text, golden_message)
+
   def testPrintField(self, message_module):
   def testPrintField(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
     field = message.DESCRIPTOR.fields_by_name['optional_float']
     field = message.DESCRIPTOR.fields_by_name['optional_float']
@@ -289,6 +358,45 @@ class TextFormatTest(TextFormatBase):
     self.assertEqual('0.0', out.getvalue())
     self.assertEqual('0.0', out.getvalue())
     out.close()
     out.close()
 
 
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatMessageToTextBytesTests(TextFormatBase):
+
+  def testMessageToBytes(self, message_module):
+    message = message_module.ForeignMessage()
+    message.c = 123
+    self.assertEqual(b'c: 123\n', text_format.MessageToBytes(message))
+
+  def testRawUtf8RoundTrip(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_string.append(u'\u00fc\t\ua71f')
+    utf8_text = text_format.MessageToBytes(message, as_utf8=True)
+    golden_bytes = b'repeated_string: "\xc3\xbc\\t\xea\x9c\x9f"\n'
+    self.CompareToGoldenText(utf8_text, golden_bytes)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(utf8_text, parsed_message)
+    self.assertEqual(
+        message, parsed_message, '\n%s != %s  (%s != %s)' %
+        (message, parsed_message, message.repeated_string[0],
+         parsed_message.repeated_string[0]))
+
+  def testEscapedUtf8ASCIIRoundTrip(self, message_module):
+    message = message_module.TestAllTypes()
+    message.repeated_string.append(u'\u00fc\t\ua71f')
+    ascii_text = text_format.MessageToBytes(message)  # as_utf8=False default
+    golden_bytes = b'repeated_string: "\\303\\274\\t\\352\\234\\237"\n'
+    self.CompareToGoldenText(ascii_text, golden_bytes)
+    parsed_message = message_module.TestAllTypes()
+    text_format.Parse(ascii_text, parsed_message)
+    self.assertEqual(
+        message, parsed_message, '\n%s != %s  (%s != %s)' %
+        (message, parsed_message, message.repeated_string[0],
+         parsed_message.repeated_string[0]))
+
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatParserTests(TextFormatBase):
+
   def testParseAllFields(self, message_module):
   def testParseAllFields(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
     test_util.SetAllFields(message)
     test_util.SetAllFields(message)
@@ -318,14 +426,14 @@ class TextFormatTest(TextFormatBase):
     if message_module is unittest_pb2:
     if message_module is unittest_pb2:
       test_util.ExpectAllFieldsSet(self, message)
       test_util.ExpectAllFieldsSet(self, message)
 
 
-    if six.PY2:
-      msg2 = message_module.TestAllTypes()
-      text = (u'optional_string: "café"')
-      text_format.Merge(text, msg2)
-      self.assertEqual(msg2.optional_string, u'café')
-      msg2.Clear()
-      text_format.Parse(text, msg2)
-      self.assertEqual(msg2.optional_string, u'café')
+    msg2 = message_module.TestAllTypes()
+    text = (u'optional_string: "café"')
+    text_format.Merge(text, msg2)
+    self.assertEqual(msg2.optional_string, u'café')
+    msg2.Clear()
+    self.assertEqual(msg2.optional_string, u'')
+    text_format.Parse(text, msg2)
+    self.assertEqual(msg2.optional_string, u'café')
 
 
   def testParseExotic(self, message_module):
   def testParseExotic(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
@@ -425,7 +533,8 @@ class TextFormatTest(TextFormatBase):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: BARR'
     text = 'optional_nested_enum: BARR'
     six.assertRaisesRegex(self, text_format.ParseError,
     six.assertRaisesRegex(self, text_format.ParseError,
-                          (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+                          (r'1:23 : \'optional_nested_enum: BARR\': '
+                           r'Enum type "\w+.TestAllTypes.NestedEnum" '
                            r'has no value named BARR.'), text_format.Parse,
                            r'has no value named BARR.'), text_format.Parse,
                           text, message)
                           text, message)
 
 
@@ -433,7 +542,8 @@ class TextFormatTest(TextFormatBase):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
     text = 'optional_int32: bork'
     text = 'optional_int32: bork'
     six.assertRaisesRegex(self, text_format.ParseError,
     six.assertRaisesRegex(self, text_format.ParseError,
-                          ('1:17 : Couldn\'t parse integer: bork'),
+                          ('1:17 : \'optional_int32: bork\': '
+                           'Couldn\'t parse integer: bork'),
                           text_format.Parse, text, message)
                           text_format.Parse, text, message)
 
 
   def testParseStringFieldUnescape(self, message_module):
   def testParseStringFieldUnescape(self, message_module):
@@ -457,6 +567,96 @@ class TextFormatTest(TextFormatBase):
                      message.repeated_string[4])
                      message.repeated_string[4])
     self.assertEqual(SLASH + 'x20', message.repeated_string[5])
     self.assertEqual(SLASH + 'x20', message.repeated_string[5])
 
 
+  def testParseOneof(self, message_module):
+    m = message_module.TestAllTypes()
+    m.oneof_uint32 = 11
+    m2 = message_module.TestAllTypes()
+    text_format.Parse(text_format.MessageToString(m), m2)
+    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
+
+  def testParseMultipleOneof(self, message_module):
+    m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
+    m2 = message_module.TestAllTypes()
+    with six.assertRaisesRegex(self, text_format.ParseError,
+                               ' is specified along with field '):
+      text_format.Parse(m_string, m2)
+
+  # This example contains non-ASCII codepoint unicode data as literals
+  # which should come through as utf-8 for bytes, and as the unicode
+  # itself for string fields.  It also demonstrates escaped binary data.
+  # The ur"" string prefix is unfortunately missing from Python 3
+  # so we resort to double escaping our \s so that they come through.
+  _UNICODE_SAMPLE = u"""
+      optional_bytes: 'Á short desçription'
+      optional_string: 'Á short desçription'
+      repeated_bytes: '\\303\\201 short des\\303\\247ription'
+      repeated_bytes: '\\x12\\x34\\x56\\x78\\x90\\xab\\xcd\\xef'
+      repeated_string: '\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82'
+      """
+  _BYTES_SAMPLE = _UNICODE_SAMPLE.encode('utf-8')
+  _GOLDEN_UNICODE = u'Á short desçription'
+  _GOLDEN_BYTES = _GOLDEN_UNICODE.encode('utf-8')
+  _GOLDEN_BYTES_1 = b'\x12\x34\x56\x78\x90\xab\xcd\xef'
+  _GOLDEN_STR_0 = u'Привет'
+
+  def testParseUnicode(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.Parse(self._UNICODE_SAMPLE, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+    # repeated_bytes[1] contained simple \ escaped non-UTF-8 raw binary data.
+    self.assertEqual(m.repeated_bytes[1], self._GOLDEN_BYTES_1)
+    # repeated_string[0] contained \ escaped data representing the UTF-8
+    # representation of _GOLDEN_STR_0 - it needs to decode as such.
+    self.assertEqual(m.repeated_string[0], self._GOLDEN_STR_0)
+
+  def testParseBytes(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.Parse(self._BYTES_SAMPLE, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+    # repeated_bytes[1] contained simple \ escaped non-UTF-8 raw binary data.
+    self.assertEqual(m.repeated_bytes[1], self._GOLDEN_BYTES_1)
+    # repeated_string[0] contained \ escaped data representing the UTF-8
+    # representation of _GOLDEN_STR_0 - it needs to decode as such.
+    self.assertEqual(m.repeated_string[0], self._GOLDEN_STR_0)
+
+  def testFromBytesFile(self, message_module):
+    m = message_module.TestAllTypes()
+    f = io.BytesIO(self._BYTES_SAMPLE)
+    text_format.ParseLines(f, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testFromUnicodeFile(self, message_module):
+    m = message_module.TestAllTypes()
+    f = io.StringIO(self._UNICODE_SAMPLE)
+    text_format.ParseLines(f, m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testFromBytesLines(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.ParseLines(self._BYTES_SAMPLE.split(b'\n'), m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+  def testFromUnicodeLines(self, message_module):
+    m = message_module.TestAllTypes()
+    text_format.ParseLines(self._UNICODE_SAMPLE.split(u'\n'), m)
+    self.assertEqual(m.optional_bytes, self._GOLDEN_BYTES)
+    self.assertEqual(m.optional_string, self._GOLDEN_UNICODE)
+    self.assertEqual(m.repeated_bytes[0], self._GOLDEN_BYTES)
+
+
+@_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
+class TextFormatMergeTests(TextFormatBase):
+
   def testMergeDuplicateScalars(self, message_module):
   def testMergeDuplicateScalars(self, message_module):
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
     text = ('optional_int32: 42 ' 'optional_int32: 67')
     text = ('optional_int32: 42 ' 'optional_int32: 67')
@@ -472,26 +672,12 @@ class TextFormatTest(TextFormatBase):
     self.assertTrue(r is message)
     self.assertTrue(r is message)
     self.assertEqual(2, message.optional_nested_message.bb)
     self.assertEqual(2, message.optional_nested_message.bb)
 
 
-  def testParseOneof(self, message_module):
-    m = message_module.TestAllTypes()
-    m.oneof_uint32 = 11
-    m2 = message_module.TestAllTypes()
-    text_format.Parse(text_format.MessageToString(m), m2)
-    self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
-
   def testMergeMultipleOneof(self, message_module):
   def testMergeMultipleOneof(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()
     text_format.Merge(m_string, m2)
     text_format.Merge(m_string, m2)
     self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
     self.assertEqual('oneof_string', m2.WhichOneof('oneof_field'))
 
 
-  def testParseMultipleOneof(self, message_module):
-    m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
-    m2 = message_module.TestAllTypes()
-    with self.assertRaisesRegexp(text_format.ParseError,
-                                 ' is specified along with field '):
-      text_format.Parse(m_string, m2)
-
 
 
 # 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
 # the moment because of differences between the proto2 and proto3 test schemas.
 # the moment because of differences between the proto2 and proto3 test schemas.
@@ -938,7 +1124,7 @@ class Proto2Tests(TextFormatBase):
                  '}\n')
                  '}\n')
     six.assertRaisesRegex(self,
     six.assertRaisesRegex(self,
                           text_format.ParseError,
                           text_format.ParseError,
-                          '5:1 : Expected ">".',
+                          '5:1 : \'}\': Expected ">".',
                           text_format.Parse,
                           text_format.Parse,
                           malformed,
                           malformed,
                           message,
                           message,
@@ -981,7 +1167,8 @@ class Proto2Tests(TextFormatBase):
     with self.assertRaises(text_format.ParseError) as e:
     with self.assertRaises(text_format.ParseError) as e:
       text_format.Parse(text, message)
       text_format.Parse(text, message)
     self.assertEqual(str(e.exception),
     self.assertEqual(str(e.exception),
-                     '1:27 : Expected identifier or number, got "bb".')
+                     '1:27 : \'optional_nested_message { "bb": 1 }\': '
+                     'Expected identifier or number, got "bb".')
 
 
   def testParseBadExtension(self):
   def testParseBadExtension(self):
     message = unittest_pb2.TestAllExtensions()
     message = unittest_pb2.TestAllExtensions()
@@ -998,7 +1185,8 @@ class Proto2Tests(TextFormatBase):
     message = unittest_pb2.TestAllTypes()
     message = unittest_pb2.TestAllTypes()
     text = 'optional_nested_enum: 100'
     text = 'optional_nested_enum: 100'
     six.assertRaisesRegex(self, text_format.ParseError,
     six.assertRaisesRegex(self, text_format.ParseError,
-                          (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+                          (r'1:23 : \'optional_nested_enum: 100\': '
+                           r'Enum type "\w+.TestAllTypes.NestedEnum" '
                            r'has no value with number 100.'), text_format.Parse,
                            r'has no value with number 100.'), text_format.Parse,
                           text, message)
                           text, message)
 
 
@@ -1448,6 +1636,26 @@ class TokenizerTest(unittest.TestCase):
     self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
     self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
     self.assertTrue(tokenizer.AtEnd())
     self.assertTrue(tokenizer.AtEnd())
 
 
+  def testConsumeOctalIntegers(self):
+    """Test support for C style octal integers."""
+    text = '00 -00 04 0755 -010 007 -0033 08 -09 01'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(4, tokenizer.ConsumeInteger())
+    self.assertEqual(0o755, tokenizer.ConsumeInteger())
+    self.assertEqual(-0o10, tokenizer.ConsumeInteger())
+    self.assertEqual(7, tokenizer.ConsumeInteger())
+    self.assertEqual(-0o033, tokenizer.ConsumeInteger())
+    with self.assertRaises(text_format.ParseError):
+      tokenizer.ConsumeInteger()  # 08
+    tokenizer.NextToken()
+    with self.assertRaises(text_format.ParseError):
+      tokenizer.ConsumeInteger()  # -09
+    tokenizer.NextToken()
+    self.assertEqual(1, tokenizer.ConsumeInteger())
+    self.assertTrue(tokenizer.AtEnd())
+
   def testConsumeByteString(self):
   def testConsumeByteString(self):
     text = '"string1\''
     text = '"string1\''
     tokenizer = text_format.Tokenizer(text.splitlines())
     tokenizer = text_format.Tokenizer(text.splitlines())
@@ -1556,6 +1764,12 @@ class TokenizerTest(unittest.TestCase):
                      tokenizer.ConsumeCommentOrTrailingComment())
                      tokenizer.ConsumeCommentOrTrailingComment())
     self.assertTrue(tokenizer.AtEnd())
     self.assertTrue(tokenizer.AtEnd())
 
 
+  def testHugeString(self):
+    # With pathologic backtracking, fails with Forge OOM.
+    text = '"' + 'a' * (10 * 1024 * 1024) + '"'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    tokenizer.ConsumeString()
+
 
 
 # Tests for pretty printer functionality.
 # Tests for pretty printer functionality.
 @_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2))
 @_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2))

+ 8 - 0
python/google/protobuf/internal/type_checkers.py

@@ -185,6 +185,14 @@ class UnicodeValueChecker(object):
                          'encoding. Non-UTF-8 strings must be converted to '
                          'encoding. Non-UTF-8 strings must be converted to '
                          'unicode objects before being added.' %
                          'unicode objects before being added.' %
                          (proposed_value))
                          (proposed_value))
+    else:
+      try:
+        proposed_value.encode('utf8')
+      except UnicodeEncodeError:
+        raise ValueError('%.1024r isn\'t a valid unicode string and '
+                         'can\'t be encoded in UTF-8.'%
+                         (proposed_value))
+
     return proposed_value
     return proposed_value
 
 
   def DefaultValue(self):
   def DefaultValue(self):

+ 123 - 42
python/google/protobuf/internal/unknown_fields_test.py

@@ -49,20 +49,12 @@ from google.protobuf.internal import missing_enum_values_pb2
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf.internal import testing_refleaks
 from google.protobuf.internal import testing_refleaks
 from google.protobuf.internal import type_checkers
 from google.protobuf.internal import type_checkers
+from google.protobuf import descriptor
 
 
 
 
 BaseTestCase = testing_refleaks.BaseTestCase
 BaseTestCase = testing_refleaks.BaseTestCase
 
 
 
 
-# CheckUnknownField() cannot be used by the C++ implementation because
-# some protect members are called. It is not a behavior difference
-# for python and C++ implementation.
-def SkipCheckUnknownFieldIfCppImplementation(func):
-  return unittest.skipIf(
-      api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
-      'Addtional test for pure python involved protect members')(func)
-
-
 class UnknownFieldsTest(BaseTestCase):
 class UnknownFieldsTest(BaseTestCase):
 
 
   def setUp(self):
   def setUp(self):
@@ -80,23 +72,11 @@ class UnknownFieldsTest(BaseTestCase):
     # stdout.
     # stdout.
     self.assertTrue(data == self.all_fields_data)
     self.assertTrue(data == self.all_fields_data)
 
 
-  def expectSerializeProto3(self, preserve):
+  def testSerializeProto3(self):
+    # Verify proto3 unknown fields behavior.
     message = unittest_proto3_arena_pb2.TestEmptyMessage()
     message = unittest_proto3_arena_pb2.TestEmptyMessage()
     message.ParseFromString(self.all_fields_data)
     message.ParseFromString(self.all_fields_data)
-    if preserve:
-      self.assertEqual(self.all_fields_data, message.SerializeToString())
-    else:
-      self.assertEqual(0, len(message.SerializeToString()))
-
-  def testSerializeProto3(self):
-    # Verify that proto3 unknown fields behavior.
-    default_preserve = (api_implementation
-                        .GetPythonProto3PreserveUnknownsDefault())
-    self.expectSerializeProto3(default_preserve)
-    api_implementation.SetPythonProto3PreserveUnknownsDefault(
-        not default_preserve)
-    self.expectSerializeProto3(not default_preserve)
-    api_implementation.SetPythonProto3PreserveUnknownsDefault(default_preserve)
+    self.assertEqual(self.all_fields_data, message.SerializeToString())
 
 
   def testByteSize(self):
   def testByteSize(self):
     self.assertEqual(self.all_fields.ByteSize(), self.empty_message.ByteSize())
     self.assertEqual(self.all_fields.ByteSize(), self.empty_message.ByteSize())
@@ -169,13 +149,15 @@ class UnknownFieldsAccessorsTest(BaseTestCase):
     self.empty_message = unittest_pb2.TestEmptyMessage()
     self.empty_message = unittest_pb2.TestEmptyMessage()
     self.empty_message.ParseFromString(self.all_fields_data)
     self.empty_message.ParseFromString(self.all_fields_data)
 
 
-  # CheckUnknownField() is an additional Pure Python check which checks
+  # InternalCheckUnknownField() is an additional Pure Python check which checks
   # a detail of unknown fields. It cannot be used by the C++
   # a detail of unknown fields. It cannot be used by the C++
   # implementation because some protect members are called.
   # implementation because some protect members are called.
   # The test is added for historical reasons. It is not necessary as
   # The test is added for historical reasons. It is not necessary as
   # serialized string is checked.
   # serialized string is checked.
-
-  def CheckUnknownField(self, name, expected_value):
+  # TODO(jieluo): Remove message._unknown_fields.
+  def InternalCheckUnknownField(self, name, expected_value):
+    if api_implementation.Type() == 'cpp':
+      return
     field_descriptor = self.descriptor.fields_by_name[name]
     field_descriptor = self.descriptor.fields_by_name[name]
     wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
     wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
     field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
     field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
@@ -183,36 +165,80 @@ class UnknownFieldsAccessorsTest(BaseTestCase):
     for tag_bytes, value in self.empty_message._unknown_fields:
     for tag_bytes, value in self.empty_message._unknown_fields:
       if tag_bytes == field_tag:
       if tag_bytes == field_tag:
         decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0]
         decoder = unittest_pb2.TestAllTypes._decoders_by_tag[tag_bytes][0]
-        decoder(value, 0, len(value), self.all_fields, result_dict)
+        decoder(memoryview(value), 0, len(value), self.all_fields, result_dict)
     self.assertEqual(expected_value, result_dict[field_descriptor])
     self.assertEqual(expected_value, result_dict[field_descriptor])
 
 
-  @SkipCheckUnknownFieldIfCppImplementation
+  def CheckUnknownField(self, name, unknown_fields, expected_value):
+    field_descriptor = self.descriptor.fields_by_name[name]
+    expected_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[
+        field_descriptor.type]
+    for unknown_field in unknown_fields:
+      if unknown_field.field_number == field_descriptor.number:
+        self.assertEqual(expected_type, unknown_field.wire_type)
+        if expected_type == 3:
+          # Check group
+          self.assertEqual(expected_value[0],
+                           unknown_field.data[0].field_number)
+          self.assertEqual(expected_value[1], unknown_field.data[0].wire_type)
+          self.assertEqual(expected_value[2], unknown_field.data[0].data)
+          continue
+        if field_descriptor.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          self.assertIn(unknown_field.data, expected_value)
+        else:
+          self.assertEqual(expected_value, unknown_field.data)
+
   def testCheckUnknownFieldValue(self):
   def testCheckUnknownFieldValue(self):
+    unknown_fields = self.empty_message.UnknownFields()
     # Test enum.
     # Test enum.
     self.CheckUnknownField('optional_nested_enum',
     self.CheckUnknownField('optional_nested_enum',
+                           unknown_fields,
                            self.all_fields.optional_nested_enum)
                            self.all_fields.optional_nested_enum)
+    self.InternalCheckUnknownField('optional_nested_enum',
+                                   self.all_fields.optional_nested_enum)
+
     # Test repeated enum.
     # Test repeated enum.
     self.CheckUnknownField('repeated_nested_enum',
     self.CheckUnknownField('repeated_nested_enum',
+                           unknown_fields,
                            self.all_fields.repeated_nested_enum)
                            self.all_fields.repeated_nested_enum)
+    self.InternalCheckUnknownField('repeated_nested_enum',
+                                   self.all_fields.repeated_nested_enum)
 
 
     # Test varint.
     # Test varint.
     self.CheckUnknownField('optional_int32',
     self.CheckUnknownField('optional_int32',
+                           unknown_fields,
                            self.all_fields.optional_int32)
                            self.all_fields.optional_int32)
+    self.InternalCheckUnknownField('optional_int32',
+                                   self.all_fields.optional_int32)
+
     # Test fixed32.
     # Test fixed32.
     self.CheckUnknownField('optional_fixed32',
     self.CheckUnknownField('optional_fixed32',
+                           unknown_fields,
                            self.all_fields.optional_fixed32)
                            self.all_fields.optional_fixed32)
+    self.InternalCheckUnknownField('optional_fixed32',
+                                   self.all_fields.optional_fixed32)
 
 
     # Test fixed64.
     # Test fixed64.
     self.CheckUnknownField('optional_fixed64',
     self.CheckUnknownField('optional_fixed64',
+                           unknown_fields,
                            self.all_fields.optional_fixed64)
                            self.all_fields.optional_fixed64)
+    self.InternalCheckUnknownField('optional_fixed64',
+                                   self.all_fields.optional_fixed64)
 
 
     # Test lengthd elimited.
     # Test lengthd elimited.
     self.CheckUnknownField('optional_string',
     self.CheckUnknownField('optional_string',
-                           self.all_fields.optional_string)
+                           unknown_fields,
+                           self.all_fields.optional_string.encode('utf-8'))
+    self.InternalCheckUnknownField('optional_string',
+                                   self.all_fields.optional_string)
 
 
     # Test group.
     # Test group.
     self.CheckUnknownField('optionalgroup',
     self.CheckUnknownField('optionalgroup',
-                           self.all_fields.optionalgroup)
+                           unknown_fields,
+                           (17, 0, 117))
+    self.InternalCheckUnknownField('optionalgroup',
+                                   self.all_fields.optionalgroup)
+
+    self.assertEqual(97, len(unknown_fields))
 
 
   def testCopyFrom(self):
   def testCopyFrom(self):
     message = unittest_pb2.TestEmptyMessage()
     message = unittest_pb2.TestEmptyMessage()
@@ -230,9 +256,18 @@ class UnknownFieldsAccessorsTest(BaseTestCase):
     message.optional_int64 = 3
     message.optional_int64 = 3
     message.optional_uint32 = 4
     message.optional_uint32 = 4
     destination = unittest_pb2.TestEmptyMessage()
     destination = unittest_pb2.TestEmptyMessage()
+    unknown_fields = destination.UnknownFields()
+    self.assertEqual(0, len(unknown_fields))
     destination.ParseFromString(message.SerializeToString())
     destination.ParseFromString(message.SerializeToString())
-
+    # ParseFromString clears the message thus unknown fields is invalid.
+    with self.assertRaises(ValueError) as context:
+      len(unknown_fields)
+    self.assertIn('UnknownFields does not exist.',
+                  str(context.exception))
+    unknown_fields = destination.UnknownFields()
+    self.assertEqual(2, len(unknown_fields))
     destination.MergeFrom(source)
     destination.MergeFrom(source)
+    self.assertEqual(4, len(unknown_fields))
     # Check that the fields where correctly merged, even stored in the unknown
     # Check that the fields where correctly merged, even stored in the unknown
     # fields set.
     # fields set.
     message.ParseFromString(destination.SerializeToString())
     message.ParseFromString(destination.SerializeToString())
@@ -241,9 +276,58 @@ class UnknownFieldsAccessorsTest(BaseTestCase):
     self.assertEqual(message.optional_int64, 3)
     self.assertEqual(message.optional_int64, 3)
 
 
   def testClear(self):
   def testClear(self):
+    unknown_fields = self.empty_message.UnknownFields()
     self.empty_message.Clear()
     self.empty_message.Clear()
     # All cleared, even unknown fields.
     # All cleared, even unknown fields.
     self.assertEqual(self.empty_message.SerializeToString(), b'')
     self.assertEqual(self.empty_message.SerializeToString(), b'')
+    with self.assertRaises(ValueError) as context:
+      len(unknown_fields)
+    self.assertIn('UnknownFields does not exist.',
+                  str(context.exception))
+
+  def testSubUnknownFields(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optionalgroup.a = 123
+    destination = unittest_pb2.TestEmptyMessage()
+    destination.ParseFromString(message.SerializeToString())
+    sub_unknown_fields = destination.UnknownFields()[0].data
+    self.assertEqual(1, len(sub_unknown_fields))
+    self.assertEqual(sub_unknown_fields[0].data, 123)
+    destination.Clear()
+    with self.assertRaises(ValueError) as context:
+      len(sub_unknown_fields)
+    self.assertIn('UnknownFields does not exist.',
+                  str(context.exception))
+    with self.assertRaises(ValueError) as context:
+      # pylint: disable=pointless-statement
+      sub_unknown_fields[0]
+    self.assertIn('UnknownFields does not exist.',
+                  str(context.exception))
+    message.Clear()
+    message.optional_uint32 = 456
+    nested_message = unittest_pb2.NestedTestAllTypes()
+    nested_message.payload.optional_nested_message.ParseFromString(
+        message.SerializeToString())
+    unknown_fields = (
+        nested_message.payload.optional_nested_message.UnknownFields())
+    self.assertEqual(unknown_fields[0].data, 456)
+    nested_message.ClearField('payload')
+    self.assertEqual(unknown_fields[0].data, 456)
+    unknown_fields = (
+        nested_message.payload.optional_nested_message.UnknownFields())
+    self.assertEqual(0, len(unknown_fields))
+
+  def testUnknownField(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optional_int32 = 123
+    destination = unittest_pb2.TestEmptyMessage()
+    destination.ParseFromString(message.SerializeToString())
+    unknown_field = destination.UnknownFields()[0]
+    destination.Clear()
+    with self.assertRaises(ValueError) as context:
+      unknown_field.data    # pylint: disable=pointless-statement
+    self.assertIn('The parent message might be cleared.',
+                  str(context.exception))
 
 
   def testUnknownExtensions(self):
   def testUnknownExtensions(self):
     message = unittest_pb2.TestEmptyMessageWithExtensions()
     message = unittest_pb2.TestEmptyMessageWithExtensions()
@@ -280,15 +364,13 @@ class UnknownEnumValuesTest(BaseTestCase):
 
 
   def CheckUnknownField(self, name, expected_value):
   def CheckUnknownField(self, name, expected_value):
     field_descriptor = self.descriptor.fields_by_name[name]
     field_descriptor = self.descriptor.fields_by_name[name]
-    wire_type = type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type]
-    field_tag = encoder.TagBytes(field_descriptor.number, wire_type)
-    result_dict = {}
-    for tag_bytes, value in self.missing_message._unknown_fields:
-      if tag_bytes == field_tag:
-        decoder = missing_enum_values_pb2.TestEnumValues._decoders_by_tag[
-            tag_bytes][0]
-        decoder(value, 0, len(value), self.message, result_dict)
-    self.assertEqual(expected_value, result_dict[field_descriptor])
+    unknown_fields = self.missing_message.UnknownFields()
+    for field in unknown_fields:
+      if field.field_number == field_descriptor.number:
+        if field_descriptor.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          self.assertIn(field.data, expected_value)
+        else:
+          self.assertEqual(expected_value, field.data)
 
 
   def testUnknownParseMismatchEnumValue(self):
   def testUnknownParseMismatchEnumValue(self):
     just_string = missing_enum_values_pb2.JustString()
     just_string = missing_enum_values_pb2.JustString()
@@ -317,7 +399,6 @@ class UnknownEnumValuesTest(BaseTestCase):
   def testUnknownPackedEnumValue(self):
   def testUnknownPackedEnumValue(self):
     self.assertEqual([], self.missing_message.packed_nested_enum)
     self.assertEqual([], self.missing_message.packed_nested_enum)
 
 
-  @SkipCheckUnknownFieldIfCppImplementation
   def testCheckUnknownFieldValueForEnum(self):
   def testCheckUnknownFieldValueForEnum(self):
     self.CheckUnknownField('optional_nested_enum',
     self.CheckUnknownField('optional_nested_enum',
                            self.message.optional_nested_enum)
                            self.message.optional_nested_enum)

+ 1 - 1
python/google/protobuf/json_format.py

@@ -482,7 +482,7 @@ class _Parser(object):
               ('Message type "{0}" has no field named "{1}".\n'
               ('Message type "{0}" has no field named "{1}".\n'
                ' Available Fields(except extensions): {2}').format(
                ' Available Fields(except extensions): {2}').format(
                    message_descriptor.full_name, name,
                    message_descriptor.full_name, name,
-                   message_descriptor.fields))
+                   [f.json_name for f in 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(

+ 4 - 0
python/google/protobuf/message.py

@@ -268,6 +268,10 @@ class Message(object):
   def ClearExtension(self, extension_handle):
   def ClearExtension(self, extension_handle):
     raise NotImplementedError
     raise NotImplementedError
 
 
+  def UnknownFields(self):
+    """Returns the UnknownFieldSet."""
+    raise NotImplementedError
+
   def DiscardUnknownFields(self):
   def DiscardUnknownFields(self):
     raise NotImplementedError
     raise NotImplementedError
 
 

+ 12 - 3
python/google/protobuf/message_factory.py

@@ -39,9 +39,18 @@ my_proto_instance = message_classes['some.proto.package.MessageName']()
 
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 
+from google.protobuf.internal import api_implementation
 from google.protobuf import descriptor_pool
 from google.protobuf import descriptor_pool
 from google.protobuf import message
 from google.protobuf import message
-from google.protobuf import reflection
+
+if api_implementation.Type() == 'cpp':
+  from google.protobuf.pyext import cpp_message as message_impl
+else:
+  from google.protobuf.internal import python_message as message_impl
+
+
+# The type of all Message classes.
+_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType
 
 
 
 
 class MessageFactory(object):
 class MessageFactory(object):
@@ -70,11 +79,11 @@ class MessageFactory(object):
       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')
-      result_class = reflection.GeneratedProtocolMessageType(
+      result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE(
           descriptor_name,
           descriptor_name,
           (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 message_factory module.
       self._classes[descriptor] = 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:

+ 5 - 6
python/google/protobuf/proto_api.h

@@ -42,16 +42,15 @@
 // Then use the methods of the returned class:
 // Then use the methods of the returned class:
 //    py_proto_api->GetMessagePointer(...);
 //    py_proto_api->GetMessagePointer(...);
 
 
-#ifndef PYTHON_GOOGLE_PROTOBUF_PROTO_API_H__
-#define PYTHON_GOOGLE_PROTOBUF_PROTO_API_H__
+#ifndef GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__
+#define GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__
 
 
 #include <Python.h>
 #include <Python.h>
 
 
+#include <google/protobuf/message.h>
+
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
-
-class Message;
-
 namespace python {
 namespace python {
 
 
 // Note on the implementation:
 // Note on the implementation:
@@ -89,4 +88,4 @@ inline const char* PyProtoAPICapsuleName() {
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
 
 
-#endif  // PYTHON_GOOGLE_PROTOBUF_PROTO_API_H__
+#endif  // GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__

+ 34 - 17
python/google/protobuf/pyext/descriptor.cc

@@ -32,8 +32,8 @@
 
 
 #include <Python.h>
 #include <Python.h>
 #include <frameobject.h>
 #include <frameobject.h>
-#include <google/protobuf/stubs/hash.h>
 #include <string>
 #include <string>
+#include <unordered_map>
 
 
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
@@ -44,6 +44,7 @@
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message_factory.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/stubs/hash.h>
 
 
 #if PY_MAJOR_VERSION >= 3
 #if PY_MAJOR_VERSION >= 3
   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
@@ -54,10 +55,12 @@
   #if PY_VERSION_HEX < 0x03030000
   #if PY_VERSION_HEX < 0x03030000
     #error "Python 3.0 - 3.2 are not supported."
     #error "Python 3.0 - 3.2 are not supported."
   #endif
   #endif
-  #define PyString_AsStringAndSize(ob, charpp, sizep) \
-    (PyUnicode_Check(ob)? \
-       ((*(charpp) = const_cast<char*>(PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL? -1: 0): \
-       PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
+  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
+                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
+                              ? -1                                            \
+                              : 0)                                            \
+                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 #endif
 #endif
 
 
 namespace google {
 namespace google {
@@ -70,7 +73,7 @@ namespace python {
 // released.
 // released.
 // This is enough to support the "is" operator on live objects.
 // This is enough to support the "is" operator on live objects.
 // All descriptors are stored here.
 // All descriptors are stored here.
-hash_map<const void*, PyObject*> interned_descriptors;
+std::unordered_map<const void*, PyObject*>* interned_descriptors;
 
 
 PyObject* PyString_FromCppString(const string& str) {
 PyObject* PyString_FromCppString(const string& str) {
   return PyString_FromStringAndSize(str.c_str(), str.size());
   return PyString_FromStringAndSize(str.c_str(), str.size());
@@ -119,8 +122,10 @@ bool _CalledFromGeneratedFile(int stacklevel) {
     PyErr_Clear();
     PyErr_Clear();
     return false;
     return false;
   }
   }
-  if ((filename_size < 3) || (strcmp(&filename[filename_size - 3], ".py") != 0)) {
-    // Cython's stack does not have .py file name and is not at global module scope.
+  if ((filename_size < 3) ||
+      (strcmp(&filename[filename_size - 3], ".py") != 0)) {
+    // Cython's stack does not have .py file name and is not at global module
+    // scope.
     return true;
     return true;
   }
   }
   if (filename_size < 7) {
   if (filename_size < 7) {
@@ -131,7 +136,7 @@ bool _CalledFromGeneratedFile(int stacklevel) {
     // Filename is not ending with _pb2.
     // Filename is not ending with _pb2.
     return false;
     return false;
   }
   }
-  
+
   if (frame->f_globals != frame->f_locals) {
   if (frame->f_globals != frame->f_locals) {
     // Not at global module scope
     // Not at global module scope
     return false;
     return false;
@@ -197,7 +202,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
   // First search in the cache.
   // First search in the cache.
   PyDescriptorPool* caching_pool = GetDescriptorPool_FromPool(
   PyDescriptorPool* caching_pool = GetDescriptorPool_FromPool(
       GetFileDescriptor(descriptor)->pool());
       GetFileDescriptor(descriptor)->pool());
-  hash_map<const void*, PyObject*>* descriptor_options =
+  std::unordered_map<const void*, PyObject*>* descriptor_options =
       caching_pool->descriptor_options;
       caching_pool->descriptor_options;
   if (descriptor_options->find(descriptor) != descriptor_options->end()) {
   if (descriptor_options->find(descriptor) != descriptor_options->end()) {
     PyObject *value = (*descriptor_options)[descriptor];
     PyObject *value = (*descriptor_options)[descriptor];
@@ -232,7 +237,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
   if (value == NULL) {
   if (value == NULL) {
     return NULL;
     return NULL;
   }
   }
-  if (!PyObject_TypeCheck(value.get(), &CMessage_Type)) {
+  if (!PyObject_TypeCheck(value.get(), CMessage_Type)) {
       PyErr_Format(PyExc_TypeError, "Invalid class for %s: %s",
       PyErr_Format(PyExc_TypeError, "Invalid class for %s: %s",
                    message_type->full_name().c_str(),
                    message_type->full_name().c_str(),
                    Py_TYPE(value.get())->tp_name);
                    Py_TYPE(value.get())->tp_name);
@@ -275,7 +280,7 @@ static PyObject* CopyToPythonProto(const DescriptorClass *descriptor,
   const Descriptor* self_descriptor =
   const Descriptor* self_descriptor =
       DescriptorProtoClass::default_instance().GetDescriptor();
       DescriptorProtoClass::default_instance().GetDescriptor();
   CMessage* message = reinterpret_cast<CMessage*>(target);
   CMessage* message = reinterpret_cast<CMessage*>(target);
-  if (!PyObject_TypeCheck(target, &CMessage_Type) ||
+  if (!PyObject_TypeCheck(target, CMessage_Type) ||
       message->message->GetDescriptor() != self_descriptor) {
       message->message->GetDescriptor() != self_descriptor) {
     PyErr_Format(PyExc_TypeError, "Not a %s message",
     PyErr_Format(PyExc_TypeError, "Not a %s message",
                  self_descriptor->full_name().c_str());
                  self_descriptor->full_name().c_str());
@@ -332,9 +337,9 @@ PyObject* NewInternedDescriptor(PyTypeObject* type,
   }
   }
 
 
   // See if the object is in the map of interned descriptors
   // See if the object is in the map of interned descriptors
-  hash_map<const void*, PyObject*>::iterator it =
-      interned_descriptors.find(descriptor);
-  if (it != interned_descriptors.end()) {
+  std::unordered_map<const void*, PyObject*>::iterator it =
+      interned_descriptors->find(descriptor);
+  if (it != interned_descriptors->end()) {
     GOOGLE_DCHECK(Py_TYPE(it->second) == type);
     GOOGLE_DCHECK(Py_TYPE(it->second) == type);
     Py_INCREF(it->second);
     Py_INCREF(it->second);
     return it->second;
     return it->second;
@@ -348,7 +353,7 @@ PyObject* NewInternedDescriptor(PyTypeObject* type,
   py_descriptor->descriptor = descriptor;
   py_descriptor->descriptor = descriptor;
 
 
   // and cache it.
   // and cache it.
-  interned_descriptors.insert(
+  interned_descriptors->insert(
       std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor)));
       std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor)));
 
 
   // Ensures that the DescriptorPool stays alive.
   // Ensures that the DescriptorPool stays alive.
@@ -370,7 +375,7 @@ PyObject* NewInternedDescriptor(PyTypeObject* type,
 
 
 static void Dealloc(PyBaseDescriptor* self) {
 static void Dealloc(PyBaseDescriptor* self) {
   // Remove from interned dictionary
   // Remove from interned dictionary
-  interned_descriptors.erase(self->descriptor);
+  interned_descriptors->erase(self->descriptor);
   Py_CLEAR(self->pool);
   Py_CLEAR(self->pool);
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 }
@@ -758,6 +763,11 @@ static PyObject* HasDefaultValue(PyBaseDescriptor *self, void *closure) {
 static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
 static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
   PyObject *result;
   PyObject *result;
 
 
+  if (_GetDescriptor(self)->is_repeated()) {
+    return PyList_New(0);
+  }
+
+
   switch (_GetDescriptor(self)->cpp_type()) {
   switch (_GetDescriptor(self)->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32: {
     case FieldDescriptor::CPPTYPE_INT32: {
       int32 value = _GetDescriptor(self)->default_value_int32();
       int32 value = _GetDescriptor(self)->default_value_int32();
@@ -805,6 +815,10 @@ static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
       result = PyInt_FromLong(value->number());
       result = PyInt_FromLong(value->number());
       break;
       break;
     }
     }
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      Py_RETURN_NONE;
+      break;
+    }
     default:
     default:
       PyErr_Format(PyExc_NotImplementedError, "default value for %s",
       PyErr_Format(PyExc_NotImplementedError, "default value for %s",
                    _GetDescriptor(self)->full_name().c_str());
                    _GetDescriptor(self)->full_name().c_str());
@@ -1919,6 +1933,9 @@ bool InitDescriptor() {
   if (!InitDescriptorMappingTypes())
   if (!InitDescriptorMappingTypes())
     return false;
     return false;
 
 
+  // Initialize globals defined in this file.
+  interned_descriptors = new std::unordered_map<const void*, PyObject*>;
+
   return true;
   return true;
 }
 }
 
 

+ 1 - 1
python/google/protobuf/pyext/descriptor.h

@@ -100,6 +100,6 @@ bool InitDescriptor();
 
 
 }  // namespace python
 }  // namespace python
 }  // namespace protobuf
 }  // namespace protobuf
-
 }  // namespace google
 }  // namespace google
+
 #endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__
 #endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__

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