From 585a39a2357dc54ae10afb6f948755dcf6395e6b Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Sun, 21 Aug 2016 14:39:54 +0200
Subject: [PATCH 1/4] improved branch coverage

---
 test/src/unit-allocator.cpp | 150 +++++++++++++++++++++++++++++++++++-
 1 file changed, 146 insertions(+), 4 deletions(-)

diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp
index dcf8aa35..948446b9 100644
--- a/test/src/unit-allocator.cpp
+++ b/test/src/unit-allocator.cpp
@@ -28,13 +28,14 @@ SOFTWARE.
 
 #include "catch.hpp"
 
+#define private public
 #include "json.hpp"
 using nlohmann::json;
 
 // special test case to check if memory is leaked if constructor throws
 
 template<class T>
-struct my_allocator : std::allocator<T>
+struct bad_allocator : std::allocator<T>
 {
     template<class... Args>
     void construct(T*, Args&& ...)
@@ -48,16 +49,157 @@ TEST_CASE("bad_alloc")
     SECTION("bad_alloc")
     {
         // create JSON type using the throwing allocator
-        using my_json = nlohmann::basic_json<std::map,
+        using bad_json = nlohmann::basic_json<std::map,
               std::vector,
               std::string,
               bool,
               std::int64_t,
               std::uint64_t,
               double,
-              my_allocator>;
+              bad_allocator>;
 
         // creating an object should throw
-        CHECK_THROWS_AS(my_json j(my_json::value_t::object), std::bad_alloc);
+        CHECK_THROWS_AS(bad_json j(bad_json::value_t::object), std::bad_alloc);
+    }
+}
+
+bool next_allocation_fails = false;
+
+template<class T>
+struct my_allocator : std::allocator<T>
+{
+    template<class... Args>
+    void construct(T* p, Args&& ... args)
+    {
+        if (next_allocation_fails)
+        {
+            throw std::bad_alloc();
+        }
+        else
+        {
+            ::new(reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
+        }
+    }
+};
+
+TEST_CASE("controlled bad_alloc")
+{
+    // create JSON type using the throwing allocator
+    using my_json = nlohmann::basic_json<std::map,
+          std::vector,
+          std::string,
+          bool,
+          std::int64_t,
+          std::uint64_t,
+          double,
+          my_allocator>;
+
+    SECTION("class json_value")
+    {
+        SECTION("json_value(value_t)")
+        {
+            SECTION("object")
+            {
+                next_allocation_fails = false;
+                auto t = my_json::value_t::object;
+                CHECK_NOTHROW(my_json::json_value j(t));
+                next_allocation_fails = true;
+                CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
+                next_allocation_fails = false;
+            }
+            SECTION("array")
+            {
+                next_allocation_fails = false;
+                auto t = my_json::value_t::array;
+                CHECK_NOTHROW(my_json::json_value j(t));
+                next_allocation_fails = true;
+                CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
+                next_allocation_fails = false;
+            }
+            SECTION("string")
+            {
+                next_allocation_fails = false;
+                auto t = my_json::value_t::string;
+                CHECK_NOTHROW(my_json::json_value j(t));
+                next_allocation_fails = true;
+                CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
+                next_allocation_fails = false;
+            }
+        }
+
+        SECTION("json_value(const string_t&)")
+        {
+            next_allocation_fails = false;
+            my_json::string_t v("foo");
+            CHECK_NOTHROW(my_json::json_value j(v));
+            next_allocation_fails = true;
+            CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
+            next_allocation_fails = false;
+        }
+
+        /*
+                SECTION("json_value(const object_t&)")
+                {
+                    next_allocation_fails = false;
+                    my_json::object_t v {{"foo", "bar"}};
+                    CHECK_NOTHROW(my_json::json_value j(v));
+                    next_allocation_fails = true;
+                    CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
+                    next_allocation_fails = false;
+                }
+        */
+        /*
+                SECTION("json_value(const array_t&)")
+                {
+                    next_allocation_fails = false;
+                    my_json::array_t v = {"foo", "bar", "baz"};
+                    CHECK_NOTHROW(my_json::json_value j(v));
+                    next_allocation_fails = true;
+                    CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
+                    next_allocation_fails = false;
+                }
+        */
+    }
+
+    SECTION("class basic_json")
+    {
+        SECTION("basic_json(const CompatibleObjectType&)")
+        {
+            next_allocation_fails = false;
+            std::map<std::string, std::string> v {{"foo", "bar"}};
+            CHECK_NOTHROW(my_json j(v));
+            next_allocation_fails = true;
+            CHECK_THROWS_AS(my_json j(v), std::bad_alloc);
+            next_allocation_fails = false;
+        }
+
+        SECTION("basic_json(const CompatibleArrayType&)")
+        {
+            next_allocation_fails = false;
+            std::vector<std::string> v {"foo", "bar", "baz"};
+            CHECK_NOTHROW(my_json j(v));
+            next_allocation_fails = true;
+            CHECK_THROWS_AS(my_json j(v), std::bad_alloc);
+            next_allocation_fails = false;
+        }
+
+        SECTION("basic_json(const typename string_t::value_type*)")
+        {
+            next_allocation_fails = false;
+            CHECK_NOTHROW(my_json v("foo"));
+            next_allocation_fails = true;
+            CHECK_THROWS_AS(my_json v("foo"), std::bad_alloc);
+            next_allocation_fails = false;
+        }
+
+        SECTION("basic_json(const typename string_t::value_type*)")
+        {
+            next_allocation_fails = false;
+            std::string s("foo");
+            CHECK_NOTHROW(my_json v(s));
+            next_allocation_fails = true;
+            CHECK_THROWS_AS(my_json v(s), std::bad_alloc);
+            next_allocation_fails = false;
+        }
     }
 }

From aa7f5ad8b123177067fb0b943866425d22e20013 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Sun, 21 Aug 2016 21:48:15 +0200
Subject: [PATCH 2/4] minor changes

---
 test/src/unit-allocator.cpp | 93 ++++++++++++++++++++++++-------------
 1 file changed, 61 insertions(+), 32 deletions(-)

diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp
index 948446b9..9ad162c1 100644
--- a/test/src/unit-allocator.cpp
+++ b/test/src/unit-allocator.cpp
@@ -63,7 +63,9 @@ TEST_CASE("bad_alloc")
     }
 }
 
