]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/third_party/nlohmann-json/test/src/unit-allocator.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / nlohmann-json / test / src / unit-allocator.cpp
CommitLineData
1e59de90
TL
1/*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++ (test suite)
4| | |__ | | | | | | version 3.10.5
5|_____|_____|_____|_|___| https://github.com/nlohmann/json
6
7Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8SPDX-License-Identifier: MIT
9Copyright (c) 2013-2022 Niels Lohmann <http://nlohmann.me>.
10
11Permission is hereby granted, free of charge, to any person obtaining a copy
12of this software and associated documentation files (the "Software"), to deal
13in the Software without restriction, including without limitation the rights
14to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15copies of the Software, and to permit persons to whom the Software is
16furnished to do so, subject to the following conditions:
17
18The above copyright notice and this permission notice shall be included in all
19copies or substantial portions of the Software.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27SOFTWARE.
28*/
29
30#include "doctest_compatibility.h"
31
32#define JSON_TESTS_PRIVATE
33#include <nlohmann/json.hpp>
34using nlohmann::json;
35
36namespace
37{
38// special test case to check if memory is leaked if constructor throws
39template<class T>
40struct bad_allocator : std::allocator<T>
41{
42 template<class... Args>
43 void construct(T* /*unused*/, Args&& ... /*unused*/)
44 {
45 throw std::bad_alloc();
46 }
47};
48} // namespace
49
50TEST_CASE("bad_alloc")
51{
52 SECTION("bad_alloc")
53 {
54 // create JSON type using the throwing allocator
55 using bad_json = nlohmann::basic_json<std::map,
56 std::vector,
57 std::string,
58 bool,
59 std::int64_t,
60 std::uint64_t,
61 double,
62 bad_allocator>;
63
64 // creating an object should throw
65 CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&);
66 }
67}
68
69namespace
70{
71bool next_construct_fails = false;
72bool next_destroy_fails = false;
73bool next_deallocate_fails = false;
74
75template<class T>
76struct my_allocator : std::allocator<T>
77{
78 using std::allocator<T>::allocator;
79
80 template<class... Args>
81 void construct(T* p, Args&& ... args)
82 {
83 if (next_construct_fails)
84 {
85 next_construct_fails = false;
86 throw std::bad_alloc();
87 }
88
89 ::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
90 }
91
92 void deallocate(T* p, std::size_t n)
93 {
94 if (next_deallocate_fails)
95 {
96 next_deallocate_fails = false;
97 throw std::bad_alloc();
98 }
99
100 std::allocator<T>::deallocate(p, n);
101 }
102
103 void destroy(T* p)
104 {
105 if (next_destroy_fails)
106 {
107 next_destroy_fails = false;
108 throw std::bad_alloc();
109 }
110
111 static_cast<void>(p); // fix MSVC's C4100 warning
112 p->~T();
113 }
114
115 template <class U>
116 struct rebind
117 {
118 using other = my_allocator<U>;
119 };
120};
121
122// allows deletion of raw pointer, usually hold by json_value
123template<class T>
124void my_allocator_clean_up(T* p)
125{
126 assert(p != nullptr);
127 my_allocator<T> alloc;
128 alloc.destroy(p);
129 alloc.deallocate(p, 1);
130}
131} // namespace
132
133TEST_CASE("controlled bad_alloc")
134{
135 // create JSON type using the throwing allocator
136 using my_json = nlohmann::basic_json<std::map,
137 std::vector,
138 std::string,
139 bool,
140 std::int64_t,
141 std::uint64_t,
142 double,
143 my_allocator>;
144
145 SECTION("class json_value")
146 {
147 SECTION("json_value(value_t)")
148 {
149 SECTION("object")
150 {
151 next_construct_fails = false;
152 auto t = my_json::value_t::object;
153 CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object));
154 next_construct_fails = true;
155 CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
156 next_construct_fails = false;
157 }
158 SECTION("array")
159 {
160 next_construct_fails = false;
161 auto t = my_json::value_t::array;
162 CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array));
163 next_construct_fails = true;
164 CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
165 next_construct_fails = false;
166 }
167 SECTION("string")
168 {
169 next_construct_fails = false;
170 auto t = my_json::value_t::string;
171 CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string));
172 next_construct_fails = true;
173 CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
174 next_construct_fails = false;
175 }
176 }
177
178 SECTION("json_value(const string_t&)")
179 {
180 next_construct_fails = false;
181 my_json::string_t v("foo");
182 CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string));
183 next_construct_fails = true;
184 CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&);
185 next_construct_fails = false;
186 }
187 }
188
189 SECTION("class basic_json")
190 {
191 SECTION("basic_json(const CompatibleObjectType&)")
192 {
193 next_construct_fails = false;
194 std::map<std::string, std::string> v {{"foo", "bar"}};
195 CHECK_NOTHROW(my_json(v));
196 next_construct_fails = true;
197 CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
198 next_construct_fails = false;
199 }
200
201 SECTION("basic_json(const CompatibleArrayType&)")
202 {
203 next_construct_fails = false;
204 std::vector<std::string> v {"foo", "bar", "baz"};
205 CHECK_NOTHROW(my_json(v));
206 next_construct_fails = true;
207 CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
208 next_construct_fails = false;
209 }
210
211 SECTION("basic_json(const typename string_t::value_type*)")
212 {
213 next_construct_fails = false;
214 CHECK_NOTHROW(my_json("foo"));
215 next_construct_fails = true;
216 CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&);
217 next_construct_fails = false;
218 }
219
220 SECTION("basic_json(const typename string_t::value_type*)")
221 {
222 next_construct_fails = false;
223 std::string s("foo");
224 CHECK_NOTHROW(my_json(s));
225 next_construct_fails = true;
226 CHECK_THROWS_AS(my_json(s), std::bad_alloc&);
227 next_construct_fails = false;
228 }
229 }
230}
231
232namespace
233{
234template<class T>
235struct allocator_no_forward : std::allocator<T>
236{
237 allocator_no_forward() = default;
238 template <class U>
239 allocator_no_forward(allocator_no_forward<U> /*unused*/) {}
240
241 template <class U>
242 struct rebind
243 {
244 using other = allocator_no_forward<U>;
245 };
246
247 template <class... Args>
248 void construct(T* p, const Args& ... args) noexcept(noexcept(::new (static_cast<void*>(p)) T(args...)))
249 {
250 // force copy even if move is available
251 ::new (static_cast<void*>(p)) T(args...);
252 }
253};
254} // namespace
255
256TEST_CASE("bad my_allocator::construct")
257{
258 SECTION("my_allocator::construct doesn't forward")
259 {
260 using bad_alloc_json = nlohmann::basic_json<std::map,
261 std::vector,
262 std::string,
263 bool,
264 std::int64_t,
265 std::uint64_t,
266 double,
267 allocator_no_forward>;
268
269 bad_alloc_json j;
270 j["test"] = bad_alloc_json::array_t();
271 j["test"].push_back("should not leak");
272 }
273}