-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2010-2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
const std::map<std::string, ConstElementPtr>& m = other->mapValue();
for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
- it != m.end() ; ++it) {
+ it != m.end() ; ++it) {
if ((*it).second && (*it).second->getType() != Element::null) {
- element->set((*it).first, (*it).second);
+ if (((*it).second->getType() == Element::map) &&
+ element->contains((*it).first)) {
+ // Sub-element is a map and is also in the original config,
+ // so we need to merge them too.
+ boost::shared_ptr<MapElement> merged_map(new MapElement());
+ ConstElementPtr orig_map = element->get((*it).first);
+ ConstElementPtr other_map = (*it).second;
+ if (orig_map->getType() == Element::map) {
+ merged_map->setValue(orig_map->mapValue());
+ }
+
+ // Now go recursive to merge the map sub-elements.
+ merge(merged_map, other_map);
+ element->set((*it).first, merged_map);
+ }
+ else {
+ element->set((*it).first, (*it).second);
+ }
} else if (element->contains((*it).first)) {
element->remove((*it).first);
}
-// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2009-2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
ElementPtr a = Element::createMap();
ElementPtr b = Element::createMap();
ConstElementPtr c = Element::createMap();
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::fromJSON("1");
a = Element::createMap();
b = Element::fromJSON("{ \"a\": 1 }");
c = Element::fromJSON("{ \"a\": 1 }");
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::createMap();
b = Element::fromJSON("{ \"a\": 1 }");
c = Element::fromJSON("{ \"a\": 1 }");
- merge(b, a);
+ ASSERT_NO_THROW(merge(b, a));
EXPECT_EQ(*b, *c);
a = Element::fromJSON("{ \"a\": 1 }");
b = Element::fromJSON("{ \"a\": 2 }");
c = Element::fromJSON("{ \"a\": 2 }");
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::fromJSON("{ \"a\": 1 }");
b = Element::fromJSON("{ \"a\": 2 }");
c = Element::fromJSON("{ \"a\": 1 }");
- merge(b, a);
+ ASSERT_NO_THROW(merge(b, a));
EXPECT_EQ(*b, *c);
a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
c = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
- merge(b, a);
+ ASSERT_NO_THROW(merge(b, a));
EXPECT_EQ(*b, *c);
a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
b = Element::fromJSON("{ \"a\": null }");
c = Element::fromJSON("{ }");
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
b = Element::fromJSON("{ \"a\": null }");
c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
- merge(b, a);
+ ASSERT_NO_THROW(merge(b, a));
EXPECT_EQ(*b, *c);
// And some tests with multiple values
a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
c = Element::fromJSON("{ \"a\": 1, \"c\": \"a string\" }");
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
c = Element::fromJSON("{ \"a\": 1, \"b\": true }");
- merge(b, a);
+ ASSERT_NO_THROW(merge(b, a));
EXPECT_EQ(*b, *c);
a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
c = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
- merge(a, b);
+ ASSERT_NO_THROW(merge(a, b));
EXPECT_EQ(*a, *c);
a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
c = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
- merge(b, a);
+ ASSERT_NO_THROW(merge(b, a));
EXPECT_EQ(*b, *c);
+ // Map sub-elements: original map element is null
+ a = Element::fromJSON("{ \"a\": 1, \"m\": null }");
+ b = Element::fromJSON("{ \"a\": 3, \"m\": { \"b\": 9 } }");
+ c = Element::fromJSON("{ \"a\": 3, \"m\": { \"b\": 9 } }");
+ ASSERT_NO_THROW(merge(a, b));
+ EXPECT_EQ(*a, *c);
+
+ // Map sub-elements new map element has less elements than original
+ a = Element::fromJSON("{ \"a\": 1, \"m\": { \"b\": 2, \"c\": 3 } }");
+ b = Element::fromJSON("{ \"a\": 3, \"m\": { \"b\": 9 } }");
+ c = Element::fromJSON("{ \"a\": 3, \"m\": { \"b\": 9, \"c\": 3 } }");
+ ASSERT_NO_THROW(merge(a, b));
+ EXPECT_EQ(*a, *c);
+
+ // Map sub-elements new map element is null
+ a = Element::fromJSON("{ \"a\": 1, \"m\": { \"b\": 2, \"c\": 3 } }");
+ b = Element::fromJSON("{ \"a\": 3, \"m\": null }");
+ c = Element::fromJSON("{ \"a\": 3 }");
+ ASSERT_NO_THROW(merge(a, b));
+ EXPECT_EQ(*a, *c);
+
+ // Map sub-elements new map element has more elments than origina
+ a = Element::fromJSON("{ \"a\": 1, \"m\": { \"b\": 2, \"c\": 3 } }");
+ b = Element::fromJSON("{ \"a\": 3, \"m\": { \"b\": 2, \"c\": 3, \"d\": 4} }");
+ c = Element::fromJSON("{ \"a\": 3, \"m\": { \"b\": 2, \"c\": 3, \"d\": 4} }");
+ ASSERT_NO_THROW(merge(a, b));
+ EXPECT_EQ(*a, *c);
}
}