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