-bool next_allocation_fails = false;
+bool next_construct_fails = false;
+bool next_destroy_fails = false;
+bool next_deallocate_fails = false;
 
 template<class T>
 struct my_allocator : std::allocator<T>
@@ -71,8 +73,9 @@ struct my_allocator : std::allocator<T>
     template<class... Args>
     void construct(T* p, Args&& ... args)
     {
-        if (next_allocation_fails)
+        if (next_construct_fails)
         {
+            next_construct_fails = false;
             throw std::bad_alloc();
         }
         else
@@ -80,6 +83,32 @@ struct my_allocator : std::allocator<T>
             ::new(reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
         }
     }
+
+    void deallocate(T* p, std::size_t n)
+    {
+        if (next_deallocate_fails)
+        {
+            next_deallocate_fails = false;
+            throw std::bad_alloc();
+        }
+        else
+        {
+            std::allocator<T>::deallocate(p, n);
+        }
+    }
+
+    void destroy(T* p)
+    {
+        if (next_destroy_fails)
+        {
+            next_destroy_fails = false;
+            throw std::bad_alloc();
+        }
+        else
+        {
+            p->~T();
+        }
+    }
 };
 
 TEST_CASE("controlled bad_alloc")
@@ -100,63 +129,63 @@ TEST_CASE("controlled bad_alloc")
         {
             SECTION("object")
             {
-                next_allocation_fails = false;
+                next_construct_fails = false;
                 auto t = my_json::value_t::object;
                 CHECK_NOTHROW(my_json::json_value j(t));
-                next_allocation_fails = true;
+                next_construct_fails = true;
                 CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
-                next_allocation_fails = false;
+                next_construct_fails = false;
             }
             SECTION("array")
             {
-                next_allocation_fails = false;
+                next_construct_fails = false;
                 auto t = my_json::value_t::array;
                 CHECK_NOTHROW(my_json::json_value j(t));
-                next_allocation_fails = true;
+                next_construct_fails = true;
                 CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
-                next_allocation_fails = false;
+                next_construct_fails = false;
             }
             SECTION("string")
             {
-                next_allocation_fails = false;
+                next_construct_fails = false;
                 auto t = my_json::value_t::string;
                 CHECK_NOTHROW(my_json::json_value j(t));
-                next_allocation_fails = true;
+                next_construct_fails = true;
                 CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
-                next_allocation_fails = false;
+                next_construct_fails = false;
             }
         }
 
         SECTION("json_value(const string_t&)")
         {
-            next_allocation_fails = false;
+            next_construct_fails = false;
             my_json::string_t v("foo");
             CHECK_NOTHROW(my_json::json_value j(v));
-            next_allocation_fails = true;
+            next_construct_fails = true;
             CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
-            next_allocation_fails = false;
+            next_construct_fails = false;
         }
 
         /*
                 SECTION("json_value(const object_t&)")
                 {
-                    next_allocation_fails = false;
+                    next_construct_fails = false;
                     my_json::object_t v {{"foo", "bar"}};
                     CHECK_NOTHROW(my_json::json_value j(v));
-                    next_allocation_fails = true;
+                    next_construct_fails = true;
                     CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
-                    next_allocation_fails = false;
+                    next_construct_fails = false;
                 }
         */
         /*
                 SECTION("json_value(const array_t&)")
                 {
-                    next_allocation_fails = false;
+                    next_construct_fails = false;
                     my_json::array_t v = {"foo", "bar", "baz"};
                     CHECK_NOTHROW(my_json::json_value j(v));
-                    next_allocation_fails = true;
+                    next_construct_fails = true;
                     CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
-                    next_allocation_fails = false;
+                    next_construct_fails = false;
                 }
         */
     }
