Browse Source

Give a specific category to each test. (#4965)

* Give a unique category to each test.

This change introduce a TestCategory enum to ConformanceRequest. Existing tests
are divided into three categories: binary format test, json format test and json
format (ignore unknown when parsing) test. For the previous two categories, there
is no change to existing testee programs. For tests with the last category, testee programs
should either enable ignoring unknown field during json parsing or skip the test.

* Fix python test

* Fix java

* Fix csharp

* Update document

* Update csharp generated code
Paul Yang 7 years ago
parent
commit
8705adc228

+ 6 - 2
conformance/ConformanceJava.java

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

+ 15 - 1
conformance/conformance.proto

@@ -57,6 +57,17 @@ enum WireFormat {
   JSON = 2;
   JSON = 2;
 }
 }
 
 
+enum TestCategory {
+  BINARY_TEST = 0;  // Test binary wire format.
+  JSON_TEST = 1;  // 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 = 2;  
+}
+
 // Represents a single test case's input.  The testee should:
 // Represents a single test case's input.  The testee should:
 //
 //
 //   1. parse this proto (which should always succeed)
 //   1. parse this proto (which should always succeed)
@@ -83,7 +94,10 @@ message ConformanceRequest {
   // protobuf_test_messages.proto2.TestAllTypesProto2.
   // protobuf_test_messages.proto2.TestAllTypesProto2.
   string message_type = 4;
   string message_type = 4;
 
 
-  bool ignore_unknown_json = 5;
+  // Each test is given a specific test category. Some category may need spedific
+  // support in testee programs. Refer to the defintion of TestCategory for
+  // more information.
+  TestCategory test_category = 5;
 }
 }
 
 
 // Represents a single test case's output.
 // Represents a single test case's output.

+ 7 - 1
conformance/conformance_cpp.cc

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

+ 5 - 1
conformance/conformance_php.php

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

+ 5 - 1
conformance/conformance_python.py

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

+ 14 - 4
conformance/conformance_test.cc

@@ -193,10 +193,11 @@ namespace protobuf {
 
 
 ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
 ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
     ConformanceLevel level, conformance::WireFormat input_format,
     ConformanceLevel level, conformance::WireFormat input_format,
-    conformance::WireFormat output_format, bool is_proto3,
+    conformance::WireFormat output_format,
+    conformance::TestCategory test_category,
+    bool is_proto3,
     const string& test_name, const string& input)
     const string& test_name, const string& input)
