Browse Source

Merge branch 'master' into 3.7.x

Bo Yang 6 years ago
parent
commit
dbfb9a8a07
100 changed files with 2864 additions and 1193 deletions
  1. 2 0
      .gitignore
  2. 7 4
      BUILD
  3. 6 0
      Makefile.am
  4. 0 1
      README.md
  5. 3 3
      benchmarks/Makefile.am
  6. 2 1
      benchmarks/php/PhpBenchmark.php
  7. 5 4
      benchmarks/python/py_benchmark.py
  8. 4 4
      benchmarks/util/result_uploader.py
  9. 3 1
      cmake/conformance.cmake
  10. 1 0
      cmake/extract_includes.bat.in
  11. 4 1
      cmake/libprotobuf-lite.cmake
  12. 0 2
      cmake/libprotobuf.cmake
  13. 24 8
      conformance/ConformanceJava.java
  14. 7 1
      conformance/Makefile.am
  15. 6 12
      conformance/binary_json_conformance_main.cc
  16. 118 89
      conformance/binary_json_conformance_suite.cc
  17. 121 0
      conformance/binary_json_conformance_suite.h
  18. 37 1
      conformance/conformance.proto
  19. 57 1
      conformance/conformance_cpp.cc
  20. 22 0
      conformance/conformance_objc.m
  21. 7 1
      conformance/conformance_php.php
  22. 67 7
      conformance/conformance_python.py
  23. 67 68
      conformance/conformance_test.cc
  24. 22 36
      conformance/conformance_test.h
  25. 23 5
      conformance/conformance_test_runner.cc
  26. 0 20
      conformance/failure_list_cpp.txt
  27. 1 28
      conformance/failure_list_php_c.txt
  28. 1 0
      conformance/failure_list_python.txt
  29. 1 32
      conformance/failure_list_python_cpp.txt
  30. 1 75
      conformance/failure_list_ruby.txt
  31. 93 0
      conformance/failure_list_ruby_mac.txt
  32. 20 20
      csharp/Google.Protobuf.Tools.nuspec
  33. 480 19
      csharp/src/Google.Protobuf.Conformance/Conformance.cs
  34. 160 156
      csharp/src/Google.Protobuf.Test/TestProtos/TestMessagesProto3.cs
  35. BIN
      csharp/src/Google.Protobuf.Test/testprotos.pb
  36. 3 2
      csharp/src/Google.Protobuf/FieldMaskTree.cs
  37. 3 2
      csharp/src/Google.Protobuf/Google.Protobuf.csproj
  38. 49 46
      csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
  39. 12 3
      csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
  40. 1 1
      csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
  41. 1 0
      docs/third_party.md
  42. 10 7
      java/compatibility_tests/v2.5.0/test.sh
  43. 1 3
      java/core/pom.xml
  44. 2 1
      java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
  45. 1 1
      java/core/src/main/java/com/google/protobuf/CodedInputStream.java
  46. 17 2
      java/core/src/main/java/com/google/protobuf/Descriptors.java
  47. 2 1
      java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
  48. 2 1
      java/core/src/main/java/com/google/protobuf/FloatArrayList.java
  49. 9 0
      java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
  50. 2 1
      java/core/src/main/java/com/google/protobuf/IntArrayList.java
  51. 2 1
      java/core/src/main/java/com/google/protobuf/LongArrayList.java
  52. 2 1
      java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
  53. 3 58
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  54. 1 3
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  55. 2 1
      java/core/src/main/java/com/google/protobuf/Utf8.java
  56. 13 0
      java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
  57. 23 0
      java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  58. 1 3
      java/pom.xml
  59. 10 7
      java/util/pom.xml
  60. 23 7
      java/util/src/main/java/com/google/protobuf/util/Durations.java
  61. 10 11
      java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
  62. 33 16
      java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
  63. 8 5
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  64. 20 6
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java
  65. 38 19
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  66. 13 1
      java/util/src/test/proto/com/google/protobuf/util/json_test.proto
  67. 2 2
      js/binary/constants.js
  68. 1 1
      js/binary/decoder.js
  69. 1 0
      js/binary/proto_test.js
  70. 1 1
      js/binary/reader.js
  71. 3 4
      js/message.js
  72. 256 228
      js/message_test.js
  73. 12 11
      js/test.proto
  74. 1 0
      js/testbinary.proto
  75. 2 1
      kokoro/linux/32-bit/build.sh
  76. 23 105
      kokoro/linux/benchmark/build.sh
  77. 105 0
      kokoro/linux/benchmark/run.sh
  78. 12 2
      kokoro/linux/build_and_run_docker.sh
  79. 13 0
      kokoro/linux/cpp_tcmalloc/build.sh
  80. 5 0
      kokoro/linux/cpp_tcmalloc/continuous.cfg
  81. 5 0
      kokoro/linux/cpp_tcmalloc/presubmit.cfg
  82. 11 5
      kokoro/linux/csharp/build.sh
  83. 29 0
      kokoro/linux/dockerfile/push_testing_images.sh
  84. 3 0
      kokoro/linux/dockerfile/release/ruby_rake_compiler/Dockerfile
  85. 29 0
      kokoro/linux/dockerfile/test/cpp_tcmalloc/Dockerfile
  86. 238 0
      kokoro/linux/dockerfile/test/php/Dockerfile
  87. 224 0
      kokoro/linux/dockerfile/test/php_32bit/Dockerfile
  88. 39 0
      kokoro/linux/dockerfile/test/python_jessie/Dockerfile
  89. 47 0
      kokoro/linux/dockerfile/test/python_stretch/Dockerfile
  90. 37 0
      kokoro/linux/dockerfile/test/ruby/Dockerfile
  91. 11 5
      kokoro/linux/java_compatibility/build.sh
  92. 2 1
      kokoro/linux/php_all/build.sh
  93. 0 13
      kokoro/linux/prepare_build_linux_rc
  94. 3 2
      kokoro/linux/python27/build.sh
  95. 1 1
      kokoro/linux/python27/continuous.cfg
  96. 1 1
      kokoro/linux/python27/presubmit.cfg
  97. 18 0
      kokoro/linux/python27_cpp/build.sh
  98. 11 0
      kokoro/linux/python27_cpp/continuous.cfg
  99. 11 0
      kokoro/linux/python27_cpp/presubmit.cfg
  100. 18 0
      kokoro/linux/python33/build.sh

+ 2 - 0
.gitignore

@@ -145,7 +145,9 @@ php/ext/google/protobuf/Makefile.objects
 php/ext/google/protobuf/acinclude.m4
 php/ext/google/protobuf/build/
 php/ext/google/protobuf/config.h
+php/ext/google/protobuf/config.h.in~
 php/ext/google/protobuf/config.nice
+php/ext/google/protobuf/configure.ac
 php/ext/google/protobuf/configure.in
 php/ext/google/protobuf/mkinstalldirs
 php/ext/google/protobuf/run-tests.php

+ 7 - 4
BUILD

@@ -54,7 +54,6 @@ COPTS = select({
         "-Wno-sign-compare",
         "-Wno-unused-function",
         # Prevents ISO C++ const string assignment warnings for pyext sources.
-        "-Wno-writable-strings",
         "-Wno-write-strings",
     ],
 })