@@ -165,41 +194,41 @@ TEST_CASE("controlled bad_alloc")
     {
         SECTION("basic_json(const CompatibleObjectType&)")
         {
-            next_allocation_fails = false;
+            next_construct_fails = false;
             std::map<std::string, std::string> v {{"foo", "bar"}};
             CHECK_NOTHROW(my_json j(v));
-            next_allocation_fails = true;
+            next_construct_fails = true;
             CHECK_THROWS_AS(my_json j(v), std::bad_alloc);
-            next_allocation_fails = false;
+            next_construct_fails = false;
         }
 
         SECTION("basic_json(const CompatibleArrayType&)")
         {
-            next_allocation_fails = false;
+            next_construct_fails = false;
             std::vector<std::string> v {"foo", "bar", "baz"};
             CHECK_NOTHROW(my_json j(v));
-            next_allocation_fails = true;
+            next_construct_fails = true;
             CHECK_THROWS_AS(my_json j(v), std::bad_alloc);
-            next_allocation_fails = false;
+            next_construct_fails = false;
         }
 
         SECTION("basic_json(const typename string_t::value_type*)")
         {
-            next_allocation_fails = false;
+            next_construct_fails = false;
             CHECK_NOTHROW(my_json v("foo"));
-            next_allocation_fails = true;
+            next_construct_fails = true;
             CHECK_THROWS_AS(my_json v("foo"), std::bad_alloc);
-            next_allocation_fails = false;
+            next_construct_fails = false;
         }
 
         SECTION("basic_json(const typename string_t::value_type*)")
         {
-            next_allocation_fails = false;
+            next_construct_fails = false;
             std::string s("foo");
             CHECK_NOTHROW(my_json v(s));
-            next_allocation_fails = true;
+            next_construct_fails = true;
             CHECK_THROWS_AS(my_json v(s), std::bad_alloc);
-            next_allocation_fails = false;
+            next_construct_fails = false;
         }
     }
 }