-    : level_(level), input_format_(input_format),
-      output_format_(output_format), is_proto3_(is_proto3) {
+    : level_(level), is_proto3_(is_proto3) {
   auto newTestMessage = [&is_proto3]() {
   auto newTestMessage = [&is_proto3]() {
     Message* newMessage;
     Message* newMessage;
     if (is_proto3) {
     if (is_proto3) {
@@ -243,6 +244,8 @@ ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
       GOOGLE_LOG(FATAL) << "Unspecified output format";
       GOOGLE_LOG(FATAL) << "Unspecified output format";
   }
   }
 
 
+  request_.set_test_category(test_category);
+
   test_name_ = ConformanceLevelToString(level) + rname +
   test_name_ = ConformanceLevelToString(level) + rname +
                input_format_string + test_name +
                input_format_string + test_name +
                output_format_string;
                output_format_string;
@@ -465,6 +468,7 @@ void ConformanceTestSuite::ExpectParseFailureForProtoWithProtoVersion (
   ConformanceRequest request;
   ConformanceRequest request;
   ConformanceResponse response;
   ConformanceResponse response;
   request.set_protobuf_payload(proto);
   request.set_protobuf_payload(proto);
+  request.set_test_category(conformance::BINARY_TEST);
   if (isProto3) {
   if (isProto3) {
     request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
     request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
   } else {
   } else {
@@ -511,11 +515,13 @@ void ConformanceTestSuite::RunValidJsonTest(
     const string& equivalent_text_format) {
     const string& equivalent_text_format) {
   ConformanceRequestSetting setting1(
   ConformanceRequestSetting setting1(
       level, conformance::JSON, conformance::PROTOBUF,
       level, conformance::JSON, conformance::PROTOBUF,
+      conformance::JSON_TEST,
       true, test_name, input_json);
       true, test_name, input_json);
   RunValidInputTest(setting1, equivalent_text_format);
   RunValidInputTest(setting1, equivalent_text_format);
 
 
   ConformanceRequestSetting setting2(
   ConformanceRequestSetting setting2(
       level, conformance::JSON, conformance::JSON,
       level, conformance::JSON, conformance::JSON,
+      conformance::JSON_TEST,
       true, test_name, input_json);
       true, test_name, input_json);
   RunValidInputTest(setting2, equivalent_text_format);
   RunValidInputTest(setting2, equivalent_text_format);
 }
 }
@@ -525,6 +531,7 @@ void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
     const string& equivalent_text_format) {
     const string& equivalent_text_format) {
   ConformanceRequestSetting setting(
   ConformanceRequestSetting setting(
       level, conformance::PROTOBUF, conformance::JSON,
       level, conformance::PROTOBUF, conformance::JSON,
+      conformance::JSON_TEST,
       true, test_name, input.SerializeAsString());
       true, test_name, input.SerializeAsString());
   RunValidInputTest(setting, equivalent_text_format);
   RunValidInputTest(setting, equivalent_text_format);
 }
 }
@@ -534,8 +541,8 @@ void ConformanceTestSuite::RunValidJsonIgnoreUnknownTest(
     const string& equivalent_text_format) {
     const string& equivalent_text_format) {
   ConformanceRequestSetting setting(
   ConformanceRequestSetting setting(
       level, conformance::JSON, conformance::PROTOBUF,
       level, conformance::JSON, conformance::PROTOBUF,
+      conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST,
       true, test_name, input_json);
       true, test_name, input_json);
-  setting.SetIgnoreUnknownJson(true);
   RunValidInputTest(setting, equivalent_text_format);
   RunValidInputTest(setting, equivalent_text_format);
 }
 }
 
 
@@ -545,12 +552,14 @@ void ConformanceTestSuite::RunValidProtobufTest(
     bool isProto3) {
     bool isProto3) {
   ConformanceRequestSetting setting1(
   ConformanceRequestSetting setting1(
       level, conformance::PROTOBUF, conformance::PROTOBUF,
       level, conformance::PROTOBUF, conformance::PROTOBUF,
+      conformance::BINARY_TEST,
       isProto3, test_name, input_protobuf);
       isProto3, test_name, input_protobuf);
   RunValidInputTest(setting1, equivalent_text_format);
   RunValidInputTest(setting1, equivalent_text_format);
 
 
   if (isProto3) {
   if (isProto3) {
     ConformanceRequestSetting setting2(
     ConformanceRequestSetting setting2(
         level, conformance::PROTOBUF, conformance::JSON,
         level, conformance::PROTOBUF, conformance::JSON,
+        conformance::BINARY_TEST,
         true, test_name, input_protobuf);
         true, test_name, input_protobuf);
     RunValidInputTest(setting2, equivalent_text_format);
     RunValidInputTest(setting2, equivalent_text_format);
   }
   }
@@ -561,6 +570,7 @@ void ConformanceTestSuite::RunValidBinaryProtobufTest(
     const string& input_protobuf, bool isProto3) {
     const string& input_protobuf, bool isProto3) {
   ConformanceRequestSetting setting(
   ConformanceRequestSetting setting(
       level, conformance::PROTOBUF, conformance::PROTOBUF,
       level, conformance::PROTOBUF, conformance::PROTOBUF,
+      conformance::BINARY_TEST,
       isProto3, test_name, input_protobuf);
       isProto3, test_name, input_protobuf);
   RunValidBinaryInputTest(setting, input_protobuf);
   RunValidBinaryInputTest(setting, input_protobuf);
 }
 }

+ 3 - 7
conformance/conformance_test.h

@@ -152,7 +152,9 @@ class ConformanceTestSuite {
    public:
    public:
     ConformanceRequestSetting(
     ConformanceRequestSetting(
         ConformanceLevel level, conformance::WireFormat input_format,
         ConformanceLevel level, conformance::WireFormat input_format,
-        conformance::WireFormat output_format, bool is_proto3,
+        conformance::WireFormat output_format,
+        conformance::TestCategory test_category,
+        bool is_proto3,
         const string& test_name, const string& input);
         const string& test_name, const string& input);
 
 
    Message* GetTestMessage() const;
    Message* GetTestMessage() const;
@@ -169,14 +171,8 @@ class ConformanceTestSuite {
      return level_;
      return level_;
    }
    }
 
 
-   void SetIgnoreUnknownJson(bool ignore_unknown_json) {
-     request_.set_ignore_unknown_json(ignore_unknown_json);
-   }
-  
    private:
    private:
     ConformanceLevel level_;
     ConformanceLevel level_;
-    conformance::WireFormat input_format_;
-    conformance::WireFormat output_format_;
     bool is_proto3_;
     bool is_proto3_;
     string test_name_;
     string test_name_;
     conformance::ConformanceRequest request_;
     conformance::ConformanceRequest request_;

+ 0 - 6
conformance/failure_list_cpp.txt

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

+ 0 - 6
conformance/failure_list_csharp.txt

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

+ 0 - 6
conformance/failure_list_java.txt

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

+ 0 - 6
conformance/failure_list_python-post26.txt

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

+ 0 - 6
conformance/failure_list_python.txt

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

+ 0 - 6
conformance/failure_list_python_cpp.txt

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

+ 53 - 27
csharp/src/Google.Protobuf.Conformance/Conformance.cs

@@ -24,22 +24,24 @@ namespace Conformance {
     static ConformanceReflection() {
     static ConformanceReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
           string.Concat(
-            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiwAEKEkNvbmZvcm1h",
+            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2Ui1QEKEkNvbmZvcm1h",
             "bmNlUmVxdWVzdBIaChBwcm90b2J1Zl9wYXlsb2FkGAEgASgMSAASFgoManNv",
             "bmNlUmVxdWVzdBIaChBwcm90b2J1Zl9wYXlsb2FkGAEgASgMSAASFgoManNv",
             "bl9wYXlsb2FkGAIgASgJSAASOAoXcmVxdWVzdGVkX291dHB1dF9mb3JtYXQY",
             "bl9wYXlsb2FkGAIgASgJSAASOAoXcmVxdWVzdGVkX291dHB1dF9mb3JtYXQY",
             "AyABKA4yFy5jb25mb3JtYW5jZS5XaXJlRm9ybWF0EhQKDG1lc3NhZ2VfdHlw",
             "AyABKA4yFy5jb25mb3JtYW5jZS5XaXJlRm9ybWF0EhQKDG1lc3NhZ2VfdHlw",
-            "ZRgEIAEoCRIbChNpZ25vcmVfdW5rbm93bl9qc29uGAUgASgIQgkKB3BheWxv",
-            "YWQisQEKE0NvbmZvcm1hbmNlUmVzcG9uc2USFQoLcGFyc2VfZXJyb3IYASAB",
-            "KAlIABIZCg9zZXJpYWxpemVfZXJyb3IYBiABKAlIABIXCg1ydW50aW1lX2Vy",
-            "cm9yGAIgASgJSAASGgoQcHJvdG9idWZfcGF5bG9hZBgDIAEoDEgAEhYKDGpz",
-            "b25fcGF5bG9hZBgEIAEoCUgAEhEKB3NraXBwZWQYBSABKAlIAEIICgZyZXN1",
-            "bHQqNQoKV2lyZUZvcm1hdBIPCgtVTlNQRUNJRklFRBAAEgwKCFBST1RPQlVG",
-            "EAESCAoESlNPThACQiEKH2NvbS5nb29nbGUucHJvdG9idWYuY29uZm9ybWFu",
-            "Y2ViBnByb3RvMw=="));
+            "ZRgEIAEoCRIwCg10ZXN0X2NhdGVnb3J5GAUgASgOMhkuY29uZm9ybWFuY2Uu",
+            "VGVzdENhdGVnb3J5QgkKB3BheWxvYWQisQEKE0NvbmZvcm1hbmNlUmVzcG9u",
+            "c2USFQoLcGFyc2VfZXJyb3IYASABKAlIABIZCg9zZXJpYWxpemVfZXJyb3IY",
+            "BiABKAlIABIXCg1ydW50aW1lX2Vycm9yGAIgASgJSAASGgoQcHJvdG9idWZf",
+            "cGF5bG9hZBgDIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgEIAEoCUgAEhEKB3Nr",
+            "aXBwZWQYBSABKAlIAEIICgZyZXN1bHQqNQoKV2lyZUZvcm1hdBIPCgtVTlNQ",
+            "RUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoESlNPThACKlQKDFRlc3RDYXRl",
+            "Z29yeRIPCgtCSU5BUllfVEVTVBAAEg0KCUpTT05fVEVTVBABEiQKIEpTT05f",
+            "SUdOT1JFX1VOS05PV05fUEFSU0lOR19URVNUEAJCIQofY29tLmdvb2dsZS5w",
+            "cm90b2J1Zi5jb25mb3JtYW5jZWIGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), }, new pbr::GeneratedClrTypeInfo[] {
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat", "MessageType", "IgnoreUnknownJson" }, new[]{ "Payload" }, null, null),
+          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.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null)
           }));
           }));
     }
     }
