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;
+        }
     }
 }