You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by qi...@apache.org on 2020/03/20 09:02:59 UTC
[mesos] 02/21: Accommodated the "Infinity" value in the JSON <->
Protobuf conversion.
This is an automated email from the ASF dual-hosted git repository.
qianzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit ec82a516918ebd663816cb110f73bdee6e5268be
Author: Qian Zhang <zh...@gmail.com>
AuthorDate: Sun Feb 23 10:09:48 2020 +0800
Accommodated the "Infinity" value in the JSON <-> Protobuf conversion.
Review: https://reviews.apache.org/r/72162
---
3rdparty/stout/include/stout/jsonify.hpp | 1 +
3rdparty/stout/include/stout/protobuf.hpp | 19 ++++++-
3rdparty/stout/tests/protobuf_tests.cpp | 82 +++++++++++++++++++++++++++++++
3rdparty/stout/tests/protobuf_tests.proto | 9 ++++
4 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/3rdparty/stout/include/stout/jsonify.hpp b/3rdparty/stout/include/stout/jsonify.hpp
index 7a239d8..e18da8f 100644
--- a/3rdparty/stout/include/stout/jsonify.hpp
+++ b/3rdparty/stout/include/stout/jsonify.hpp
@@ -14,6 +14,7 @@
#define __STOUT_JSONIFY__
#define RAPIDJSON_HAS_STDSTRING 1
+#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
// TODO(bmahler): Consider enabling UTF-8 validation when writing
// json. Prior to the introduction of rapidjson, we performed no
diff --git a/3rdparty/stout/include/stout/protobuf.hpp b/3rdparty/stout/include/stout/protobuf.hpp
index fcd91d5..9a82a30 100644
--- a/3rdparty/stout/include/stout/protobuf.hpp
+++ b/3rdparty/stout/include/stout/protobuf.hpp
@@ -540,7 +540,24 @@ struct Parser : boost::static_visitor<Try<Nothing>>
break;
}
case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
- case google::protobuf::FieldDescriptor::TYPE_FLOAT:
+ case google::protobuf::FieldDescriptor::TYPE_FLOAT: {
+ if (string.value == "Infinity") {
+ return operator()(JSON::Number(
+ std::numeric_limits<double>::infinity()));
+ } else if (string.value == "-Infinity") {
+ return operator()(JSON::Number(
+ -std::numeric_limits<double>::infinity()));
+ } else {
+ Try<JSON::Number> number = JSON::parse<JSON::Number>(string.value);
+ if (number.isError()) {
+ return Error(
+ "Failed to parse '" + string.value + "' as a JSON number "
+ "for field '" + field->name() + "': " + number.error());
+ }
+
+ return operator()(number.get());
+ }
+ }
case google::protobuf::FieldDescriptor::TYPE_INT64:
case google::protobuf::FieldDescriptor::TYPE_SINT64:
case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
diff --git a/3rdparty/stout/tests/protobuf_tests.cpp b/3rdparty/stout/tests/protobuf_tests.cpp
index 55889dc..46249ea 100644
--- a/3rdparty/stout/tests/protobuf_tests.cpp
+++ b/3rdparty/stout/tests/protobuf_tests.cpp
@@ -15,6 +15,7 @@
#include <gmock/gmock.h>
#include <algorithm>
+#include <limits>
#include <string>
#include <google/protobuf/util/message_differencer.h>
@@ -53,6 +54,25 @@ bool operator!=(const SimpleMessage& left, const SimpleMessage& right)
return !(left == right);
}
+
+bool operator==(const FloatMessage& left, const FloatMessage& right)
+{
+ if (left.f1() == right.f1() &&
+ left.f2() == right.f2() &&
+ left.d1() == right.d1() &&
+ left.d2() == right.d2()) {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool operator!=(const FloatMessage& left, const FloatMessage& right)
+{
+ return !(left == right);
+}
+
} // namespace tests {
@@ -852,3 +872,65 @@ TEST(ProtobufTest, JsonifyMap)
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
message, *protoFromJson));
}
+
+
+TEST(ProtobufTest, JsonInfinity)
+{
+ tests::FloatMessage message;
+ message.set_f1(std::numeric_limits<float>::infinity());
+ message.set_f2(-std::numeric_limits<float>::infinity());
+ message.set_d1(std::numeric_limits<double>::infinity());
+ message.set_d2(-std::numeric_limits<double>::infinity());
+
+ // The keys are in alphabetical order.
+ string expected =
+ R"~(
+ {
+ "d1": "Infinity",
+ "d2": "-Infinity",
+ "f1": "Infinity",
+ "f2": "-Infinity"
+ })~";
+
+ // Remove ' ' and '\n' from `expected` so that we can compare
+ // it with the JSON string parsed from protobuf message.
+ expected.erase(
+ std::remove_if(expected.begin(), expected.end(), ::isspace),
+ expected.end());
+
+ JSON::Object referenceObject;
+ referenceObject.values["d1"] = JSON::Number(std::numeric_limits<double>::infinity());
+ referenceObject.values["d2"] = JSON::Number(-std::numeric_limits<double>::infinity());
+ referenceObject.values["f1"] = JSON::Number(std::numeric_limits<double>::infinity());
+ referenceObject.values["f2"] = JSON::Number(-std::numeric_limits<double>::infinity());
+
+ // Check Protobuf -> JSON.
+ JSON::Object protobufObject = JSON::protobuf(message);
+ EXPECT_EQ(referenceObject, protobufObject);
+ EXPECT_EQ(expected, stringify(protobufObject));
+
+ // Check JSON -> Protobuf.
+ Try<tests::FloatMessage> parse =
+ protobuf::parse<tests::FloatMessage>(protobufObject);
+
+ ASSERT_SOME(parse);
+ EXPECT_EQ(message, parse.get());
+
+ // Check String -> JSON.
+ Try<JSON::Object> parsedObject = JSON::parse<JSON::Object>(expected);
+
+ // Unlike `JSON::protobuf()`, `JSON::parse()` does not have the
+ // field type information, so it will just parse "Infinity" as a
+ // `JSON::String` instead of `JSON::Number`.
+ referenceObject.values["d1"] = JSON::String("Infinity");
+ referenceObject.values["d2"] = JSON::String("-Infinity");
+ referenceObject.values["f1"] = JSON::String("Infinity");
+ referenceObject.values["f2"] = JSON::String("-Infinity");
+
+ EXPECT_SOME_EQ(referenceObject, parsedObject);
+
+ // Check JSON -> Protobuf.
+ parse = protobuf::parse<tests::FloatMessage>(parsedObject.get());
+ ASSERT_SOME(parse);
+ EXPECT_EQ(message, parse.get());
+}
diff --git a/3rdparty/stout/tests/protobuf_tests.proto b/3rdparty/stout/tests/protobuf_tests.proto
index 5e20215..3a6a458 100644
--- a/3rdparty/stout/tests/protobuf_tests.proto
+++ b/3rdparty/stout/tests/protobuf_tests.proto
@@ -130,3 +130,12 @@ message MapMessage {
map<sint32, string> sint32_to_string = 19;
map<sint64, string> sint64_to_string = 20;
}
+
+
+// A message for testing infinite floating point numbers.
+message FloatMessage {
+ required float f1 = 1;
+ required float f2 = 2;
+ required double d1 = 3;
+ required double d2 = 4;
+}