@@ -94,7 +93,6 @@ cc_library(
     srcs = [
         # AUTOGEN(protobuf_lite_srcs)
         "src/google/protobuf/arena.cc",
-        "src/google/protobuf/arenastring.cc",
         "src/google/protobuf/extension_set.cc",
         "src/google/protobuf/generated_message_table_driven_lite.cc",
         "src/google/protobuf/generated_message_util.cc",
@@ -514,7 +512,6 @@ cc_test(
         "src/google/protobuf/arena_unittest.cc",
         "src/google/protobuf/arenastring_unittest.cc",
         "src/google/protobuf/compiler/annotation_test_util.cc",
-        "src/google/protobuf/compiler/command_line_interface_unittest.cc",
         "src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc",
         "src/google/protobuf/compiler/cpp/cpp_move_unittest.cc",
         "src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc",
@@ -583,7 +580,13 @@ cc_test(
         "src/google/protobuf/util/type_resolver_util_test.cc",
         "src/google/protobuf/well_known_types_unittest.cc",
         "src/google/protobuf/wire_format_unittest.cc",
-    ],
+    ] + select({
+        "//conditions:default" : [
+            # Doesn't pass on Windows with MSVC
+            "src/google/protobuf/compiler/command_line_interface_unittest.cc",
+        ],
+        ":msvc": []
+    }),
     copts = COPTS,
     data = [
         ":test_plugin",

+ 6 - 0
Makefile.am

@@ -473,6 +473,12 @@ objectivec_EXTRA_DIST=                                                       \
   objectivec/ProtocolBuffers_OSX.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
   objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
   objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
+  objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj                  \
+  objectivec/ProtocolBuffers_tvOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/ProtocolBuffers_tvOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist \
+  objectivec/ProtocolBuffers_tvOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
+  objectivec/ProtocolBuffers_tvOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
+  objectivec/ProtocolBuffers_tvOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
   objectivec/README.md                                                       \
   objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester.xcodeproj/project.pbxproj \
   objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester.xcodeproj/project.xcworkspace/contents.xcworkspacedata \

File diff suppressed because it is too large
+ 0 - 1
README.md


+ 3 - 3
benchmarks/Makefile.am

@@ -521,10 +521,10 @@ php-benchmark: proto3_middleman_php generate_proto3_data
 	@chmod +x php-benchmark
 
 php: php-benchmark proto3_middleman_php
-	./php-benchmark $(proto3_data)
+	./php-benchmark --behavior_prefix="php" $(proto3_data)
 
 php_c_extension:
-	cd $(top_srcdir)/php/ext/google/protobuf && ./configure CFLAGS='-O3' && make -j8
+	cd $(top_srcdir)/php/ext/google/protobuf && phpize && ./configure CFLAGS='-O3' && make -j8
 
 php-c-benchmark: proto3_middleman_php generate_proto3_data php_c_extension php_c_extension
 	mkdir -p "tmp/php/Google/Protobuf/Benchmark" && cp php/PhpBenchmark.php "tmp/php/Google/Protobuf/Benchmark" 
@@ -540,7 +540,7 @@ php-c-benchmark: proto3_middleman_php generate_proto3_data php_c_extension php_c
 	@chmod +x php-c-benchmark
 
 php_c: php-c-benchmark proto3_middleman_php
-	./php-c-benchmark $(proto3_data)
+	./php-c-benchmark --behavior_prefix="php_c" $(proto3_data)
 
 
 ############ PHP RULES END #################

+ 2 - 1
benchmarks/php/PhpBenchmark.php

@@ -1,6 +1,7 @@
 <?php
 
 namespace Google\Protobuf\Benchmark;
+ini_set('memory_limit', '4096M');
 
 const NAME = "PhpBenchmark.php";
 
@@ -62,7 +63,7 @@ class Benchmark
         $t = $this->runBenchmarkWithTimes(1);
         $times = ceil($this->benchmark_time / $t);
         return $this->total_bytes * $times /
-        $this->runBenchmarkWithTimes($times) *
+        ($times == 1 ? $t : $this->runBenchmarkWithTimes($times)) *
         $this->coefficient;
     }
     

+ 5 - 4
benchmarks/python/py_benchmark.py

@@ -134,10 +134,11 @@ class Benchmark:
     t = self.dry_run(test_method_args, setup_method_args);
     if t < 3 :
       reps = int(math.ceil(3 / t)) * self.full_iteration
-    t = timeit.timeit(stmt="%s(%s)" % (self.test_method, test_method_args),
-                      setup=self.full_setup_code(setup_method_args),
-                      number=reps);
-    return self.total_bytes * 1.0 / 2 ** 20 / (1.0 * t / reps)
+    if reps != self.full_iteration:
+        t = timeit.timeit(stmt="%s(%s)" % (self.test_method, test_method_args),
+                          setup=self.full_setup_code(setup_method_args),
+                          number=reps);
+    return self.total_bytes * 1.0 / 2 ** 20 / (1.0 * t / reps * self.full_iteration)  
   
 
 if __name__ == "__main__":

+ 4 - 4
benchmarks/util/result_uploader.py

@@ -61,12 +61,12 @@ def upload_result(result_list, metadata):
     new_result["timestamp"] = _INITIAL_TIME
     print(labels_string)
  
-     bq = big_query_utils.create_big_query()
-     row = big_query_utils.make_row(str(uuid.uuid4()), new_result)
-     if not big_query_utils.insert_rows(bq, _PROJECT_ID, _DATASET,
+    bq = big_query_utils.create_big_query()
+    row = big_query_utils.make_row(str(uuid.uuid4()), new_result)
+    if not big_query_utils.insert_rows(bq, _PROJECT_ID, _DATASET,
                                         _TABLE + "$" + _NOW,
                                         [row]):
-       print('Error when uploading result', new_result)
+      print('Error when uploading result', new_result)
 
 
 if __name__ == "__main__":

+ 3 - 1
cmake/conformance.cmake

@@ -21,7 +21,9 @@ add_custom_command(
 add_executable(conformance_test_runner
   ${protobuf_source_dir}/conformance/conformance.pb.cc
   ${protobuf_source_dir}/conformance/conformance_test.cc
-  ${protobuf_source_dir}/conformance/conformance_test_impl.cc
+  ${protobuf_source_dir}/conformance/binary_json_conformance_main.cc
+  ${protobuf_source_dir}/conformance/binary_json_conformance_suite.cc
+  ${protobuf_source_dir}/conformance/binary_json_conformance_suite.h
   ${protobuf_source_dir}/conformance/conformance_test_runner.cc
   ${protobuf_source_dir}/conformance/third_party/jsoncpp/json.h
   ${protobuf_source_dir}/conformance/third_party/jsoncpp/jsoncpp.cpp

+ 1 - 0
cmake/extract_includes.bat.in

@@ -97,6 +97,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\platform_macros
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\port.h" include\google\protobuf\stubs\port.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\status.h" include\google\protobuf\stubs\status.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stl_util.h" include\google\protobuf\stubs\stl_util.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\strutil.h" include\google\protobuf\stubs\strutil.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stringpiece.h" include\google\protobuf\stubs\stringpiece.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\strutil.h" include\google\protobuf\stubs\strutil.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\template_util.h" include\google\protobuf\stubs\template_util.h

+ 4 - 1
cmake/libprotobuf-lite.cmake

@@ -1,11 +1,12 @@
 set(libprotobuf_lite_files
   ${protobuf_source_dir}/src/google/protobuf/arena.cc
-  ${protobuf_source_dir}/src/google/protobuf/arenastring.cc
   ${protobuf_source_dir}/src/google/protobuf/extension_set.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.cc
   ${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/parse_context.cc
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.cc
+  ${protobuf_source_dir}/src/google/protobuf/io/strtod.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/message_lite.cc
@@ -30,7 +31,9 @@ set(libprotobuf_lite_includes
   ${protobuf_source_dir}/src/google/protobuf/extension_set.h
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.h
   ${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.h
+  ${protobuf_source_dir}/src/google/protobuf/parse_context.h
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.h
+  ${protobuf_source_dir}/src/google/protobuf/io/strtod.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.h
   ${protobuf_source_dir}/src/google/protobuf/message_lite.h

+ 0 - 2
cmake/libprotobuf.cmake

@@ -16,7 +16,6 @@ set(libprotobuf_files
   ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven.cc
   ${protobuf_source_dir}/src/google/protobuf/io/gzip_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/printer.cc
-  ${protobuf_source_dir}/src/google/protobuf/io/strtod.cc
   ${protobuf_source_dir}/src/google/protobuf/io/tokenizer.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.cc
   ${protobuf_source_dir}/src/google/protobuf/map_field.cc
@@ -72,7 +71,6 @@ set(libprotobuf_includes
   ${protobuf_source_dir}/src/google/protobuf/generated_message_reflection.h
   ${protobuf_source_dir}/src/google/protobuf/io/gzip_stream.h
   ${protobuf_source_dir}/src/google/protobuf/io/printer.h
-  ${protobuf_source_dir}/src/google/protobuf/io/strtod.h
   ${protobuf_source_dir}/src/google/protobuf/io/tokenizer.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.h
   ${protobuf_source_dir}/src/google/protobuf/map_field.h

+ 24 - 8
conformance/ConformanceJava.java

@@ -1,16 +1,17 @@
-import com.google.protobuf.ByteString;
 import com.google.protobuf.AbstractMessage;
-import com.google.protobuf.Parser;
+import com.google.protobuf.ByteString;
 import com.google.protobuf.CodedInputStream;
-import com.google.protobuf.conformance.Conformance;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf_test_messages.proto3.TestMessagesProto3;
-import com.google.protobuf_test_messages.proto3.TestMessagesProto3.TestAllTypesProto3;
-import com.google.protobuf_test_messages.proto2.TestMessagesProto2;
-import com.google.protobuf_test_messages.proto2.TestMessagesProto2.TestAllTypesProto2;
 import com.google.protobuf.ExtensionRegistry;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Parser;
+import com.google.protobuf.TextFormat;
+import com.google.protobuf.conformance.Conformance;
 import com.google.protobuf.util.JsonFormat;
 import com.google.protobuf.util.JsonFormat.TypeRegistry;
+import com.google.protobuf_test_messages.proto2.TestMessagesProto2;
+import com.google.protobuf_test_messages.proto2.TestMessagesProto2.TestAllTypesProto2;
+import com.google.protobuf_test_messages.proto3.TestMessagesProto3;
+import com.google.protobuf_test_messages.proto3.TestMessagesProto3.TestAllTypesProto3;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
@@ -247,6 +248,17 @@ class ConformanceJava {
         }
         break;
       }
+      case TEXT_PAYLOAD: {
+        try {
+          TestMessagesProto3.TestAllTypesProto3.Builder builder =
+              TestMessagesProto3.TestAllTypesProto3.newBuilder();
+          TextFormat.merge(request.getTextPayload(), builder);
+          testMessage = builder.build();
+        } catch (TextFormat.ParseException e) {
+          return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
+        }
+        break;
+      }
       case PAYLOAD_NOT_SET: {
         throw new RuntimeException("Request didn't have payload.");
       }
@@ -274,6 +286,10 @@ class ConformanceJava {
               e.getMessage()).build();
         }
 
+      case TEXT_FORMAT:
+        return Conformance.ConformanceResponse.newBuilder().setTextPayload(
+            TextFormat.printToString(testMessage)).build();
+
       default: {
         throw new RuntimeException("Unexpected request output.");
       }

+ 7 - 1
conformance/Makefile.am

@@ -107,6 +107,7 @@ other_language_protoc_outputs =                                \
   google/protobuf/wrappers_pb2.py                              \
   Conformance/ConformanceRequest.php                           \
   Conformance/ConformanceResponse.php                          \
+  Conformance/FailureSet.php                                   \
   Conformance/WireFormat.php                                   \
   GPBMetadata/Conformance.php                                  \
   GPBMetadata/Google/Protobuf/Any.php                          \
@@ -206,7 +207,9 @@ EXTRA_DIST =                  \
 
 conformance_test_runner_LDADD = $(top_srcdir)/src/libprotobuf.la
 conformance_test_runner_SOURCES = conformance_test.h conformance_test.cc \
-                                  conformance_test_impl.cc               \
+                                  binary_json_conformance_main.cc        \
+                                  binary_json_conformance_suite.h        \
+                                  binary_json_conformance_suite.cc       \
                                   conformance_test_runner.cc             \
                                   third_party/jsoncpp/json.h             \
                                   third_party/jsoncpp/jsoncpp.cpp
@@ -342,6 +345,9 @@ test_csharp: protoc_middleman conformance-test-runner conformance-csharp
 test_ruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
 	RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby.txt ./conformance_ruby.rb
 
+test_ruby_mac: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
+	RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby_mac.txt ./conformance_ruby.rb
+
 test_php: protoc_middleman conformance-test-runner conformance-php $(other_language_protoc_outputs)
 	./conformance-test-runner --enforce_recommended --failure_list failure_list_php.txt ./conformance-php
 

+ 6 - 12
src/google/protobuf/arenastring.cc → conformance/binary_json_conformance_main.cc

@@ -28,16 +28,10 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// The ArenaString implementation is not included in the open-source release. Do
-// not include this file in the distribution.
+#include "binary_json_conformance_suite.h"
+#include "conformance_test.h"
 
-#include <google/protobuf/arenastring.h>
-
-namespace google {
-namespace protobuf {
-namespace internal {
-
-
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
+int main(int argc, char *argv[]) {
+  google::protobuf::BinaryAndJsonConformanceSuite suite;
+  return google::protobuf::ForkPipeRunner::Run(argc, argv, &suite);
+}

+ 118 - 89
conformance/conformance_test_impl.cc → conformance/binary_json_conformance_suite.cc

@@ -28,6 +28,7 @@
 // (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 "binary_json_conformance_suite.h"
 #include "conformance_test.h"
 #include "third_party/jsoncpp/json.h"
 
@@ -37,11 +38,13 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/text_format.h>
+#include <google/protobuf/util/json_util.h>
 #include <google/protobuf/util/type_resolver_util.h>
 #include <google/protobuf/wire_format_lite.h>
 
 using conformance::ConformanceRequest;
 using conformance::ConformanceResponse;
+using conformance::WireFormat;
 using google::protobuf::Descriptor;
 using google::protobuf::FieldDescriptor;
 using google::protobuf::Message;
@@ -189,73 +192,83 @@ std::unique_ptr<Message> NewTestMessage(bool is_proto3) {
 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 (
+bool BinaryAndJsonConformanceSuite::ParseJsonResponse(
+    const ConformanceResponse& response,
+    Message* test_message) {
+  string binary_protobuf;
+  util::Status status =
+      JsonToBinaryString(type_resolver_.get(), type_url_,
+                         response.json_payload(), &binary_protobuf);
+
+  if (!status.ok()) {
+    return false;
+  }
+
+  if (!test_message->ParseFromString(binary_protobuf)) {
+    GOOGLE_LOG(FATAL)
+        << "INTERNAL ERROR: internal JSON->protobuf transcode "
+        << "yielded unparseable proto.";
+    return false;
+  }
+
+  return true;
+}
+
+bool BinaryAndJsonConformanceSuite::ParseResponse(
+    const ConformanceResponse& response,
+    const ConformanceRequestSetting& setting,
+    Message* test_message) {
+  const ConformanceRequest& request = setting.GetRequest();
+  WireFormat requested_output = request.requested_output_format();
+  const string& test_name = setting.GetTestName();
+  ConformanceLevel level = setting.GetLevel();
+
+  switch (response.result_case()) {
+    case ConformanceResponse::kProtobufPayload: {
+      if (requested_output != conformance::PROTOBUF) {
+        ReportFailure(
+            test_name, level, request, response,
+            StrCat("Test was asked for ", WireFormatToString(requested_output),
+                   " output but provided PROTOBUF instead.").c_str());
+        return false;
+      }
+
+      if (!test_message->ParseFromString(response.protobuf_payload())) {
+        ReportFailure(test_name, level, request, response,
+                   "Protobuf output we received from test was unparseable.");
+        return false;
+      }
+
+      break;
+    }
+
+    case ConformanceResponse::kJsonPayload: {
+      if (requested_output != conformance::JSON) {
+        ReportFailure(
+            test_name, level, request, response,
+            StrCat("Test was asked for ", WireFormatToString(requested_output),
+                   " output but provided JSON instead.").c_str());
+        return false;
+      }
+
+      if (!ParseJsonResponse(response, test_message)) {
+        ReportFailure(test_name, level, request, response,
+                      "JSON output we received from test was unparseable.");
+        return false;
+      }
+
+      break;
+    }
+
+    default:
+      GOOGLE_LOG(FATAL) << test_name << ": unknown payload type: "
+                        << response.result_case();
+  }
+
+  return true;
+}
+
+void BinaryAndJsonConformanceSuite::ExpectParseFailureForProtoWithProtoVersion (
     const string& proto, const string& test_name, ConformanceLevel level,
     bool is_proto3) {
   std::unique_ptr<Message> prototype = NewTestMessage(is_proto3);
@@ -285,7 +298,7 @@ void ConformanceTestSuiteImpl::ExpectParseFailureForProtoWithProtoVersion (
 }
 
 // Expect that this precise protobuf will cause a parse error.
-void ConformanceTestSuiteImpl::ExpectParseFailureForProto(
+void BinaryAndJsonConformanceSuite::ExpectParseFailureForProto(
     const string& proto, const string& test_name, ConformanceLevel level) {
   ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, true);
   ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, false);
@@ -296,12 +309,12 @@ void ConformanceTestSuiteImpl::ExpectParseFailureForProto(
 // data verbatim and once with this data followed by some valid data.
 //
 // TODO(haberman): implement the second of these.
-void ConformanceTestSuiteImpl::ExpectHardParseFailureForProto(
+void BinaryAndJsonConformanceSuite::ExpectHardParseFailureForProto(
     const string& proto, const string& test_name, ConformanceLevel level) {
   return ExpectParseFailureForProto(proto, test_name, level);
 }
 
-void ConformanceTestSuiteImpl::RunValidJsonTest(
+void BinaryAndJsonConformanceSuite::RunValidJsonTest(
     const string& test_name, ConformanceLevel level, const string& input_json,
     const string& equivalent_text_format) {
   TestAllTypesProto3 prototype;
@@ -317,7 +330,7 @@ void ConformanceTestSuiteImpl::RunValidJsonTest(
   RunValidInputTest(setting2, equivalent_text_format);
 }
 
-void ConformanceTestSuiteImpl::RunValidJsonTestWithProtobufInput(
+void BinaryAndJsonConformanceSuite::RunValidJsonTestWithProtobufInput(
     const string& test_name, ConformanceLevel level, const TestAllTypesProto3& input,
     const string& equivalent_text_format) {
   ConformanceRequestSetting setting(
@@ -327,7 +340,7 @@ void ConformanceTestSuiteImpl::RunValidJsonTestWithProtobufInput(
   RunValidInputTest(setting, equivalent_text_format);
 }
 
-void ConformanceTestSuiteImpl::RunValidJsonIgnoreUnknownTest(
+void BinaryAndJsonConformanceSuite::RunValidJsonIgnoreUnknownTest(
     const string& test_name, ConformanceLevel level, const string& input_json,
     const string& equivalent_text_format) {
   TestAllTypesProto3 prototype;
@@ -338,7 +351,7 @@ void ConformanceTestSuiteImpl::RunValidJsonIgnoreUnknownTest(
   RunValidInputTest(setting, equivalent_text_format);
 }
 
-void ConformanceTestSuiteImpl::RunValidProtobufTest(
+void BinaryAndJsonConformanceSuite::RunValidProtobufTest(
     const string& test_name, ConformanceLevel level,
     const string& input_protobuf, const string& equivalent_text_format,
     bool is_proto3) {
@@ -359,7 +372,7 @@ void ConformanceTestSuiteImpl::RunValidProtobufTest(
   }
 }
 
-void ConformanceTestSuiteImpl::RunValidBinaryProtobufTest(
+void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest(
     const string& test_name, ConformanceLevel level,
     const string& input_protobuf, bool is_proto3) {
   std::unique_ptr<Message> prototype = NewTestMessage(is_proto3);
@@ -370,7 +383,7 @@ void ConformanceTestSuiteImpl::RunValidBinaryProtobufTest(
   RunValidBinaryInputTest(setting, input_protobuf);
 }
 
-void ConformanceTestSuiteImpl::RunValidProtobufTestWithMessage(
+void BinaryAndJsonConformanceSuite::RunValidProtobufTestWithMessage(
     const string& test_name, ConformanceLevel level, const Message *input,
     const string& equivalent_text_format, bool is_proto3) {
   RunValidProtobufTest(test_name, level, input->SerializeAsString(),
@@ -382,7 +395,7 @@ void ConformanceTestSuiteImpl::RunValidProtobufTestWithMessage(
 // 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(
+void BinaryAndJsonConformanceSuite::RunValidJsonTestWithValidator(
     const string& test_name, ConformanceLevel level, const string& input_json,
     const Validator& validator) {
   TestAllTypesProto3 prototype;
@@ -426,7 +439,7 @@ void ConformanceTestSuiteImpl::RunValidJsonTestWithValidator(
   ReportSuccess(effective_test_name);
 }
 
-void ConformanceTestSuiteImpl::ExpectParseFailureForJson(
+void BinaryAndJsonConformanceSuite::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
@@ -452,7 +465,7 @@ void ConformanceTestSuiteImpl::ExpectParseFailureForJson(
   }
 }
 
-void ConformanceTestSuiteImpl::ExpectSerializeFailureForJson(
+void BinaryAndJsonConformanceSuite::ExpectSerializeFailureForJson(
     const string& test_name, ConformanceLevel level, const string& text_format) {
   TestAllTypesProto3 payload_message;
   GOOGLE_CHECK(
@@ -482,7 +495,7 @@ void ConformanceTestSuiteImpl::ExpectSerializeFailureForJson(
 }
 
 //TODO: proto2?
-void ConformanceTestSuiteImpl::TestPrematureEOFForType(
+void BinaryAndJsonConformanceSuite::TestPrematureEOFForType(
     FieldDescriptor::Type type) {
   // Incomplete values for each wire type.
   static const string incompletes[6] = {
@@ -570,7 +583,7 @@ void ConformanceTestSuiteImpl::TestPrematureEOFForType(
   }
 }
 
-void ConformanceTestSuiteImpl::TestValidDataForType(
+void BinaryAndJsonConformanceSuite::TestValidDataForType(
     FieldDescriptor::Type type,
     std::vector<std::pair<std::string, std::string>> values) {
   for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
@@ -606,7 +619,7 @@ void ConformanceTestSuiteImpl::TestValidDataForType(
 }
 
 // TODO: proto2?
-void ConformanceTestSuiteImpl::TestIllegalTags() {
+void BinaryAndJsonConformanceSuite::TestIllegalTags() {
   // field num 0 is illegal
   string nullfield[] = {
     "\1DEADBEEF",
@@ -621,7 +634,7 @@ void ConformanceTestSuiteImpl::TestIllegalTags() {
   }
 }
 template <class MessageType>
-void ConformanceTestSuiteImpl::TestOneofMessage (
+void BinaryAndJsonConformanceSuite::TestOneofMessage (
     MessageType &message, bool is_proto3) {
   message.set_oneof_uint32(0);
   RunValidProtobufTestWithMessage(
@@ -660,14 +673,14 @@ void ConformanceTestSuiteImpl::TestOneofMessage (
 }
 
 template <class MessageType>
-void ConformanceTestSuiteImpl::TestUnknownMessage(
+void BinaryAndJsonConformanceSuite::TestUnknownMessage(
     MessageType& message, bool is_proto3) {
   message.ParseFromString("\xA8\x1F\x01");
   RunValidBinaryProtobufTest("UnknownVarint", REQUIRED,
                              message.SerializeAsString(), is_proto3);
 }
 
-void ConformanceTestSuiteImpl::RunSuiteImpl() {
+void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
   type_resolver_.reset(NewTypeResolverForDescriptorPool(
       kTypeUrlPrefix, DescriptorPool::generated_pool()));
   type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor());
@@ -1373,6 +1386,23 @@ void ConformanceTestSuiteImpl::RunSuiteImpl() {
       "EnumField", REQUIRED,
       R"({"optionalNestedEnum": "FOO"})",
       "optional_nested_enum: FOO");
+  // Enum fields with alias
+  RunValidJsonTest(
+      "EnumFieldWithAlias", REQUIRED,
+      R"({"optionalAliasedEnum": "ALIAS_BAZ"})",
+      "optional_aliased_enum: ALIAS_BAZ");
+  RunValidJsonTest(
+      "EnumFieldWithAliasUseAlias", REQUIRED,
+      R"({"optionalAliasedEnum": "QUX"})",
+      "optional_aliased_enum: ALIAS_BAZ");
+  RunValidJsonTest(
+      "EnumFieldWithAliasLowerCase", REQUIRED,
+      R"({"optionalAliasedEnum": "qux"})",
+      "optional_aliased_enum: ALIAS_BAZ");
+  RunValidJsonTest(
+      "EnumFieldWithAliasDifferentCase", REQUIRED,
+      R"({"optionalAliasedEnum": "bAz"})",
+      "optional_aliased_enum: ALIAS_BAZ");
   // Enum values must be represented as strings.
   ExpectParseFailureForJson(
       "EnumFieldNotQuoted", REQUIRED,
@@ -2012,6 +2042,10 @@ void ConformanceTestSuiteImpl::RunSuiteImpl() {
       "FieldMask", REQUIRED,
       R"({"optionalFieldMask": "foo,barBaz"})",
       R"(optional_field_mask: {paths: "foo" paths: "bar_baz"})");
+  RunValidJsonTest(
+      "EmptyFieldMask", REQUIRED,
+      R"({"optionalFieldMask": ""})",
+      R"(optional_field_mask: {})");
   ExpectParseFailureForJson(
       "FieldMaskInvalidCharacter", RECOMMENDED,
       R"({"optionalFieldMask": "foo,bar_bar"})");
@@ -2360,8 +2394,3 @@ void ConformanceTestSuiteImpl::RunSuiteImpl() {
 
 }  // namespace protobuf
 }  // namespace google
-
-int main(int argc, char *argv[]) {
-  google::protobuf::ConformanceTestSuiteImpl suite;
-  return google::protobuf::ForkPipeRunner::Run(argc, argv, &suite);
-}

+ 121 - 0
conformance/binary_json_conformance_suite.h

@@ -0,0 +1,121 @@
+// 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.
+
+#ifndef CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
+#define CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
+
+#include "conformance_test.h"
+#include "third_party/jsoncpp/json.h"
+
+namespace google {
+namespace protobuf {
+
+class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
+ public:
+  BinaryAndJsonConformanceSuite() {}
+
+ 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);
+
+  bool ParseJsonResponse(
+      const conformance::ConformanceResponse& response,
+      Message* test_message);
+  bool ParseResponse(
+      const conformance::ConformanceResponse& response,
+      const ConformanceRequestSetting& setting,
+      Message* test_message) override;
+
+  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);
+
+  std::unique_ptr<google::protobuf::util::TypeResolver>
+      type_resolver_;
+  std::string type_url_;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H

+ 37 - 1
conformance/conformance.proto

@@ -55,18 +55,32 @@ enum WireFormat {
   UNSPECIFIED = 0;
   PROTOBUF = 1;
   JSON = 2;
+  JSPB = 3;  // Google internal only. Opensource testees just skip it.
+  TEXT_FORMAT = 4;
 }
 
 enum TestCategory {
   UNSPECIFIED_TEST = 0;
   BINARY_TEST = 1;  // Test binary wire format.
-  JSON_TEST = 2;  // Test json 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;
+  // Test jspb wire format. Google internal only. Opensource testees just skip it.
+  JSPB_TEST = 4;
+  // Test text format. For cpp, java and python, testees can already deal with
+  // this type. Testees of other languages can simply skip it.
+  TEXT_FORMAT_TEST = 5;
+}
+
+// The conformance runner will request a list of failures as the first request.
+// This will be known by message_type == "conformance.FailureSet", a conformance
+// test should return a serialized FailureSet in protobuf_payload.
+message FailureSet {
+  repeated string failure = 1;
 }
 
 // Represents a single test case's input.  The testee should:
@@ -85,6 +99,9 @@ message ConformanceRequest {
   oneof payload {
     bytes protobuf_payload = 1;
     string json_payload = 2;
+    // Google internal only.  Opensource testees just skip it.
+    string jspb_payload = 7;
+    string text_payload = 8;
   }
 
   // Which format should the testee serialize its message to?
@@ -99,6 +116,9 @@ message ConformanceRequest {
   // spedific support in testee programs. Refer to the defintion of TestCategory
   // for more information.
   TestCategory test_category = 5;
+
+  // Specify details for how to encode jspb.
+  JspbEncodingConfig jspb_encoding_options = 6;
 }
 
 // Represents a single test case's output.
@@ -132,5 +152,21 @@ message ConformanceResponse {
     // For when the testee skipped the test, likely because a certain feature
     // wasn't supported, like JSON input/output.
     string skipped = 5;
+
+    // If the input was successfully parsed and the requested output was JSPB,
+    // serialize to JSPB and set it in this field. JSPB is google internal only
+    // format. Opensource testees can just skip it.
+    string jspb_payload = 7;
+
+    // If the input was successfully parsed and the requested output was
+    // TEXT_FORMAT, serialize to TEXT_FORMAT and set it in this field.
+    string text_payload = 8;
   }
 }
+
+// Encoding options for jspb format.
+message JspbEncodingConfig {
+  // Encode the value field of Any as jspb array if ture, otherwise binary.
+  bool use_jspb_array_any_format = 1;
+}
+

+ 57 - 1
conformance/conformance_cpp.cc

@@ -36,6 +36,7 @@
 #include <google/protobuf/test_messages_proto3.pb.h>
 #include <google/protobuf/test_messages_proto2.pb.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/text_format.h>
 #include <google/protobuf/util/json_util.h>
 #include <google/protobuf/util/type_resolver_util.h>
 
@@ -45,18 +46,48 @@ using google::protobuf::Descriptor;
 using google::protobuf::DescriptorPool;
 using google::protobuf::Message;
 using google::protobuf::MessageFactory;
+using google::protobuf::TextFormat;
 using google::protobuf::util::BinaryToJsonString;
 using google::protobuf::util::JsonParseOptions;
 using google::protobuf::util::JsonToBinaryString;
 using google::protobuf::util::NewTypeResolverForDescriptorPool;
 using google::protobuf::util::Status;
 using google::protobuf::util::TypeResolver;
-using protobuf_test_messages::proto3::TestAllTypesProto3;
 using protobuf_test_messages::proto2::TestAllTypesProto2;
+using protobuf_test_messages::proto3::TestAllTypesProto3;
 using std::string;
 
 static const char kTypeUrlPrefix[] = "type.googleapis.com";
 
+const char* kFailures[] = {
+#if !GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+    "Required.Proto2.ProtobufInput."
+    "PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE",
+    "Required.Proto2.ProtobufInput."
+    "PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.BOOL",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.ENUM",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT32",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT64",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32",
+    "Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64",
+    "Required.Proto3.ProtobufInput."
+    "PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE",
+    "Required.Proto3.ProtobufInput."
+    "PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.BOOL",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.ENUM",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT32",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT64",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT32",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT64",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT32",
+    "Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT64",
+#endif
+};
+
 static string GetTypeUrl(const Descriptor* message) {
   return string(kTypeUrlPrefix) + "/" + message->full_name();
 }
@@ -134,9 +165,28 @@ void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
       break;
     }
 
+    case ConformanceRequest::kTextPayload: {
+      if (!TextFormat::ParseFromString(request.text_payload(), test_message)) {
+        response->set_parse_error("Parse error");
+        return;
+      }
+      break;
+    }
+
     case ConformanceRequest::PAYLOAD_NOT_SET:
       GOOGLE_LOG(FATAL) << "Request didn't have payload.";
       break;
+
+    default:
+      GOOGLE_LOG(FATAL) << "unknown payload type: "
+                        << request.payload_case();
+      break;
+  }
+
+  conformance::FailureSet failures;
+  if (descriptor == failures.GetDescriptor()) {
+    for (const char* s : kFailures) failures.add_failure(s);
+    test_message = &failures;
   }
 
   switch (request.requested_output_format()) {
@@ -163,6 +213,12 @@ void DoTest(const ConformanceRequest& request, ConformanceResponse* response) {
       break;
     }
 
+    case conformance::TEXT_FORMAT: {
+      GOOGLE_CHECK(TextFormat::PrintToString(*test_message,
+                                             response->mutable_text_payload()));
+      break;
+    }
+
     default:
       GOOGLE_LOG(FATAL) << "Unknown output format: "
                         << request.requested_output_format();

+ 22 - 0
conformance/conformance_objc.m

@@ -92,6 +92,16 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) {
     case ConformanceRequest_Payload_OneOfCase_JsonPayload:
       response.skipped = @"ObjC doesn't support parsing JSON";
       break;
+
+    case ConformanceRequest_Payload_OneOfCase_JspbPayload:
+      response.skipped =
+          @"ConformanceRequest had a jspb_payload ConformanceRequest.payload;"
+          " those aren't supposed to happen with opensource.";
+      break;
+
+    case ConformanceRequest_Payload_OneOfCase_TextPayload:
+      response.skipped = @"ObjC doesn't support parsing TextFormat";
+      break;
   }
 
   if (testMessage) {
@@ -112,6 +122,18 @@ static ConformanceResponse *DoTest(ConformanceRequest *request) {
       case WireFormat_Json:
         response.skipped = @"ObjC doesn't support generating JSON";
         break;
+
+      case WireFormat_Jspb:
+        response.skipped =
+            @"ConformanceRequest had a requested_output_format of JSPB WireFormat; that"
+            " isn't supposed to happen with opensource.";
+        break;
+
+      case WireFormat_TextFormat:
+        // ObjC only has partial objc generation, so don't attempt any tests that need
+        // support.
+        response.skipped = @"ObjC doesn't support generating TextFormat";
+        break;
     }
   }
 

+ 7 - 1
conformance/conformance_php.php

@@ -3,10 +3,13 @@
 require_once("Conformance/WireFormat.php");
 require_once("Conformance/ConformanceResponse.php");
 require_once("Conformance/ConformanceRequest.php");
+require_once("Conformance/FailureSet.php");
+require_once("Conformance/JspbEncodingConfig.php");
 require_once("Conformance/TestCategory.php");
 require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
 require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
+require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/AliasedEnum.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedMessage.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php");
 
@@ -27,7 +30,10 @@ function doTest($request)
     $test_message = new \Protobuf_test_messages\Proto3\TestAllTypesProto3();
     $response = new \Conformance\ConformanceResponse();
     if ($request->getPayload() == "protobuf_payload") {
-      if ($request->getMessageType() == "protobuf_test_messages.proto3.TestAllTypesProto3") {
+      if ($request->getMessageType() == "conformance.FailureSet") {
+        $response->setProtobufPayload("");
+        return $response;
+      } elseif ($request->getMessageType() == "protobuf_test_messages.proto3.TestAllTypesProto3") {
         try {
           $test_message->mergeFromString($request->getProtobufPayload());
         } catch (Exception $e) {

+ 67 - 7
conformance/conformance_python.py

@@ -44,6 +44,7 @@ from google.protobuf import json_format
 from google.protobuf import message
 from google.protobuf import test_messages_proto3_pb2
 from google.protobuf import test_messages_proto2_pb2
+from google.protobuf import text_format
 import conformance_pb2
 
 sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
@@ -56,26 +57,75 @@ class ProtocolError(Exception):
   pass
 
 def do_test(request):
+  response = conformance_pb2.ConformanceResponse()
+
+  if request.message_type == "conformance.FailureSet":
+    failure_set = conformance_pb2.FailureSet()
+    failures = []
+    # TODO(gerbens): Remove, this is a hack to detect if the old vs new
+    # parser is used by the cpp code. Relying on a bug in the old parser.
+    hack_proto = test_messages_proto2_pb2.TestAllTypesProto2()
+    if hack_proto.ParseFromString(b"\322\002\001"):
+      # the string above is one of the failing conformance test strings of the
+      # old parser. If we succeed the c++ implementation is using the old
+      # parser so we add the list of failing conformance tests.
+      failures = [
+          "Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE",
+          "Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.BOOL",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.DOUBLE",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.ENUM",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.FIXED32",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.FIXED64",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.FLOAT",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT32",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT64",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SFIXED32",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SFIXED64",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT32",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT64",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT32",
+          "Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT64",
+          "Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE",
+          "Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.BOOL",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.DOUBLE",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.ENUM",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.FIXED32",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.FIXED64",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.FLOAT",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT32",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT64",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SFIXED32",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SFIXED64",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32",
+          "Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64",
+      ]
+    for x in failures:
+      failure_set.failure.append(x)
+    response.protobuf_payload = failure_set.SerializeToString()
+    return response
+
   isProto3 = (request.message_type == "protobuf_test_messages.proto3.TestAllTypesProto3")
   isJson = (request.WhichOneof('payload') == 'json_payload')
   isProto2 = (request.message_type == "protobuf_test_messages.proto2.TestAllTypesProto2")
-  
+
   if (not isProto3) and (not isJson) and (not isProto2):
     raise ProtocolError("Protobuf request doesn't have specific payload type")
-      
+
   test_message = test_messages_proto2_pb2.TestAllTypesProto2() if isProto2 else \
     test_messages_proto3_pb2.TestAllTypesProto3()
 
-  response = conformance_pb2.ConformanceResponse()
-
   try:
     if request.WhichOneof('payload') == 'protobuf_payload':
       try:
         test_message.ParseFromString(request.protobuf_payload)
       except message.DecodeError as e:
         response.parse_error = str(e)
-        return response  
-      
+        return response
+
     elif request.WhichOneof('payload') == 'json_payload':
       try:
         ignore_unknown_fields = \
@@ -87,6 +137,13 @@ def do_test(request):
         response.parse_error = str(e)
         return response
 
+    elif request.WhichOneof('payload') == 'text_payload':
+      try:
+        text_format.Parse(request.text_payload, test_message)
+      except Exception as e:
+        response.parse_error = str(e)
+        return response
+
     else:
       raise ProtocolError("Request didn't have payload.")
 
@@ -97,12 +154,15 @@ def do_test(request):
       response.protobuf_payload = test_message.SerializeToString()
 
     elif request.requested_output_format == conformance_pb2.JSON:
-      try: 
+      try:
         response.json_payload = json_format.MessageToJson(test_message)
       except Exception as e:
         response.serialize_error = str(e)
         return response
 
+    elif request.requested_output_format == conformance_pb2.TEXT_FORMAT:
+      response.text_payload = text_format.MessageToString(test_message)
+
   except Exception as e:
     response.runtime_error = str(e)
 

+ 67 - 68
conformance/conformance_test.cc

@@ -80,6 +80,16 @@ ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
       break;
     }
 
+    case conformance::JSPB: {
+      request_.set_jspb_payload(input);
+      break;
+    }
+
+    case conformance::TEXT_FORMAT: {
+      request_.set_text_payload(input);
+      break;
+    }
+
     default:
       GOOGLE_LOG(FATAL) << "Unspecified input format";
   }
@@ -126,6 +136,8 @@ string ConformanceTestSuite::ConformanceRequestSetting::
       return "ProtobufInput";
     case conformance::JSON:
       return "JsonInput";
+    case conformance::TEXT_FORMAT:
+      return "TextFormatInput";
     default:
       GOOGLE_LOG(FATAL) << "Unspecified output format";
   }
@@ -139,21 +151,14 @@ string ConformanceTestSuite::ConformanceRequestSetting::
       return "ProtobufOutput";
     case conformance::JSON:
       return "JsonOutput";
+    case conformance::TEXT_FORMAT:
+      return "TextFormatOutput";
     default:
       GOOGLE_LOG(FATAL) << "Unspecified output format";
   }
   return "";
 }
 
-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) {
   if (expected_to_fail_.erase(test_name) != 0) {
     StringAppendF(&output_,
@@ -215,23 +220,27 @@ void ConformanceTestSuite::RunValidInputTest(
 void ConformanceTestSuite::RunValidBinaryInputTest(
     const ConformanceRequestSetting& setting,
     const string& equivalent_wire_format) {
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  RunTest(setting.GetTestName(), request, &response);
+  VerifyResponse(setting, equivalent_wire_format, response, true);
+}
+
+void ConformanceTestSuite::VerifyResponse(
+    const ConformanceRequestSetting& setting,
+    const string& equivalent_wire_format,
+    const ConformanceResponse& response,
+    bool need_report_success) {
+  Message* test_message = setting.GetTestMessage();
+  const ConformanceRequest& request = setting.GetRequest();
   const string& test_name = setting.GetTestName();
   ConformanceLevel level = setting.GetLevel();
-
   Message* reference_message = setting.GetTestMessage();
+
   GOOGLE_CHECK(
       reference_message->ParseFromString(equivalent_wire_format))
           << "Failed to parse wire data for test case: " << test_name;
 
-  const ConformanceRequest& request = setting.GetRequest();
-  ConformanceResponse response;
-
-  RunTest(test_name, request, &response);
-
-  Message* test_message = setting.GetTestMessage();
-
-  WireFormat requested_output = request.requested_output_format();
-
   switch (response.result_case()) {
     case ConformanceResponse::RESULT_NOT_SET:
       ReportFailure(test_name, level, request, response,
@@ -249,53 +258,8 @@ void ConformanceTestSuite::RunValidBinaryInputTest(
       ReportSkip(test_name, request, response);
       return;
 
-    case ConformanceResponse::kJsonPayload: {
-      if (requested_output != conformance::JSON) {
-        ReportFailure(
-            test_name, level, request, response,
-            "Test was asked for protobuf output but provided JSON instead.");
-        return;
-      }
-      string binary_protobuf;
-      Status status =
-          JsonToBinaryString(type_resolver_.get(), type_url_,
-                             response.json_payload(), &binary_protobuf);
-      if (!status.ok()) {
-        ReportFailure(test_name, level, request, response,
-                      "JSON output we received from test was unparseable.");
-        return;
-      }
-
-      if (!test_message->ParseFromString(binary_protobuf)) {
-        ReportFailure(test_name, level, request, response,
-                    "INTERNAL ERROR: internal JSON->protobuf transcode "
-                    "yielded unparseable proto.");
-        return;
-      }
-
-      break;
-    }
-
-    case ConformanceResponse::kProtobufPayload: {
-      if (requested_output != conformance::PROTOBUF) {
-        ReportFailure(
-            test_name, level, request, response,
-            "Test was asked for JSON output but provided protobuf instead.");
-        return;
-      }
-
-      if (!test_message->ParseFromString(response.protobuf_payload())) {
-        ReportFailure(test_name, level, request, response,
-                   "Protobuf output we received from test was unparseable.");
-        return;
-      }
-
-      break;
-    }
-
     default:
-      GOOGLE_LOG(FATAL) << test_name << ": unknown payload type: "
-                        << response.result_case();
+      if (!ParseResponse(response, setting, test_message)) return;
   }
 
   MessageDifferencer differencer;
@@ -308,7 +272,9 @@ void ConformanceTestSuite::RunValidBinaryInputTest(
   bool check;
   check = differencer.Compare(*reference_message, *test_message);
   if (check) {
-    ReportSuccess(test_name);
+    if (need_report_success) {
+      ReportSuccess(test_name);
+    }
   } else {
     ReportFailure(test_name, level, request, response,
                   "Output was not equivalent to reference message: %s.",
@@ -375,8 +341,29 @@ bool ConformanceTestSuite::CheckSetEmpty(
   }
 }
 
-bool ConformanceTestSuite::RunSuite(
-    ConformanceTestRunner* runner, std::string* output) {
+string ConformanceTestSuite::WireFormatToString(
+    WireFormat wire_format) {
+  switch (wire_format) {
+    case conformance::PROTOBUF:
+      return "PROTOBUF";
+    case conformance::JSON:
+      return "JSON";
+    case conformance::JSPB:
+      return "JSPB";
+    case conformance::TEXT_FORMAT:
+      return "TEXT_FORMAT";
+    case conformance::UNSPECIFIED:
+      return "UNSPECIFIED";
+    default:
+      GOOGLE_LOG(FATAL) << "unknown wire type: "
+                        << wire_format;
+  }
+  return "";
+}
+
+bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
+                                    std::string* output, const string& filename,
+                                    conformance::FailureSet* failure_list) {
   runner_ = runner;
   successes_ = 0;
   expected_failures_ = 0;
@@ -387,6 +374,18 @@ bool ConformanceTestSuite::RunSuite(
 
   output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n";
 
+  ConformanceRequest req;
+  ConformanceResponse res;
+  req.set_message_type(failure_list->GetTypeName());
+  req.set_protobuf_payload("");
+  req.set_requested_output_format(conformance::WireFormat::PROTOBUF);
+  RunTest("FindFailures", req, &res);
+  GOOGLE_CHECK(failure_list->MergeFromString(res.protobuf_payload()));
+  failure_list_filename_ = filename;
+  expected_to_fail_.clear();
+  for (const string& failure : failure_list->failure()) {
+    expected_to_fail_.insert(failure);
+  }
   RunSuiteImpl();
 
   bool ok = true;

+ 22 - 36
conformance/conformance_test.h

@@ -87,7 +87,6 @@ class ForkPipeRunner : public ConformanceTestRunner {
   static int Run(int argc, char *argv[],
                  ConformanceTestSuite* suite);
 
- private:
   ForkPipeRunner(const std::string &executable)
       : child_pid_(-1), executable_(executable) {}
 
@@ -97,24 +96,7 @@ class ForkPipeRunner : public ConformanceTestRunner {
                const std::string& request,
                std::string* response);
 
-  // TODO(haberman): make this work on Windows, instead of using these
-  // UNIX-specific APIs.
-  //
-  // There is a platform-agnostic API in
-  //    src/google/protobuf/compiler/subprocess.h
-  //
-  // However that API only supports sending a single message to the subprocess.
-  // We really want to be able to send messages and receive responses one at a
-  // time:
-  //
-  // 1. Spawning a new process for each test would take way too long for thousands
-  //    of tests and subprocesses like java that can take 100ms or more to start
-  //    up.
-  //
-  // 2. Sending all the tests in one big message and receiving all results in one
-  //    big message would take away our visibility about which test(s) caused a
-  //    crash or other fatal error.  It would also give us only a single failure
-  //    instead of all of them.
+ private:
   void SpawnTestProgram();
 
   void CheckedWrite(int fd, const void *buf, size_t len);
@@ -162,15 +144,6 @@ class ConformanceTestSuite {
 
   void SetVerbose(bool verbose) { verbose_ = verbose; }
 
-  // Sets the list of tests that are expected to fail when RunSuite() is called.
-  // RunSuite() will fail unless the set of failing tests is exactly the same
-  // as this list.
-  //
-  // The filename here is *only* used to create/format useful error messages for
-  // how to update the failure list.  We do NOT read this file at all.
-  void SetFailureList(const std::string& filename,
-                      const std::vector<std::string>& failure_list);
-
   // Whether to require the testee to pass RECOMMENDED tests. By default failing
   // a RECOMMENDED test case will not fail the entire suite but will only
   // generated a warning. If this flag is set to true, RECOMMENDED tests will
@@ -187,9 +160,12 @@ class ConformanceTestSuite {
   // Test output will be stored in "output".
   //
   // Returns true if the set of failing tests was exactly the same as the
-  // failure list.  If SetFailureList() was not called, returns true if all
-  // tests passed.
-  bool RunSuite(ConformanceTestRunner* runner, std::string* output);
+  // failure list.
+  // The filename here is *only* used to create/format useful error messages for
+  // how to update the failure list.  We do NOT read this file at all.
+  bool RunSuite(ConformanceTestRunner* runner, std::string* output,
+                const std::string& filename,
+                conformance::FailureSet* failure_list);
 
  protected:
   // Test cases are classified into a few categories:
@@ -237,6 +213,7 @@ class ConformanceTestSuite {
    protected:
     virtual string InputFormatString(conformance::WireFormat format) const;
     virtual string OutputFormatString(conformance::WireFormat format) const;
+    conformance::ConformanceRequest request_;
 
    private:
     ConformanceLevel level_;
@@ -244,11 +221,24 @@ class ConformanceTestSuite {
     ::conformance::WireFormat output_format_;
     const Message& prototype_message_;
     string test_name_;
-    conformance::ConformanceRequest request_;
   };
 
   bool CheckSetEmpty(const std::set<string>& set_to_check,
                      const std::string& write_to_file, const std::string& msg);
+  string WireFormatToString(conformance::WireFormat wire_format);
+
+  // Parse payload in the response to the given message. Returns true on
+  // success.
+  virtual bool ParseResponse(
+      const conformance::ConformanceResponse& response,
+      const ConformanceRequestSetting& setting,
+      Message* test_message) = 0;
+
+  void VerifyResponse(
+      const ConformanceRequestSetting& setting,
+      const string& equivalent_wire_format,
+      const conformance::ConformanceResponse& response,
+      bool need_report_success);
 
   void ReportSuccess(const std::string& test_name);
   void ReportFailure(const string& test_name,
@@ -295,10 +285,6 @@ class ConformanceTestSuite {
 
   // The set of tests that the testee opted out of;
   std::set<std::string> skipped_;
-
-  std::unique_ptr<google::protobuf::util::TypeResolver>
-      type_resolver_;
-  std::string type_url_;
 };
 
 }  // namespace protobuf

+ 23 - 5
conformance/conformance_test_runner.cc

@@ -84,7 +84,7 @@ namespace google {
 namespace protobuf {
 
 void ParseFailureList(const char *filename,
-                      std::vector<string>* failure_list) {
+                      conformance::FailureSet *failure_list) {
   std::ifstream infile(filename);
 
   if (!infile.is_open()) {
@@ -101,7 +101,7 @@ void ParseFailureList(const char *filename,
     line = line.substr(0, line.find("#"));
 
     if (!line.empty()) {
-      failure_list->push_back(line);
+      failure_list->add_failure(line);
     }
   }
 }
@@ -178,7 +178,7 @@ int ForkPipeRunner::Run(
     int argc, char *argv[], ConformanceTestSuite* suite) {
   char *program;
   string failure_list_filename;
-  std::vector<string> failure_list;
+  conformance::FailureSet failure_list;
 
   for (int arg = 1; arg < argc; ++arg) {
     if (strcmp(argv[arg], "--failure_list") == 0) {
@@ -201,17 +201,35 @@ int ForkPipeRunner::Run(
     }
   }
 
-  suite->SetFailureList(failure_list_filename, failure_list);
   ForkPipeRunner runner(program);
 
   std::string output;
-  bool ok =  suite->RunSuite(&runner, &output);
+  bool ok =
+      suite->RunSuite(&runner, &output, failure_list_filename, &failure_list);
 
   fwrite(output.c_str(), 1, output.size(), stderr);
 
   return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
+// TODO(haberman): make this work on Windows, instead of using these
+// UNIX-specific APIs.
+//
+// There is a platform-agnostic API in
+//    src/google/protobuf/compiler/subprocess.h
+//
+// However that API only supports sending a single message to the subprocess.
+// We really want to be able to send messages and receive responses one at a
+// time:
+//
+// 1. Spawning a new process for each test would take way too long for thousands
+//    of tests and subprocesses like java that can take 100ms or more to start
+//    up.
+//
+// 2. Sending all the tests in one big message and receiving all results in one
+//    big message would take away our visibility about which test(s) caused a
+//    crash or other fatal error.  It would also give us only a single failure
+//    instead of all of them.
 void ForkPipeRunner::SpawnTestProgram() {
   int toproc_pipe_fd[2];
   int fromproc_pipe_fd[2];

+ 0 - 20
conformance/failure_list_cpp.txt

@@ -34,23 +34,3 @@ Recommended.Proto3.JsonInput.TrailingCommaInAnObject
 Recommended.Proto3.JsonInput.TrailingCommaInAnObjectWithNewlines
 Recommended.Proto3.JsonInput.TrailingCommaInAnObjectWithSpace
 Recommended.Proto3.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
-Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
-Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.BOOL
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.ENUM
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT64
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT64
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT64
-Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
-Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.BOOL
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.ENUM
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT64
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64

+ 1 - 28
conformance/failure_list_php_c.txt

@@ -5,6 +5,7 @@ Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
+Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
 Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
 Recommended.Proto3.JsonInput.MapFieldValueIsNull
 Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput
@@ -22,26 +23,6 @@ Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
-Required.Proto3.JsonInput.Any.JsonOutput
-Required.Proto3.JsonInput.Any.ProtobufOutput
-Required.Proto3.JsonInput.AnyNested.JsonOutput
-Required.Proto3.JsonInput.AnyNested.ProtobufOutput
-Required.Proto3.JsonInput.AnyUnorderedTypeTag.JsonOutput
-Required.Proto3.JsonInput.AnyUnorderedTypeTag.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithDuration.JsonOutput
-Required.Proto3.JsonInput.AnyWithDuration.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithFieldMask.JsonOutput
-Required.Proto3.JsonInput.AnyWithFieldMask.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithInt32ValueWrapper.JsonOutput
-Required.Proto3.JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithStruct.JsonOutput
-Required.Proto3.JsonInput.AnyWithStruct.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithTimestamp.JsonOutput
-Required.Proto3.JsonInput.AnyWithTimestamp.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithValueForInteger.JsonOutput
-Required.Proto3.JsonInput.AnyWithValueForInteger.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithValueForJsonObject.JsonOutput
-Required.Proto3.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
 Required.Proto3.JsonInput.BoolMapField.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
@@ -50,22 +31,14 @@ Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
 Required.Proto3.JsonInput.DurationMinValue.JsonOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
-Required.Proto3.JsonInput.FieldMask.JsonOutput
-Required.Proto3.JsonInput.FieldMask.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
 Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
-Required.Proto3.JsonInput.StringFieldEscape.JsonOutput
-Required.Proto3.JsonInput.StringFieldEscape.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
-Required.Proto3.JsonInput.StringFieldUnicodeEscape.JsonOutput
-Required.Proto3.JsonInput.StringFieldUnicodeEscape.ProtobufOutput
-Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
-Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput

+ 1 - 0
conformance/failure_list_python.txt

@@ -19,3 +19,4 @@ Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_0
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
+Required.Proto3.JsonInput.EmptyFieldMask.ProtobufOutput

+ 1 - 32
conformance/failure_list_python_cpp.txt

@@ -20,35 +20,4 @@ Required.Proto3.JsonInput.FloatFieldTooLarge
 Required.Proto3.JsonInput.FloatFieldTooSmall
 Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
 Required.Proto3.JsonInput.TimestampJsonInputLowercaseT
-Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
-Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.BOOL
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.DOUBLE
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.ENUM
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.FIXED32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.FIXED64
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.FLOAT
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.INT64
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.SFIXED32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.SFIXED64
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.SINT64
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT32
-Required.Proto3.ProtobufInput.PrematureEofInPackedField.UINT64
-Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
-Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.BOOL
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.DOUBLE
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.ENUM
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.FIXED32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.FIXED64
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.FLOAT
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.INT64
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.SFIXED32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.SFIXED64
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
-Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
+Required.Proto3.JsonInput.EmptyFieldMask.ProtobufOutput

+ 1 - 75
conformance/failure_list_ruby.txt

@@ -5,8 +5,7 @@ Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
-Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
-Recommended.Proto3.JsonInput.DurationHasZeroFractionalDigit.Validator
+Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
 Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
 Recommended.Proto3.JsonInput.MapFieldValueIsNull
 Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
@@ -17,115 +16,42 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 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
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
-Required.Proto3.JsonInput.Any.JsonOutput
-Required.Proto3.JsonInput.Any.ProtobufOutput
-Required.Proto3.JsonInput.AnyNested.JsonOutput
-Required.Proto3.JsonInput.AnyNested.ProtobufOutput
-Required.Proto3.JsonInput.AnyUnorderedTypeTag.JsonOutput
-Required.Proto3.JsonInput.AnyUnorderedTypeTag.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithDuration.JsonOutput
-Required.Proto3.JsonInput.AnyWithDuration.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithFieldMask.JsonOutput
-Required.Proto3.JsonInput.AnyWithFieldMask.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithInt32ValueWrapper.JsonOutput
-Required.Proto3.JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithStruct.JsonOutput
-Required.Proto3.JsonInput.AnyWithStruct.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithTimestamp.JsonOutput
-Required.Proto3.JsonInput.AnyWithTimestamp.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithValueForInteger.JsonOutput
-Required.Proto3.JsonInput.AnyWithValueForInteger.ProtobufOutput
-Required.Proto3.JsonInput.AnyWithValueForJsonObject.JsonOutput
-Required.Proto3.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
-Required.Proto3.JsonInput.DurationMaxValue.JsonOutput
-Required.Proto3.JsonInput.DurationMaxValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationMinValue.JsonOutput
-Required.Proto3.JsonInput.DurationMinValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
-Required.Proto3.JsonInput.DurationRepeatedValue.ProtobufOutput
-Required.Proto3.JsonInput.FieldMask.JsonOutput
-Required.Proto3.JsonInput.FieldMask.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
 Required.Proto3.JsonInput.OneofFieldDuplicate
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalBoolWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalBytesWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalDoubleWrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalDoubleWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalFloatWrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalFloatWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalInt32Wrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalInt32Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalInt64Wrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalInt64Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalStringWrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalStringWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalUint32Wrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalUint32Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalUint64Wrapper.JsonOutput
-Required.Proto3.JsonInput.OptionalUint64Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
 Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedBoolWrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedBoolWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedBytesWrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedBytesWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedFloatWrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedFloatWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedInt32Wrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedInt32Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedInt64Wrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedInt64Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedStringWrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedStringWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedUint32Wrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedUint32Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedUint64Wrapper.JsonOutput
-Required.Proto3.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
-Required.Proto3.JsonInput.Struct.JsonOutput
-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.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptFloat.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptInteger.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptObject.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptString.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptString.ProtobufOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput

+ 93 - 0
conformance/failure_list_ruby_mac.txt

@@ -0,0 +1,93 @@
+Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
+Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
+Recommended.FieldMaskTooManyUnderscore.JsonOutput
+Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
+Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
+Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
+Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
+Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
+Recommended.Proto3.JsonInput.MapFieldValueIsNull
+Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
+Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
+Recommended.Proto3.JsonInput.StringEndsWithEscapeChar
+Recommended.Proto3.JsonInput.StringFieldSurrogateInWrongOrder
+Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
+Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
+Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
+Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
+Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
+Required.DurationProtoInputTooLarge.JsonOutput
+Required.DurationProtoInputTooSmall.JsonOutput
+Required.Proto3.JsonInput.Any.JsonOutput
+Required.Proto3.JsonInput.Any.ProtobufOutput
+Required.Proto3.JsonInput.AnyNested.JsonOutput
+Required.Proto3.JsonInput.AnyNested.ProtobufOutput
+Required.Proto3.JsonInput.AnyUnorderedTypeTag.JsonOutput
+Required.Proto3.JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithDuration.JsonOutput
+Required.Proto3.JsonInput.AnyWithDuration.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithFieldMask.JsonOutput
+Required.Proto3.JsonInput.AnyWithFieldMask.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+Required.Proto3.JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithStruct.JsonOutput
+Required.Proto3.JsonInput.AnyWithStruct.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithTimestamp.JsonOutput
+Required.Proto3.JsonInput.AnyWithTimestamp.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithValueForInteger.JsonOutput
+Required.Proto3.JsonInput.AnyWithValueForInteger.ProtobufOutput
+Required.Proto3.JsonInput.AnyWithValueForJsonObject.JsonOutput
+Required.Proto3.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
+Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
+Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
+Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
+Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
+Required.Proto3.JsonInput.DurationMinValue.JsonOutput
+Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
+Required.Proto3.JsonInput.FieldMask.JsonOutput
+Required.Proto3.JsonInput.FieldMask.ProtobufOutput
+Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
+Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
+Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
+Required.Proto3.JsonInput.OneofFieldDuplicate
+Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalDoubleWrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalFloatWrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalInt32Wrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalInt64Wrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalStringWrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalUint32Wrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalUint64Wrapper.JsonOutput
+Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
+Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+Required.Proto3.JsonInput.RepeatedBoolWrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedBytesWrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedDoubleWrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedFloatWrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedInt32Wrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedInt64Wrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedStringWrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedUint32Wrapper.JsonOutput
+Required.Proto3.JsonInput.RepeatedUint64Wrapper.JsonOutput
+Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
+Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
+Required.Proto3.JsonInput.TimestampJsonInputTooSmall
+Required.Proto3.JsonInput.TimestampMinValue.JsonOutput
+Required.Proto3.JsonInput.TimestampMinValue.ProtobufOutput
+Required.Proto3.JsonInput.TimestampRepeatedValue.JsonOutput
+Required.Proto3.JsonInput.TimestampRepeatedValue.ProtobufOutput
+Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
+Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
+Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
+Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
+Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
+Required.TimestampProtoInputTooLarge.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

+ 20 - 20
csharp/Google.Protobuf.Tools.nuspec

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <package>
   <metadata>
     <id>Google.Protobuf.Tools</id>
@@ -16,24 +16,24 @@
     <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
   </metadata>
   <files>
-    <file src="protoc\windows_x86\protoc.exe" target="tools\windows_x86\protoc.exe" />
-    <file src="protoc\windows_x64\protoc.exe" target="tools\windows_x64\protoc.exe" />
-    <file src="protoc\linux_x86\protoc" target="tools\linux_x86\protoc" />
-    <file src="protoc\linux_x64\protoc" target="tools\linux_x64\protoc" />
-    <file src="protoc\macosx_x86\protoc" target="tools\macosx_x86\protoc" />
-    <file src="protoc\macosx_x64\protoc" target="tools\macosx_x64\protoc" />
-    <file src="..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
-    <file src="..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
-    <file src="Google.Protobuf.Tools.targets" target="buildCrossTargeting" />
-    <file src="Google.Protobuf.Tools.targets" target="build" />
+    <file src="protoc\windows_x86\protoc.exe" target="tools\windows_x86\protoc.exe"/>
+    <file src="protoc\windows_x64\protoc.exe" target="tools\windows_x64\protoc.exe"/>
+    <file src="protoc\linux_x86\protoc" target="tools\linux_x86\protoc"/>
+    <file src="protoc\linux_x64\protoc" target="tools\linux_x64\protoc"/>
+    <file src="protoc\macosx_x86\protoc" target="tools\macosx_x86\protoc"/>
+    <file src="protoc\macosx_x64\protoc" target="tools\macosx_x64\protoc"/>
+    <file src="..\src\google\protobuf\any.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\api.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\duration.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\empty.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\source_context.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\struct.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\type.proto" target="tools\google\protobuf"/>
+    <file src="..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf"/>
+    <file src="Google.Protobuf.Tools.targets" target="buildCrossTargeting"/>
+    <file src="Google.Protobuf.Tools.targets" target="build"/>
   </files>
 </package>

+ 480 - 19
csharp/src/Google.Protobuf.Conformance/Conformance.cs

@@ -24,26 +24,35 @@ namespace Conformance {
     static ConformanceReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2Ui1QEKEkNvbmZvcm1h",
-            "bmNlUmVxdWVzdBIaChBwcm90b2J1Zl9wYXlsb2FkGAEgASgMSAASFgoManNv",
-            "bl9wYXlsb2FkGAIgASgJSAASOAoXcmVxdWVzdGVkX291dHB1dF9mb3JtYXQY",
-            "AyABKA4yFy5jb25mb3JtYW5jZS5XaXJlRm9ybWF0EhQKDG1lc3NhZ2VfdHlw",
-            "ZRgEIAEoCRIwCg10ZXN0X2NhdGVnb3J5GAUgASgOMhkuY29uZm9ybWFuY2Uu",
-            "VGVzdENhdGVnb3J5QgkKB3BheWxvYWQisQEKE0NvbmZvcm1hbmNlUmVzcG9u",
-            "c2USFQoLcGFyc2VfZXJyb3IYASABKAlIABIZCg9zZXJpYWxpemVfZXJyb3IY",
-            "BiABKAlIABIXCg1ydW50aW1lX2Vycm9yGAIgASgJSAASGgoQcHJvdG9idWZf",
-            "cGF5bG9hZBgDIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgEIAEoCUgAEhEKB3Nr",
-            "aXBwZWQYBSABKAlIAEIICgZyZXN1bHQqNQoKV2lyZUZvcm1hdBIPCgtVTlNQ",
-            "RUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoESlNPThACKmoKDFRlc3RDYXRl",
-            "Z29yeRIUChBVTlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RFU1QQARIN",
-            "CglKU09OX1RFU1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BBUlNJTkdf",
-            "VEVTVBADQiEKH2NvbS5nb29nbGUucHJvdG9idWYuY29uZm9ybWFuY2ViBnBy",
-            "b3RvMw=="));
+            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiHQoKRmFpbHVyZVNl",
+            "dBIPCgdmYWlsdXJlGAEgAygJIsUCChJDb25mb3JtYW5jZVJlcXVlc3QSGgoQ",
+            "cHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgCIAEo",
+            "CUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9hZBgI",
+            "IAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0GAMgASgOMhcuY29u",
+            "Zm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5cGUYBCABKAkSMAoN",
+            "dGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNlLlRlc3RDYXRlZ29y",
+            "eRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsyHy5jb25mb3JtYW5j",
+            "ZS5Kc3BiRW5jb2RpbmdDb25maWdCCQoHcGF5bG9hZCLhAQoTQ29uZm9ybWFu",
+            "Y2VSZXNwb25zZRIVCgtwYXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6",
+            "ZV9lcnJvchgGIAEoCUgAEhcKDXJ1bnRpbWVfZXJyb3IYAiABKAlIABIaChBw",
+            "cm90b2J1Zl9wYXlsb2FkGAMgASgMSAASFgoManNvbl9wYXlsb2FkGAQgASgJ",
+            "SAASEQoHc2tpcHBlZBgFIAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgA",
+            "EhYKDHRleHRfcGF5bG9hZBgIIAEoCUgAQggKBnJlc3VsdCI3ChJKc3BiRW5j",
+            "b2RpbmdDb25maWcSIQoZdXNlX2pzcGJfYXJyYXlfYW55X2Zvcm1hdBgBIAEo",
+            "CCpQCgpXaXJlRm9ybWF0Eg8KC1VOU1BFQ0lGSUVEEAASDAoIUFJPVE9CVUYQ",
+            "ARIICgRKU09OEAISCAoESlNQQhADEg8KC1RFWFRfRk9STUFUEAQqjwEKDFRl",
+            "c3RDYXRlZ29yeRIUChBVTlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RF",
+            "U1QQARINCglKU09OX1RFU1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BB",
+            "UlNJTkdfVEVTVBADEg0KCUpTUEJfVEVTVBAEEhQKEFRFWFRfRk9STUFUX1RF",
+            "U1QQBUIhCh9jb20uZ29vZ2xlLnByb3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90",
+            "bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.TestCategory), }, new pbr::GeneratedClrTypeInfo[] {
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat", "MessageType", "TestCategory" }, new[]{ "Payload" }, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null)
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.FailureSet), global::Conformance.FailureSet.Parser, new[]{ "Failure" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "JspbPayload", "TextPayload", "RequestedOutputFormat", "MessageType", "TestCategory", "JspbEncodingOptions" }, new[]{ "Payload" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.JspbEncodingConfig), global::Conformance.JspbEncodingConfig.Parser, new[]{ "UseJspbArrayAnyFormat" }, null, null, null)
           }));
     }
     #endregion
@@ -54,6 +63,11 @@ namespace Conformance {
     [pbr::OriginalName("UNSPECIFIED")] Unspecified = 0,
     [pbr::OriginalName("PROTOBUF")] Protobuf = 1,
     [pbr::OriginalName("JSON")] Json = 2,
+    /// <summary>
+    /// Google internal only. Opensource testees just skip it.
+    /// </summary>
+    [pbr::OriginalName("JSPB")] Jspb = 3,
+    [pbr::OriginalName("TEXT_FORMAT")] TextFormat = 4,
   }
 
   public enum TestCategory {
@@ -74,11 +88,148 @@ namespace Conformance {
     /// for more detail.
     /// </summary>
     [pbr::OriginalName("JSON_IGNORE_UNKNOWN_PARSING_TEST")] JsonIgnoreUnknownParsingTest = 3,
+    /// <summary>
+    /// Test jspb wire format. Google internal only. Opensource testees just skip it.
+    /// </summary>
+    [pbr::OriginalName("JSPB_TEST")] JspbTest = 4,
+    /// <summary>
+    /// Test text format. For cpp, java and python, testees can already deal with
+    /// this type. Testees of other languages can simply skip it.
+    /// </summary>
+    [pbr::OriginalName("TEXT_FORMAT_TEST")] TextFormatTest = 5,
   }
 
   #endregion
 
   #region Messages
+  /// <summary>
+  /// The conformance runner will request a list of failures as the first request.
+  /// This will be known by message_type == "conformance.FailureSet", a conformance
+  /// test should return a serialized FailureSet in protobuf_payload.
+  /// </summary>
+  public sealed partial class FailureSet : pb::IMessage<FailureSet> {
+    private static readonly pb::MessageParser<FailureSet> _parser = new pb::MessageParser<FailureSet>(() => new FailureSet());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<FailureSet> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FailureSet() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FailureSet(FailureSet other) : this() {
+      failure_ = other.failure_.Clone();
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public FailureSet Clone() {
+      return new FailureSet(this);
+    }
+
+    /// <summary>Field number for the "failure" field.</summary>
+    public const int FailureFieldNumber = 1;
+    private static readonly pb::FieldCodec<string> _repeated_failure_codec
+        = pb::FieldCodec.ForString(10);
+    private readonly pbc::RepeatedField<string> failure_ = new pbc::RepeatedField<string>();
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public pbc::RepeatedField<string> Failure {
+      get { return failure_; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as FailureSet);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(FailureSet other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!failure_.Equals(other.failure_)) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= failure_.GetHashCode();
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb::CodedOutputStream output) {
+      failure_.WriteTo(output, _repeated_failure_codec);
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      size += failure_.CalculateSize(_repeated_failure_codec);
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(FailureSet other) {
+      if (other == null) {
+        return;
+      }
+      failure_.Add(other.failure_);
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            if (!pb::UnknownFieldSet.MergeFieldFrom(ref _unknownFields, input)) {
+              return;
+            }
+            break;
+          case 10: {
+            failure_.AddEntriesFrom(input, _repeated_failure_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
   /// <summary>
   /// Represents a single test case's input.  The testee should:
   ///
@@ -94,7 +245,7 @@ namespace Conformance {
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[0]; }
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[1]; }
     }
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -114,6 +265,7 @@ namespace Conformance {
       requestedOutputFormat_ = other.requestedOutputFormat_;
       messageType_ = other.messageType_;
       testCategory_ = other.testCategory_;
+      jspbEncodingOptions_ = other.jspbEncodingOptions_ != null ? other.jspbEncodingOptions_.Clone() : null;
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
@@ -121,6 +273,12 @@ namespace Conformance {
         case PayloadOneofCase.JsonPayload:
           JsonPayload = other.JsonPayload;
           break;
+        case PayloadOneofCase.JspbPayload:
+          JspbPayload = other.JspbPayload;
+          break;
+        case PayloadOneofCase.TextPayload:
+          TextPayload = other.TextPayload;
+          break;
       }
 
       _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
@@ -153,6 +311,31 @@ namespace Conformance {
       }
     }
 
+    /// <summary>Field number for the "jspb_payload" field.</summary>
+    public const int JspbPayloadFieldNumber = 7;
+    /// <summary>
+    /// Google internal only.  Opensource testees just skip it.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string JspbPayload {
+      get { return payloadCase_ == PayloadOneofCase.JspbPayload ? (string) payload_ : ""; }
+      set {
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        payloadCase_ = PayloadOneofCase.JspbPayload;
+      }
+    }
+
+    /// <summary>Field number for the "text_payload" field.</summary>
+    public const int TextPayloadFieldNumber = 8;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string TextPayload {
+      get { return payloadCase_ == PayloadOneofCase.TextPayload ? (string) payload_ : ""; }
+      set {
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        payloadCase_ = PayloadOneofCase.TextPayload;
+      }
+    }
+
     /// <summary>Field number for the "requested_output_format" field.</summary>
     public const int RequestedOutputFormatFieldNumber = 3;
     private global::Conformance.WireFormat requestedOutputFormat_ = 0;
@@ -199,12 +382,28 @@ namespace Conformance {
       }
     }
 
+    /// <summary>Field number for the "jspb_encoding_options" field.</summary>
+    public const int JspbEncodingOptionsFieldNumber = 6;
+    private global::Conformance.JspbEncodingConfig jspbEncodingOptions_;
+    /// <summary>
+    /// Specify details for how to encode jspb.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public global::Conformance.JspbEncodingConfig JspbEncodingOptions {
+      get { return jspbEncodingOptions_; }
+      set {
+        jspbEncodingOptions_ = value;
+      }
+    }
+
     private object payload_;
     /// <summary>Enum of possible cases for the "payload" oneof.</summary>
     public enum PayloadOneofCase {
       None = 0,
       ProtobufPayload = 1,
       JsonPayload = 2,
+      JspbPayload = 7,
+      TextPayload = 8,
     }
     private PayloadOneofCase payloadCase_ = PayloadOneofCase.None;
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -233,9 +432,12 @@ namespace Conformance {
       }
       if (ProtobufPayload != other.ProtobufPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
+      if (JspbPayload != other.JspbPayload) return false;
+      if (TextPayload != other.TextPayload) return false;
       if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
       if (MessageType != other.MessageType) return false;
       if (TestCategory != other.TestCategory) return false;
+      if (!object.Equals(JspbEncodingOptions, other.JspbEncodingOptions)) return false;
       if (PayloadCase != other.PayloadCase) return false;
       return Equals(_unknownFields, other._unknownFields);
     }
@@ -245,9 +447,12 @@ namespace Conformance {
       int hash = 1;
       if (payloadCase_ == PayloadOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
       if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
+      if (payloadCase_ == PayloadOneofCase.JspbPayload) hash ^= JspbPayload.GetHashCode();
+      if (payloadCase_ == PayloadOneofCase.TextPayload) hash ^= TextPayload.GetHashCode();
       if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
       if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
       if (TestCategory != 0) hash ^= TestCategory.GetHashCode();
+      if (jspbEncodingOptions_ != null) hash ^= JspbEncodingOptions.GetHashCode();
       hash ^= (int) payloadCase_;
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
@@ -282,6 +487,18 @@ namespace Conformance {
         output.WriteRawTag(40);
         output.WriteEnum((int) TestCategory);
       }
+      if (jspbEncodingOptions_ != null) {
+        output.WriteRawTag(50);
+        output.WriteMessage(JspbEncodingOptions);
+      }
+      if (payloadCase_ == PayloadOneofCase.JspbPayload) {
+        output.WriteRawTag(58);
+        output.WriteString(JspbPayload);
+      }
+      if (payloadCase_ == PayloadOneofCase.TextPayload) {
+        output.WriteRawTag(66);
+        output.WriteString(TextPayload);
+      }
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
       }
@@ -296,6 +513,12 @@ namespace Conformance {
       if (payloadCase_ == PayloadOneofCase.JsonPayload) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonPayload);
       }
+      if (payloadCase_ == PayloadOneofCase.JspbPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JspbPayload);
+      }
+      if (payloadCase_ == PayloadOneofCase.TextPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TextPayload);
+      }
       if (RequestedOutputFormat != 0) {
         size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RequestedOutputFormat);
       }
@@ -305,6 +528,9 @@ namespace Conformance {
       if (TestCategory != 0) {
         size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) TestCategory);
       }
+      if (jspbEncodingOptions_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(JspbEncodingOptions);
+      }
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
       }
@@ -325,6 +551,12 @@ namespace Conformance {
       if (other.TestCategory != 0) {
         TestCategory = other.TestCategory;
       }
+      if (other.jspbEncodingOptions_ != null) {
+        if (jspbEncodingOptions_ == null) {
+          JspbEncodingOptions = new global::Conformance.JspbEncodingConfig();
+        }
+        JspbEncodingOptions.MergeFrom(other.JspbEncodingOptions);
+      }
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
@@ -332,6 +564,12 @@ namespace Conformance {
         case PayloadOneofCase.JsonPayload:
           JsonPayload = other.JsonPayload;
           break;
+        case PayloadOneofCase.JspbPayload:
+          JspbPayload = other.JspbPayload;
+          break;
+        case PayloadOneofCase.TextPayload:
+          TextPayload = other.TextPayload;
+          break;
       }
 
       _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
@@ -367,6 +605,21 @@ namespace Conformance {
             TestCategory = (global::Conformance.TestCategory) input.ReadEnum();
             break;
           }
+          case 50: {
+            if (jspbEncodingOptions_ == null) {
+              JspbEncodingOptions = new global::Conformance.JspbEncodingConfig();
+            }
+            input.ReadMessage(JspbEncodingOptions);
+            break;
+          }
+          case 58: {
+            JspbPayload = input.ReadString();
+            break;
+          }
+          case 66: {
+            TextPayload = input.ReadString();
+            break;
+          }
         }
       }
     }
@@ -384,7 +637,7 @@ namespace Conformance {
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[1]; }
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[2]; }
     }
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -420,6 +673,12 @@ namespace Conformance {
         case ResultOneofCase.Skipped:
           Skipped = other.Skipped;
           break;
+        case ResultOneofCase.JspbPayload:
+          JspbPayload = other.JspbPayload;
+          break;
+        case ResultOneofCase.TextPayload:
+          TextPayload = other.TextPayload;
+          break;
       }
 
       _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
@@ -525,6 +784,37 @@ namespace Conformance {
       }
     }
 
+    /// <summary>Field number for the "jspb_payload" field.</summary>
+    public const int JspbPayloadFieldNumber = 7;
+    /// <summary>
+    /// If the input was successfully parsed and the requested output was JSPB,
+    /// serialize to JSPB and set it in this field. JSPB is google internal only
+    /// format. Opensource testees can just skip it.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string JspbPayload {
+      get { return resultCase_ == ResultOneofCase.JspbPayload ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.JspbPayload;
+      }
+    }
+
+    /// <summary>Field number for the "text_payload" field.</summary>
+    public const int TextPayloadFieldNumber = 8;
+    /// <summary>
+    /// If the input was successfully parsed and the requested output was
+    /// TEXT_FORMAT, serialize to TEXT_FORMAT and set it in this field.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string TextPayload {
+      get { return resultCase_ == ResultOneofCase.TextPayload ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.TextPayload;
+      }
+    }
+
     private object result_;
     /// <summary>Enum of possible cases for the "result" oneof.</summary>
     public enum ResultOneofCase {
@@ -535,6 +825,8 @@ namespace Conformance {
       ProtobufPayload = 3,
       JsonPayload = 4,
       Skipped = 5,
+      JspbPayload = 7,
+      TextPayload = 8,
     }
     private ResultOneofCase resultCase_ = ResultOneofCase.None;
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -567,6 +859,8 @@ namespace Conformance {
       if (ProtobufPayload != other.ProtobufPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
       if (Skipped != other.Skipped) return false;
+      if (JspbPayload != other.JspbPayload) return false;
+      if (TextPayload != other.TextPayload) return false;
       if (ResultCase != other.ResultCase) return false;
       return Equals(_unknownFields, other._unknownFields);
     }
@@ -580,6 +874,8 @@ namespace Conformance {
       if (resultCase_ == ResultOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
       if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (resultCase_ == ResultOneofCase.Skipped) hash ^= Skipped.GetHashCode();
+      if (resultCase_ == ResultOneofCase.JspbPayload) hash ^= JspbPayload.GetHashCode();
+      if (resultCase_ == ResultOneofCase.TextPayload) hash ^= TextPayload.GetHashCode();
       hash ^= (int) resultCase_;
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
@@ -618,6 +914,14 @@ namespace Conformance {
         output.WriteRawTag(50);
         output.WriteString(SerializeError);
       }
+      if (resultCase_ == ResultOneofCase.JspbPayload) {
+        output.WriteRawTag(58);
+        output.WriteString(JspbPayload);
+      }
+      if (resultCase_ == ResultOneofCase.TextPayload) {
+        output.WriteRawTag(66);
+        output.WriteString(TextPayload);
+      }
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
       }
@@ -644,6 +948,12 @@ namespace Conformance {
       if (resultCase_ == ResultOneofCase.Skipped) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(Skipped);
       }
+      if (resultCase_ == ResultOneofCase.JspbPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JspbPayload);
+      }
+      if (resultCase_ == ResultOneofCase.TextPayload) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TextPayload);
+      }
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
       }
@@ -674,6 +984,12 @@ namespace Conformance {
         case ResultOneofCase.Skipped:
           Skipped = other.Skipped;
           break;
+        case ResultOneofCase.JspbPayload:
+          JspbPayload = other.JspbPayload;
+          break;
+        case ResultOneofCase.TextPayload:
+          TextPayload = other.TextPayload;
+          break;
       }
 
       _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
@@ -713,6 +1029,151 @@ namespace Conformance {
             SerializeError = input.ReadString();
             break;
           }
+          case 58: {
+            JspbPayload = input.ReadString();
+            break;
+          }
+          case 66: {
+            TextPayload = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// Encoding options for jspb format.
+  /// </summary>
+  public sealed partial class JspbEncodingConfig : pb::IMessage<JspbEncodingConfig> {
+    private static readonly pb::MessageParser<JspbEncodingConfig> _parser = new pb::MessageParser<JspbEncodingConfig>(() => new JspbEncodingConfig());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<JspbEncodingConfig> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[3]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public JspbEncodingConfig() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public JspbEncodingConfig(JspbEncodingConfig other) : this() {
+      useJspbArrayAnyFormat_ = other.useJspbArrayAnyFormat_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public JspbEncodingConfig Clone() {
+      return new JspbEncodingConfig(this);
+    }
+
+    /// <summary>Field number for the "use_jspb_array_any_format" field.</summary>
+    public const int UseJspbArrayAnyFormatFieldNumber = 1;
+    private bool useJspbArrayAnyFormat_;
+    /// <summary>
+    /// Encode the value field of Any as jspb array if ture, otherwise binary.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool UseJspbArrayAnyFormat {
+      get { return useJspbArrayAnyFormat_; }
+      set {
+        useJspbArrayAnyFormat_ = value;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as JspbEncodingConfig);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(JspbEncodingConfig other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (UseJspbArrayAnyFormat != other.UseJspbArrayAnyFormat) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (UseJspbArrayAnyFormat != false) hash ^= UseJspbArrayAnyFormat.GetHashCode();
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (UseJspbArrayAnyFormat != false) {
+        output.WriteRawTag(8);
+        output.WriteBool(UseJspbArrayAnyFormat);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (UseJspbArrayAnyFormat != false) {
+        size += 1 + 1;
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(JspbEncodingConfig other) {
+      if (other == null) {
+        return;
+      }
+      if (other.UseJspbArrayAnyFormat != false) {
+        UseJspbArrayAnyFormat = other.UseJspbArrayAnyFormat;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            if (!pb::UnknownFieldSet.MergeFieldFrom(ref _unknownFields, input)) {
+              return;
+            }
+            break;
+          case 8: {
+            UseJspbArrayAnyFormat = input.ReadBool();
+            break;
+          }
         }
       }
     }

File diff suppressed because it is too large
+ 160 - 156
csharp/src/Google.Protobuf.Test/TestProtos/TestMessagesProto3.cs


BIN
csharp/src/Google.Protobuf.Test/testprotos.pb


+ 3 - 2
csharp/src/Google.Protobuf/FieldMaskTree.cs

@@ -120,7 +120,8 @@ namespace Google.Protobuf
                     return this;
                 }
 
-                if (!node.Children.TryGetValue(part, out var childNode))
+                Node childNode;
+                if (!node.Children.TryGetValue(part, out childNode))
                 {
                     createNewBranch = true;
                     childNode = new Node();
@@ -361,4 +362,4 @@ namespace Google.Protobuf
             }
         }
     }
-}
+}

+ 3 - 2
csharp/src/Google.Protobuf/Google.Protobuf.csproj

@@ -1,10 +1,11 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <Description>C# runtime library for Protocol Buffers - Google's data interchange format.</Description>
     <Copyright>Copyright 2015, Google Inc.</Copyright>
     <AssemblyTitle>Google Protocol Buffers</AssemblyTitle>
     <VersionPrefix>3.6.1</VersionPrefix>
+    <LangVersion>6</LangVersion>
     <Authors>Google Inc.</Authors>
     <TargetFrameworks>netstandard1.0;net45</TargetFrameworks>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -29,7 +30,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="SourceLink.Create.CommandLine" Version="2.7.6" PrivateAssets="All" /> 
+    <PackageReference Include="SourceLink.Create.CommandLine" PrivateAssets="All" Version="2.7.6"/> 
   </ItemGroup>
 
 </Project>

+ 49 - 46
csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs

@@ -98,64 +98,65 @@ namespace Google.Protobuf.Reflection
                 }
             }
             return dictionary;
+        }
 
-            IDescriptor FindDescriptorForPath(IList<int> path)
+        private IDescriptor FindDescriptorForPath(IList<int> path)
+        {
+            // All complete declarations have an even, non-empty path length
+            // (There can be an empty path for a descriptor declaration, but that can't have any comments,
+            // so we currently ignore it.)
+            if (path.Count == 0 || (path.Count & 1) != 0)
             {
-                // All complete declarations have an even, non-empty path length
-                // (There can be an empty path for a descriptor declaration, but that can't have any comments,
-                // so we currently ignore it.)
-                if (path.Count == 0 || (path.Count & 1) != 0)
-                {
-                    return null;
-                }
-                IReadOnlyList<DescriptorBase> topLevelList = GetNestedDescriptorListForField(path[0]);
-                DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]);
+                return null;
+            }
+            IReadOnlyList<DescriptorBase> topLevelList = GetNestedDescriptorListForField(path[0]);
+            DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]);
 
-                for (int i = 2; current != null && i < path.Count; i += 2)
-                {
-                    var list = current.GetNestedDescriptorListForField(path[i]);
-                    current = GetDescriptorFromList(list, path[i + 1]);
-                }
-                return current;
+            for (int i = 2; current != null && i < path.Count; i += 2)
+            {
+                var list = current.GetNestedDescriptorListForField(path[i]);
+                current = GetDescriptorFromList(list, path[i + 1]);
             }
+            return current;
+        }
 
-            DescriptorBase GetDescriptorFromList(IReadOnlyList<DescriptorBase> list, int index)
+        private DescriptorBase GetDescriptorFromList(IReadOnlyList<DescriptorBase> list, int index)
+        {
+            // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor
+            // field.
+            if (list == null)
             {
-                // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor
-                // field.
-                if (list == null)
-                {
-                    return null;
-                }
-                // We *could* return null to silently continue, but this is basically data corruption.
-                if (index < 0 || index >= list.Count)
-                {
-                    // We don't have much extra information to give at this point unfortunately. If this becomes a problem,
-                    // we can pass in the complete path and report that and the file name.
-                    throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range");
-                }
-                return list[index];
+                return null;
+            }
+            // We *could* return null to silently continue, but this is basically data corruption.
+            if (index < 0 || index >= list.Count)
+            {
+                // We don't have much extra information to give at this point unfortunately. If this becomes a problem,
+                // we can pass in the complete path and report that and the file name.
+                throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range");
             }
+            return list[index];
+        }
 
-            IReadOnlyList<DescriptorBase> GetNestedDescriptorListForField(int fieldNumber)
+        private IReadOnlyList<DescriptorBase> GetNestedDescriptorListForField(int fieldNumber)
+        {
+            switch (fieldNumber)
             {
-                switch (fieldNumber)
-                {
-                    case FileDescriptorProto.ServiceFieldNumber:
-                        return (IReadOnlyList<DescriptorBase>) Services;
-                    case FileDescriptorProto.MessageTypeFieldNumber:
-                        return (IReadOnlyList<DescriptorBase>) MessageTypes;
-                    case FileDescriptorProto.EnumTypeFieldNumber:
-                        return (IReadOnlyList<DescriptorBase>) EnumTypes;
-                    default:
-                        return null;
-                }
+                case FileDescriptorProto.ServiceFieldNumber:
+                    return (IReadOnlyList<DescriptorBase>) Services;
+                case FileDescriptorProto.MessageTypeFieldNumber:
+                    return (IReadOnlyList<DescriptorBase>) MessageTypes;
+                case FileDescriptorProto.EnumTypeFieldNumber:
+                    return (IReadOnlyList<DescriptorBase>) EnumTypes;
+                default:
+                    return null;
             }
         }
 
         internal DescriptorDeclaration GetDeclaration(IDescriptor descriptor)
         {
-            declarations.Value.TryGetValue(descriptor, out var declaration);
+            DescriptorDeclaration declaration;
+            declarations.Value.TryGetValue(descriptor, out declaration);
             return declaration;
         }
 
@@ -191,7 +192,8 @@ namespace Google.Protobuf.Reflection
                     throw new DescriptorValidationException(@this, "Invalid public dependency index.");
                 }
                 string name = proto.Dependency[index];
-                if (!nameToFileMap.TryGetValue(name, out var file))
+                FileDescriptor file;
+                if (!nameToFileMap.TryGetValue(name, out file))
                 {
                     if (!allowUnknownDependencies)
                     {
@@ -414,7 +416,8 @@ namespace Google.Protobuf.Reflection
                 var dependencies = new List<FileDescriptor>();
                 foreach (var dependencyName in proto.Dependency)
                 {
-                    if (!descriptorsByName.TryGetValue(dependencyName, out var dependency))
+                    FileDescriptor dependency;
+                    if (!descriptorsByName.TryGetValue(dependencyName, out dependency))
                     {
                         throw new ArgumentException($"Dependency missing: {dependencyName}");
                     }

+ 12 - 3
csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs

@@ -60,13 +60,22 @@ namespace Google.Protobuf.Reflection
             if (descriptor.File.Proto.Syntax == "proto2")
             {
                 MethodInfo hasMethod = property.DeclaringType.GetRuntimeProperty("Has" + property.Name).GetMethod;
-                hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod ?? throw new ArgumentException("Not all required properties/methods are available"));
+                if (hasMethod == null) {
+                  throw new ArgumentException("Not all required properties/methods are available");
+                }
+                hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod);
                 MethodInfo clearMethod = property.DeclaringType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes);
-                clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod ?? throw new ArgumentException("Not all required properties/methods are available"));
+                if (clearMethod == null) {
+                  throw new ArgumentException("Not all required properties/methods are available");
+                }
+                clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod);
             }
             else
             {
-                hasDelegate = (_) => throw new InvalidOperationException("HasValue is not implemented for proto3 fields"); var clrType = property.PropertyType;
+                hasDelegate = message => {
+                  throw new InvalidOperationException("HasValue is not implemented for proto3 fields");
+                };
+                var clrType = property.PropertyType;
 
                 // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.) 
                 object defaultValue =

+ 1 - 1
csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs

@@ -308,7 +308,7 @@ namespace Google.Protobuf.WellKnownTypes
         /// <returns>true if the two timestamps refer to the same nanosecond</returns>
         public static bool operator ==(Timestamp a, Timestamp b)
         {
-            return ReferenceEquals(a, b) || (a is null ? (b is null ? true : false) : a.Equals(b));
+            return ReferenceEquals(a, b) || (ReferenceEquals(a, null) ? (ReferenceEquals(b, null) ? true : false) : a.Equals(b));
         }
 
         /// <summary>

+ 1 - 0
docs/third_party.md

@@ -89,6 +89,7 @@ These are projects we know about implementing Protocol Buffers for other program
 * Scala: http://code.google.com/p/protobuf-scala
 * Scala: https://github.com/SandroGrzicic/ScalaBuff
 * Scala: https://scalapb.github.io
+* Solidity: https://github.com/celer-network/pb3-gen-sol
 * Swift: https://github.com/alexeyxo/protobuf-swift
 * Swift: https://github.com/apple/swift-protobuf/
 * Vala: https://launchpad.net/protobuf-vala

+ 10 - 7
java/compatibility_tests/v2.5.0/test.sh

@@ -5,6 +5,9 @@ set -ex
 # Change to the script's directory.
 cd $(dirname $0)
 
+MAVEN_LOCAL_REPOSITORY=/var/maven_local_repository
+MVN="mvn --batch-mode -e -X -Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY"
+
 # Version of the tests (i.e., the version of protobuf from where we extracted
 # these tests).
 TEST_VERSION=`grep "^  <version>.*</version>" pom.xml | sed "s|  <version>\(.*\)</version>|\1|"`
@@ -59,7 +62,7 @@ echo "Running compatibility tests between $VERSION_NUMBER and $OLD_VERSION"
 # Build and install protobuf-java-$VERSION_NUMBER.jar
 [ -f ../../core/target/protobuf-java-$VERSION_NUMBER.jar ] || {
   pushd ../..
-  mvn install -Dmaven.test.skip=true
+  $MVN install -Dmaven.test.skip=true
   popd
 }
 
@@ -81,7 +84,7 @@ chmod +x protoc
 # Test A.1:
 #   protos: use new version
 #   more_protos: use old version
-mvn clean test \
+$MVN clean test \
   -Dprotobuf.test.source.path=$(pwd)/protobuf \
   -Dprotoc.path=$(pwd)/protoc \
   -Dprotos.protoc.path=$(pwd)/../../../src/protoc \
@@ -90,7 +93,7 @@ mvn clean test \
 # Test A.2:
 #   protos: use old version
 #   more_protos: use new version
-mvn clean test \
+$MVN clean test \
   -Dprotobuf.test.source.path=$(pwd)/protobuf \
   -Dprotoc.path=$(pwd)/protoc \
   -Dmore_protos.protoc.path=$(pwd)/../../../src/protoc \
@@ -103,12 +106,12 @@ mvn clean test \
 # make it easier to run binary compatibility test (where we will need to run
 # the jar files directly).
 cd deps
-mvn assembly:single
+$MVN assembly:single
 cd ..
 cp -f deps/target/compatibility-test-deps-${TEST_VERSION}-jar-with-dependencies.jar deps.jar
 
 # Build the old version of all 3 artifacts.
-mvn clean install -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/protoc -Dprotobuf.version=$OLD_VERSION
+$MVN clean install -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/protoc -Dprotobuf.version=$OLD_VERSION
 cp -f protos/target/compatibility-protos-${TEST_VERSION}.jar protos.jar
 cp -f more_protos/target/compatibility-more-protos-${TEST_VERSION}.jar more_protos.jar
 cp -f tests/target/compatibility-tests-${TEST_VERSION}.jar tests.jar
@@ -125,7 +128,7 @@ cd ..
 
 # Test B.2: update protos.jar only.
 cd protos
-mvn clean package -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/../../../../src/protoc -Dprotobuf.version=$VERSION_NUMBER
+$MVN clean package -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/../../../../src/protoc -Dprotobuf.version=$VERSION_NUMBER
 cd ..
 cd protobuf
 java -cp ../../../core/target/protobuf-java-$VERSION_NUMBER.jar:../protos/target/compatibility-protos-${TEST_VERSION}.jar:../more_protos.jar:../tests.jar:../deps.jar org.junit.runner.JUnitCore $TESTS
@@ -133,7 +136,7 @@ cd ..
 
 # Test B.3: update more_protos.jar only.
 cd more_protos
-mvn clean package -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/../../../../src/protoc -Dprotobuf.version=$VERSION_NUMBER
+$MVN clean package -Dmaven.test.skip=true -Dprotoc.path=$(pwd)/../../../../src/protoc -Dprotobuf.version=$VERSION_NUMBER
 cd ..
 cd protobuf
 java -cp ../../../core/target/protobuf-java-$VERSION_NUMBER.jar:../protos.jar:../more_protos/target/compatibility-more-protos-${TEST_VERSION}.jar:../tests.jar:../deps.jar org.junit.runner.JUnitCore $TESTS

+ 1 - 3
java/core/pom.xml

@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>com.google.protobuf</groupId>

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

@@ -45,7 +45,8 @@ import java.util.RandomAccess;
 final class BooleanArrayList extends AbstractProtobufList<Boolean>
     implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
 
-  private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
+  private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(new boolean[0], 0);
+
   static {
     EMPTY_LIST.makeImmutable();
   }

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

@@ -377,7 +377,7 @@ public abstract class CodedInputStream {
   /**
    * Set the maximum message recursion depth. In order to prevent malicious messages from causing
    * stack overflows, {@code CodedInputStream} limits how deeply messages may be nested. The default
-   * limit is 64.
+   * limit is 100.
    *
    * @return the old limit.
    */

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

@@ -32,7 +32,22 @@ package com.google.protobuf;
 
 import static com.google.protobuf.Internal.checkNotNull;
 
-import com.google.protobuf.DescriptorProtos.*;
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumOptions;
+import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
+import com.google.protobuf.DescriptorProtos.EnumValueOptions;
+import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FieldOptions;
+import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
+import com.google.protobuf.DescriptorProtos.FileOptions;
+import com.google.protobuf.DescriptorProtos.MessageOptions;
+import com.google.protobuf.DescriptorProtos.MethodDescriptorProto;
+import com.google.protobuf.DescriptorProtos.MethodOptions;
+import com.google.protobuf.DescriptorProtos.OneofDescriptorProto;
+import com.google.protobuf.DescriptorProtos.OneofOptions;
+import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto;
+import com.google.protobuf.DescriptorProtos.ServiceOptions;
 import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -1211,7 +1226,7 @@ public final class Descriptors {
       StringBuilder result = new StringBuilder(name.length());
       boolean isNextUpperCase = false;
       for (int i = 0; i < name.length(); i++) {
-        Character ch = name.charAt(i);
+        char ch = name.charAt(i);
         if (ch == '_') {
           isNextUpperCase = true;
         } else if (isNextUpperCase) {

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

@@ -45,7 +45,8 @@ import java.util.RandomAccess;
 final class DoubleArrayList extends AbstractProtobufList<Double>
     implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
 
-  private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
+  private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(new double[0], 0);
+
   static {
     EMPTY_LIST.makeImmutable();
   }

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

@@ -45,7 +45,8 @@ import java.util.RandomAccess;
 final class FloatArrayList extends AbstractProtobufList<Float>
     implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
 
-  private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
+  private static final FloatArrayList EMPTY_LIST = new FloatArrayList(new float[0], 0);
+
   static {
     EMPTY_LIST.makeImmutable();
   }

+ 9 - 0
java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java

@@ -1681,6 +1681,15 @@ public abstract class GeneratedMessageV3 extends AbstractMessage
       }
     }
 
+    @Override
+    public Message.Builder newBuilderForField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        return DynamicMessage.newBuilder(field.getMessageType());
+      } else {
+        return super.newBuilderForField(field);
+      }
+    }
+
     protected final void mergeExtensionFields(final ExtendableMessage other) {
       ensureExtensionsIsMutable();
       extensions.mergeFrom(other.extensions);

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

@@ -45,7 +45,8 @@ import java.util.RandomAccess;
 final class IntArrayList extends AbstractProtobufList<Integer>
     implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
 
-  private static final IntArrayList EMPTY_LIST = new IntArrayList();
+  private static final IntArrayList EMPTY_LIST = new IntArrayList(new int[0], 0);
+
   static {
     EMPTY_LIST.makeImmutable();
   }

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

@@ -45,7 +45,8 @@ import java.util.RandomAccess;
 final class LongArrayList extends AbstractProtobufList<Long>
     implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
 
-  private static final LongArrayList EMPTY_LIST = new LongArrayList();
+  private static final LongArrayList EMPTY_LIST = new LongArrayList(new long[0], 0);
+
   static {
     EMPTY_LIST.makeImmutable();
   }

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

@@ -37,7 +37,8 @@ import java.util.List;
 /** Implements {@link ProtobufList} for non-primitive and {@link String} types. */
 final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
 
-  private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
+  private static final ProtobufArrayList<Object> EMPTY_LIST =
+      new ProtobufArrayList<Object>(new ArrayList<Object>(0));
 
   static {
     EMPTY_LIST.makeImmutable();

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

@@ -1127,7 +1127,6 @@ public final class TextFormat {
     PARSER.merge(input, builder);
   }
 
-
   /**
    * Parse a text-format message from {@code input}.
    *
@@ -1167,7 +1166,6 @@ public final class TextFormat {
     PARSER.merge(input, extensionRegistry, builder);
   }
 
-
   /**
    * Parse a text-format message from {@code input}. Extensions will be recognized if they are
    * registered in {@code extensionRegistry}.
@@ -1187,7 +1185,6 @@ public final class TextFormat {
   }
 
 
-
   /**
    * Parser for text-format proto2 instances. This class is thread-safe. The implementation largely
    * follows google/protobuf/text_format.cc.
@@ -1217,36 +1214,6 @@ public final class TextFormat {
       FORBID_SINGULAR_OVERWRITES
     }
 
-    /**
-     * Determines how to deal with repeated values for singular Message fields. For example,
-     * given a field "foo" containing subfields "baz" and "qux":
-     *
-     * <ul>
-     *   <li>"foo { baz: 1 } foo { baz: 2 }", or
-     *   <li>"foo { baz: 1 } foo { qux: 2 }"
-     * </ul>
-     */
-    public enum MergingStyle {
-      /**
-       * Merge the values in standard protobuf fashion:
-       *
-       * <ul>
-       *   <li>"foo { baz: 2 }" and
-       *   <li>"foo { baz: 1, qux: 2 }", respectively.
-       * </ul>
-       */
-      RECURSIVE,
-      /**
-       * Later values overwrite ("clobber") previous values:
-       *
-       * <ul>
-       *   <li>"foo { baz: 2 }" and
-       *   <li>"foo { qux: 2 }", respectively.
-       * </ul>
-       */
-      NON_RECURSIVE
-    }
-
     private final boolean allowUnknownFields;
     private final boolean allowUnknownEnumValues;
     private final boolean allowUnknownExtensions;
@@ -1349,7 +1316,6 @@ public final class TextFormat {
     }
 
 
-
     private static final int BUFFER_SIZE = 4096;
 
     // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
@@ -1435,20 +1401,18 @@ public final class TextFormat {
       List<UnknownField> unknownFields = new ArrayList<UnknownField>();
 
       while (!tokenizer.atEnd()) {
-        mergeField(tokenizer, extensionRegistry, target, MergingStyle.RECURSIVE, unknownFields);
+        mergeField(tokenizer, extensionRegistry, target, unknownFields);
       }
 
       checkUnknownFields(unknownFields);
     }
 
 
-
     /** Parse a single field from {@code tokenizer} and merge it into {@code builder}. */
     private void mergeField(
         final Tokenizer tokenizer,
         final ExtensionRegistry extensionRegistry,
         final MessageReflection.MergeTarget target,
-        final MergingStyle mergingStyle,
         List<UnknownField> unknownFields)
         throws ParseException {
       mergeField(
@@ -1456,7 +1420,6 @@ public final class TextFormat {
           extensionRegistry,
           target,
           parseInfoTreeBuilder,
-          mergingStyle,
           unknownFields);
     }
 
@@ -1466,7 +1429,6 @@ public final class TextFormat {
         final ExtensionRegistry extensionRegistry,
         final MessageReflection.MergeTarget target,
         TextFormatParseInfoTree.Builder parseTreeBuilder,
-        final MergingStyle mergingStyle,
         List<UnknownField> unknownFields)
         throws ParseException {
       FieldDescriptor field = null;
@@ -1573,7 +1535,6 @@ public final class TextFormat {
               field,
               extension,
               childParseTreeBuilder,
-              mergingStyle,
               unknownFields);
         } else {
           consumeFieldValues(
@@ -1583,7 +1544,6 @@ public final class TextFormat {
               field,
               extension,
               parseTreeBuilder,
-              mergingStyle,
               unknownFields);
         }
       } else {
@@ -1595,7 +1555,6 @@ public final class TextFormat {
             field,
             extension,
             parseTreeBuilder,
-            mergingStyle,
             unknownFields);
       }
 
@@ -1620,7 +1579,6 @@ public final class TextFormat {
         final FieldDescriptor field,
         final ExtensionRegistry.ExtensionInfo extension,
         final TextFormatParseInfoTree.Builder parseTreeBuilder,
-        final MergingStyle mergingStyle,
         List<UnknownField> unknownFields)
         throws ParseException {
       // Support specifying repeated field values as a comma-separated list.
@@ -1635,7 +1593,6 @@ public final class TextFormat {
                 field,
                 extension,
                 parseTreeBuilder,
-                mergingStyle,
                 unknownFields);
             if (tokenizer.tryConsume("]")) {
               // End of list.
@@ -1652,7 +1609,6 @@ public final class TextFormat {
             field,
             extension,
             parseTreeBuilder,
-            mergingStyle,
             unknownFields);
       }
     }
@@ -1665,7 +1621,6 @@ public final class TextFormat {
         final FieldDescriptor field,
         final ExtensionRegistry.ExtensionInfo extension,
         final TextFormatParseInfoTree.Builder parseTreeBuilder,
-        final MergingStyle mergingStyle,
         List<UnknownField> unknownFields)
         throws ParseException {
       if (singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES
@@ -1698,18 +1653,9 @@ public final class TextFormat {
           endToken = "}";
         }
 
-        final MessageReflection.MergeTarget subField;
         Message defaultInstance = (extension == null) ? null : extension.defaultInstance;
-        switch (mergingStyle) {
-          case RECURSIVE:
-            subField = target.newMergeTargetForField(field, defaultInstance);
-            break;
-          case NON_RECURSIVE:
-            subField = target.newEmptyTargetForField(field, defaultInstance);
-            break;
-          default:
-            throw new AssertionError();
-        }
+        MessageReflection.MergeTarget subField =
+            target.newMergeTargetForField(field, defaultInstance);
 
         while (!tokenizer.tryConsume(endToken)) {
           if (tokenizer.atEnd()) {
@@ -1720,7 +1666,6 @@ public final class TextFormat {
               extensionRegistry,
               subField,
               parseTreeBuilder,
-              mergingStyle,
               unknownFields);
         }
 

+ 1 - 3
java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

@@ -391,14 +391,12 @@ final class UnsafeUtil {
   }
 
   /**
-   * Gets the field with the given name within the class, or {@code null} if not found. If found,
-   * the field is made accessible.
+   * Gets the field with the given name within the class, or {@code null} if not found.
    */
   private static Field field(Class<?> clazz, String fieldName) {
     Field field;
     try {
       field = clazz.getDeclaredField(fieldName);
-      field.setAccessible(true);
     } catch (Throwable t) {
       // Failed to access the fields.
       field = null;

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

@@ -1104,7 +1104,8 @@ final class Utf8 {
 
     private static int partialIsValidUtf8NonAscii(byte[] bytes, int index, int limit) {
       for (; ; ) {
-        int byte1, byte2;
+        int byte1;
+        int byte2;
 
         // Optimize for interior runs of ASCII bytes.
         do {

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

@@ -33,8 +33,10 @@ package com.google.protobuf;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
+import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import java.util.Arrays;
@@ -223,6 +225,17 @@ public class DynamicMessageTest extends TestCase {
     packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
   }
 
+  public void testGetBuilderForExtensionField() {
+    DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+    Message.Builder fieldBuilder =
+        builder.newBuilderForField(UnittestProto.optionalNestedMessageExtension.getDescriptor());
+    final int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(expected, fieldBuilder.build().getField(field));
+  }
+
   public void testDynamicMessageCopy() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);

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

@@ -578,6 +578,29 @@ public class GeneratedMessageTest extends TestCase {
     TestUtil.assertAllExtensionsSet(message);
   }
 
+  public void testGetBuilderForExtensionField() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    Message.Builder fieldBuilder =
+        builder.newBuilderForField(UnittestProto.optionalNestedMessageExtension.getDescriptor());
+    final int expected = 7432;
+    FieldDescriptor field =
+        NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER);
+    fieldBuilder.setField(field, expected);
+    assertEquals(expected, fieldBuilder.build().getField(field));
+  }
+
+
+  public void testGetBuilderForNonMessageExtensionField() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    try {
+      // This should throw an exception because the extension field is not a message.
+      builder.newBuilderForField(UnittestProto.optionalInt32Extension.getDescriptor());
+      fail("Exception was not thrown");
+    } catch (UnsupportedOperationException e) {
+      // This exception is expected.
+    }
+  }
+
   public void testExtensionRepeatedSetters() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestUtil.setAllExtensions(builder);

+ 1 - 3
java/pom.xml

@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
   <groupId>com.google.protobuf</groupId>

+ 10 - 7
java/util/pom.xml

@@ -1,7 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>com.google.protobuf</groupId>
@@ -24,6 +22,11 @@
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
     </dependency>
+    <dependency>
+      <groupId>com.google.errorprone</groupId>
+      <artifactId>error_prone_annotations</artifactId>
+      <version>2.3.2</version>
+    </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava-testlib</artifactId>
@@ -69,10 +72,10 @@
 
                 <!-- Generate additional test protos for this module -->
                 <exec executable="${protoc}">
-                  <arg value="--java_out=${generated.testsources.dir}" />
-                  <arg value="--proto_path=${protobuf.source.dir}" />
-                  <arg value="--proto_path=src/test/proto" />
-                  <arg value="src/test/proto/com/google/protobuf/util/json_test.proto" />
+                  <arg value="--java_out=${generated.testsources.dir}"/>
+                  <arg value="--proto_path=${protobuf.source.dir}"/>
+                  <arg value="--proto_path=src/test/proto"/>
+                  <arg value="src/test/proto/com/google/protobuf/util/json_test.proto"/>
                 </exec>
               </target>
             </configuration>

+ 23 - 7
java/util/src/main/java/com/google/protobuf/util/Durations.java

@@ -42,6 +42,7 @@ import static com.google.protobuf.util.Timestamps.NANOS_PER_MICROSECOND;
 import static com.google.protobuf.util.Timestamps.NANOS_PER_MILLISECOND;
 import static com.google.protobuf.util.Timestamps.NANOS_PER_SECOND;
 
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.protobuf.Duration;
 import java.text.ParseException;
 import java.util.Comparator;
@@ -91,8 +92,8 @@ public final class Durations {
   }
 
   /**
-   * Compares two durations. The value returned is identical to what would be returned by:
-   * {@code Durations.comparator().compare(x, y)}.
+   * Compares two durations. The value returned is identical to what would be returned by: {@code
+   * Durations.comparator().compare(x, y)}.
    *
    * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y};
    *     and a value greater than {@code 0} if {@code x > y}
@@ -151,6 +152,7 @@ public final class Durations {
    * @throws IllegalArgumentException if {@code duration} is negative or invalid
    * @throws NullPointerException if {@code duration} is {@code null}
    */
+  @CanIgnoreReturnValue
   public static Duration checkNotNegative(Duration duration) {
     checkValid(duration);
     checkArgument(!isNegative(duration), "duration (%s) must not be negative", toString(duration));
@@ -163,6 +165,7 @@ public final class Durations {
    * @throws IllegalArgumentException if {@code duration} is negative, {@code ZERO}, or invalid
    * @throws NullPointerException if {@code duration} is {@code null}
    */
+  @CanIgnoreReturnValue
   public static Duration checkPositive(Duration duration) {
     checkValid(duration);
     checkArgument(
@@ -173,19 +176,32 @@ public final class Durations {
   }
 
   /** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
+  @CanIgnoreReturnValue
   public static Duration checkValid(Duration duration) {
     long seconds = duration.getSeconds();
     int nanos = duration.getNanos();
     if (!isValid(seconds, nanos)) {
-        throw new IllegalArgumentException(String.format(
-            "Duration is not valid. See proto definition for valid values. "
-            + "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
-            + "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
-            + "Nanos must have the same sign as seconds", seconds, nanos));
+      throw new IllegalArgumentException(
+          String.format(
+              "Duration is not valid. See proto definition for valid values. "
+                  + "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
+                  + "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+                  + "Nanos must have the same sign as seconds",
+              seconds, nanos));
     }
     return duration;
   }
 
+  /**
+   * Builds the given builder and throws an {@link IllegalArgumentException} if it is not valid. See
+   * {@link #checkValid(Duration}).
+   *
+   * @return A valid, built {@link Duration}.
+   */
+  public static Duration checkValid(Duration.Builder durationBuilder) {
+    return checkValid(durationBuilder.build());
+  }
+
   /**
    * Convert Duration to string format. The string format will contains 3, 6, or 9 fractional digits
    * depending on the precision required to represent the exact Duration value. For example: "1s",

+ 10 - 11
java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java

@@ -30,6 +30,7 @@
 
 package com.google.protobuf.util;
 
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldMask;
@@ -88,15 +89,14 @@ final class FieldMaskTree {
   }
 
   /**
-   * Adds a field path to the tree. In a FieldMask, every field path matches the
-   * specified field as well as all its sub-fields. For example, a field path
-   * "foo.bar" matches field "foo.bar" and also "foo.bar.baz", etc. When adding
-   * a field path to the tree, redundant sub-paths will be removed. That is,
-   * after adding "foo.bar" to the tree, "foo.bar.baz" will be removed if it
-   * exists, which will turn the tree node for "foo.bar" to a leaf node.
-   * Likewise, if the field path to add is a sub-path of an existing leaf node,
-   * nothing will be changed in the tree.
+   * Adds a field path to the tree. In a FieldMask, every field path matches the specified field as
+   * well as all its sub-fields. For example, a field path "foo.bar" matches field "foo.bar" and
+   * also "foo.bar.baz", etc. When adding a field path to the tree, redundant sub-paths will be
+   * removed. That is, after adding "foo.bar" to the tree, "foo.bar.baz" will be removed if it
+   * exists, which will turn the tree node for "foo.bar" to a leaf node. Likewise, if the field path
+   * to add is a sub-path of an existing leaf node, nothing will be changed in the tree.
    */
+  @CanIgnoreReturnValue
   FieldMaskTree addFieldPath(String path) {
     String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
     if (parts.length == 0) {
@@ -125,9 +125,8 @@ final class FieldMaskTree {
     return this;
   }
 
-  /**
-   * Merges all field paths in a FieldMask into this tree.
-   */
+  /** Merges all field paths in a FieldMask into this tree. */
+  @CanIgnoreReturnValue
   FieldMaskTree mergeFromFieldMask(FieldMask mask) {
     for (String path : mask.getPathsList()) {
       addFieldPath(path);

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

@@ -36,12 +36,12 @@ import com.google.common.base.CaseFormat;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 import com.google.common.primitives.Ints;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldMask;
 import com.google.protobuf.Internal;
 import com.google.protobuf.Message;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -277,9 +277,7 @@ public class FieldMaskUtil {
 
     /**
      * Whether to replace message fields (i.e., discard existing content in
-     * destination message fields) when merging.
-     * Default behavior is to merge the source message field into the
-     * destination message field.
+     * destination message fields).
      */
     public boolean replaceMessageFields() {
       return replaceMessageFields;
@@ -287,9 +285,7 @@ public class FieldMaskUtil {
 
     /**
      * Whether to replace repeated fields (i.e., discard existing content in
-     * destination repeated fields) when merging.
-     * Default behavior is to append elements from source repeated field to the
-     * destination repeated field.
+     * destination repeated fields).
      */
     public boolean replaceRepeatedFields() {
       return replaceRepeatedFields;
@@ -297,30 +293,51 @@ public class FieldMaskUtil {
 
     /**
      * Whether to replace primitive (non-repeated and non-message) fields in
-     * destination message fields with the source primitive fields (i.e., if the
-     * field is set in the source, the value is copied to the
-     * destination; if the field is unset in the source, the field is cleared
-     * from the destination) when merging.
-     *
-     * <p>Default behavior is to always set the value of the source primitive
-     * field to the destination primitive field, and if the source field is
-     * unset, the default value of the source field is copied to the
-     * destination.
+     * destination message fields with the source primitive fields (i.e., clear
+     * destination field if source field is not set).
      */
     public boolean replacePrimitiveFields() {
       return replacePrimitiveFields;
     }
 
+    /**
+     * Specify whether to replace message fields. Defaults to false.
+     *
+     * <p>If true, discard existing content in destination message fields when merging.
+     *
+     * <p>If false, merge the source message field into the destination message field.
+     */
+    @CanIgnoreReturnValue
     public MergeOptions setReplaceMessageFields(boolean value) {
       replaceMessageFields = value;
       return this;
     }
 
+    /**
+     * Specify whether to replace repeated fields. Defaults to false.
+     *
+     * <p>If true, discard existing content in destination repeated fields) when merging.
+     *
+     * <p>If false, append elements from source repeated field to the destination repeated field.
+     */
+    @CanIgnoreReturnValue
     public MergeOptions setReplaceRepeatedFields(boolean value) {
       replaceRepeatedFields = value;
       return this;
     }
 
+    /**
+     * Specify whether to replace primitive (non-repeated and non-message) fields in destination
+     * message fields with the source primitive fields. Defaults to false.
+     *
+     * <p>If true, set the value of the destination primitive field to the source primitive field if
+     * the source field is set, but clear the destination field otherwise.
+     *
+     * <p>If false, always set the value of the destination primitive field to the source primitive
+     * field, and if the source field is unset, the default value of the source field is copied to
+     * the destination.
+     */
+    @CanIgnoreReturnValue
     public MergeOptions setReplacePrimitiveFields(boolean value) {
       replacePrimitiveFields = value;
       return this;

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

@@ -32,6 +32,7 @@ package com.google.protobuf.util;
 
 import com.google.common.base.Preconditions;
 import com.google.common.io.BaseEncoding;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonArray;
@@ -226,7 +227,7 @@ public class JsonFormat {
       return new Printer(
           registry,
           false,
-          fieldsToAlwaysOutput,
+          Collections.unmodifiableSet(new HashSet<>(fieldsToAlwaysOutput)),
           preservingProtoFieldNames,
           omittingInsignificantWhitespace,
           printingEnumsAsInts,
@@ -467,9 +468,10 @@ public class JsonFormat {
       private Builder() {}
 
       /**
-       * Adds a message type and all types defined in the same .proto file as
-       * well as all transitively imported .proto files to this {@link Builder}.
+       * Adds a message type and all types defined in the same .proto file as well as all
+       * transitively imported .proto files to this {@link Builder}.
        */
+      @CanIgnoreReturnValue
       public Builder add(Descriptor messageType) {
         if (types == null) {
           throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
@@ -479,9 +481,10 @@ public class JsonFormat {
       }
 
       /**
-       * Adds message types and all types defined in the same .proto file as
-       * well as all transitively imported .proto files to this {@link Builder}.
+       * Adds message types and all types defined in the same .proto file as well as all
+       * transitively imported .proto files to this {@link Builder}.
        */
+      @CanIgnoreReturnValue
       public Builder add(Iterable<Descriptor> messageTypes) {
         if (types == null) {
           throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");

+ 20 - 6
java/util/src/main/java/com/google/protobuf/util/Timestamps.java

@@ -36,6 +36,7 @@ import static com.google.common.math.LongMath.checkedAdd;
 import static com.google.common.math.LongMath.checkedMultiply;
 import static com.google.common.math.LongMath.checkedSubtract;
 
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import com.google.protobuf.Duration;
 import com.google.protobuf.Timestamp;
 import java.text.ParseException;
@@ -119,8 +120,8 @@ public final class Timestamps {
   }
 
   /**
-   * Compares two timestamps. The value returned is identical to what would be returned by:
-   * {@code Timestamps.comparator().compare(x, y)}.
+   * Compares two timestamps. The value returned is identical to what would be returned by: {@code
+   * Timestamps.comparator().compare(x, y)}.
    *
    * @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y};
    *     and a value greater than {@code 0} if {@code x > y}
@@ -162,18 +163,31 @@ public final class Timestamps {
   }
 
   /** Throws an {@link IllegalArgumentException} if the given {@link Timestamp} is not valid. */
+  @CanIgnoreReturnValue
   public static Timestamp checkValid(Timestamp timestamp) {
     long seconds = timestamp.getSeconds();
     int nanos = timestamp.getNanos();
     if (!isValid(seconds, nanos)) {
-        throw new IllegalArgumentException(String.format(
-            "Timestamp is not valid. See proto definition for valid values. "
-            + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
-            + "Nanos (%s) must be in range [0, +999,999,999].", seconds, nanos));
+      throw new IllegalArgumentException(
+          String.format(
+              "Timestamp is not valid. See proto definition for valid values. "
+                  + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
+                  + "Nanos (%s) must be in range [0, +999,999,999].",
+              seconds, nanos));
     }
     return timestamp;
   }
 
+  /**
+   * Builds the given builder and throws an {@link IllegalArgumentException} if it is not valid. See
+   * {@link #checkValid(Timestamp}).
+   *
+   * @return A valid, built {@link Timestamp}.
+   */
+  public static Timestamp checkValid(Timestamp.Builder timestampBuilder) {
+    return checkValid(timestampBuilder.build());
+  }
+
   /**
    * Convert Timestamp to RFC 3339 date string format. The output will always be Z-normalized and
    * uses 3, 6 or 9 fractional digits as required to represent the exact value. Note that Timestamp

+ 38 - 19
java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java

@@ -49,19 +49,20 @@ import com.google.protobuf.UInt32Value;
 import com.google.protobuf.UInt64Value;
 import com.google.protobuf.Value;
 import com.google.protobuf.util.JsonFormat.TypeRegistry;
-import com.google.protobuf.util.JsonTestProto.TestAllTypes;
-import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedEnum;
-import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedMessage;
-import com.google.protobuf.util.JsonTestProto.TestAny;
-import com.google.protobuf.util.JsonTestProto.TestCustomJsonName;
-import com.google.protobuf.util.JsonTestProto.TestDuration;
-import com.google.protobuf.util.JsonTestProto.TestFieldMask;
-import com.google.protobuf.util.JsonTestProto.TestMap;
-import com.google.protobuf.util.JsonTestProto.TestOneof;
-import com.google.protobuf.util.JsonTestProto.TestRecursive;
-import com.google.protobuf.util.JsonTestProto.TestStruct;
-import com.google.protobuf.util.JsonTestProto.TestTimestamp;
-import com.google.protobuf.util.JsonTestProto.TestWrappers;
+import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes;
+import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes.AliasedEnum;
+import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes.NestedEnum;
+import com.google.protobuf.util.proto.JsonTestProto.TestAllTypes.NestedMessage;
+import com.google.protobuf.util.proto.JsonTestProto.TestAny;
+import com.google.protobuf.util.proto.JsonTestProto.TestCustomJsonName;
+import com.google.protobuf.util.proto.JsonTestProto.TestDuration;
+import com.google.protobuf.util.proto.JsonTestProto.TestFieldMask;
+import com.google.protobuf.util.proto.JsonTestProto.TestMap;
+import com.google.protobuf.util.proto.JsonTestProto.TestOneof;
+import com.google.protobuf.util.proto.JsonTestProto.TestRecursive;
+import com.google.protobuf.util.proto.JsonTestProto.TestStruct;
+import com.google.protobuf.util.proto.JsonTestProto.TestTimestamp;
+import com.google.protobuf.util.proto.JsonTestProto.TestWrappers;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -676,7 +677,7 @@ public class JsonFormatTest extends TestCase {
               + "}",
           builder);
       fail();
-        
+
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
@@ -1159,8 +1160,8 @@ public class JsonFormatTest extends TestCase {
   }
 
   public void testParserAcceptBase64Variants() throws Exception {
-    assertAccepts("optionalBytes", "AQI");  // No padding
-    assertAccepts("optionalBytes", "-_w");  // base64Url, no padding
+    assertAccepts("optionalBytes", "AQI"); // No padding
+    assertAccepts("optionalBytes", "-_w"); // base64Url, no padding
   }
 
   public void testParserRejectInvalidEnumValue() throws Exception {
@@ -1197,6 +1198,23 @@ public class JsonFormatTest extends TestCase {
     assertEquals(0, builder.getOptionalNestedEnumValue());
   }
 
+  public void testParserSupportAliasEnums() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    String json = "{\n" + "  \"optionalAliasedEnum\": \"QUX\"\n" + "}";
+    JsonFormat.parser().merge(json, builder);
+    assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum());
+
+    builder = TestAllTypes.newBuilder();
+    json = "{\n" + "  \"optionalAliasedEnum\": \"qux\"\n" + "}";
+    JsonFormat.parser().merge(json, builder);
+    assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum());
+
+    builder = TestAllTypes.newBuilder();
+    json = "{\n" + "  \"optionalAliasedEnum\": \"bAz\"\n" + "}";
+    JsonFormat.parser().merge(json, builder);
+    assertEquals(AliasedEnum.ALIAS_BAZ, builder.getOptionalAliasedEnum());
+  }
+
   public void testUnknownEnumMap() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     JsonFormat.parser()
@@ -1280,7 +1298,8 @@ public class JsonFormatTest extends TestCase {
             + "  \"repeatedString\": [],\n"
             + "  \"repeatedBytes\": [],\n"
             + "  \"repeatedNestedMessage\": [],\n"
-            + "  \"repeatedNestedEnum\": []\n"
+            + "  \"repeatedNestedEnum\": [],\n"
+            + "  \"optionalAliasedEnum\": \"ALIAS_FOO\"\n"
             + "}",
         JsonFormat.printer().includingDefaultValueFields().print(message));
 
@@ -1644,11 +1663,11 @@ public class JsonFormatTest extends TestCase {
     mapBuilder.putStringToInt32Map("\ud834\udd20", 3); // utf-8 F0 9D 84 A0
     mapBuilder.putStringToInt32Map("foo", 99);
     mapBuilder.putStringToInt32Map("xxx", 123);
-    mapBuilder.putStringToInt32Map("\u20ac", 1);  // utf-8 E2 82 AC
+    mapBuilder.putStringToInt32Map("\u20ac", 1); // utf-8 E2 82 AC
     mapBuilder.putStringToInt32Map("abc", 20);
     mapBuilder.putStringToInt32Map("19", 19);
     mapBuilder.putStringToInt32Map("8", 8);
-    mapBuilder.putStringToInt32Map("\ufb00", 2);  // utf-8 EF AC 80
+    mapBuilder.putStringToInt32Map("\ufb00", 2); // utf-8 EF AC 80
     mapBuilder.putInt32ToInt32Map(3, 3);
     mapBuilder.putInt32ToInt32Map(10, 10);
     mapBuilder.putInt32ToInt32Map(5, 5);

+ 13 - 1
java/util/src/test/proto/com/google/protobuf/util/json_test.proto

@@ -32,7 +32,7 @@ syntax = "proto3";
 
 package json_test;
 
-option java_package = "com.google.protobuf.util";
+option java_package = "com.google.protobuf.util.proto";
 option java_outer_classname = "JsonTestProto";
 
 import "google/protobuf/any.proto";
@@ -48,6 +48,17 @@ message TestAllTypes {
     BAR = 1;
     BAZ = 2;
   }
+
+  enum AliasedEnum {
+    option allow_alias = true;
+
+    ALIAS_FOO = 0;
+    ALIAS_BAR = 1;
+    ALIAS_BAZ = 2;
+    QUX = 2;
+    qux = 2;
+    bAz = 2;
+  }
   message NestedMessage {
     int32 value = 1;
   }
@@ -69,6 +80,7 @@ message TestAllTypes {
   bytes optional_bytes = 15;
   NestedMessage optional_nested_message = 18;
   NestedEnum optional_nested_enum = 21;
+  AliasedEnum optional_aliased_enum = 52;
 
   // Repeated
   repeated int32 repeated_int32 = 31;

+ 2 - 2
js/binary/constants.js

@@ -55,7 +55,7 @@ goog.forwardDeclare('jspb.BinaryMessage');
 goog.forwardDeclare('jspb.BinaryReader');
 goog.forwardDeclare('jspb.BinaryWriter');
 goog.forwardDeclare('jspb.Message');
-goog.forwardDeclare('jsproto.BinaryExtension');
+goog.forwardDeclare('jsprotolib.BinaryExtension');
 
 
 
@@ -122,7 +122,7 @@ jspb.RepeatedFieldType;
              !Uint8Array|
              !jspb.ConstBinaryMessage|
              !jspb.BinaryMessage|
-             !jsproto.BinaryExtension}
+             !jsprotolib.BinaryExtension}
  */
 jspb.AnyFieldType;
 

+ 1 - 1
js/binary/decoder.js

@@ -63,7 +63,7 @@ goog.require('jspb.utils');
  * @struct
  */
 jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
-  /** @private {jspb.BinaryDecoder} */
+  /** @private {?jspb.BinaryDecoder} */
   this.decoder_ = null;
 
   /**

+ 1 - 0
js/binary/proto_test.js

@@ -661,4 +661,5 @@ describe('protoBinaryTest', function() {
     checkAllFields(msg, msg2);
 
   });
+
 });

+ 1 - 1
js/binary/reader.js

@@ -97,7 +97,7 @@ jspb.BinaryReader = function(opt_bytes, opt_start, opt_length) {
 
   /**
    * User-defined reader callbacks.
-   * @private {Object<string, function(!jspb.BinaryReader):*>}
+   * @private {?Object<string, function(!jspb.BinaryReader):*>}
    */
   this.readCallbacks_ = null;
 };

+ 3 - 4
js/message.js

@@ -41,6 +41,8 @@ goog.provide('jspb.Message');
 goog.require('goog.array');
 goog.require('goog.asserts');
 goog.require('goog.crypt.base64');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryReader');
 goog.require('jspb.Map');
 
 // Not needed in compilation units that have no protos with xids.
@@ -622,10 +624,7 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
  * Reads an extension field from the given reader and, if a valid extension,
  * sets the extension value.
  * @param {!jspb.Message} msg A jspb proto.
- * @param {{
- *   skipField:function(this:jspb.BinaryReader),
- *   getFieldNumber:function(this:jspb.BinaryReader):number
- * }} reader
+ * @param {!jspb.BinaryReader} reader
  * @param {!Object} extensions The extensions object.
  * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo)} getExtensionFn
  * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo, ?)} setExtensionFn

+ 256 - 228
js/message_test.js

@@ -149,58 +149,60 @@ describe('Message test suite', function() {
   });
 
   it('testComplexConversion', function() {
-    var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
-    var data2 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var data1 = ['a', , , [, 11], [[, 22], [, 33]], , ['s1', 's2'], , 1];
+    var data2 = ['a', , , [, 11], [[, 22], [, 33]], , ['s1', 's2'], , 1];
     var foo = new proto.jspb.test.Complex(data1);
     var bar = new proto.jspb.test.Complex(data2);
     var result = foo.toObject();
-    assertObjectEquals({
-      aString: 'a',
-      anOutOfOrderBool: 1,
-      aNestedMessage: {
-        anInt: 11
-      },
-      aRepeatedMessageList: [{anInt: 22}, {anInt: 33}],
-      aRepeatedStringList: ['s1', 's2']
-    }, result);
+    assertObjectEquals(
+        {
+          aString: 'a',
+          anOutOfOrderBool: 1,
+          aNestedMessage: {anInt: 11},
+          aRepeatedMessageList: [{anInt: 22}, {anInt: 33}],
+          aRepeatedStringList: ['s1', 's2']
+        },
+        result);
 
     // Now test with the jspb instances included.
     result = foo.toObject(true /* opt_includeInstance */);
-    assertObjectEquals({
-      aString: 'a',
-      anOutOfOrderBool: 1,
-      aNestedMessage: {
-        anInt: 11,
-        $jspbMessageInstance: foo.getANestedMessage()
-      },
-      aRepeatedMessageList: [
-        {anInt: 22, $jspbMessageInstance: foo.getARepeatedMessageList()[0]},
-        {anInt: 33, $jspbMessageInstance: foo.getARepeatedMessageList()[1]}
-      ],
-      aRepeatedStringList: ['s1', 's2'],
-      $jspbMessageInstance: foo
-    }, result);
+    assertObjectEquals(
+        {
+          aString: 'a',
+          anOutOfOrderBool: 1,
+          aNestedMessage:
+              {anInt: 11, $jspbMessageInstance: foo.getANestedMessage()},
+          aRepeatedMessageList: [
+            {anInt: 22, $jspbMessageInstance: foo.getARepeatedMessageList()[0]},
+            {anInt: 33, $jspbMessageInstance: foo.getARepeatedMessageList()[1]}
+          ],
+          aRepeatedStringList: ['s1', 's2'],
+          $jspbMessageInstance: foo
+        },
+        result);
 
   });
 
   it('testMissingFields', function() {
     var foo = new proto.jspb.test.Complex([
-        undefined, undefined, undefined, [],
-        undefined, undefined, undefined, undefined]);
+      undefined, undefined, undefined, [], undefined, undefined, undefined,
+      undefined
+    ]);
     var bar = new proto.jspb.test.Complex([
-        undefined, undefined, undefined, [],
-        undefined, undefined, undefined, undefined]);
+      undefined, undefined, undefined, [], undefined, undefined, undefined,
+      undefined
+    ]);
     var result = foo.toObject();
-    assertObjectEquals({
-      aString: undefined,
-      anOutOfOrderBool: undefined,
-      aNestedMessage: {
-        anInt: undefined
-      },
-      // Note: JsPb converts undefined repeated fields to empty arrays.
-      aRepeatedMessageList: [],
-      aRepeatedStringList: []
-    }, result);
+    assertObjectEquals(
+        {
+          aString: undefined,
+          anOutOfOrderBool: undefined,
+          aNestedMessage: {anInt: undefined},
+          // Note: JsPb converts undefined repeated fields to empty arrays.
+          aRepeatedMessageList: [],
+          aRepeatedStringList: []
+        },
+        result);
 
   });
 
@@ -214,20 +216,21 @@ describe('Message test suite', function() {
   it('testSpecialCases', function() {
     // Note: Some property names are reserved in JavaScript.
     // These names are converted to the Js property named pb_<reserved_name>.
-    var special =
-        new proto.jspb.test.SpecialCases(['normal', 'default', 'function',
-        'var']);
+    var special = new proto.jspb.test.SpecialCases(
+        ['normal', 'default', 'function', 'var']);
     var result = special.toObject();
-    assertObjectEquals({
-      normal: 'normal',
-      pb_default: 'default',
-      pb_function: 'function',
-      pb_var: 'var'
-    }, result);
+    assertObjectEquals(
+        {
+          normal: 'normal',
+          pb_default: 'default',
+          pb_function: 'function',
+          pb_var: 'var'
+        },
+        result);
   });
 
   it('testDefaultValues', function() {
-    var defaultString = "default<>\'\"abc";
+    var defaultString = 'default<>\'"abc';
     var response = new proto.jspb.test.DefaultValues();
 
     // Test toObject
@@ -291,8 +294,10 @@ describe('Message test suite', function() {
 
     // Test that clearing the values reverts them to the default state.
     response = makeDefault(['blah', false, 111, 77]);
-    response.clearStringField(); response.clearBoolField();
-    response.clearIntField(); response.clearEnumField();
+    response.clearStringField();
+    response.clearBoolField();
+    response.clearIntField();
+    response.clearEnumField();
     assertEquals(defaultString, response.getStringField());
     assertEquals(true, response.getBoolField());
     assertEquals(11, response.getIntField());
@@ -304,8 +309,10 @@ describe('Message test suite', function() {
 
     // Test that setFoo(null) clears the values.
     response = makeDefault(['blah', false, 111, 77]);
-    response.setStringField(null); response.setBoolField(null);
-    response.setIntField(undefined); response.setEnumField(undefined);
+    response.setStringField(null);
+    response.setBoolField(null);
+    response.setIntField(undefined);
+    response.setEnumField(undefined);
     assertEquals(defaultString, response.getStringField());
     assertEquals(true, response.getBoolField());
     assertEquals(11, response.getIntField());
@@ -321,13 +328,13 @@ describe('Message test suite', function() {
     assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi'])));
     assertFalse(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['bye'])));
     var s1b = new proto.jspb.test.Simple1(['hi', ['hello']]);
-    assertTrue(jspb.Message.equals(s1b,
-        new proto.jspb.test.Simple1(['hi', ['hello']])));
-    assertTrue(jspb.Message.equals(s1b,
-        new proto.jspb.test.Simple1(['hi', ['hello', undefined,
-                                            undefined, undefined]])));
-    assertFalse(jspb.Message.equals(s1b,
-        new proto.jspb.test.Simple1(['no', ['hello']])));
+    assertTrue(jspb.Message.equals(
+        s1b, new proto.jspb.test.Simple1(['hi', ['hello']])));
+    assertTrue(jspb.Message.equals(s1b, new proto.jspb.test.Simple1([
+      'hi', ['hello', undefined, undefined, undefined]
+    ])));
+    assertFalse(jspb.Message.equals(
+        s1b, new proto.jspb.test.Simple1(['no', ['hello']])));
     // Test with messages of different types
     var s2 = new proto.jspb.test.Simple2(['hi']);
     assertFalse(jspb.Message.equals(s1, s2));
@@ -335,18 +342,18 @@ describe('Message test suite', function() {
 
   it('testEquals_softComparison', function() {
     var s1 = new proto.jspb.test.Simple1(['hi', [], null]);
-    assertTrue(jspb.Message.equals(s1,
-        new proto.jspb.test.Simple1(['hi', []])));
+    assertTrue(
+        jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi', []])));
 
     var s1b = new proto.jspb.test.Simple1(['hi', [], true]);
-    assertTrue(jspb.Message.equals(s1b,
-        new proto.jspb.test.Simple1(['hi', [], 1])));
+    assertTrue(
+        jspb.Message.equals(s1b, new proto.jspb.test.Simple1(['hi', [], 1])));
   });
 
   it('testEqualsComplex', function() {
-    var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
-    var data2 = ['a',,, [, 11], [[, 22], [, 34]],, ['s1', 's2'],, 1];
-    var data3 = ['a',,, [, 11], [[, 22]],, ['s1', 's2'],, 1];
+    var data1 = ['a', , , [, 11], [[, 22], [, 33]], , ['s1', 's2'], , 1];
+    var data2 = ['a', , , [, 11], [[, 22], [, 34]], , ['s1', 's2'], , 1];
+    var data3 = ['a', , , [, 11], [[, 22]], , ['s1', 's2'], , 1];
     var data4 = ['hi'];
     var c1a = new proto.jspb.test.Complex(data1);
     var c1b = new proto.jspb.test.Complex(data1);
@@ -363,42 +370,34 @@ describe('Message test suite', function() {
   it('testEqualsExtensionsConstructed', function() {
     assertTrue(jspb.Message.equals(
         new proto.jspb.test.HasExtensions([]),
-        new proto.jspb.test.HasExtensions([{}])
-    ));
+        new proto.jspb.test.HasExtensions([{}])));
     assertTrue(jspb.Message.equals(
         new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])
-    ));
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])));
     assertFalse(jspb.Message.equals(
         new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'b'}]}])
-    ));
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'b'}]}])));
     assertTrue(jspb.Message.equals(
         new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])
-    ));
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])));
     assertTrue(jspb.Message.equals(
         new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions([,,, {100: [{200: 'a'}]}])
-    ));
+        new proto.jspb.test.HasExtensions([, , , {100: [{200: 'a'}]}])));
     assertTrue(jspb.Message.equals(
-        new proto.jspb.test.HasExtensions([,,, {100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])
-    ));
+        new proto.jspb.test.HasExtensions([, , , {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])));
     assertTrue(jspb.Message.equals(
         new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions(['hi',,, {100: [{200: 'a'}]}])
-    ));
+        new proto.jspb.test.HasExtensions(['hi', , , {100: [{200: 'a'}]}])));
     assertTrue(jspb.Message.equals(
-        new proto.jspb.test.HasExtensions(['hi',,, {100: [{200: 'a'}]}]),
-        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])
-    ));
+        new proto.jspb.test.HasExtensions(['hi', , , {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])));
   });
 
   it('testEqualsExtensionsUnconstructed', function() {
     assertTrue(jspb.Message.compareFields([], [{}]));
-    assertTrue(jspb.Message.compareFields([,,, {}], []));
-    assertTrue(jspb.Message.compareFields([,,, {}], [,, {}]));
+    assertTrue(jspb.Message.compareFields([, , , {}], []));
+    assertTrue(jspb.Message.compareFields([, , , {}], [, , {}]));
     assertTrue(jspb.Message.compareFields(
         ['hi', {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
     assertFalse(jspb.Message.compareFields(
@@ -406,13 +405,13 @@ describe('Message test suite', function() {
     assertTrue(jspb.Message.compareFields(
         [{100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
     assertTrue(jspb.Message.compareFields(
-        [{100: [{200: 'a'}]}], [,,, {100: [{200: 'a'}]}]));
+        [{100: [{200: 'a'}]}], [, , , {100: [{200: 'a'}]}]));
     assertTrue(jspb.Message.compareFields(
-        [,,, {100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
+        [, , , {100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
     assertTrue(jspb.Message.compareFields(
-        ['hi', {100: [{200: 'a'}]}], ['hi',,, {100: [{200: 'a'}]}]));
+        ['hi', {100: [{200: 'a'}]}], ['hi', , , {100: [{200: 'a'}]}]));
     assertTrue(jspb.Message.compareFields(
-        ['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
+        ['hi', , , {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
   });
 
   it('testInitializeMessageWithLastFieldNull', function() {
@@ -436,13 +435,13 @@ describe('Message test suite', function() {
   it('testToMap', function() {
     var p1 = new proto.jspb.test.Simple1(['k', ['v']]);
     var p2 = new proto.jspb.test.Simple1(['k1', ['v1', 'v2']]);
-    var soymap = jspb.Message.toMap([p1, p2],
-        proto.jspb.test.Simple1.prototype.getAString,
+    var soymap = jspb.Message.toMap(
+        [p1, p2], proto.jspb.test.Simple1.prototype.getAString,
         proto.jspb.test.Simple1.prototype.toObject);
     assertEquals('k', soymap['k'].aString);
     assertArrayEquals(['v'], soymap['k'].aRepeatedStringList);
-    var protomap = jspb.Message.toMap([p1, p2],
-        proto.jspb.test.Simple1.prototype.getAString);
+    var protomap = jspb.Message.toMap(
+        [p1, p2], proto.jspb.test.Simple1.prototype.getAString);
     assertEquals('k', protomap['k'].getAString());
     assertArrayEquals(['v'], protomap['k'].getARepeatedStringList());
   });
@@ -463,8 +462,12 @@ describe('Message test suite', function() {
     extension.setExt('e1');
     original.setExtension(proto.jspb.test.IsExtension.extField, extension);
     var clone = original.clone();
-    assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
-      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
+    assertArrayEquals(
+        [
+          'v1', , ['x1', ['y1', 'z1']], ,
+          [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1, ,
+          {100: [, 'e1']}
+        ],
         clone.toArray());
     clone.setStr('v2');
     var simple4 = new proto.jspb.test.Simple1(['a1', ['b1', 'c1']]);
@@ -481,11 +484,19 @@ describe('Message test suite', function() {
     var newExtension = new proto.jspb.test.CloneExtension();
     newExtension.setExt('e2');
     clone.setExtension(proto.jspb.test.CloneExtension.extField, newExtension);
-    assertArrayEquals(['v2',, ['a1', ['b1', 'c1']],,
-      [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]], bytes2,, { 100: [, 'e2'] }],
+    assertArrayEquals(
+        [
+          'v2', , ['a1', ['b1', 'c1']], ,
+          [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]], bytes2, ,
+          {100: [, 'e2']}
+        ],
         clone.toArray());
-    assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
-      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
+    assertArrayEquals(
+        [
+          'v1', , ['x1', ['y1', 'z1']], ,
+          [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1, ,
+          {100: [, 'e1']}
+        ],
         original.toArray());
   });
 
@@ -517,11 +528,12 @@ describe('Message test suite', function() {
     jspb.Message.copyInto(original, dest);
     assertArrayEquals(original.toArray(), dest.toArray());
     assertEquals('x1', dest.getSimple1().getAString());
-    assertEquals('e1',
+    assertEquals(
+        'e1',
         dest.getExtension(proto.jspb.test.CloneExtension.extField).getExt());
     dest.getSimple1().setAString('new value');
-    assertNotEquals(dest.getSimple1().getAString(),
-        original.getSimple1().getAString());
+    assertNotEquals(
+        dest.getSimple1().getAString(), original.getSimple1().getAString());
     if (supportsUint8Array) {
       dest.getBytesField()[0] = 7;
       assertObjectEquals(bytes1, original.getBytesField());
@@ -531,12 +543,12 @@ describe('Message test suite', function() {
       assertObjectEquals(bytes1, original.getBytesField());
       assertObjectEquals('789', dest.getBytesField());
     }
-    dest.getExtension(proto.jspb.test.CloneExtension.extField).
-        setExt('new value');
+    dest.getExtension(proto.jspb.test.CloneExtension.extField)
+        .setExt('new value');
     assertNotEquals(
         dest.getExtension(proto.jspb.test.CloneExtension.extField).getExt(),
-        original.getExtension(
-            proto.jspb.test.CloneExtension.extField).getExt());
+        original.getExtension(proto.jspb.test.CloneExtension.extField)
+            .getExt());
   });
 
   it('testCopyInto_notSameType', function() {
@@ -554,26 +566,32 @@ describe('Message test suite', function() {
     var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2']]);
     var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
     extendable.setExtension(proto.jspb.test.IsExtension.extField, extension1);
-    extendable.setExtension(proto.jspb.test.IndirectExtension.simple,
-                            extension2);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.simple, extension2);
     extendable.setExtension(proto.jspb.test.IndirectExtension.str, 'xyzzy');
-    extendable.setExtension(proto.jspb.test.IndirectExtension.repeatedStrList,
-        ['a', 'b']);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.repeatedStrList, ['a', 'b']);
     var s1 = new proto.jspb.test.Simple1(['foo', ['s1', 's2']]);
     var s2 = new proto.jspb.test.Simple1(['bar', ['t1', 't2']]);
     extendable.setExtension(
-        proto.jspb.test.IndirectExtension.repeatedSimpleList,
-        [s1, s2]);
-    assertObjectEquals(extension1,
+        proto.jspb.test.IndirectExtension.repeatedSimpleList, [s1, s2]);
+    assertObjectEquals(
+        extension1,
         extendable.getExtension(proto.jspb.test.IsExtension.extField));
-    assertObjectEquals(extension2,
+    assertObjectEquals(
+        extension2,
         extendable.getExtension(proto.jspb.test.IndirectExtension.simple));
-    assertObjectEquals('xyzzy',
+    assertObjectEquals(
+        'xyzzy',
         extendable.getExtension(proto.jspb.test.IndirectExtension.str));
-    assertObjectEquals(['a', 'b'], extendable.getExtension(
-        proto.jspb.test.IndirectExtension.repeatedStrList));
-    assertObjectEquals([s1, s2], extendable.getExtension(
-        proto.jspb.test.IndirectExtension.repeatedSimpleList));
+    assertObjectEquals(
+        ['a', 'b'],
+        extendable.getExtension(
+            proto.jspb.test.IndirectExtension.repeatedStrList));
+    assertObjectEquals(
+        [s1, s2],
+        extendable.getExtension(
+            proto.jspb.test.IndirectExtension.repeatedSimpleList));
     // Not supported yet, but it should work...
     extendable.setExtension(proto.jspb.test.IndirectExtension.simple, null);
     assertNull(
@@ -592,29 +610,35 @@ describe('Message test suite', function() {
     var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
     var extension = new proto.jspb.test.Simple1(['foo', ['s1', 's2']]);
     extendable.setExtension(proto.jspb.test.simple1, extension);
-    assertObjectEquals(extension,
-        extendable.getExtension(proto.jspb.test.simple1));
+    assertObjectEquals(
+        extension, extendable.getExtension(proto.jspb.test.simple1));
 
     // From _lib mode.
     extension = new proto.jspb.test.ExtensionMessage(['s1']);
     extendable = new proto.jspb.test.TestExtensionsMessage([16]);
     extendable.setExtension(proto.jspb.test.floatingMsgField, extension);
     extendable.setExtension(proto.jspb.test.floatingStrField, 's2');
-    assertObjectEquals(extension,
-        extendable.getExtension(proto.jspb.test.floatingMsgField));
-    assertObjectEquals('s2',
-        extendable.getExtension(proto.jspb.test.floatingStrField));
+    assertObjectEquals(
+        extension, extendable.getExtension(proto.jspb.test.floatingMsgField));
+    assertObjectEquals(
+        's2', extendable.getExtension(proto.jspb.test.floatingStrField));
     assertNotUndefined(proto.jspb.exttest.floatingMsgField);
     assertNotUndefined(proto.jspb.exttest.floatingMsgFieldTwo);
     assertNotUndefined(proto.jspb.exttest.beta.floatingStrField);
   });
 
   it('testNestedExtensions', function() {
-    var extendable = new proto.jspb.exttest.nested.TestNestedExtensionsMessage();
-    var extension = new proto.jspb.exttest.nested.TestOuterMessage.NestedExtensionMessage(['s1']);
-    extendable.setExtension(proto.jspb.exttest.nested.TestOuterMessage.innerExtension, extension);
-    assertObjectEquals(extension,
-        extendable.getExtension(proto.jspb.exttest.nested.TestOuterMessage.innerExtension));
+    var extendable =
+        new proto.jspb.exttest.nested.TestNestedExtensionsMessage();
+    var extension =
+        new proto.jspb.exttest.nested.TestOuterMessage.NestedExtensionMessage(
+            ['s1']);
+    extendable.setExtension(
+        proto.jspb.exttest.nested.TestOuterMessage.innerExtension, extension);
+    assertObjectEquals(
+        extension,
+        extendable.getExtension(
+            proto.jspb.exttest.nested.TestOuterMessage.innerExtension));
   });
 
   it('testToObject_extendedObject', function() {
@@ -622,60 +646,72 @@ describe('Message test suite', function() {
     var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2'], true]);
     var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
     extendable.setExtension(proto.jspb.test.IsExtension.extField, extension1);
-    extendable.setExtension(proto.jspb.test.IndirectExtension.simple,
-                            extension2);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.simple, extension2);
     extendable.setExtension(proto.jspb.test.IndirectExtension.str, 'xyzzy');
-    extendable.setExtension(proto.jspb.test.IndirectExtension.repeatedStrList,
-        ['a', 'b']);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.repeatedStrList, ['a', 'b']);
     var s1 = new proto.jspb.test.Simple1(['foo', ['s1', 's2'], true]);
     var s2 = new proto.jspb.test.Simple1(['bar', ['t1', 't2'], false]);
     extendable.setExtension(
-        proto.jspb.test.IndirectExtension.repeatedSimpleList,
-        [s1, s2]);
-    assertObjectEquals({
-      str1: 'v1', str2: 'v2', str3: 'v3',
-      extField: { ext1: 'ext1field' },
-      simple: {
-        aString: 'str', aRepeatedStringList: ['s1', 's2'], aBoolean: true
-      },
-      str: 'xyzzy',
-      repeatedStrList: ['a', 'b'],
-      repeatedSimpleList: [
-        { aString: 'foo', aRepeatedStringList: ['s1', 's2'], aBoolean: true},
-        { aString: 'bar', aRepeatedStringList: ['t1', 't2'], aBoolean: false}
-      ]
-    }, extendable.toObject());
+        proto.jspb.test.IndirectExtension.repeatedSimpleList, [s1, s2]);
+    assertObjectEquals(
+        {
+          str1: 'v1',
+          str2: 'v2',
+          str3: 'v3',
+          extField: {ext1: 'ext1field'},
+          simple: {
+            aString: 'str',
+            aRepeatedStringList: ['s1', 's2'],
+            aBoolean: true
+          },
+          str: 'xyzzy',
+          repeatedStrList: ['a', 'b'],
+          repeatedSimpleList: [
+            {aString: 'foo', aRepeatedStringList: ['s1', 's2'], aBoolean: true},
+            {aString: 'bar', aRepeatedStringList: ['t1', 't2'], aBoolean: false}
+          ]
+        },
+        extendable.toObject());
 
     // Now, with instances included.
-    assertObjectEquals({
-      str1: 'v1', str2: 'v2', str3: 'v3',
-      extField: {
-        ext1: 'ext1field',
-        $jspbMessageInstance:
-            extendable.getExtension(proto.jspb.test.IsExtension.extField)
-      },
-      simple: {
-        aString: 'str',
-        aRepeatedStringList: ['s1', 's2'],
-        aBoolean: true,
-        $jspbMessageInstance:
-            extendable.getExtension(proto.jspb.test.IndirectExtension.simple)
-      },
-      str: 'xyzzy',
-      repeatedStrList: ['a', 'b'],
-      repeatedSimpleList: [{
-        aString: 'foo',
-        aRepeatedStringList: ['s1', 's2'],
-        aBoolean: true,
-        $jspbMessageInstance: s1
-      }, {
-        aString: 'bar',
-        aRepeatedStringList: ['t1', 't2'],
-        aBoolean: false,
-        $jspbMessageInstance: s2
-      }],
-      $jspbMessageInstance: extendable
-    }, extendable.toObject(true /* opt_includeInstance */));
+    assertObjectEquals(
+        {
+          str1: 'v1',
+          str2: 'v2',
+          str3: 'v3',
+          extField: {
+            ext1: 'ext1field',
+            $jspbMessageInstance:
+                extendable.getExtension(proto.jspb.test.IsExtension.extField)
+          },
+          simple: {
+            aString: 'str',
+            aRepeatedStringList: ['s1', 's2'],
+            aBoolean: true,
+            $jspbMessageInstance: extendable.getExtension(
+                proto.jspb.test.IndirectExtension.simple)
+          },
+          str: 'xyzzy',
+          repeatedStrList: ['a', 'b'],
+          repeatedSimpleList: [
+            {
+              aString: 'foo',
+              aRepeatedStringList: ['s1', 's2'],
+              aBoolean: true,
+              $jspbMessageInstance: s1
+            },
+            {
+              aString: 'bar',
+              aRepeatedStringList: ['t1', 't2'],
+              aBoolean: false,
+              $jspbMessageInstance: s2
+            }
+          ],
+          $jspbMessageInstance: extendable
+        },
+        extendable.toObject(true /* opt_includeInstance */));
   });
 
   it('testInitialization_emptyArray', function() {
@@ -708,7 +744,8 @@ describe('Message test suite', function() {
      });
 
   it('testToObject_hasExtensionField', function() {
-    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1'], 102: ''}]);
+    var data =
+        new proto.jspb.test.HasExtensions(['str1', {100: ['ext1'], 102: ''}]);
     var obj = data.toObject();
     assertEquals('str1', obj.str1);
     assertEquals('ext1', obj.extField.ext1);
@@ -728,8 +765,7 @@ describe('Message test suite', function() {
     var extensionMessage = new proto.jspb.test.IsExtension(['is_extension']);
     data.setExtension(proto.jspb.test.IsExtension.extField, extensionMessage);
     var obj = data.toObject();
-    assertNotNull(
-        data.getExtension(proto.jspb.test.IsExtension.extField));
+    assertNotNull(data.getExtension(proto.jspb.test.IsExtension.extField));
     assertEquals('is_extension', obj.extField.ext1);
   });
 
@@ -746,16 +782,18 @@ describe('Message test suite', function() {
     var groups = group.getRepeatedGroupList();
     assertEquals('g1', groups[0].getId());
     assertObjectEquals([true, false], groups[0].getSomeBoolList());
-    assertObjectEquals({id: 'g1', someBoolList: [true, false]},
-        groups[0].toObject());
-    assertObjectEquals({
-      repeatedGroupList: [{id: 'g1', someBoolList: [true, false]}],
-      requiredGroup: {id: undefined},
-      optionalGroup: undefined,
-      requiredSimple: {aRepeatedStringList: [], aString: undefined},
-      optionalSimple: undefined,
-      id: undefined
-    }, group.toObject());
+    assertObjectEquals(
+        {id: 'g1', someBoolList: [true, false]}, groups[0].toObject());
+    assertObjectEquals(
+        {
+          repeatedGroupList: [{id: 'g1', someBoolList: [true, false]}],
+          requiredGroup: {id: undefined},
+          optionalGroup: undefined,
+          requiredSimple: {aRepeatedStringList: [], aString: undefined},
+          optionalSimple: undefined,
+          id: undefined
+        },
+        group.toObject());
     var group1 = new proto.jspb.test.TestGroup1();
     group1.setGroup(someGroup);
     assertEquals(someGroup, group1.getGroup());
@@ -772,28 +810,29 @@ describe('Message test suite', function() {
     message.setExtension$(11);
     message.setExtension(proto.jspb.test.TestReservedNamesExtension.foo, 12);
     assertEquals(11, message.getExtension$());
-    assertEquals(12, message.getExtension(
-        proto.jspb.test.TestReservedNamesExtension.foo));
+    assertEquals(
+        12,
+        message.getExtension(proto.jspb.test.TestReservedNamesExtension.foo));
     assertObjectEquals({extension: 11, foo: 12}, message.toObject());
   });
 
   it('testInitializeMessageWithUnsetOneof', function() {
     var message = new proto.jspb.test.TestMessageWithOneof([]);
     assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
-            PARTIAL_ONEOF_NOT_SET,
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase
+            .PARTIAL_ONEOF_NOT_SET,
         message.getPartialOneofCase());
     assertEquals(
-        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
-            RECURSIVE_ONEOF_NOT_SET,
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase
+            .RECURSIVE_ONEOF_NOT_SET,
         message.getRecursiveOneofCase());
   });
 
   it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
     var message = new proto.jspb.test.TestMessageWithOneof;
     assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
-            PARTIAL_ONEOF_NOT_SET,
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase
+            .PARTIAL_ONEOF_NOT_SET,
         message.getPartialOneofCase());
 
     message.setPone('hi');
@@ -803,20 +842,20 @@ describe('Message test suite', function() {
 
     message.clearPone();
     assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
-            PARTIAL_ONEOF_NOT_SET,
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase
+            .PARTIAL_ONEOF_NOT_SET,
         message.getPartialOneofCase());
   });
 
   it('testFloatingPointFieldsSupportNan', function() {
     var assertNan = function(x) {
-      assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.',
+      assertTrue(
+          'Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.',
           goog.isNumber(x) && isNaN(x));
     };
 
     var message = new proto.jspb.test.FloatingPointFields([
-      'NaN', 'NaN', ['NaN', 'NaN'], 'NaN',
-      'NaN', 'NaN', ['NaN', 'NaN'], 'NaN'
+      'NaN', 'NaN', ['NaN', 'NaN'], 'NaN', 'NaN', 'NaN', ['NaN', 'NaN'], 'NaN'
     ]);
     assertNan(message.getOptionalFloatField());
     assertNan(message.getRequiredFloatField());
@@ -837,12 +876,9 @@ describe('Message test suite', function() {
     message2.setExtension(
         proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a, 233);
     message2.setExtension(
-        proto
-            .jspb
-            .exttest
-            .reverse
-            .TestExtensionReverseOrderMessage1
-            .TestExtensionReverseOrderNestedMessage1.b, 2333);
+        proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1
+            .TestExtensionReverseOrderNestedMessage1.b,
+        2333);
     message2.setExtension(proto.jspb.exttest.reverse.c, 23333);
 
     assertEquals(
@@ -852,15 +888,9 @@ describe('Message test suite', function() {
     assertEquals(
         2333,
         message2.getExtension(
-            proto
-                .jspb
-                .exttest
-                .reverse
-                .TestExtensionReverseOrderMessage1
+            proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1
                 .TestExtensionReverseOrderNestedMessage1.b));
-    assertEquals(
-        23333,
-        message2.getExtension(proto.jspb.exttest.reverse.c));
+    assertEquals(23333, message2.getExtension(proto.jspb.exttest.reverse.c));
   });
 
   it('testCircularDepsBaseOnMessageField', function() {
@@ -983,16 +1013,14 @@ describe('Message test suite', function() {
     var package1Message = new proto.jspb.filenametest.package1.TestMessage;
     var package2Message = new proto.jspb.filenametest.package2.TestMessage;
 
-    package1Message.setExtension(
-        proto.jspb.filenametest.package1.a, 10);
-    package1Message.setExtension(
-        proto.jspb.filenametest.package1.b, 11);
+    package1Message.setExtension(proto.jspb.filenametest.package1.a, 10);
+    package1Message.setExtension(proto.jspb.filenametest.package1.b, 11);
     package2Message.setA(12);
 
-    assertEquals(10,
-        package1Message.getExtension(proto.jspb.filenametest.package1.a));
-    assertEquals(11,
-        package1Message.getExtension(proto.jspb.filenametest.package1.b));
+    assertEquals(
+        10, package1Message.getExtension(proto.jspb.filenametest.package1.a));
+    assertEquals(
+        11, package1Message.getExtension(proto.jspb.filenametest.package1.b));
     assertEquals(12, package2Message.getA());
   });
 

+ 12 - 11
js/test.proto

@@ -39,8 +39,7 @@ import "google/protobuf/descriptor.proto";
 
 package jspb.test;
 
-message Empty {
-}
+message Empty {}
 
 enum OuterEnum {
   FOO = 1;
@@ -137,12 +136,13 @@ message DefaultValues {
     E1 = 13;
     E2 = 77;
   }
-  optional string string_field = 1 [default="default<>\'\"abc"];
-  optional bool bool_field = 2 [default=true];
-  optional int64 int_field = 3 [default=11];
-  optional Enum enum_field = 4 [default=E1];
-  optional string empty_field = 6 [default=""];
-  optional bytes bytes_field = 8 [default="moo"]; // Base64 encoding is "bW9v"
+  optional string string_field = 1 [default = "default<>\'\"abc"];
+  optional bool bool_field = 2 [default = true];
+  optional int64 int_field = 3 [default = 11];
+  optional Enum enum_field = 4 [default = E1];
+  optional string empty_field = 6 [default = ""];
+  optional bytes bytes_field = 8
+      [default = "moo"];  // Base64 encoding is "bW9v"
 }
 
 message FloatingPointFields {
@@ -254,9 +254,9 @@ extend TestLastFieldBeforePivot {
 
 
 message Int64Types {
-  optional int64 int64_normal = 1 [jstype=JS_NORMAL];
-  optional sint64 int64_string = 2 [jstype=JS_STRING];
-  optional uint64 int64_number = 3 [jstype=JS_NUMBER];
+  optional int64 int64_normal = 1 [jstype = JS_NORMAL];
+  optional sint64 int64_string = 2 [jstype = JS_STRING];
+  optional uint64 int64_number = 3 [jstype = JS_NUMBER];
 
 }
 
@@ -297,3 +297,4 @@ message Deeply {
   }
 }
 
+

+ 1 - 0
js/testbinary.proto

@@ -242,3 +242,4 @@ enum MapValueEnum {
 message MapValueMessage {
   optional int32 foo = 1;
 }
+

+ 2 - 1
kokoro/linux/32-bit/build.sh

@@ -10,7 +10,8 @@
 # Change to repo root
 cd $(dirname $0)/../../..
 
-export DOCKERFILE_DIR=kokoro/linux/32-bit
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/php_32bit
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="php_all_32"

+ 23 - 105
kokoro/linux/benchmark/build.sh

@@ -1,108 +1,26 @@
 #!/bin/bash
-#
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export OUTPUT_DIR=testoutput
-oldpwd=`pwd`
-
-# tcmalloc
-if [ ! -f gperftools/.libs/libtcmalloc.so ]; then
-  git clone https://github.com/gperftools/gperftools.git
-  cd gperftools
-  ./autogen.sh
-  ./configure
-  make -j8
-  cd ..
-fi
-
-# download datasets for benchmark
-cd benchmarks
-./download_data.sh
-datasets=$(for file in $(find . -type f -name "dataset.*.pb" -not -path "./tmp/*"); do echo "$(pwd)/$file"; done | xargs)
-echo $datasets
-cd $oldpwd
-
-# build Python protobuf
-./autogen.sh
-./configure CXXFLAGS="-fPIC -O2"
-make -j8
-cd python
-python setup.py build --cpp_implementation
-pip install . --user
-
-
-# build and run Python benchmark
-cd ../benchmarks
-make python-pure-python-benchmark
-make python-cpp-reflection-benchmark
-make -j8 python-cpp-generated-code-benchmark
-echo "[" > tmp/python_result.json
-echo "benchmarking pure python..."
-./python-pure-python-benchmark --json --behavior_prefix="pure-python-benchmark" $datasets  >> tmp/python_result.json
-echo "," >> "tmp/python_result.json"
-echo "benchmarking python cpp reflection..."
-env LD_PRELOAD="$oldpwd/gperftools/.libs/libtcmalloc.so" LD_LIBRARY_PATH="$oldpwd/src/.libs" ./python-cpp-reflection-benchmark --json --behavior_prefix="cpp-reflection-benchmark" $datasets  >> tmp/python_result.json
-echo "," >> "tmp/python_result.json"
-echo "benchmarking python cpp generated code..."
-env LD_PRELOAD="$oldpwd/gperftools/.libs/libtcmalloc.so" LD_LIBRARY_PATH="$oldpwd/src/.libs" ./python-cpp-generated-code-benchmark --json --behavior_prefix="cpp-generated-code-benchmark" $datasets >> tmp/python_result.json
-echo "]" >> "tmp/python_result.json"
-cd $oldpwd
-
-# build CPP protobuf
-./configure
-make clean && make -j8
 
-# build Java protobuf
-cd java
-mvn package
-cd ..
-
-# build CPP benchmark
-cd benchmarks
-mv tmp/python_result.json . && make clean && make -j8 cpp-benchmark && mv python_result.json tmp
-echo "benchmarking cpp..."
-env LD_PRELOAD="$oldpwd/gperftools/.libs/libtcmalloc.so" ./cpp-benchmark --benchmark_min_time=5.0 --benchmark_out_format=json --benchmark_out="tmp/cpp_result.json" $datasets
-cd $oldpwd
-
-# build go protobuf 
-export PATH="`pwd`/src:$PATH"
-export GOPATH="$HOME/gocode"
-mkdir -p "$GOPATH/src/github.com/google"
-rm -f "$GOPATH/src/github.com/protocolbuffers/protobuf"
-ln -s "`pwd`" "$GOPATH/src/github.com/protocolbuffers/protobuf"
-export PATH="$GOPATH/bin:$PATH"
-go get github.com/golang/protobuf/protoc-gen-go
-
-# build go benchmark
-cd benchmarks
-make go-benchmark
-echo "benchmarking go..."
-./go-benchmark $datasets > tmp/go_result.txt
-
-# build java benchmark
-make java-benchmark
-echo "benchmarking java..."
-./java-benchmark -Cresults.file.options.file="tmp/java_result.json" $datasets
-
-make js-benchmark
-echo "benchmarking js..."
-./js-benchmark $datasets  --json_output=$(pwd)/tmp/node_result.json
-
-make -j8 generate_proto3_data
-proto3_datasets=$(for file in $datasets; do echo $(pwd)/tmp/proto3_data/${file#$(pwd)}; done | xargs)
-echo $proto3_datasets
-
-# build php benchmark
-make -j8 php-benchmark
-echo "benchmarking php..."
-./php-benchmark $proto3_datasets --json --behavior_prefix="php" > tmp/php_result.json
-make -j8 php-c-benchmark
-echo "benchmarking php_c..."
-./php-c-benchmark $proto3_datasets --json --behavior_prefix="php_c" > tmp/php_c_result.json
+cd $(dirname $0)/../../..
 
-# upload result to bq
-make python_add_init
-env LD_LIBRARY_PATH="$oldpwd/src/.libs" python -m util.result_uploader -php="../tmp/php_result.json" -php_c="../tmp/php_c_result.json"  \
-	-cpp="../tmp/cpp_result.json" -java="../tmp/java_result.json" -go="../tmp/go_result.txt" -python="../tmp/python_result.json" -node="../tmp/node_result.json"
-cd $oldpwd
+# prepare php environments
+sudo apt-get update && sudo apt-get install -y --force-yes php5
+sudo ln -sf /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h
+mkdir php_temp
+cd php_temp
+curl -sS https://getcomposer.org/installer | php
+sudo mv composer.phar /usr/local/bin/composer
+git clone https://github.com/php/php-src
+cd php-src && git checkout PHP-7.2.13 && ./buildconf --force
+./configure \
+	--enable-bcmatch \
+	--with-gmp --with-openssl \
+	--with-zlib  \
+	--prefix=/usr/local/php-7.2 && \
+make -j8 && sudo make install && make clean
+wget -O phpunit https://phar.phpunit.de/phpunit-7.phar && \
+	chmod +x phpunit && \
+	sudo cp phpunit /usr/local/php-7.2/bin
+sudo apt-get install -y --force-yes valgrind
+cd ../..
+
+./tests.sh benchmark

+ 105 - 0
kokoro/linux/benchmark/run.sh

@@ -0,0 +1,105 @@
+#!/bin/bash
+#
+# Change to repo root
+cd $(dirname $0)/../../..
+
+export OUTPUT_DIR=testoutput
+oldpwd=`pwd`
+
+# tcmalloc
+if [ ! -f gperftools/.libs/libtcmalloc.so ]; then
+  git clone https://github.com/gperftools/gperftools.git
+  cd gperftools
+  ./autogen.sh
+  ./configure
+  make -j8
+  cd ..
+fi
+
+# download datasets for benchmark
+cd benchmarks
+./download_data.sh
+datasets=$(for file in $(find . -type f -name "dataset.*.pb" -not -path "./tmp/*"); do echo "$(pwd)/$file"; done | xargs)
+echo $datasets
+cd $oldpwd
+
+# build Python protobuf
+./autogen.sh
+./configure CXXFLAGS="-fPIC -O2"
+make -j8
+cd python
+python setup.py build --cpp_implementation
+pip install . --user
+
+
+# build and run Python benchmark
+cd ../benchmarks
+make python-pure-python-benchmark
+make python-cpp-reflection-benchmark
+make -j8 python-cpp-generated-code-benchmark
+echo "[" > tmp/python_result.json
+echo "benchmarking pure python..."
+./python-pure-python-benchmark --json --behavior_prefix="pure-python-benchmark" $datasets  >> tmp/python_result.json
+echo "," >> "tmp/python_result.json"
+echo "benchmarking python cpp reflection..."
+env LD_PRELOAD="$oldpwd/gperftools/.libs/libtcmalloc.so" LD_LIBRARY_PATH="$oldpwd/src/.libs" ./python-cpp-reflection-benchmark --json --behavior_prefix="cpp-reflection-benchmark" $datasets  >> tmp/python_result.json
+echo "," >> "tmp/python_result.json"
+echo "benchmarking python cpp generated code..."
+env LD_PRELOAD="$oldpwd/gperftools/.libs/libtcmalloc.so" LD_LIBRARY_PATH="$oldpwd/src/.libs" ./python-cpp-generated-code-benchmark --json --behavior_prefix="cpp-generated-code-benchmark" $datasets >> tmp/python_result.json
+echo "]" >> "tmp/python_result.json"
+cd $oldpwd
+
+# build CPP protobuf
+./configure
+make clean && make -j8
+
+# build Java protobuf
+cd java
+mvn package
+cd ..
+
+# build CPP benchmark
+cd benchmarks
+mv tmp/python_result.json . && make clean && make -j8 cpp-benchmark && mv python_result.json tmp
+echo "benchmarking cpp..."
+env LD_PRELOAD="$oldpwd/gperftools/.libs/libtcmalloc.so" ./cpp-benchmark --benchmark_min_time=5.0 --benchmark_out_format=json --benchmark_out="tmp/cpp_result.json" $datasets
+cd $oldpwd
+
+# build go protobuf 
+export PATH="`pwd`/src:$PATH"
+export GOPATH="$HOME/gocode"
+mkdir -p "$GOPATH/src/github.com/google"
+rm -f "$GOPATH/src/github.com/protocolbuffers/protobuf"
+ln -s "`pwd`" "$GOPATH/src/github.com/protocolbuffers/protobuf"
+export PATH="$GOPATH/bin:$PATH"
+go get github.com/golang/protobuf/protoc-gen-go
+
+# build go benchmark
+cd benchmarks
+make go-benchmark
+echo "benchmarking go..."
+./go-benchmark $datasets > tmp/go_result.txt
+
+# build java benchmark
+make java-benchmark
+echo "benchmarking java..."
+./java-benchmark -Cresults.file.options.file="tmp/java_result.json" $datasets
+
+make js-benchmark
+echo "benchmarking js..."
+./js-benchmark $datasets  --json_output=$(pwd)/tmp/node_result.json
+
+make -j8 generate_proto3_data
+proto3_datasets=$(for file in $datasets; do echo $(pwd)/tmp/proto3_data/${file#$(pwd)}; done | xargs)
+echo $proto3_datasets
+
+# build php benchmark
+make -j8 php-c-benchmark
+echo "benchmarking php_c..."
+./php-c-benchmark $proto3_datasets --json --behavior_prefix="php_c" > tmp/php_c_result.json
+
+# upload result to bq
+make python_add_init
+env LD_LIBRARY_PATH="$oldpwd/src/.libs" python -m util.result_uploader -php_c="../tmp/php_c_result.json"  \
+	-cpp="../tmp/cpp_result.json" -java="../tmp/java_result.json" -go="../tmp/go_result.txt" -python="../tmp/python_result.json" -node="../tmp/node_result.json"
+cd $oldpwd

+ 12 - 2
kokoro/linux/build_and_run_docker.sh

@@ -3,6 +3,8 @@
 # Builds docker image and runs a command under it.
 # This is a generic script that is configured with the following variables:
 #
+# DOCKERHUB_ORGANIZATION - The organization on docker hub storing the
+# Dockerfile.
 # DOCKERFILE_DIR - Directory in which Dockerfile file is located.
 # DOCKER_RUN_SCRIPT - Script to run under docker (relative to protobuf repo root)
 # OUTPUT_DIR - Directory that will be copied from inside docker after finishing.
@@ -15,8 +17,16 @@ git_root=$(pwd)
 cd -
 
 # Use image name based on Dockerfile sha1
-DOCKERHUB_ORGANIZATION=grpctesting/protobuf
-DOCKER_IMAGE_NAME=${DOCKERHUB_ORGANIZATION}_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
+if [ -z "$DOCKERHUB_ORGANIZATION" ]
+then
+  DOCKERHUB_ORGANIZATION=grpctesting/protobuf
+  DOCKER_IMAGE_NAME=${DOCKERHUB_ORGANIZATION}_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
+else
+  # TODO(teboring): Remove this when all tests have been migrated to separate
+  # docker images.
+  DOCKERFILE_PREFIX=$(basename $DOCKERFILE_DIR)
+  DOCKER_IMAGE_NAME=${DOCKERHUB_ORGANIZATION}/${DOCKERFILE_PREFIX}_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
+fi
 
 # Pull dockerimage from Dockerhub
 docker pull $DOCKER_IMAGE_NAME

+ 13 - 0
kokoro/linux/cpp_tcmalloc/build.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Build file to set up and run tests
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/cpp_tcmalloc
+export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+export TEST_SET="cpp_tcmalloc"
+./kokoro/linux/build_and_run_docker.sh

+ 5 - 0
kokoro/linux/cpp_tcmalloc/continuous.cfg

@@ -0,0 +1,5 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cpp_tcmalloc/build.sh"
+timeout_mins: 1440

+ 5 - 0
kokoro/linux/cpp_tcmalloc/presubmit.cfg

@@ -0,0 +1,5 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/cpp_tcmalloc/build.sh"
+timeout_mins: 1440

+ 11 - 5
kokoro/linux/csharp/build.sh

@@ -1,11 +1,17 @@
 #!/bin/bash
 #
-# Build file to set up and run tests
+# This is the top-level script we give to Kokoro as the entry point for
+# running the "pull request" project:
+#
+# This script selects a specific Dockerfile (for building a Docker image) and
+# a script to run inside that image.  Then we delegate to the general
+# build_and_run_docker.sh script.
 
 # Change to repo root
 cd $(dirname $0)/../../..
 
-# Prepare worker environment to run tests
-source kokoro/linux/prepare_build_linux_rc
-
-./tests.sh csharp
+export DOCKERFILE_DIR=kokoro/linux/64-bit
+export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+export TEST_SET="csharp"
+./kokoro/linux/build_and_run_docker.sh

+ 29 - 0
kokoro/linux/dockerfile/push_testing_images.sh

@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -ex
+
+cd $(dirname $0)/../../..
+git_root=$(pwd)
+cd -
+
+DOCKERHUB_ORGANIZATION=protobuftesting
+
+for DOCKERFILE_DIR in test/* release/*
+do
+  # Generate image name based on Dockerfile checksum. That works well as long
+  # as can count on dockerfiles being written in a way that changing the logical
+  # contents of the docker image always changes the SHA (e.g. using "ADD file"
+  # cmd in the dockerfile in not ok as contents of the added file will not be
+  # reflected in the SHA).
+  DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
+
+  echo $DOCKER_IMAGE_NAME
+  # skip the image if it already exists in the repo
+  curl --silent -f -lSL https://registry.hub.docker.com/v2/repositories/${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}/tags/latest > /dev/null \
+      && continue
+
+  docker build -t ${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME} ${DOCKERFILE_DIR}
+
+  # "docker login" needs to be run in advance
+  docker push ${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}
+done

+ 3 - 0
kokoro/linux/dockerfile/release/ruby_rake_compiler/Dockerfile

@@ -0,0 +1,3 @@
+FROM grpctesting/rake-compiler-dock_53c22085d091183c528303791e7771359f699bcf
+
+RUN /bin/bash -l -c "gem install bundler"

+ 29 - 0
kokoro/linux/dockerfile/test/cpp_tcmalloc/Dockerfile

@@ -0,0 +1,29 @@
+FROM debian:jessie
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean
+
+# Install dependencies for TC malloc
+RUN apt-get install -y \
+  google-perftools \
+  libgoogle-perftools4 \
+  libgoogle-perftools-dev

+ 238 - 0
kokoro/linux/dockerfile/test/php/Dockerfile

@@ -0,0 +1,238 @@
+FROM debian:jessie
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean
+
+# Install php dependencies
+RUN apt-get clean && apt-get update && apt-get install -y --force-yes \
+  php5 \
+  libcurl4-openssl-dev \
+  libgmp-dev \
+  libgmp3-dev \
+  libssl-dev \
+  libxml2-dev \
+  unzip \
+  zlib1g-dev \
+  pkg-config \
+  && apt-get clean
+
+# Install other dependencies
+RUN ln -sf /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h
+RUN wget http://ftp.gnu.org/gnu/bison/bison-2.6.4.tar.gz -O /var/local/bison-2.6.4.tar.gz
+RUN cd /var/local \
+  && tar -zxvf bison-2.6.4.tar.gz \
+  && cd /var/local/bison-2.6.4 \
+  && ./configure \
+  && make \
+  && make install
+
+# Install composer
+RUN curl -sS https://getcomposer.org/installer | php
+RUN mv composer.phar /usr/local/bin/composer
+
+# Download php source code
+RUN git clone https://github.com/php/php-src
+
+# php 5.5
+RUN cd php-src \
+  && git checkout PHP-5.5.38 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.5 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.5-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-4.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-5.5/bin \
+  && mv phpunit /usr/local/php-5.5-zts/bin
+
+# php 5.6
+RUN cd php-src \
+  && git checkout PHP-5.6.39 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.6 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.6-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-5.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-5.6/bin \
+  && mv phpunit /usr/local/php-5.6-zts/bin
+
+# php 7.0
+RUN cd php-src \
+  && git checkout PHP-7.0.33 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.0 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.0-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-6.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.0/bin \
+  && mv phpunit /usr/local/php-7.0-zts/bin
+
+# php 7.1
+RUN cd php-src \
+  && git checkout PHP-7.1.25 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.1 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.1-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.1/bin \
+  && mv phpunit /usr/local/php-7.1-zts/bin
+
+# php 7.2
+RUN cd php-src \
+  && git checkout PHP-7.2.13 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.2 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.2-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.2/bin \
+  && mv phpunit /usr/local/php-7.2-zts/bin
+
+# php 7.3
+RUN cd php-src \
+  && git checkout PHP-7.3.0 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.3 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-gmp \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.3-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.3/bin \
+  && mv phpunit /usr/local/php-7.3-zts/bin
+
+# Install php dependencies
+RUN apt-get clean && apt-get update && apt-get install -y --force-yes \
+  valgrind \
+  && apt-get clean

+ 224 - 0
kokoro/linux/dockerfile/test/php_32bit/Dockerfile

@@ -0,0 +1,224 @@
+FROM 32bit/debian:jessie
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean
+
+# Install php dependencies
+RUN apt-get clean && apt-get update && apt-get install -y --force-yes \
+  bison \
+  php5 \
+  libcurl4-openssl-dev \
+  libssl-dev \
+  libxml2-dev \
+  unzip \
+  zlib1g-dev \
+  pkg-config \
+  && apt-get clean
+
+# Install other dependencies
+RUN wget http://ftp.gnu.org/gnu/bison/bison-2.6.4.tar.gz -O /var/local/bison-2.6.4.tar.gz
+RUN cd /var/local \
+  && tar -zxvf bison-2.6.4.tar.gz \
+  && cd /var/local/bison-2.6.4 \
+  && ./configure \
+  && make \
+  && make install
+
+# Install composer
+RUN curl -sS https://getcomposer.org/installer | php
+RUN mv composer.phar /usr/local/bin/composer
+
+# Download php source code
+RUN git clone https://github.com/php/php-src
+
+# php 5.5
+RUN cd php-src \
+  && git checkout PHP-5.5.38 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.5 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.5-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-4.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-5.5/bin \
+  && mv phpunit /usr/local/php-5.5-zts/bin
+
+# php 5.6
+RUN cd php-src \
+  && git checkout PHP-5.6.39 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.6 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-5.6-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-5.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-5.6/bin \
+  && mv phpunit /usr/local/php-5.6-zts/bin
+
+# php 7.0
+RUN cd php-src \
+  && git checkout PHP-7.0.33 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.0 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.0-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-6.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.0/bin \
+  && mv phpunit /usr/local/php-7.0-zts/bin
+
+# php 7.1
+RUN cd php-src \
+  && git checkout PHP-7.1.25 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.1 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.1-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.1/bin \
+  && mv phpunit /usr/local/php-7.1-zts/bin
+
+# php 7.2
+RUN cd php-src \
+  && git checkout PHP-7.2.13 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.2 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.2-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.2/bin \
+  && mv phpunit /usr/local/php-7.2-zts/bin
+
+# php 7.3
+RUN cd php-src \
+  && git checkout PHP-7.3.0 \
+  && ./buildconf --force
+RUN cd php-src \
+  && ./configure \
+  --enable-bcmath \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.3 \
+  && make \
+  && make install \
+  && make clean
+RUN cd php-src \
+  && ./configure \
+  --enable-maintainer-zts \
+  --with-openssl \
+  --with-zlib \
+  --prefix=/usr/local/php-7.3-zts \
+  && make \
+  && make install \
+  && make clean
+
+RUN wget -O phpunit https://phar.phpunit.de/phpunit-7.phar \
+  && chmod +x phpunit \
+  && cp phpunit /usr/local/php-7.3/bin \
+  && mv phpunit /usr/local/php-7.3-zts/bin
+
+# Install php dependencies
+RUN apt-get clean && apt-get update && apt-get install -y --force-yes \
+  valgrind \
+  && apt-get clean

+ 39 - 0
kokoro/linux/dockerfile/test/python_jessie/Dockerfile

@@ -0,0 +1,39 @@
+FROM debian:jessie
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean
+
+# Install python dependencies
+RUN apt-get update && apt-get install -y \
+  python-setuptools \
+  python-all-dev \
+  python3-all-dev \
+  python-pip
+
+# Install Python packages from PyPI
+RUN pip install --upgrade pip==10.0.1
+RUN pip install virtualenv
+RUN pip install six==1.10.0 twisted==17.5.0
+
+# Install pip and virtualenv for Python 3.4
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.4
+RUN python3.4 -m pip install virtualenv

+ 47 - 0
kokoro/linux/dockerfile/test/python_stretch/Dockerfile

@@ -0,0 +1,47 @@
+FROM debian:stretch
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean
+
+# Install Python 2.7
+RUN apt-get update && apt-get install -y python2.7 python-all-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python2.7
+
+# Install python dependencies
+RUN apt-get update && apt-get install -y \
+  python-setuptools \
+  python-pip
+
+# Add Debian 'testing' repository
+RUN echo 'deb http://ftp.de.debian.org/debian testing main' >> /etc/apt/sources.list
+RUN echo 'APT::Default-Release "stable";' | tee -a /etc/apt/apt.conf.d/00local
+
+# Install Python3
+RUN apt-get update && apt-get -t testing install -y \
+  python3.5 \
+  python3.6 \
+  python3.7 \
+  python3-all-dev
+
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.5
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.6
+RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7

+ 37 - 0
kokoro/linux/dockerfile/test/ruby/Dockerfile

@@ -0,0 +1,37 @@
+FROM debian:jessie
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys \
+    409B6B1796C275462A1703113804BB82D39DC0E3 \
+    7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+RUN /bin/bash -l -c "rvm install 2.3.8"
+RUN /bin/bash -l -c "rvm install 2.4.5"
+RUN /bin/bash -l -c "rvm install 2.5.1"
+RUN /bin/bash -l -c "rvm install 2.6.0"
+
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"

+ 11 - 5
kokoro/linux/java_compatibility/build.sh

@@ -1,11 +1,17 @@
 #!/bin/bash
 #
-# Build file to set up and run tests
+# This is the top-level script we give to Kokoro as the entry point for
+# running the "pull request" project:
+#
+# This script selects a specific Dockerfile (for building a Docker image) and
+# a script to run inside that image.  Then we delegate to the general
+# build_and_run_docker.sh script.
 
 # Change to repo root
 cd $(dirname $0)/../../..
 
-# Prepare worker environment to run tests
-source kokoro/linux/prepare_build_linux_rc
-
-./tests.sh java_compatibility
+export DOCKERFILE_DIR=kokoro/linux/64-bit
+export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+export TEST_SET="java_compatibility"
+./kokoro/linux/build_and_run_docker.sh

+ 2 - 1
kokoro/linux/php_all/build.sh

@@ -10,7 +10,8 @@
 # Change to repo root
 cd $(dirname $0)/../../..
 
-export DOCKERFILE_DIR=kokoro/linux/64-bit
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/php
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
 export TEST_SET="php_all"

+ 0 - 13
kokoro/linux/prepare_build_linux_rc

@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# Source this rc script to prepare the environment for Linux builds
-
-# Set up dotnet
-sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
-sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EB3E94ADBE1229CF
-sudo apt-get update
-# We use the .NET Core SDK 2.x to build...
-sudo apt-get install -y dotnet-sdk-2.1.3
-# But we also need the 1.x framework to test against, as we
-# target netstandard1.x
-sudo apt-get install -y dotnet-sharedframework-microsoft.netcore.app-1.0.5

+ 3 - 2
kokoro/linux/64-bit/build.sh → kokoro/linux/python27/build.sh

@@ -10,8 +10,9 @@
 # Change to repo root
 cd $(dirname $0)/../../..
 
-export DOCKERFILE_DIR=kokoro/linux/64-bit
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
-export TEST_SET="csharp java_jdk7 javanano_jdk7 java_oracle7 javanano_oracle7 python python_cpp ruby_all javascript golang php_all"
+export TEST_SET="python27"
 ./kokoro/linux/build_and_run_docker.sh

+ 1 - 1
kokoro/linux/64-bit/continuous.cfg → kokoro/linux/python27/continuous.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/64-bit/build.sh"
+build_file: "protobuf/kokoro/linux/python/build.sh"
 timeout_mins: 120
 
 action {

+ 1 - 1
kokoro/linux/64-bit/presubmit.cfg → kokoro/linux/python27/presubmit.cfg

@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/64-bit/build.sh"
+build_file: "protobuf/kokoro/linux/python/build.sh"
 timeout_mins: 120
 
 action {

+ 18 - 0
kokoro/linux/python27_cpp/build.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# This is the top-level script we give to Kokoro as the entry point for
+# running the "pull request" project:
+#
+# This script selects a specific Dockerfile (for building a Docker image) and
+# a script to run inside that image.  Then we delegate to the general
+# build_and_run_docker.sh script.
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
+export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+export TEST_SET="python27_cpp"
+./kokoro/linux/build_and_run_docker.sh

+ 11 - 0
kokoro/linux/python27_cpp/continuous.cfg

@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+timeout_mins: 120
+
+action {
+  define_artifacts {
+    regex: "**/sponge_log.xml"
+  }
+}

+ 11 - 0
kokoro/linux/python27_cpp/presubmit.cfg

@@ -0,0 +1,11 @@
+# Config file for running tests in Kokoro
+
+# Location of the build script in repository
+build_file: "protobuf/kokoro/linux/python_cpp/build.sh"
+timeout_mins: 120
+
+action {
+  define_artifacts {
+    regex: "**/sponge_log.xml"
+  }
+}

+ 18 - 0
kokoro/linux/python33/build.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# This is the top-level script we give to Kokoro as the entry point for
+# running the "pull request" project:
+#
+# This script selects a specific Dockerfile (for building a Docker image) and
+# a script to run inside that image.  Then we delegate to the general
+# build_and_run_docker.sh script.
+
+# Change to repo root
+cd $(dirname $0)/../../..
+
+export DOCKERHUB_ORGANIZATION=protobuftesting
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python_jessie
+export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
+export OUTPUT_DIR=testoutput
+export TEST_SET="python33"
+./kokoro/linux/build_and_run_docker.sh

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