Browse Source

equality functions for data::Element + tests
added a removeIdentical(mapelement, mapelement) for use in config update handlers


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1040 e5f2f494-b856-4b98-b285-d166d9295462

Jelte Jansen 15 years ago
parent
commit
2f66bfbea6
3 changed files with 231 additions and 0 deletions
  1. 106 0
      src/lib/cc/cpp/data.cc
  2. 21 0
      src/lib/cc/cpp/data.h
  3. 104 0
      src/lib/cc/cpp/data_unittests.cc

+ 106 - 0
src/lib/cc/cpp/data.cc

@@ -58,6 +58,11 @@ std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
     return out << e->str();
 }
 
+bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b)
+{
+    return a->equals(b);
+};
+
 //
 // factory functions
 //
@@ -912,8 +917,109 @@ MapElement::find(const std::string& id, ElementPtr& t) {
 }
 
 bool
+IntElement::equals(ElementPtr other)
+{
+    return (other->getType() == Element::integer) &&
+           (i == other->intValue());
+}
+
+bool
+DoubleElement::equals(ElementPtr other)
+{
+    return (other->getType() == Element::real) &&
+           (d == other->doubleValue());
+}
+
+bool
+BoolElement::equals(ElementPtr other)
+{
+    return (other->getType() == Element::boolean) &&
+           (b == other->boolValue());
+}
+
+bool
+StringElement::equals(ElementPtr other)
+{
+    return (other->getType() == Element::string) &&
+           (s == other->stringValue());
+}
+
+bool
+ListElement::equals(ElementPtr other)
+{
+    if (other->getType() == Element::list) {
+        int s = size();
+        if (s != other->size()) {
+            return false;
+        }
+        for (int i = 0; i < s; i++) {
+            if (!get(i)->equals(other->get(i))) {
+                return false;
+            }
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool
+MapElement::equals(ElementPtr other)
+{
+    if (other->getType() == Element::map) {
+        std::map<std::string, ElementPtr> m = mapValue();
+        for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
+             it != m.end() ; ++it) {
+            if (other->contains((*it).first)) {
+                if (!get((*it).first)->equals(other->get((*it).first))) {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        }
+        // quickly walk through the other map too, to see if there's
+        // anything in there that we don't have. We don't need to
+        // compare those elements; if one of them is missing we
+        // differ (and if it's not missing the loop above has checked
+        // it)
+        m = other->mapValue();
+        for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
+             it != m.end() ; ++it) {
+            if (!contains((*it).first)) {
+                return false;
+            }
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool
 isc::data::isNull(ElementPtr p)
 {
     return !p;
 }
 
+void
+isc::data::removeIdentical(ElementPtr a, const ElementPtr b)
+{
+    if (a->getType() != Element::map || b->getType() != Element::map) {
+        dns_throw(TypeError, "Non-map Elements passed to removeIdentical");
+    }
+    std::cout<<"[XX] removeidentical from " << a << " and " << b << std::endl;
+    
+    std::map<std::string, ElementPtr> m = a->mapValue();
+    for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
+         it != m.end() ; ++it) {
+        if (b->contains((*it).first)) {
+            if (a->get((*it).first)->equals(b->get((*it).first))) {
+                std::cout<<"[XX] remove " << (*it).first << std::endl;
+                a->remove((*it).first);
+            }
+        }
+    }
+    std::cout<<"[XX] a now " << a << std::endl;
+
+}

+ 21 - 0
src/lib/cc/cpp/data.h

@@ -103,6 +103,10 @@ public:
 
     /// \return the type of this element
     int getType() { return type; };
+
+    /// \returns true if the other ElementPtr has the same type and
+    ///          value
+    virtual bool equals(ElementPtr other) = 0;
     
     // pure virtuals, every derived class must implement these
 
@@ -332,6 +336,7 @@ public:
     bool setValue(const int v) { i = v; return true; };
     std::string str();
     void toWire(std::stringstream& ss, int omit_length = 1);
+    bool equals(ElementPtr other);
 };
 
 class DoubleElement : public Element {
@@ -346,6 +351,7 @@ public:
     bool setValue(const double v) { d = v; return true; };
     std::string str();
     void toWire(std::stringstream& ss, int omit_length = 1);
+    bool equals(ElementPtr other);
 };
 
 class BoolElement : public Element {
@@ -360,6 +366,7 @@ public:
     bool setValue(const bool v) { b = v; return true; };
     std::string str();
     void toWire(std::stringstream& ss, int omit_length = 1);
+    bool equals(ElementPtr other);
 };
 
 class StringElement : public Element {
@@ -374,6 +381,7 @@ public:
     bool setValue(const std::string& v) { s = v; return true; };
     std::string str();
     void toWire(std::stringstream& ss, int omit_length = 1);
+    bool equals(ElementPtr other);
 };
 
 class ListElement : public Element {
@@ -396,6 +404,7 @@ public:
     std::string str();
     void toWire(std::stringstream& ss, int omit_length = 1);
     size_t size() { return l.size(); }
+    bool equals(ElementPtr other);
 };
 
 class MapElement : public Element {
@@ -435,6 +444,8 @@ public:
     // it doesnt exist or one of the elements in the path is not
     // a MapElement)
     bool find(const std::string& id, ElementPtr& t);
+
+    bool equals(ElementPtr other);
 };
 
 /// Checks whether the given ElementPtr is a NULL pointer
@@ -442,6 +453,14 @@ public:
 /// \return true if it is NULL, false if not.
 bool isNull(ElementPtr p);
 
+///
+/// \brief Remove all values from the first ElementPtr that are
+/// also present in the second. Both ElementPtrs MUST be MapElements
+/// The use for this function is to end up with a MapElement that
+/// only contains new and changed values (for ModuleCCSession and
+/// configuration update handlers)
+/// Raises a TypeError if a or b are not MapElements
+void removeIdentical(ElementPtr a, const ElementPtr b);
 
 } }
 
@@ -462,6 +481,8 @@ bool isNull(ElementPtr p);
 /// parameter \c os after the insertion operation.
 std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e);
 
+bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b);
+
 #endif // _ISC_DATA_H
 
 // Local Variables: 