@@ -53,6 +55,25 @@ namespace Conformance {
     [pbr::OriginalName("JSON")] Json = 2,
     [pbr::OriginalName("JSON")] Json = 2,
   }
   }
 
 
+  public enum TestCategory {
+    /// <summary>
+    /// Test binary wire format.
+    /// </summary>
+    [pbr::OriginalName("BINARY_TEST")] BinaryTest = 0,
+    /// <summary>
+    /// Test json wire format.
+    /// </summary>
+    [pbr::OriginalName("JSON_TEST")] JsonTest = 1,
+    /// <summary>
+    /// 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.
+    /// </summary>
+    [pbr::OriginalName("JSON_IGNORE_UNKNOWN_PARSING_TEST")] JsonIgnoreUnknownParsingTest = 2,
+  }
+
   #endregion
   #endregion
 
 
   #region Messages
   #region Messages
@@ -90,7 +111,7 @@ namespace Conformance {
     public ConformanceRequest(ConformanceRequest other) : this() {
     public ConformanceRequest(ConformanceRequest other) : this() {
       requestedOutputFormat_ = other.requestedOutputFormat_;
       requestedOutputFormat_ = other.requestedOutputFormat_;
       messageType_ = other.messageType_;
       messageType_ = other.messageType_;
-      ignoreUnknownJson_ = other.ignoreUnknownJson_;
+      testCategory_ = other.testCategory_;
       switch (other.PayloadCase) {
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
           ProtobufPayload = other.ProtobufPayload;
@@ -160,14 +181,19 @@ namespace Conformance {
       }
       }
     }
     }
 
 
-    /// <summary>Field number for the "ignore_unknown_json" field.</summary>
-    public const int IgnoreUnknownJsonFieldNumber = 5;
-    private bool ignoreUnknownJson_;
+    /// <summary>Field number for the "test_category" field.</summary>
+    public const int TestCategoryFieldNumber = 5;
+    private global::Conformance.TestCategory testCategory_ = 0;
+    /// <summary>
+    /// Each test is given a specific test category. Some category may need spedific
+    /// support in testee programs. Refer to the defintion of TestCategory for
+    /// more information.
+    /// </summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
-    public bool IgnoreUnknownJson {
-      get { return ignoreUnknownJson_; }
+    public global::Conformance.TestCategory TestCategory {
+      get { return testCategory_; }
       set {
       set {
-        ignoreUnknownJson_ = value;
+        testCategory_ = value;
       }
       }
     }
     }
 
 
@@ -207,7 +233,7 @@ namespace Conformance {
       if (JsonPayload != other.JsonPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
       if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
       if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
       if (MessageType != other.MessageType) return false;
       if (MessageType != other.MessageType) return false;
-      if (IgnoreUnknownJson != other.IgnoreUnknownJson) return false;
+      if (TestCategory != other.TestCategory) return false;
       if (PayloadCase != other.PayloadCase) return false;
       if (PayloadCase != other.PayloadCase) return false;
       return Equals(_unknownFields, other._unknownFields);
       return Equals(_unknownFields, other._unknownFields);
     }
     }
@@ -219,7 +245,7 @@ namespace Conformance {
       if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
       if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
       if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
       if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
-      if (IgnoreUnknownJson != false) hash ^= IgnoreUnknownJson.GetHashCode();
+      if (TestCategory != 0) hash ^= TestCategory.GetHashCode();
       hash ^= (int) payloadCase_;
       hash ^= (int) payloadCase_;
       if (_unknownFields != null) {
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
         hash ^= _unknownFields.GetHashCode();
@@ -250,9 +276,9 @@ namespace Conformance {
         output.WriteRawTag(34);
         output.WriteRawTag(34);
         output.WriteString(MessageType);
         output.WriteString(MessageType);
       }
       }
-      if (IgnoreUnknownJson != false) {
+      if (TestCategory != 0) {
         output.WriteRawTag(40);
         output.WriteRawTag(40);
-        output.WriteBool(IgnoreUnknownJson);
+        output.WriteEnum((int) TestCategory);
       }
       }
       if (_unknownFields != null) {
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
         _unknownFields.WriteTo(output);
@@ -274,8 +300,8 @@ namespace Conformance {
       if (MessageType.Length != 0) {
       if (MessageType.Length != 0) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageType);
         size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageType);
       }
       }
-      if (IgnoreUnknownJson != false) {
-        size += 1 + 1;
+      if (TestCategory != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) TestCategory);
       }
       }
       if (_unknownFields != null) {
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
         size += _unknownFields.CalculateSize();
@@ -294,8 +320,8 @@ namespace Conformance {
       if (other.MessageType.Length != 0) {
       if (other.MessageType.Length != 0) {
         MessageType = other.MessageType;
         MessageType = other.MessageType;
       }
       }
-      if (other.IgnoreUnknownJson != false) {
-        IgnoreUnknownJson = other.IgnoreUnknownJson;
+      if (other.TestCategory != 0) {
+        TestCategory = other.TestCategory;
       }
       }
       switch (other.PayloadCase) {
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
         case PayloadOneofCase.ProtobufPayload:
@@ -334,7 +360,7 @@ namespace Conformance {
             break;
             break;
           }
           }
           case 40: {
           case 40: {
-            IgnoreUnknownJson = input.ReadBool();
+            testCategory_ = (global::Conformance.TestCategory) input.ReadEnum();
             break;
             break;
           }
           }
         }
         }

+ 3 - 0
csharp/src/Google.Protobuf.Conformance/Program.cs

@@ -87,6 +87,9 @@ namespace Google.Protobuf.Conformance
                 switch (request.PayloadCase)
                 switch (request.PayloadCase)
                 {
                 {
                     case ConformanceRequest.PayloadOneofCase.JsonPayload:
                     case ConformanceRequest.PayloadOneofCase.JsonPayload:
+                        if (request.TestCategory == global::Conformance.TestCategory.JsonIgnoreUnknownParsingTest) {
+                            return new ConformanceResponse { Skipped = "CSharp doesn't support skipping unknown fields in json parsing." };
+                        }
                         var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry));
                         var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry));
                         message = parser.Parse<ProtobufTestMessages.Proto3.TestAllTypesProto3>(request.JsonPayload);
                         message = parser.Parse<ProtobufTestMessages.Proto3.TestAllTypesProto3>(request.JsonPayload);
                         break;
                         break;