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 -struct my_allocator : std::allocator +struct bad_allocator : std::allocator { template 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; + 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 +struct my_allocator : std::allocator +{ + template + void construct(T* p, Args&& ... args) + { + if (next_allocation_fails) + { + throw std::bad_alloc(); + } + else + { + ::new(reinterpret_cast(p)) T(std::forward(args)...); + } + } +}; + +TEST_CASE("controlled bad_alloc") +{ + // create JSON type using the throwing allocator + using my_json = nlohmann::basic_json; + + 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 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 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; + } } }