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