From 94331a355d5fc2032810af7160504addcf86f783 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Sun, 21 Aug 2016 21:50:13 +0200
Subject: [PATCH 3/4] removed LCOV_EXCL_LINE

---
 src/json.hpp      | 22 +++++++++++-----------
 src/json.hpp.re2c |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index a8289a49..b5e24206 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -7734,7 +7734,7 @@ class basic_json
                     };
                     if ((m_limit - m_cursor) < 5)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yybm[0 + yych] & 32)
@@ -7868,7 +7868,7 @@ basic_json_parser_6:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yybm[0 + yych] & 32)
@@ -7938,7 +7938,7 @@ basic_json_parser_15:
                     m_marker = ++m_cursor;
                     if ((m_limit - m_cursor) < 3)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yybm[0 + yych] & 64)
@@ -8031,7 +8031,7 @@ basic_json_parser_31:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
 basic_json_parser_32:
@@ -8068,7 +8068,7 @@ basic_json_parser_36:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= 'e')
@@ -8212,7 +8212,7 @@ basic_json_parser_43:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8248,7 +8248,7 @@ basic_json_parser_44:
                     m_marker = ++m_cursor;
                     if ((m_limit - m_cursor) < 3)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= 'D')
@@ -8289,7 +8289,7 @@ basic_json_parser_47:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= '/')
@@ -8331,7 +8331,7 @@ basic_json_parser_54:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8385,7 +8385,7 @@ basic_json_parser_60:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
@@ -8426,7 +8426,7 @@ basic_json_parser_63:
                     ++m_cursor;
                     if (m_limit <= m_cursor)
                     {
-                        yyfill();    // LCOV_EXCL_LINE;
+                        yyfill();
                     }
                     yych = *m_cursor;
                     if (yych <= '@')
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index ffa20f39..fdc00638 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -7698,7 +7698,7 @@ class basic_json
                     re2c:define:YYCURSOR  = m_cursor;
                     re2c:define:YYLIMIT   = m_limit;
                     re2c:define:YYMARKER  = m_marker;
-                    re2c:define:YYFILL    = "yyfill(); // LCOV_EXCL_LINE";
+                    re2c:define:YYFILL    = "yyfill()";
                     re2c:yyfill:parameter = 0;
                     re2c:indent:string    = "    ";
                     re2c:indent:top       = 1;

From 1e896eb91ef940cda23a4bb49a302ed227c442d7 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Sun, 21 Aug 2016 22:38:56 +0200
Subject: [PATCH 4/4] improved code coverage

---
 test/src/unit-class_parser.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp
index fe005503..259daf84 100644
--- a/test/src/unit-class_parser.cpp
+++ b/test/src/unit-class_parser.cpp
@@ -445,6 +445,10 @@ TEST_CASE("parser class")
         CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument);
         CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument);
         CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("\"\\u").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("\"\\u0").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("\"\\u01").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("\"\\u012").parse(), std::invalid_argument);
         CHECK_THROWS_WITH(json::parser("\"").parse(),
                           "parse error - unexpected '\"'");
         CHECK_THROWS_WITH(json::parser("\"\\\"").parse(),
@@ -457,6 +461,14 @@ TEST_CASE("parser class")
                           "parse error - unexpected '\"'");
         CHECK_THROWS_WITH(json::parser("\"\\u012\"").parse(),
                           "parse error - unexpected '\"'");
+        CHECK_THROWS_WITH(json::parser("\"\\u").parse(),
+                          "parse error - unexpected '\"'");
+        CHECK_THROWS_WITH(json::parser("\"\\u0").parse(),
+                          "parse error - unexpected '\"'");
+        CHECK_THROWS_WITH(json::parser("\"\\u01").parse(),
+                          "parse error - unexpected '\"'");
+        CHECK_THROWS_WITH(json::parser("\"\\u012").parse(),
+                          "parse error - unexpected '\"'");
 
         // invalid escapes
         for (int c = 1; c < 128; ++c)