Down-integrate internal changes (#5467)

* Down-integrate internal changes

* Update generated code for php, objc and csharp.

* Add missing dependency in conformance_php
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
index 29d9a98..97e252e 100644
--- a/conformance/Makefile.am
+++ b/conformance/Makefile.am
@@ -206,7 +206,9 @@
 
 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
diff --git a/conformance/binary_json_conformance_main.cc b/conformance/binary_json_conformance_main.cc
new file mode 100644
index 0000000..3e8df73
--- /dev/null
+++ b/conformance/binary_json_conformance_main.cc
@@ -0,0 +1,37 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "binary_json_conformance_suite.h"
+#include "conformance_test.h"
+
+int main(int argc, char *argv[]) {
+  google::protobuf::BinaryAndJsonConformanceSuite suite;
+  return google::protobuf::ForkPipeRunner::Run(argc, argv, &suite);
+}
diff --git a/conformance/conformance_test_impl.cc b/conformance/binary_json_conformance_suite.cc
similarity index 94%
rename from conformance/conformance_test_impl.cc
rename to conformance/binary_json_conformance_suite.cc
index a884dea..53430a71 100644
--- a/conformance/conformance_test_impl.cc
+++ b/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 @@
 namespace google {
 namespace protobuf {
 
-class ConformanceTestSuiteImpl : public ConformanceTestSuite {
- public:
-  ConformanceTestSuiteImpl() {}
+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);
 
- 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);
+  if (!status.ok()) {
+    return false;
+  }
 
-  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);
-};
+  if (!test_message->ParseFromString(binary_protobuf)) {
+    GOOGLE_LOG(FATAL)
+        << "INTERNAL ERROR: internal JSON->protobuf transcode "
+        << "yielded unparseable proto.";
+    return false;
+  }
 
-void ConformanceTestSuiteImpl::ExpectParseFailureForProtoWithProtoVersion (
+  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 @@
 }
 
 // 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 @@
 // 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 @@
   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 @@
   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 @@
   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::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 @@
   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 @@
 // 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 @@
   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::ExpectSerializeFailureForJson(
+void BinaryAndJsonConformanceSuite::ExpectSerializeFailureForJson(
     const string& test_name, ConformanceLevel level, const string& text_format) {
   TestAllTypesProto3 payload_message;
   GOOGLE_CHECK(
@@ -482,7 +495,7 @@
 }
 
 //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::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 @@
 }
 
 // TODO: proto2?
-void ConformanceTestSuiteImpl::TestIllegalTags() {
+void BinaryAndJsonConformanceSuite::TestIllegalTags() {
   // field num 0 is illegal
   string nullfield[] = {
     "\1DEADBEEF",
@@ -621,7 +634,7 @@
   }
 }
 template <class MessageType>
-void ConformanceTestSuiteImpl::TestOneofMessage (
+void BinaryAndJsonConformanceSuite::TestOneofMessage (
     MessageType &message, bool is_proto3) {
   message.set_oneof_uint32(0);
   RunValidProtobufTestWithMessage(
@@ -660,14 +673,14 @@
 }
 
 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());
@@ -2360,8 +2373,3 @@
 
 }  // namespace protobuf
 }  // namespace google
-
-int main(int argc, char *argv[]) {
-  google::protobuf::ConformanceTestSuiteImpl suite;
-  return google::protobuf::ForkPipeRunner::Run(argc, argv, &suite);
-}
diff --git a/conformance/binary_json_conformance_suite.h b/conformance/binary_json_conformance_suite.h
new file mode 100644
index 0000000..7a03545
--- /dev/null
+++ b/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
diff --git a/conformance/conformance.proto b/conformance/conformance.proto
index af89152..b0dc762 100644
--- a/conformance/conformance.proto
+++ b/conformance/conformance.proto
@@ -55,6 +55,7 @@
   UNSPECIFIED = 0;
   PROTOBUF = 1;
   JSON = 2;
+  JSPB = 3;  // Google internal only. Opensource testees just skip it.
 }
 
 enum TestCategory {
@@ -67,6 +68,8 @@
   // https://developers.google.com/protocol-buffers/docs/proto3#json_options
   // for more detail.
   JSON_IGNORE_UNKNOWN_PARSING_TEST = 3;
+  JSPB_TEST = 4;  // Test jspb wire format. Google internal only.
+                  // Opensource testees just skip it.
 }
 
 // Represents a single test case's input.  The testee should:
@@ -85,6 +88,8 @@
   oneof payload {
     bytes protobuf_payload = 1;
     string json_payload = 2;
+    string jspb_payload = 7;  // Google internal only.
+                              // Opensource testees just skip it.
   }
 
   // Which format should the testee serialize its message to?
@@ -99,6 +104,9 @@
   // 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 +140,16 @@
     // 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;
   }
 }
+
+// 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;
+}
diff --git a/conformance/conformance_cpp.cc b/conformance/conformance_cpp.cc
index ac2f6de..ce333ee 100644
--- a/conformance/conformance_cpp.cc
+++ b/conformance/conformance_cpp.cc
@@ -137,6 +137,11 @@
     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;
   }
 
   switch (request.requested_output_format()) {
diff --git a/conformance/conformance_php.php b/conformance/conformance_php.php
index 799cc3e..cc6d4b9 100755
--- a/conformance/conformance_php.php
+++ b/conformance/conformance_php.php
@@ -3,6 +3,7 @@
 require_once("Conformance/WireFormat.php");
 require_once("Conformance/ConformanceResponse.php");
 require_once("Conformance/ConformanceRequest.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");
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index 2d822c2..68b813d 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -80,6 +80,11 @@
       break;
     }
 
+    case conformance::JSPB: {
+      request_.set_jspb_payload(input);
+      break;
+    }
+
     default:
       GOOGLE_LOG(FATAL) << "Unspecified input format";
   }
@@ -215,23 +220,27 @@
 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 @@
       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 @@
   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,6 +341,24 @@
   }
 }
 
+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::UNSPECIFIED:
+      return "UNSPECIFIED";
+    default:
+      GOOGLE_LOG(FATAL) << "unknown wire type: "
+                        << wire_format;
+  }
+  return "";
+}
+
 bool ConformanceTestSuite::RunSuite(
     ConformanceTestRunner* runner, std::string* output) {
   runner_ = runner;
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
index d5c2f3d..ab82bbe 100644
--- a/conformance/conformance_test.h
+++ b/conformance/conformance_test.h
@@ -87,7 +87,6 @@
   static int Run(int argc, char *argv[],
                  ConformanceTestSuite* suite);
 
- private:
   ForkPipeRunner(const std::string &executable)
       : child_pid_(-1), executable_(executable) {}
 
@@ -97,24 +96,7 @@
                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);
@@ -237,6 +219,7 @@
    protected:
     virtual string InputFormatString(conformance::WireFormat format) const;
     virtual string OutputFormatString(conformance::WireFormat format) const;
+    conformance::ConformanceRequest request_;
 
    private:
     ConformanceLevel level_;
@@ -244,11 +227,24 @@
     ::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 +291,6 @@
 
   // 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
diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc
index 9c37712..8b44752 100644
--- a/conformance/conformance_test_runner.cc
+++ b/conformance/conformance_test_runner.cc
@@ -212,6 +212,24 @@
   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];