+ 104 - 0
src/lib/cc/cpp/data_unittests.cc

@@ -276,3 +276,107 @@ TEST(Element, to_and_from_wire) {
     EXPECT_EQ(ddef, ddef2);
 }
 
+ElementPtr efs(const std::string& str) {
+    return Element::createFromString(str);
+}
+
+TEST(Element, equals) {
+    // why does EXPECT_EQ not work?
+    EXPECT_TRUE(efs("1") == efs("1"));
+    EXPECT_FALSE(efs("1") == efs("2"));
+    EXPECT_FALSE(efs("1") == efs("\"1\""));
+    EXPECT_FALSE(efs("1") == efs("[]"));
+    EXPECT_FALSE(efs("1") == efs("True"));
+    EXPECT_FALSE(efs("1") == efs("{}"));
+
+    EXPECT_TRUE(efs("1.1") == efs("1.1"));
+    EXPECT_FALSE(efs("1.0") == efs("1"));
+    EXPECT_FALSE(efs("1.1") == efs("\"1\""));
+    EXPECT_FALSE(efs("1.1") == efs("[]"));
+    EXPECT_FALSE(efs("1.1") == efs("True"));
+    EXPECT_FALSE(efs("1.1") == efs("{}"));
+
+    EXPECT_TRUE(efs("True") == efs("True"));
+    EXPECT_FALSE(efs("True") == efs("False"));
+    EXPECT_FALSE(efs("True") == efs("1"));
+    EXPECT_FALSE(efs("True") == efs("\"1\""));
+    EXPECT_FALSE(efs("True") == efs("[]"));
+    EXPECT_FALSE(efs("True") == efs("{}"));
+
+    EXPECT_TRUE(efs("\"foo\"") == efs("\"foo\""));
+    EXPECT_FALSE(efs("\"foo\"") == efs("\"bar\""));
+    EXPECT_FALSE(efs("\"foo\"") == efs("1"));
+    EXPECT_FALSE(efs("\"foo\"") == efs("\"1\""));
+    EXPECT_FALSE(efs("\"foo\"") == efs("True"));
+    EXPECT_FALSE(efs("\"foo\"") == efs("[]"));
+    EXPECT_FALSE(efs("\"foo\"") == efs("{}"));
+
+    EXPECT_TRUE(efs("[]") == efs("[]"));
+    EXPECT_TRUE(efs("[ 1, 2, 3 ]") == efs("[ 1, 2, 3 ]"));
+    EXPECT_TRUE(efs("[ \"a\", [ True, 1], 2.2 ]") == efs("[ \"a\", [ True, 1], 2.2 ]"));
+    EXPECT_FALSE(efs("[ \"a\", [ True, 1], 2.2 ]") == efs("[ \"a\", [ True, 2], 2.2 ]"));
+    EXPECT_FALSE(efs("[]") == efs("[1]"));
+    EXPECT_FALSE(efs("[]") == efs("1"));
+    EXPECT_FALSE(efs("[]") == efs("\"1\""));
+    EXPECT_FALSE(efs("[]") == efs("{}"));
+
+    EXPECT_TRUE(efs("{}") == efs("{}"));
+    EXPECT_TRUE(efs("{ \"foo\": \"bar\" }") == efs("{ \"foo\": \"bar\" }"));
+    EXPECT_TRUE(efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }") == efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"));
+    EXPECT_FALSE(efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }") == efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar2\" } }"));
+    EXPECT_FALSE(efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }") == efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\", 1 ], \"item3\": { \"foo\": \"bar\" } }"));
+    EXPECT_FALSE(efs("{ \"foo\": \"bar\" }") == efs("1"));
+    EXPECT_FALSE(efs("{ \"foo\": \"bar\" }") == efs("\"1\""));
+    EXPECT_FALSE(efs("{ \"foo\": \"bar\" }") == efs("[]"));
+    EXPECT_FALSE(efs("{ \"foo\": \"bar\" }") == efs("{}"));
+}
+
+TEST(Element, removeIdentical) {
+    ElementPtr a = Element::createFromString("{}");
+    ElementPtr b = Element::createFromString("{}");
+    ElementPtr c = Element::createFromString("{}");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": 1 }");
+    b = Element::createFromString("{ \"a\": 1 }");
+    c = Element::createFromString("{}");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    b = Element::createFromString("{}");
+    c = Element::createFromString("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    b = Element::createFromString("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    c = Element::createFromString("{}");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    b = Element::createFromString("{ \"a\": 1, \"b\": [ 1, 3 ] }");
+    c = Element::createFromString("{ \"b\": [ 1, 2 ] }");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::createFromString("{}");
+    c = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    c = Element::createFromString("{}");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::createFromString("{ \"a\": { \"b\": \"d\" } }");
+    c = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    removeIdentical(a, b);
+    EXPECT_TRUE(a == c);
+}