You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ti...@apache.org on 2015/05/07 23:31:56 UTC

[2/2] mesos git commit: Added a function which checks if a JSON object is contained within another.

Added a function which checks if a JSON object is contained within another.

Adds a function which allows to perform comparison tests on subsets of JSON
blobs, increasing readability for tests that include JSON.

Example:
JSON::Value expected = JSON::parse(
    "{"
    "  \"key\" : true"
    "}").get();

// Returned json:
// {
//   "uptime" : 45234.123,
//   "key" : true
// }
JSON::Value actual = bar();

// I'm only interested on the "key" entry and ignore the rest.
EXPECT_TRUE(contains(actual, expected));

Review: https://reviews.apache.org/r/32163


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/da088003
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/da088003
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/da088003

Branch: refs/heads/master
Commit: da0880035692e8431e8d688f1ae9d7b3bf5d62a6
Parents: 49ea887
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Thu May 7 13:39:41 2015 -0700
Committer: Till Toenshoff <to...@me.com>
Committed: Thu May 7 14:30:57 2015 -0700

----------------------------------------------------------------------
 .../3rdparty/stout/include/stout/json.hpp       | 144 +++++++++
 .../3rdparty/stout/tests/json_tests.cpp         | 304 +++++++++++++++++++
 2 files changed, 448 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/da088003/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
index 2337337..8784e76 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/json.hpp
@@ -181,6 +181,50 @@ struct Value : internal::Variant
 
   template <typename T>
   const T& as() const;
+
+  // Returns true if and only if 'other' is contained by 'this'.
+  // 'Other' is contained by 'this' if the following conditions are
+  // fulfilled:
+  // 1. If 'other' is a JSON object, then 'this' is also a JSON
+  //    object, all keys of 'other' are also present in 'this' and
+  //    the value for each key in 'this' also contain the value for
+  //    the same key in 'other', i.e. for all keys 'k' in 'other',
+  //    'this[k].contains(other[k])' is true.
+  // 2. If 'other' is a JSON array, 'this' is also a JSON array, the
+  //    length of both arrays is the same and each element in 'this'
+  //    also contains the element in 'other' at the same position,
+  //    i.e. it holds that this.length() == other.length() and
+  //    for each i, 0 <= i < this.length,
+  //    'this[i].contains(other[i])'.
+  // 3. For all other types, 'this' is of the same type as 'other' and
+  //    'this == other'.
+  // NOTE: For a given key 'k', if 'this[k] == null' then
+  // 'this.contains(other)' holds if either 'k' is not present in
+  // 'other.keys()' or 'other[k] == null'.
+  // Similarly, if 'other[k] == null', 'this.contains(other)' only if
+  // 'this[k] == null'. This is a consequence of the containment
+  // definition.
+  bool contains(const Value& other) const;
+
+private:
+  // A class which follows the visitor pattern and implements the
+  // containment rules described in the documentation of 'contains'.
+  // See 'bool Value::contains(const Value& other) const'.
+  struct ContainmentComparator : public boost::static_visitor<bool>
+  {
+    explicit ContainmentComparator(const Value& _self)
+      : self(_self) {}
+
+    bool operator () (const Object& other) const;
+    bool operator () (const Array& other) const;
+    bool operator () (const String& other) const;
+    bool operator () (const Number& other) const;
+    bool operator () (const Boolean& other) const;
+    bool operator () (const Null&) const;
+
+  private:
+    const Value& self;
+  };
 };
 
 
@@ -285,6 +329,106 @@ Result<T> Object::find(const std::string& path) const
 }
 
 
