1c5f01b2fSopenharmony_ci// __ _____ _____ _____ 2c5f01b2fSopenharmony_ci// __| | __| | | | JSON for Modern C++ (supporting code) 3c5f01b2fSopenharmony_ci// | | |__ | | | | | | version 3.11.2 4c5f01b2fSopenharmony_ci// |_____|_____|_____|_|___| https://github.com/nlohmann/json 5c5f01b2fSopenharmony_ci// 6c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 7c5f01b2fSopenharmony_ci// SPDX-License-Identifier: MIT 8c5f01b2fSopenharmony_ci 9c5f01b2fSopenharmony_ci#include "doctest_compatibility.h" 10c5f01b2fSopenharmony_ci 11c5f01b2fSopenharmony_ci#define JSON_TESTS_PRIVATE 12c5f01b2fSopenharmony_ci#include <nlohmann/json.hpp> 13c5f01b2fSopenharmony_ciusing nlohmann::json; 14c5f01b2fSopenharmony_ci 15c5f01b2fSopenharmony_cinamespace 16c5f01b2fSopenharmony_ci{ 17c5f01b2fSopenharmony_ci// special test case to check if memory is leaked if constructor throws 18c5f01b2fSopenharmony_citemplate<class T> 19c5f01b2fSopenharmony_cistruct bad_allocator : std::allocator<T> 20c5f01b2fSopenharmony_ci{ 21c5f01b2fSopenharmony_ci using std::allocator<T>::allocator; 22c5f01b2fSopenharmony_ci 23c5f01b2fSopenharmony_ci template<class... Args> 24c5f01b2fSopenharmony_ci void construct(T* /*unused*/, Args&& ... /*unused*/) 25c5f01b2fSopenharmony_ci { 26c5f01b2fSopenharmony_ci throw std::bad_alloc(); 27c5f01b2fSopenharmony_ci } 28c5f01b2fSopenharmony_ci}; 29c5f01b2fSopenharmony_ci} // namespace 30c5f01b2fSopenharmony_ci 31c5f01b2fSopenharmony_ciTEST_CASE("bad_alloc") 32c5f01b2fSopenharmony_ci{ 33c5f01b2fSopenharmony_ci SECTION("bad_alloc") 34c5f01b2fSopenharmony_ci { 35c5f01b2fSopenharmony_ci // create JSON type using the throwing allocator 36c5f01b2fSopenharmony_ci using bad_json = nlohmann::basic_json<std::map, 37c5f01b2fSopenharmony_ci std::vector, 38c5f01b2fSopenharmony_ci std::string, 39c5f01b2fSopenharmony_ci bool, 40c5f01b2fSopenharmony_ci std::int64_t, 41c5f01b2fSopenharmony_ci std::uint64_t, 42c5f01b2fSopenharmony_ci double, 43c5f01b2fSopenharmony_ci bad_allocator>; 44c5f01b2fSopenharmony_ci 45c5f01b2fSopenharmony_ci // creating an object should throw 46c5f01b2fSopenharmony_ci CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&); 47c5f01b2fSopenharmony_ci } 48c5f01b2fSopenharmony_ci} 49c5f01b2fSopenharmony_ci 50c5f01b2fSopenharmony_cinamespace 51c5f01b2fSopenharmony_ci{ 52c5f01b2fSopenharmony_cibool next_construct_fails = false; 53c5f01b2fSopenharmony_cibool next_destroy_fails = false; 54c5f01b2fSopenharmony_cibool next_deallocate_fails = false; 55c5f01b2fSopenharmony_ci 56c5f01b2fSopenharmony_citemplate<class T> 57c5f01b2fSopenharmony_cistruct my_allocator : std::allocator<T> 58c5f01b2fSopenharmony_ci{ 59c5f01b2fSopenharmony_ci using std::allocator<T>::allocator; 60c5f01b2fSopenharmony_ci 61c5f01b2fSopenharmony_ci template<class... Args> 62c5f01b2fSopenharmony_ci void construct(T* p, Args&& ... args) 63c5f01b2fSopenharmony_ci { 64c5f01b2fSopenharmony_ci if (next_construct_fails) 65c5f01b2fSopenharmony_ci { 66c5f01b2fSopenharmony_ci next_construct_fails = false; 67c5f01b2fSopenharmony_ci throw std::bad_alloc(); 68c5f01b2fSopenharmony_ci } 69c5f01b2fSopenharmony_ci 70c5f01b2fSopenharmony_ci ::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...); 71c5f01b2fSopenharmony_ci } 72c5f01b2fSopenharmony_ci 73c5f01b2fSopenharmony_ci void deallocate(T* p, std::size_t n) 74c5f01b2fSopenharmony_ci { 75c5f01b2fSopenharmony_ci if (next_deallocate_fails) 76c5f01b2fSopenharmony_ci { 77c5f01b2fSopenharmony_ci next_deallocate_fails = false; 78c5f01b2fSopenharmony_ci throw std::bad_alloc(); 79c5f01b2fSopenharmony_ci } 80c5f01b2fSopenharmony_ci 81c5f01b2fSopenharmony_ci std::allocator<T>::deallocate(p, n); 82c5f01b2fSopenharmony_ci } 83c5f01b2fSopenharmony_ci 84c5f01b2fSopenharmony_ci void destroy(T* p) 85c5f01b2fSopenharmony_ci { 86c5f01b2fSopenharmony_ci if (next_destroy_fails) 87c5f01b2fSopenharmony_ci { 88c5f01b2fSopenharmony_ci next_destroy_fails = false; 89c5f01b2fSopenharmony_ci throw std::bad_alloc(); 90c5f01b2fSopenharmony_ci } 91c5f01b2fSopenharmony_ci 92c5f01b2fSopenharmony_ci static_cast<void>(p); // fix MSVC's C4100 warning 93c5f01b2fSopenharmony_ci p->~T(); 94c5f01b2fSopenharmony_ci } 95c5f01b2fSopenharmony_ci 96c5f01b2fSopenharmony_ci template <class U> 97c5f01b2fSopenharmony_ci struct rebind 98c5f01b2fSopenharmony_ci { 99c5f01b2fSopenharmony_ci using other = my_allocator<U>; 100c5f01b2fSopenharmony_ci }; 101c5f01b2fSopenharmony_ci}; 102c5f01b2fSopenharmony_ci 103c5f01b2fSopenharmony_ci// allows deletion of raw pointer, usually hold by json_value 104c5f01b2fSopenharmony_citemplate<class T> 105c5f01b2fSopenharmony_civoid my_allocator_clean_up(T* p) 106c5f01b2fSopenharmony_ci{ 107c5f01b2fSopenharmony_ci assert(p != nullptr); 108c5f01b2fSopenharmony_ci my_allocator<T> alloc; 109c5f01b2fSopenharmony_ci alloc.destroy(p); 110c5f01b2fSopenharmony_ci alloc.deallocate(p, 1); 111c5f01b2fSopenharmony_ci} 112c5f01b2fSopenharmony_ci} // namespace 113c5f01b2fSopenharmony_ci 114c5f01b2fSopenharmony_ciTEST_CASE("controlled bad_alloc") 115c5f01b2fSopenharmony_ci{ 116c5f01b2fSopenharmony_ci // create JSON type using the throwing allocator 117c5f01b2fSopenharmony_ci using my_json = nlohmann::basic_json<std::map, 118c5f01b2fSopenharmony_ci std::vector, 119c5f01b2fSopenharmony_ci std::string, 120c5f01b2fSopenharmony_ci bool, 121c5f01b2fSopenharmony_ci std::int64_t, 122c5f01b2fSopenharmony_ci std::uint64_t, 123c5f01b2fSopenharmony_ci double, 124c5f01b2fSopenharmony_ci my_allocator>; 125c5f01b2fSopenharmony_ci 126c5f01b2fSopenharmony_ci SECTION("class json_value") 127c5f01b2fSopenharmony_ci { 128c5f01b2fSopenharmony_ci SECTION("json_value(value_t)") 129c5f01b2fSopenharmony_ci { 130c5f01b2fSopenharmony_ci SECTION("object") 131c5f01b2fSopenharmony_ci { 132c5f01b2fSopenharmony_ci next_construct_fails = false; 133c5f01b2fSopenharmony_ci auto t = my_json::value_t::object; 134c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object)); 135c5f01b2fSopenharmony_ci next_construct_fails = true; 136c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); 137c5f01b2fSopenharmony_ci next_construct_fails = false; 138c5f01b2fSopenharmony_ci } 139c5f01b2fSopenharmony_ci SECTION("array") 140c5f01b2fSopenharmony_ci { 141c5f01b2fSopenharmony_ci next_construct_fails = false; 142c5f01b2fSopenharmony_ci auto t = my_json::value_t::array; 143c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array)); 144c5f01b2fSopenharmony_ci next_construct_fails = true; 145c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); 146c5f01b2fSopenharmony_ci next_construct_fails = false; 147c5f01b2fSopenharmony_ci } 148c5f01b2fSopenharmony_ci SECTION("string") 149c5f01b2fSopenharmony_ci { 150c5f01b2fSopenharmony_ci next_construct_fails = false; 151c5f01b2fSopenharmony_ci auto t = my_json::value_t::string; 152c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string)); 153c5f01b2fSopenharmony_ci next_construct_fails = true; 154c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&); 155c5f01b2fSopenharmony_ci next_construct_fails = false; 156c5f01b2fSopenharmony_ci } 157c5f01b2fSopenharmony_ci } 158c5f01b2fSopenharmony_ci 159c5f01b2fSopenharmony_ci SECTION("json_value(const string_t&)") 160c5f01b2fSopenharmony_ci { 161c5f01b2fSopenharmony_ci next_construct_fails = false; 162c5f01b2fSopenharmony_ci my_json::string_t v("foo"); 163c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string)); 164c5f01b2fSopenharmony_ci next_construct_fails = true; 165c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&); 166c5f01b2fSopenharmony_ci next_construct_fails = false; 167c5f01b2fSopenharmony_ci } 168c5f01b2fSopenharmony_ci } 169c5f01b2fSopenharmony_ci 170c5f01b2fSopenharmony_ci SECTION("class basic_json") 171c5f01b2fSopenharmony_ci { 172c5f01b2fSopenharmony_ci SECTION("basic_json(const CompatibleObjectType&)") 173c5f01b2fSopenharmony_ci { 174c5f01b2fSopenharmony_ci next_construct_fails = false; 175c5f01b2fSopenharmony_ci std::map<std::string, std::string> v {{"foo", "bar"}}; 176c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_json(v)); 177c5f01b2fSopenharmony_ci next_construct_fails = true; 178c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json(v), std::bad_alloc&); 179c5f01b2fSopenharmony_ci next_construct_fails = false; 180c5f01b2fSopenharmony_ci } 181c5f01b2fSopenharmony_ci 182c5f01b2fSopenharmony_ci SECTION("basic_json(const CompatibleArrayType&)") 183c5f01b2fSopenharmony_ci { 184c5f01b2fSopenharmony_ci next_construct_fails = false; 185c5f01b2fSopenharmony_ci std::vector<std::string> v {"foo", "bar", "baz"}; 186c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_json(v)); 187c5f01b2fSopenharmony_ci next_construct_fails = true; 188c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json(v), std::bad_alloc&); 189c5f01b2fSopenharmony_ci next_construct_fails = false; 190c5f01b2fSopenharmony_ci } 191c5f01b2fSopenharmony_ci 192c5f01b2fSopenharmony_ci SECTION("basic_json(const typename string_t::value_type*)") 193c5f01b2fSopenharmony_ci { 194c5f01b2fSopenharmony_ci next_construct_fails = false; 195c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_json("foo")); 196c5f01b2fSopenharmony_ci next_construct_fails = true; 197c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&); 198c5f01b2fSopenharmony_ci next_construct_fails = false; 199c5f01b2fSopenharmony_ci } 200c5f01b2fSopenharmony_ci 201c5f01b2fSopenharmony_ci SECTION("basic_json(const typename string_t::value_type*)") 202c5f01b2fSopenharmony_ci { 203c5f01b2fSopenharmony_ci next_construct_fails = false; 204c5f01b2fSopenharmony_ci std::string s("foo"); 205c5f01b2fSopenharmony_ci CHECK_NOTHROW(my_json(s)); 206c5f01b2fSopenharmony_ci next_construct_fails = true; 207c5f01b2fSopenharmony_ci CHECK_THROWS_AS(my_json(s), std::bad_alloc&); 208c5f01b2fSopenharmony_ci next_construct_fails = false; 209c5f01b2fSopenharmony_ci } 210c5f01b2fSopenharmony_ci } 211c5f01b2fSopenharmony_ci} 212c5f01b2fSopenharmony_ci 213c5f01b2fSopenharmony_cinamespace 214c5f01b2fSopenharmony_ci{ 215c5f01b2fSopenharmony_citemplate<class T> 216c5f01b2fSopenharmony_cistruct allocator_no_forward : std::allocator<T> 217c5f01b2fSopenharmony_ci{ 218c5f01b2fSopenharmony_ci allocator_no_forward() = default; 219c5f01b2fSopenharmony_ci template <class U> 220c5f01b2fSopenharmony_ci allocator_no_forward(allocator_no_forward<U> /*unused*/) {} 221c5f01b2fSopenharmony_ci 222c5f01b2fSopenharmony_ci template <class U> 223c5f01b2fSopenharmony_ci struct rebind 224c5f01b2fSopenharmony_ci { 225c5f01b2fSopenharmony_ci using other = allocator_no_forward<U>; 226c5f01b2fSopenharmony_ci }; 227c5f01b2fSopenharmony_ci 228c5f01b2fSopenharmony_ci template <class... Args> 229c5f01b2fSopenharmony_ci void construct(T* p, const Args& ... args) noexcept(noexcept(::new (static_cast<void*>(p)) T(args...))) 230c5f01b2fSopenharmony_ci { 231c5f01b2fSopenharmony_ci // force copy even if move is available 232c5f01b2fSopenharmony_ci ::new (static_cast<void*>(p)) T(args...); 233c5f01b2fSopenharmony_ci } 234c5f01b2fSopenharmony_ci}; 235c5f01b2fSopenharmony_ci} // namespace 236c5f01b2fSopenharmony_ci 237c5f01b2fSopenharmony_ciTEST_CASE("bad my_allocator::construct") 238c5f01b2fSopenharmony_ci{ 239c5f01b2fSopenharmony_ci SECTION("my_allocator::construct doesn't forward") 240c5f01b2fSopenharmony_ci { 241c5f01b2fSopenharmony_ci using bad_alloc_json = nlohmann::basic_json<std::map, 242c5f01b2fSopenharmony_ci std::vector, 243c5f01b2fSopenharmony_ci std::string, 244c5f01b2fSopenharmony_ci bool, 245c5f01b2fSopenharmony_ci std::int64_t, 246c5f01b2fSopenharmony_ci std::uint64_t, 247c5f01b2fSopenharmony_ci double, 248c5f01b2fSopenharmony_ci allocator_no_forward>; 249c5f01b2fSopenharmony_ci 250c5f01b2fSopenharmony_ci bad_alloc_json j; 251c5f01b2fSopenharmony_ci j["test"] = bad_alloc_json::array_t(); 252c5f01b2fSopenharmony_ci j["test"].push_back("should not leak"); 253c5f01b2fSopenharmony_ci } 254c5f01b2fSopenharmony_ci} 255