From d2c3592908fcea433f08481231de41b68fe929fd Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Wed, 2 Aug 2017 22:44:58 +0200
Subject: [PATCH] :white_check_mark: added test cases for update #661

---
 src/json.hpp                | 52 ++++++++++++++++++++++++++++++++++---
 test/src/unit-modifiers.cpp | 49 +++++++++++++++++++++++++++++++++-
 2 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 5253a613..bd44237c 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -12066,6 +12066,18 @@ class basic_json
         m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
     }
 
+    /*!
+    @brief updates a JSON object from another object, overwriting existing keys
+
+    Inserts all values from JSON object @a j and overwrites existing keys.
+
+    @param[in] j  JSON object to read values from
+
+    @complexity O(N*log(size() + N)), where N is the number of elements to
+                insert.
+
+    @since version 3.0.0
+    */
     void update(const_reference j)
     {
         // implicitly convert null value to an empty object
@@ -12078,16 +12090,50 @@ class basic_json
 
         if (JSON_UNLIKELY(not is_object()))
         {
-            JSON_THROW(type_error::create(305, "cannot use merge with " + type_name()));
+            JSON_THROW(type_error::create(305, "cannot use merge() with " + std::string(type_name())));
         }
         if (JSON_UNLIKELY(not j.is_object()))
         {
-            JSON_THROW(type_error::create(305, "cannot use merge with " + j.type_name()));
+            JSON_THROW(type_error::create(305, "cannot use merge() with " + std::string(j.type_name())));
         }
 
         for (auto it = j.begin(); it != j.end(); ++it)
         {
-            m_value.object->emplace(it.key(), it.value());
+            m_value.object->operator[](it.key()) = it.value();
+        }
+    }
+
+    void update(const_iterator first, const_iterator last)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
+
+        if (JSON_UNLIKELY(not is_object()))
+        {
+            JSON_THROW(type_error::create(305, "cannot use merge() with " + std::string(type_name())));
+        }
+
+        // check if range iterators belong to the same JSON object
+        if (JSON_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
+        }
+
+        // passed iterators must belong to objects
+        if (JSON_UNLIKELY(not first.m_object->is_object()
+                          or not first.m_object->is_object()))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
+        }
+
+        for (auto it = first; it != last; ++it)
+        {
+            m_value.object->operator[](it.key()) = it.value();
         }
     }
 
diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp
index eeb70a0c..64ac0b03 100644
--- a/test/src/unit-modifiers.cpp
+++ b/test/src/unit-modifiers.cpp
@@ -489,7 +489,7 @@ TEST_CASE("modifiers")
         }
     }
 
-    SECTION("insert")
+    SECTION("insert()")
     {
         json j_array = {1, 2, 3, 4};
         json j_value = 5;
@@ -740,6 +740,53 @@ TEST_CASE("modifiers")
         }
     }
 
+    SECTION("update()")
+    {
+        json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
+        json j_object2 = {{"three", "drei"}, {"two", "zwo"}};
+        json j_array = {1, 2, 3, 4};
+
+        SECTION("const reference")
+        {
+            SECTION("proper usage")
+            {
+                j_object1.update(j_object2);
+                CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
+            }
+        }
+
+        SECTION("iterator range")
+        {
+            SECTION("proper usage")
+            {
+                j_object1.update(j_object2.begin(), j_object2.end());
+                CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
+            }
+
+            SECTION("empty range")
+            {
+                j_object1.update(j_object2.begin(), j_object2.begin());
+                CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwei"}}));
+            }
+
+            SECTION("invalid iterators")
+            {
+                json j_other_array2 = {"first", "second"};
+
+                CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error&);
+                CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator&);
+                CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator&);
+
+                CHECK_THROWS_WITH(j_array.update(j_object2.begin(), j_object2.end()),
+                                  "[json.exception.type_error.305] cannot use merge() with array");
+                CHECK_THROWS_WITH(j_object1.update(j_object1.begin(), j_object2.end()),
+                                  "[json.exception.invalid_iterator.210] iterators do not fit");
+                CHECK_THROWS_WITH(j_object1.update(j_array.begin(), j_array.end()),
+                                  "[json.exception.invalid_iterator.202] iterators first and last must point to objects");
+            }
+        }
+    }
+
     SECTION("swap()")
     {
         SECTION("json")