+inline bool Value::contains(const Value& other) const
+{
+  return boost::apply_visitor(Value::ContainmentComparator(*this), other);
+}
+
+
+inline bool Value::ContainmentComparator::operator () (
+    const Object& other) const
+{
+  if (!self.is<Object>()) {
+    return false;
+  }
+
+  // The empty set is contained in every set.
+  if (other.values.empty()) {
+    return true;
+  }
+
+  const Object& _self = self.as<Object>();
+
+  // All entries in 'other' should exists in 'self', which implies
+  // there should be at most as many entries in other as in self.
+  if (other.values.size() > _self.values.size()) {
+    return false;
+  }
+
+  foreachpair (const std::string& key, const Value& value, other.values) {
+    auto _selfIterator = _self.values.find(key);
+
+    if (_selfIterator == _self.values.end()) {
+      return false;
+    }
+
+    if (!_selfIterator->second.contains(value)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+inline bool Value::ContainmentComparator::operator () (
+    const String& other) const
+{
+  if (!self.is<String>()) {
+    return false;
+  }
+  return self.as<String>().value == other.value;
+}
+
+
+inline bool Value::ContainmentComparator::operator () (
+    const Number& other) const
+{
+  if (!self.is<Number>()) {
+    return false;
+  }
+  return self.as<Number>().value == other.value;
+}
+
+
+inline bool Value::ContainmentComparator::operator () (const Array& other) const
+{
+  if (!self.is<Array>()) {
+    return false;
+  }
+
+  const Array& _self = self.as<Array>();
+
+  if (_self.values.size() != other.values.size()) {
+    return false;
+  }
+
+  for (unsigned i = 0; i < other.values.size(); ++i) {
+    if (!_self.values[i].contains(other.values[i])) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+inline bool Value::ContainmentComparator::operator () (
+    const Boolean& other) const
+{
+  if (!self.is<Boolean>()) {
+    return false;
+  }
+  return self.as<Boolean>().value == other.value;
+}
+
+
+inline bool Value::ContainmentComparator::operator () (const Null&) const
+{
+  return self.is<Null>();
+}
+
+
 struct Comparator : boost::static_visitor<bool>
 {
   Comparator(const Value& _value)

http://git-wip-us.apache.org/repos/asf/mesos/blob/da088003/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
index d1f0248..60c0336 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/json_tests.cpp
@@ -303,3 +303,307 @@ TEST(JsonTest, Equals)
   EXPECT_SOME_NE(object, JSON::parse("{\"a\" : 1}"));
   EXPECT_SOME_NE(object, JSON::parse("{}"));
 }
+
+
+// Test the containment of JSON objects where one is a JSON array.
+TEST(JsonTest, ContainsArray)
+{
+  Try<JSON::Value> _array = JSON::parse("{\"array\" : [1, 2, 3]}");
+  ASSERT_SOME(_array);
+  const JSON::Value array = _array.get();
+
+  Try<JSON::Value> arrayTest = JSON::parse("{\"array\" : [1, 2, 3]}");
+  EXPECT_TRUE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{}");
+  EXPECT_TRUE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : [3, 2, 1, 0]}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : [1, 2, 3, 4]}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : [3, 2, 1]}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : [1, 2, 4]}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : [1, 2]}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : []}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : null}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : 42}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+  arrayTest = JSON::parse("{\"array\" : \"A string\"}");
+  EXPECT_FALSE(array.contains(arrayTest.get()));
+
+
+  // Test arrays of doubles.
+  Try<JSON::Value> _doubleArray =
+    JSON::parse("{\"array_of_doubles\" : [1.0, -22.33, 99.987, 100]}");
+  ASSERT_SOME(_doubleArray);
+  const JSON::Value doubleArray = _doubleArray.get();
+
+  Try<JSON::Value> doubleArrayTest =
+    JSON::parse("{\"array_of_doubles\" : [1.0, -22.33, 99.987, 100]}");
+  EXPECT_TRUE(doubleArray.contains(doubleArrayTest.get()));
+
+  doubleArrayTest =
+    JSON::parse("{\"array_of_doubles\" : [1.0, -22.33, 99.999, 100]}");
+  EXPECT_FALSE(doubleArray.contains(doubleArrayTest.get()));
+
+  doubleArrayTest = JSON::parse("{\"array_of_doubles\" : [1.0, -22.33, 100]}");
+  EXPECT_FALSE(doubleArray.contains(doubleArrayTest.get()));
+
+
+  // Test array of arrays.
+  Try<JSON::Value> _arrayArray =
+    JSON::parse("{\"array_of_arrays\" : [[1.0, -22.33], [1, 2]]}");
+  ASSERT_SOME(_arrayArray);
+  const JSON::Value arrayArray = _arrayArray.get();
+
+  Try<JSON::Value> arrayArrayTest =
+    JSON::parse("{\"array_of_arrays\" : [[1.0, -22.33], [1, 2]]}");
+  EXPECT_TRUE(arrayArray.contains(arrayArrayTest.get()));
+
+  arrayArrayTest =
+    JSON::parse("{\"array_of_arrays\" : [[1.0, -22.33], [1, 3]]}");
+  EXPECT_FALSE(arrayArray.contains(arrayArrayTest.get()));
+
+  arrayArrayTest =
+    JSON::parse("{\"array_of_arrays\" : [[1.0, -33.44], [1, 3]]}");
+  EXPECT_FALSE(arrayArray.contains(arrayArrayTest.get()));
+
+  arrayArrayTest =
+    JSON::parse("{\"array_of_arrays\" : [[1.0, -22.33], [1]]}");
+  EXPECT_FALSE(arrayArray.contains(arrayArrayTest.get()));
+}
+
+
+// Test the containment of JSON objects where one is a JSON boolean.
+TEST(JsonTest, ContainsBoolean)
+{
+  Try<JSON::Value> _boolean = JSON::parse("{\"boolean\" : true}");
+  ASSERT_SOME(_boolean);
+  const JSON::Value boolean = _boolean.get();
+
+  Try<JSON::Value> booleanTest = JSON::parse("{\"boolean\" : true}");
+  EXPECT_TRUE(boolean.contains(booleanTest.get()));
+
+  booleanTest = JSON::parse("{}");
+  EXPECT_TRUE(boolean.contains(booleanTest.get()));
+
+  booleanTest = JSON::parse("{\"boolean\" : false}");
+  EXPECT_FALSE(boolean.contains(booleanTest.get()));
+
+  booleanTest = JSON::parse("{\"boolean\" : null}");
+  EXPECT_FALSE(boolean.contains(booleanTest.get()));
+
+  booleanTest = JSON::parse("{\"boolean\" : 42}");
+  EXPECT_FALSE(boolean.contains(booleanTest.get()));
+
+  booleanTest = JSON::parse("{\"boolean\" : \"A string\"}");
+  EXPECT_FALSE(boolean.contains(booleanTest.get()));
+}
+
+
+// Test the containment of JSON objects where one is a JSON null.
+TEST(JsonTest, ContainsNull)
+{
+  Try<JSON::Value> _nullEntry = JSON::parse("{\"null_entry\" : null}");
+  ASSERT_SOME(_nullEntry);
+  const JSON::Value nullEntry = _nullEntry.get();
+
+  Try<JSON::Value> nullEntryTest = JSON::parse("{\"null_entry\" : null}");
+  EXPECT_TRUE(nullEntry.contains(nullEntryTest.get()));
+
+  nullEntryTest = JSON::parse("{}");
+  EXPECT_TRUE(nullEntry.contains(nullEntryTest.get()));
+
+  nullEntryTest = JSON::parse("{\"null_entry\" : 42}");
+  EXPECT_FALSE(nullEntry.contains(nullEntryTest.get()));
+
+  nullEntryTest = JSON::parse("{\"null_entry\" : \"A string\"}");
+  EXPECT_FALSE(nullEntry.contains(nullEntryTest.get()));
+}
+
+
+// Test the containment of JSON objects where one is a JSON string.
+TEST(JsonTest, ContainsString)
+{
+  Try<JSON::Value> _str = JSON::parse("{\"string\" : \"Hello World!\"}");
+  ASSERT_SOME(_str);
+  const JSON::Value str = _str.get();
+
+  Try<JSON::Value> strTest = JSON::parse("{\"string\" : \"Hello World!\"}");
+  EXPECT_TRUE(str.contains(strTest.get()));
+
+  strTest = JSON::parse("{}");
+  EXPECT_TRUE(str.contains(strTest.get()));
+
+  strTest = JSON::parse("{\"string\" : \"Goodbye World!\"}");
+  EXPECT_FALSE(str.contains(strTest.get()));
+
+  strTest = JSON::parse("{\"string\" : \"\"}");
+  EXPECT_FALSE(str.contains(strTest.get()));
+
+  strTest = JSON::parse("{\"string\" : null}");
+  EXPECT_FALSE(str.contains(strTest.get()));
+
+  strTest = JSON::parse("{\"string\" : 42}");
+  EXPECT_FALSE(str.contains(strTest.get()));
+
+  strTest = JSON::parse("{\"string\" : [42]}");
+  EXPECT_FALSE(str.contains(strTest.get()));
+}
+
+
+// Test the containment of JSON objects to JSON objects.
+TEST(JsonTest, ContainsObject)
+{
+  Try<JSON::Value> _object = JSON::parse("{\"a\" : 1, \"b\" : 2}");
+  ASSERT_SOME(_object);
+  const JSON::Value object = _object.get();
+
+  Try<JSON::Value> objectTest = JSON::parse("{\"a\" : 1, \"b\" : 2}");
+  EXPECT_TRUE(object.contains(objectTest.get()));
+
+  objectTest = JSON::parse("{\"a\" : 1}");
+  EXPECT_TRUE(object.contains(objectTest.get()));
+
+  objectTest = JSON::parse("{\"b\" : 2}");
+  EXPECT_TRUE(object.contains(objectTest.get()));
+
+  objectTest = JSON::parse("{}");
+  EXPECT_TRUE(object.contains(objectTest.get()));
+
+  objectTest = JSON::parse("{\"a\" : 2}");
+  EXPECT_FALSE(object.contains(objectTest.get()));
+
+  objectTest = JSON::parse("{\"a\" : 1, \"b\" : []}");
+  EXPECT_FALSE(object.contains(objectTest.get()));
+
+
+  // Array of objects checks.
+  Try<JSON::Value> _objectArray = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {\"a\" : 1, \"b\" : 2},"
+      "    {\"c\" : 3, \"d\" : 4}"
+      "  ]"
+      "}").get();
+  ASSERT_SOME(_objectArray);
+  const JSON::Value objectArray = _objectArray.get();
+
+  Try<JSON::Value> objectArrayTest = objectArray;
+  EXPECT_TRUE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse("{}");
+  EXPECT_TRUE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {\"a\" : 1, \"b\" : 2},"
+      "    {\"c\" : 3}"
+      "  ]"
+      "}");
+  EXPECT_TRUE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {\"a\" : 1},"
+      "    {}"
+      "  ]"
+      "}");
+  EXPECT_TRUE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {},"
+      "    {}"
+      "  ]"
+      "}");
+  EXPECT_TRUE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {\"c\" : 3, \"d\" : 4},"
+      "    {\"a\" : 1, \"b\" : 2}"
+      "  ]"
+      "}");
+  EXPECT_FALSE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {\"e\" : 5},"
+      "    {}"
+      "  ]"
+      "}");
+  EXPECT_FALSE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : []"
+      "}");
+  EXPECT_FALSE(objectArray.contains(objectArrayTest.get()));
+
+  objectArrayTest = JSON::parse(
+      "{"
+      "  \"objectarray\" : ["
+      "    {},"
+      "    {},"
+      "    {}"
+      "  ]"
+      "}");
+  EXPECT_FALSE(objectArray.contains(objectArrayTest.get()));
+
+
+  // Tests on nested objects.
+  Try<JSON::Value> _nested = JSON::parse(
+      "{"
+      "  \"object\" : {"
+      "    \"a\" : 1,"
+      "    \"b\" : 2"
+      "  }"
+      "}");
+  ASSERT_SOME(_nested);
+  const JSON::Value nested = _nested.get();
+
+  Try<JSON::Value> nestedTest = nested;
+  EXPECT_TRUE(nested.contains(nestedTest.get()));
+
+  nestedTest = JSON::parse("{}");
+  EXPECT_TRUE(nested.contains(nestedTest.get()));
+
+  nestedTest = JSON::parse("{\"object\" : {}}");
+  EXPECT_TRUE(nested.contains(nestedTest.get()));
+
+  nestedTest = JSON::parse("{\"object\" : {\"a\" : 1}}");
+  EXPECT_TRUE(nested.contains(nestedTest.get()));
+
+  nestedTest = JSON::parse("{\"object\" : {\"c\" : 1}}");
+  EXPECT_FALSE(nested.contains(nestedTest.get()));
+
+  nestedTest = JSON::parse(
+      "{"
+      "  \"object\" : {"
+      "    \"a\" : 1,"
+      "    \"b\" : 2,"
+      "    \"c\" : 3"
+      "  }"
+      "}");
+  EXPECT_FALSE(nested.contains(nestedTest.get()));
+}