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// disable -Wnoexcept due to class Evil
12c5f01b2fSopenharmony_ciDOCTEST_GCC_SUPPRESS_WARNING_PUSH
13c5f01b2fSopenharmony_ciDOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
14c5f01b2fSopenharmony_ci
15c5f01b2fSopenharmony_ci#include <nlohmann/json.hpp>
16c5f01b2fSopenharmony_ciusing nlohmann::json;
17c5f01b2fSopenharmony_ci#ifdef JSON_TEST_NO_GLOBAL_UDLS
18c5f01b2fSopenharmony_ci    using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
19c5f01b2fSopenharmony_ci#endif
20c5f01b2fSopenharmony_ci
21c5f01b2fSopenharmony_ci#include <map>
22c5f01b2fSopenharmony_ci#include <memory>
23c5f01b2fSopenharmony_ci#include <string>
24c5f01b2fSopenharmony_ci#include <utility>
25c5f01b2fSopenharmony_ci
26c5f01b2fSopenharmony_cinamespace udt
27c5f01b2fSopenharmony_ci{
28c5f01b2fSopenharmony_cienum class country
29c5f01b2fSopenharmony_ci{
30c5f01b2fSopenharmony_ci    china,
31c5f01b2fSopenharmony_ci    france,
32c5f01b2fSopenharmony_ci    russia
33c5f01b2fSopenharmony_ci};
34c5f01b2fSopenharmony_ci
35c5f01b2fSopenharmony_cistruct age
36c5f01b2fSopenharmony_ci{
37c5f01b2fSopenharmony_ci    int m_val;
38c5f01b2fSopenharmony_ci    age(int rhs = 0) : m_val(rhs) {}
39c5f01b2fSopenharmony_ci};
40c5f01b2fSopenharmony_ci
41c5f01b2fSopenharmony_cistruct name
42c5f01b2fSopenharmony_ci{
43c5f01b2fSopenharmony_ci    std::string m_val;
44c5f01b2fSopenharmony_ci    name(std::string rhs = "") : m_val(std::move(rhs)) {}
45c5f01b2fSopenharmony_ci};
46c5f01b2fSopenharmony_ci
47c5f01b2fSopenharmony_cistruct address
48c5f01b2fSopenharmony_ci{
49c5f01b2fSopenharmony_ci    std::string m_val;
50c5f01b2fSopenharmony_ci    address(std::string rhs = "") : m_val(std::move(rhs)) {}
51c5f01b2fSopenharmony_ci};
52c5f01b2fSopenharmony_ci
53c5f01b2fSopenharmony_cistruct person
54c5f01b2fSopenharmony_ci{
55c5f01b2fSopenharmony_ci    age m_age{};
56c5f01b2fSopenharmony_ci    name m_name{};
57c5f01b2fSopenharmony_ci    country m_country{};
58c5f01b2fSopenharmony_ci    person() = default;
59c5f01b2fSopenharmony_ci    person(const age& a, name  n, const country& c) : m_age(a), m_name(std::move(n)), m_country(c) {}
60c5f01b2fSopenharmony_ci};
61c5f01b2fSopenharmony_ci
62c5f01b2fSopenharmony_cistruct contact
63c5f01b2fSopenharmony_ci{
64c5f01b2fSopenharmony_ci    person m_person{};
65c5f01b2fSopenharmony_ci    address m_address{};
66c5f01b2fSopenharmony_ci    contact() = default;
67c5f01b2fSopenharmony_ci    contact(person p, address a) : m_person(std::move(p)), m_address(std::move(a)) {}
68c5f01b2fSopenharmony_ci};
69c5f01b2fSopenharmony_ci
70c5f01b2fSopenharmony_cistruct contact_book
71c5f01b2fSopenharmony_ci{
72c5f01b2fSopenharmony_ci    name m_book_name{};
73c5f01b2fSopenharmony_ci    std::vector<contact> m_contacts{};
74c5f01b2fSopenharmony_ci    contact_book() = default;
75c5f01b2fSopenharmony_ci    contact_book(name n, std::vector<contact> c) : m_book_name(std::move(n)), m_contacts(std::move(c)) {}
76c5f01b2fSopenharmony_ci};
77c5f01b2fSopenharmony_ci} // namespace udt
78c5f01b2fSopenharmony_ci
79c5f01b2fSopenharmony_ci// to_json methods
80c5f01b2fSopenharmony_cinamespace udt
81c5f01b2fSopenharmony_ci{
82c5f01b2fSopenharmony_ci// templates because of the custom_json tests (see below)
83c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
84c5f01b2fSopenharmony_cistatic void to_json(BasicJsonType& j, age a)
85c5f01b2fSopenharmony_ci{
86c5f01b2fSopenharmony_ci    j = a.m_val;
87c5f01b2fSopenharmony_ci}
88c5f01b2fSopenharmony_ci
89c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
90c5f01b2fSopenharmony_cistatic void to_json(BasicJsonType& j, const name& n)
91c5f01b2fSopenharmony_ci{
92c5f01b2fSopenharmony_ci    j = n.m_val;
93c5f01b2fSopenharmony_ci}
94c5f01b2fSopenharmony_ci
95c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
96c5f01b2fSopenharmony_cistatic void to_json(BasicJsonType& j, country c)
97c5f01b2fSopenharmony_ci{
98c5f01b2fSopenharmony_ci    switch (c)
99c5f01b2fSopenharmony_ci    {
100c5f01b2fSopenharmony_ci        case country::china:
101c5f01b2fSopenharmony_ci            j = "中华人民共和国";
102c5f01b2fSopenharmony_ci            return;
103c5f01b2fSopenharmony_ci        case country::france:
104c5f01b2fSopenharmony_ci            j = "France";
105c5f01b2fSopenharmony_ci            return;
106c5f01b2fSopenharmony_ci        case country::russia:
107c5f01b2fSopenharmony_ci            j = "Российская Федерация";
108c5f01b2fSopenharmony_ci            return;
109c5f01b2fSopenharmony_ci        default:
110c5f01b2fSopenharmony_ci            break;
111c5f01b2fSopenharmony_ci    }
112c5f01b2fSopenharmony_ci}
113c5f01b2fSopenharmony_ci
114c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
115c5f01b2fSopenharmony_cistatic void to_json(BasicJsonType& j, const person& p)
116c5f01b2fSopenharmony_ci{
117c5f01b2fSopenharmony_ci    j = BasicJsonType{{"age", p.m_age}, {"name", p.m_name}, {"country", p.m_country}};
118c5f01b2fSopenharmony_ci}
119c5f01b2fSopenharmony_ci
120c5f01b2fSopenharmony_cistatic void to_json(nlohmann::json& j, const address& a)
121c5f01b2fSopenharmony_ci{
122c5f01b2fSopenharmony_ci    j = a.m_val;
123c5f01b2fSopenharmony_ci}
124c5f01b2fSopenharmony_ci
125c5f01b2fSopenharmony_cistatic void to_json(nlohmann::json& j, const contact& c)
126c5f01b2fSopenharmony_ci{
127c5f01b2fSopenharmony_ci    j = json{{"person", c.m_person}, {"address", c.m_address}};
128c5f01b2fSopenharmony_ci}
129c5f01b2fSopenharmony_ci
130c5f01b2fSopenharmony_cistatic void to_json(nlohmann::json& j, const contact_book& cb)
131c5f01b2fSopenharmony_ci{
132c5f01b2fSopenharmony_ci    j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}};
133c5f01b2fSopenharmony_ci}
134c5f01b2fSopenharmony_ci
135c5f01b2fSopenharmony_ci// operators
136c5f01b2fSopenharmony_cistatic bool operator==(age lhs, age rhs)
137c5f01b2fSopenharmony_ci{
138c5f01b2fSopenharmony_ci    return lhs.m_val == rhs.m_val;
139c5f01b2fSopenharmony_ci}
140c5f01b2fSopenharmony_ci
141c5f01b2fSopenharmony_cistatic bool operator==(const address& lhs, const address& rhs)
142c5f01b2fSopenharmony_ci{
143c5f01b2fSopenharmony_ci    return lhs.m_val == rhs.m_val;
144c5f01b2fSopenharmony_ci}
145c5f01b2fSopenharmony_ci
146c5f01b2fSopenharmony_cistatic bool operator==(const name& lhs, const name& rhs)
147c5f01b2fSopenharmony_ci{
148c5f01b2fSopenharmony_ci    return lhs.m_val == rhs.m_val;
149c5f01b2fSopenharmony_ci}
150c5f01b2fSopenharmony_ci
151c5f01b2fSopenharmony_cistatic bool operator==(const person& lhs, const person& rhs)
152c5f01b2fSopenharmony_ci{
153c5f01b2fSopenharmony_ci    return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age);
154c5f01b2fSopenharmony_ci}
155c5f01b2fSopenharmony_ci
156c5f01b2fSopenharmony_cistatic bool operator==(const contact& lhs, const contact& rhs)
157c5f01b2fSopenharmony_ci{
158c5f01b2fSopenharmony_ci    return std::tie(lhs.m_person, lhs.m_address) ==
159c5f01b2fSopenharmony_ci           std::tie(rhs.m_person, rhs.m_address);
160c5f01b2fSopenharmony_ci}
161c5f01b2fSopenharmony_ci
162c5f01b2fSopenharmony_cistatic bool operator==(const contact_book& lhs, const contact_book& rhs)
163c5f01b2fSopenharmony_ci{
164c5f01b2fSopenharmony_ci    return std::tie(lhs.m_book_name, lhs.m_contacts) ==
165c5f01b2fSopenharmony_ci           std::tie(rhs.m_book_name, rhs.m_contacts);
166c5f01b2fSopenharmony_ci}
167c5f01b2fSopenharmony_ci} // namespace udt
168c5f01b2fSopenharmony_ci
169c5f01b2fSopenharmony_ci// from_json methods
170c5f01b2fSopenharmony_cinamespace udt
171c5f01b2fSopenharmony_ci{
172c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
173c5f01b2fSopenharmony_cistatic void from_json(const BasicJsonType& j, age& a)
174c5f01b2fSopenharmony_ci{
175c5f01b2fSopenharmony_ci    a.m_val = j.template get<int>();
176c5f01b2fSopenharmony_ci}
177c5f01b2fSopenharmony_ci
178c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
179c5f01b2fSopenharmony_cistatic void from_json(const BasicJsonType& j, name& n)
180c5f01b2fSopenharmony_ci{
181c5f01b2fSopenharmony_ci    n.m_val = j.template get<std::string>();
182c5f01b2fSopenharmony_ci}
183c5f01b2fSopenharmony_ci
184c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
185c5f01b2fSopenharmony_cistatic void from_json(const BasicJsonType& j, country& c)
186c5f01b2fSopenharmony_ci{
187c5f01b2fSopenharmony_ci    const auto str = j.template get<std::string>();
188c5f01b2fSopenharmony_ci    const std::map<std::string, country> m =
189c5f01b2fSopenharmony_ci    {
190c5f01b2fSopenharmony_ci        {"中华人民共和国", country::china},
191c5f01b2fSopenharmony_ci        {"France", country::france},
192c5f01b2fSopenharmony_ci        {"Российская Федерация", country::russia}
193c5f01b2fSopenharmony_ci    };
194c5f01b2fSopenharmony_ci
195c5f01b2fSopenharmony_ci    const auto it = m.find(str);
196c5f01b2fSopenharmony_ci    // TODO(nlohmann) test exceptions
197c5f01b2fSopenharmony_ci    c = it->second;
198c5f01b2fSopenharmony_ci}
199c5f01b2fSopenharmony_ci
200c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
201c5f01b2fSopenharmony_cistatic void from_json(const BasicJsonType& j, person& p)
202c5f01b2fSopenharmony_ci{
203c5f01b2fSopenharmony_ci    p.m_age = j["age"].template get<age>();
204c5f01b2fSopenharmony_ci    p.m_name = j["name"].template get<name>();
205c5f01b2fSopenharmony_ci    p.m_country = j["country"].template get<country>();
206c5f01b2fSopenharmony_ci}
207c5f01b2fSopenharmony_ci
208c5f01b2fSopenharmony_cistatic void from_json(const nlohmann::json& j, address& a)
209c5f01b2fSopenharmony_ci{
210c5f01b2fSopenharmony_ci    a.m_val = j.get<std::string>();
211c5f01b2fSopenharmony_ci}
212c5f01b2fSopenharmony_ci
213c5f01b2fSopenharmony_cistatic void from_json(const nlohmann::json& j, contact& c)
214c5f01b2fSopenharmony_ci{
215c5f01b2fSopenharmony_ci    c.m_person = j["person"].get<person>();
216c5f01b2fSopenharmony_ci    c.m_address = j["address"].get<address>();
217c5f01b2fSopenharmony_ci}
218c5f01b2fSopenharmony_ci
219c5f01b2fSopenharmony_cistatic void from_json(const nlohmann::json& j, contact_book& cb)
220c5f01b2fSopenharmony_ci{
221c5f01b2fSopenharmony_ci    cb.m_book_name = j["name"].get<name>();
222c5f01b2fSopenharmony_ci    cb.m_contacts = j["contacts"].get<std::vector<contact>>();
223c5f01b2fSopenharmony_ci}
224c5f01b2fSopenharmony_ci} // namespace udt
225c5f01b2fSopenharmony_ci
226c5f01b2fSopenharmony_ciTEST_CASE("basic usage" * doctest::test_suite("udt"))
227c5f01b2fSopenharmony_ci{
228c5f01b2fSopenharmony_ci
229c5f01b2fSopenharmony_ci    // a bit narcissistic maybe :) ?
230c5f01b2fSopenharmony_ci    const udt::age a
231c5f01b2fSopenharmony_ci    {
232c5f01b2fSopenharmony_ci        23
233c5f01b2fSopenharmony_ci    };
234c5f01b2fSopenharmony_ci    const udt::name n{"theo"};
235c5f01b2fSopenharmony_ci    const udt::country c{udt::country::france};
236c5f01b2fSopenharmony_ci    const udt::person sfinae_addict{a, n, c};
237c5f01b2fSopenharmony_ci    const udt::person senior_programmer{{42}, {"王芳"}, udt::country::china};
238c5f01b2fSopenharmony_ci    const udt::address addr{"Paris"};
239c5f01b2fSopenharmony_ci    const udt::contact cpp_programmer{sfinae_addict, addr};
240c5f01b2fSopenharmony_ci    const udt::contact_book book{{"C++"}, {cpp_programmer, {senior_programmer, addr}}};
241c5f01b2fSopenharmony_ci
242c5f01b2fSopenharmony_ci    SECTION("conversion to json via free-functions")
243c5f01b2fSopenharmony_ci    {
244c5f01b2fSopenharmony_ci        CHECK(json(a) == json(23));
245c5f01b2fSopenharmony_ci        CHECK(json(n) == json("theo"));
246c5f01b2fSopenharmony_ci        CHECK(json(c) == json("France"));
247c5f01b2fSopenharmony_ci        CHECK(json(sfinae_addict) == R"({"name":"theo", "age":23, "country":"France"})"_json);
248c5f01b2fSopenharmony_ci        CHECK(json("Paris") == json(addr));
249c5f01b2fSopenharmony_ci        CHECK(json(cpp_programmer) ==
250c5f01b2fSopenharmony_ci              R"({"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"})"_json);
251c5f01b2fSopenharmony_ci
252c5f01b2fSopenharmony_ci        CHECK(
253c5f01b2fSopenharmony_ci            json(book) ==
254c5f01b2fSopenharmony_ci            R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json);
255c5f01b2fSopenharmony_ci
256c5f01b2fSopenharmony_ci    }
257c5f01b2fSopenharmony_ci
258c5f01b2fSopenharmony_ci    SECTION("conversion from json via free-functions")
259c5f01b2fSopenharmony_ci    {
260c5f01b2fSopenharmony_ci        const auto big_json =
261c5f01b2fSopenharmony_ci            R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json;
262c5f01b2fSopenharmony_ci        SECTION("via explicit calls to get")
263c5f01b2fSopenharmony_ci        {
264c5f01b2fSopenharmony_ci            const auto parsed_book = big_json.get<udt::contact_book>();
265c5f01b2fSopenharmony_ci            const auto book_name = big_json["name"].get<udt::name>();
266c5f01b2fSopenharmony_ci            const auto contacts =
267c5f01b2fSopenharmony_ci                big_json["contacts"].get<std::vector<udt::contact>>();
268c5f01b2fSopenharmony_ci            const auto contact_json = big_json["contacts"].at(0);
269c5f01b2fSopenharmony_ci            const auto contact = contact_json.get<udt::contact>();
270c5f01b2fSopenharmony_ci            const auto person = contact_json["person"].get<udt::person>();
271c5f01b2fSopenharmony_ci            const auto address = contact_json["address"].get<udt::address>();
272c5f01b2fSopenharmony_ci            const auto age = contact_json["person"]["age"].get<udt::age>();
273c5f01b2fSopenharmony_ci            const auto country =
274c5f01b2fSopenharmony_ci                contact_json["person"]["country"].get<udt::country>();
275c5f01b2fSopenharmony_ci            const auto name = contact_json["person"]["name"].get<udt::name>();
276c5f01b2fSopenharmony_ci
277c5f01b2fSopenharmony_ci            CHECK(age == a);
278c5f01b2fSopenharmony_ci            CHECK(name == n);
279c5f01b2fSopenharmony_ci            CHECK(country == c);
280c5f01b2fSopenharmony_ci            CHECK(address == addr);
281c5f01b2fSopenharmony_ci            CHECK(person == sfinae_addict);
282c5f01b2fSopenharmony_ci            CHECK(contact == cpp_programmer);
283c5f01b2fSopenharmony_ci            CHECK(contacts == book.m_contacts);
284c5f01b2fSopenharmony_ci            CHECK(book_name == udt::name{"C++"});
285c5f01b2fSopenharmony_ci            CHECK(book == parsed_book);
286c5f01b2fSopenharmony_ci        }
287c5f01b2fSopenharmony_ci
288c5f01b2fSopenharmony_ci        SECTION("via explicit calls to get_to")
289c5f01b2fSopenharmony_ci        {
290c5f01b2fSopenharmony_ci            udt::person person;
291c5f01b2fSopenharmony_ci            udt::name name;
292c5f01b2fSopenharmony_ci
293c5f01b2fSopenharmony_ci            json person_json = big_json["contacts"][0]["person"];
294c5f01b2fSopenharmony_ci            CHECK(person_json.get_to(person) == sfinae_addict);
295c5f01b2fSopenharmony_ci
296c5f01b2fSopenharmony_ci            // correct reference gets returned
297c5f01b2fSopenharmony_ci            person_json["name"].get_to(name).m_val = "new name";
298c5f01b2fSopenharmony_ci            CHECK(name.m_val == "new name");
299c5f01b2fSopenharmony_ci        }
300c5f01b2fSopenharmony_ci
301c5f01b2fSopenharmony_ci#if JSON_USE_IMPLICIT_CONVERSIONS
302c5f01b2fSopenharmony_ci        SECTION("implicit conversions")
303c5f01b2fSopenharmony_ci        {
304c5f01b2fSopenharmony_ci            const udt::contact_book parsed_book = big_json;
305c5f01b2fSopenharmony_ci            const udt::name book_name = big_json["name"];
306c5f01b2fSopenharmony_ci            const std::vector<udt::contact> contacts = big_json["contacts"];
307c5f01b2fSopenharmony_ci            const auto contact_json = big_json["contacts"].at(0);
308c5f01b2fSopenharmony_ci            const udt::contact contact = contact_json;
309c5f01b2fSopenharmony_ci            const udt::person person = contact_json["person"];
310c5f01b2fSopenharmony_ci            const udt::address address = contact_json["address"];
311c5f01b2fSopenharmony_ci            const udt::age age = contact_json["person"]["age"];
312c5f01b2fSopenharmony_ci            const udt::country country = contact_json["person"]["country"];
313c5f01b2fSopenharmony_ci            const udt::name name = contact_json["person"]["name"];
314c5f01b2fSopenharmony_ci
315c5f01b2fSopenharmony_ci            CHECK(age == a);
316c5f01b2fSopenharmony_ci            CHECK(name == n);
317c5f01b2fSopenharmony_ci            CHECK(country == c);
318c5f01b2fSopenharmony_ci            CHECK(address == addr);
319c5f01b2fSopenharmony_ci            CHECK(person == sfinae_addict);
320c5f01b2fSopenharmony_ci            CHECK(contact == cpp_programmer);
321c5f01b2fSopenharmony_ci            CHECK(contacts == book.m_contacts);
322c5f01b2fSopenharmony_ci            CHECK(book_name == udt::name{"C++"});
323c5f01b2fSopenharmony_ci            CHECK(book == parsed_book);
324c5f01b2fSopenharmony_ci        }
325c5f01b2fSopenharmony_ci#endif
326c5f01b2fSopenharmony_ci    }
327c5f01b2fSopenharmony_ci}
328c5f01b2fSopenharmony_ci
329c5f01b2fSopenharmony_cinamespace udt
330c5f01b2fSopenharmony_ci{
331c5f01b2fSopenharmony_cistruct legacy_type
332c5f01b2fSopenharmony_ci{
333c5f01b2fSopenharmony_ci    std::string number{};
334c5f01b2fSopenharmony_ci    legacy_type() = default;
335c5f01b2fSopenharmony_ci    legacy_type(std::string n) : number(std::move(n)) {}
336c5f01b2fSopenharmony_ci};
337c5f01b2fSopenharmony_ci} // namespace udt
338c5f01b2fSopenharmony_ci
339c5f01b2fSopenharmony_cinamespace nlohmann
340c5f01b2fSopenharmony_ci{
341c5f01b2fSopenharmony_citemplate <typename T>
342c5f01b2fSopenharmony_cistruct adl_serializer<std::shared_ptr<T>>
343c5f01b2fSopenharmony_ci{
344c5f01b2fSopenharmony_ci    static void to_json(json& j, const std::shared_ptr<T>& opt)
345c5f01b2fSopenharmony_ci    {
346c5f01b2fSopenharmony_ci        if (opt)
347c5f01b2fSopenharmony_ci        {
348c5f01b2fSopenharmony_ci            j = *opt;
349c5f01b2fSopenharmony_ci        }
350c5f01b2fSopenharmony_ci        else
351c5f01b2fSopenharmony_ci        {
352c5f01b2fSopenharmony_ci            j = nullptr;
353c5f01b2fSopenharmony_ci        }
354c5f01b2fSopenharmony_ci    }
355c5f01b2fSopenharmony_ci
356c5f01b2fSopenharmony_ci    static void from_json(const json& j, std::shared_ptr<T>& opt)
357c5f01b2fSopenharmony_ci    {
358c5f01b2fSopenharmony_ci        if (j.is_null())
359c5f01b2fSopenharmony_ci        {
360c5f01b2fSopenharmony_ci            opt = nullptr;
361c5f01b2fSopenharmony_ci        }
362c5f01b2fSopenharmony_ci        else
363c5f01b2fSopenharmony_ci        {
364c5f01b2fSopenharmony_ci            opt.reset(new T(j.get<T>())); // NOLINT(cppcoreguidelines-owning-memory)
365c5f01b2fSopenharmony_ci        }
366c5f01b2fSopenharmony_ci    }
367c5f01b2fSopenharmony_ci};
368c5f01b2fSopenharmony_ci
369c5f01b2fSopenharmony_citemplate <>
370c5f01b2fSopenharmony_cistruct adl_serializer<udt::legacy_type>
371c5f01b2fSopenharmony_ci{
372c5f01b2fSopenharmony_ci    static void to_json(json& j, const udt::legacy_type& l)
373c5f01b2fSopenharmony_ci    {
374c5f01b2fSopenharmony_ci        j = std::stoi(l.number);
375c5f01b2fSopenharmony_ci    }
376c5f01b2fSopenharmony_ci
377c5f01b2fSopenharmony_ci    static void from_json(const json& j, udt::legacy_type& l)
378c5f01b2fSopenharmony_ci    {
379c5f01b2fSopenharmony_ci        l.number = std::to_string(j.get<int>());
380c5f01b2fSopenharmony_ci    }
381c5f01b2fSopenharmony_ci};
382c5f01b2fSopenharmony_ci} // namespace nlohmann
383c5f01b2fSopenharmony_ci
384c5f01b2fSopenharmony_ciTEST_CASE("adl_serializer specialization" * doctest::test_suite("udt"))
385c5f01b2fSopenharmony_ci{
386c5f01b2fSopenharmony_ci    SECTION("partial specialization")
387c5f01b2fSopenharmony_ci    {
388c5f01b2fSopenharmony_ci        SECTION("to_json")
389c5f01b2fSopenharmony_ci        {
390c5f01b2fSopenharmony_ci            std::shared_ptr<udt::person> optPerson;
391c5f01b2fSopenharmony_ci
392c5f01b2fSopenharmony_ci            json j = optPerson;
393c5f01b2fSopenharmony_ci            CHECK(j.is_null());
394c5f01b2fSopenharmony_ci
395c5f01b2fSopenharmony_ci            optPerson.reset(new udt::person{{42}, {"John Doe"}, udt::country::russia}); // NOLINT(cppcoreguidelines-owning-memory,modernize-make-shared)
396c5f01b2fSopenharmony_ci            j = optPerson;
397c5f01b2fSopenharmony_ci            CHECK_FALSE(j.is_null());
398c5f01b2fSopenharmony_ci
399c5f01b2fSopenharmony_ci            CHECK(j.get<udt::person>() == *optPerson);
400c5f01b2fSopenharmony_ci        }
401c5f01b2fSopenharmony_ci
402c5f01b2fSopenharmony_ci        SECTION("from_json")
403c5f01b2fSopenharmony_ci        {
404c5f01b2fSopenharmony_ci            auto person = udt::person{{42}, {"John Doe"}, udt::country::russia};
405c5f01b2fSopenharmony_ci            json j = person;
406c5f01b2fSopenharmony_ci
407c5f01b2fSopenharmony_ci            auto optPerson = j.get<std::shared_ptr<udt::person>>();
408c5f01b2fSopenharmony_ci            REQUIRE(optPerson);
409c5f01b2fSopenharmony_ci            CHECK(*optPerson == person);
410c5f01b2fSopenharmony_ci
411c5f01b2fSopenharmony_ci            j = nullptr;
412c5f01b2fSopenharmony_ci            optPerson = j.get<std::shared_ptr<udt::person>>();
413c5f01b2fSopenharmony_ci            CHECK(!optPerson);
414c5f01b2fSopenharmony_ci        }
415c5f01b2fSopenharmony_ci    }
416c5f01b2fSopenharmony_ci
417c5f01b2fSopenharmony_ci    SECTION("total specialization")
418c5f01b2fSopenharmony_ci    {
419c5f01b2fSopenharmony_ci        SECTION("to_json")
420c5f01b2fSopenharmony_ci        {
421c5f01b2fSopenharmony_ci            udt::legacy_type lt{"4242"};
422c5f01b2fSopenharmony_ci
423c5f01b2fSopenharmony_ci            json j = lt;
424c5f01b2fSopenharmony_ci            CHECK(j.get<int>() == 4242);
425c5f01b2fSopenharmony_ci        }
426c5f01b2fSopenharmony_ci
427c5f01b2fSopenharmony_ci        SECTION("from_json")
428c5f01b2fSopenharmony_ci        {
429c5f01b2fSopenharmony_ci            json j = 4242;
430c5f01b2fSopenharmony_ci            auto lt = j.get<udt::legacy_type>();
431c5f01b2fSopenharmony_ci            CHECK(lt.number == "4242");
432c5f01b2fSopenharmony_ci        }
433c5f01b2fSopenharmony_ci    }
434c5f01b2fSopenharmony_ci}
435c5f01b2fSopenharmony_ci
436c5f01b2fSopenharmony_cinamespace nlohmann
437c5f01b2fSopenharmony_ci{
438c5f01b2fSopenharmony_citemplate <>
439c5f01b2fSopenharmony_cistruct adl_serializer<std::vector<float>>
440c5f01b2fSopenharmony_ci{
441c5f01b2fSopenharmony_ci    using type = std::vector<float>;
442c5f01b2fSopenharmony_ci    static void to_json(json& j, const type& /*type*/)
443c5f01b2fSopenharmony_ci    {
444c5f01b2fSopenharmony_ci        j = "hijacked!";
445c5f01b2fSopenharmony_ci    }
446c5f01b2fSopenharmony_ci
447c5f01b2fSopenharmony_ci    static void from_json(const json& /*unnamed*/, type& opt)
448c5f01b2fSopenharmony_ci    {
449c5f01b2fSopenharmony_ci        opt = {42.0, 42.0, 42.0};
450c5f01b2fSopenharmony_ci    }
451c5f01b2fSopenharmony_ci
452c5f01b2fSopenharmony_ci    // preferred version
453c5f01b2fSopenharmony_ci    static type from_json(const json& /*unnamed*/)
454c5f01b2fSopenharmony_ci    {
455c5f01b2fSopenharmony_ci        return {4.0, 5.0, 6.0};
456c5f01b2fSopenharmony_ci    }
457c5f01b2fSopenharmony_ci};
458c5f01b2fSopenharmony_ci} // namespace nlohmann
459c5f01b2fSopenharmony_ci
460c5f01b2fSopenharmony_ciTEST_CASE("even supported types can be specialized" * doctest::test_suite("udt"))
461c5f01b2fSopenharmony_ci{
462c5f01b2fSopenharmony_ci    json j = std::vector<float> {1.0, 2.0, 3.0};
463c5f01b2fSopenharmony_ci    CHECK(j.dump() == R"("hijacked!")");
464c5f01b2fSopenharmony_ci    auto f = j.get<std::vector<float>>();
465c5f01b2fSopenharmony_ci    // the single argument from_json method is preferred
466c5f01b2fSopenharmony_ci    CHECK((f == std::vector<float> {4.0, 5.0, 6.0}));
467c5f01b2fSopenharmony_ci}
468c5f01b2fSopenharmony_ci
469c5f01b2fSopenharmony_cinamespace nlohmann
470c5f01b2fSopenharmony_ci{
471c5f01b2fSopenharmony_citemplate <typename T>
472c5f01b2fSopenharmony_cistruct adl_serializer<std::unique_ptr<T>>
473c5f01b2fSopenharmony_ci{
474c5f01b2fSopenharmony_ci    static void to_json(json& j, const std::unique_ptr<T>& opt)
475c5f01b2fSopenharmony_ci    {
476c5f01b2fSopenharmony_ci        if (opt)
477c5f01b2fSopenharmony_ci        {
478c5f01b2fSopenharmony_ci            j = *opt;
479c5f01b2fSopenharmony_ci        }
480c5f01b2fSopenharmony_ci        else
481c5f01b2fSopenharmony_ci        {
482c5f01b2fSopenharmony_ci            j = nullptr;
483c5f01b2fSopenharmony_ci        }
484c5f01b2fSopenharmony_ci    }
485c5f01b2fSopenharmony_ci
486c5f01b2fSopenharmony_ci    // this is the overload needed for non-copyable types,
487c5f01b2fSopenharmony_ci    static std::unique_ptr<T> from_json(const json& j)
488c5f01b2fSopenharmony_ci    {
489c5f01b2fSopenharmony_ci        if (j.is_null())
490c5f01b2fSopenharmony_ci        {
491c5f01b2fSopenharmony_ci            return nullptr;
492c5f01b2fSopenharmony_ci        }
493c5f01b2fSopenharmony_ci
494c5f01b2fSopenharmony_ci        return std::unique_ptr<T>(new T(j.get<T>()));
495c5f01b2fSopenharmony_ci    }
496c5f01b2fSopenharmony_ci};
497c5f01b2fSopenharmony_ci} // namespace nlohmann
498c5f01b2fSopenharmony_ci
499c5f01b2fSopenharmony_ciTEST_CASE("Non-copyable types" * doctest::test_suite("udt"))
500c5f01b2fSopenharmony_ci{
501c5f01b2fSopenharmony_ci    SECTION("to_json")
502c5f01b2fSopenharmony_ci    {
503c5f01b2fSopenharmony_ci        std::unique_ptr<udt::person> optPerson;
504c5f01b2fSopenharmony_ci
505c5f01b2fSopenharmony_ci        json j = optPerson;
506c5f01b2fSopenharmony_ci        CHECK(j.is_null());
507c5f01b2fSopenharmony_ci
508c5f01b2fSopenharmony_ci        optPerson.reset(new udt::person{{42}, {"John Doe"}, udt::country::russia}); // NOLINT(cppcoreguidelines-owning-memory,modernize-make-unique)
509c5f01b2fSopenharmony_ci        j = optPerson;
510c5f01b2fSopenharmony_ci        CHECK_FALSE(j.is_null());
511c5f01b2fSopenharmony_ci
512c5f01b2fSopenharmony_ci        CHECK(j.get<udt::person>() == *optPerson);
513c5f01b2fSopenharmony_ci    }
514c5f01b2fSopenharmony_ci
515c5f01b2fSopenharmony_ci    SECTION("from_json")
516c5f01b2fSopenharmony_ci    {
517c5f01b2fSopenharmony_ci        auto person = udt::person{{42}, {"John Doe"}, udt::country::russia};
518c5f01b2fSopenharmony_ci        json j = person;
519c5f01b2fSopenharmony_ci
520c5f01b2fSopenharmony_ci        auto optPerson = j.get<std::unique_ptr<udt::person>>();
521c5f01b2fSopenharmony_ci        REQUIRE(optPerson);
522c5f01b2fSopenharmony_ci        CHECK(*optPerson == person);
523c5f01b2fSopenharmony_ci
524c5f01b2fSopenharmony_ci        j = nullptr;
525c5f01b2fSopenharmony_ci        optPerson = j.get<std::unique_ptr<udt::person>>();
526c5f01b2fSopenharmony_ci        CHECK(!optPerson);
527c5f01b2fSopenharmony_ci    }
528c5f01b2fSopenharmony_ci}
529c5f01b2fSopenharmony_ci
530c5f01b2fSopenharmony_ci// custom serializer - advanced usage
531c5f01b2fSopenharmony_ci// pack structs that are pod-types (but not scalar types)
532c5f01b2fSopenharmony_ci// relies on adl for any other type
533c5f01b2fSopenharmony_citemplate <typename T, typename = void>
534c5f01b2fSopenharmony_cistruct pod_serializer
535c5f01b2fSopenharmony_ci{
536c5f01b2fSopenharmony_ci    // use adl for non-pods, or scalar types
537c5f01b2fSopenharmony_ci    template <
538c5f01b2fSopenharmony_ci        typename BasicJsonType, typename U = T,
539c5f01b2fSopenharmony_ci        typename std::enable_if <
540c5f01b2fSopenharmony_ci            !(std::is_pod<U>::value && std::is_class<U>::value), int >::type = 0 >
541c5f01b2fSopenharmony_ci    static void from_json(const BasicJsonType& j, U& t)
542c5f01b2fSopenharmony_ci    {
543c5f01b2fSopenharmony_ci        using nlohmann::from_json;
544c5f01b2fSopenharmony_ci        from_json(j, t);
545c5f01b2fSopenharmony_ci    }
546c5f01b2fSopenharmony_ci
547c5f01b2fSopenharmony_ci    // special behaviour for pods
548c5f01b2fSopenharmony_ci    template < typename BasicJsonType, typename U = T,
549c5f01b2fSopenharmony_ci               typename std::enable_if <
550c5f01b2fSopenharmony_ci                   std::is_pod<U>::value && std::is_class<U>::value, int >::type = 0 >
551c5f01b2fSopenharmony_ci    static void from_json(const  BasicJsonType& j, U& t)
552c5f01b2fSopenharmony_ci    {
553c5f01b2fSopenharmony_ci        std::uint64_t value = 0;
554c5f01b2fSopenharmony_ci        // The following block is no longer relevant in this serializer, make another one that shows the issue
555c5f01b2fSopenharmony_ci        // the problem arises only when one from_json method is defined without any constraint
556c5f01b2fSopenharmony_ci        //
557c5f01b2fSopenharmony_ci        // Why cannot we simply use: j.get<std::uint64_t>() ?
558c5f01b2fSopenharmony_ci        // Well, with the current experiment, the get method looks for a from_json
559c5f01b2fSopenharmony_ci        // function, which we are currently defining!
560c5f01b2fSopenharmony_ci        // This would end up in a stack overflow. Calling nlohmann::from_json is a
561c5f01b2fSopenharmony_ci        // workaround (is it?).
562c5f01b2fSopenharmony_ci        // I shall find a good way to avoid this once all constructors are converted
563c5f01b2fSopenharmony_ci        // to free methods
564c5f01b2fSopenharmony_ci        //
565c5f01b2fSopenharmony_ci        // In short, constructing a json by constructor calls to_json
566c5f01b2fSopenharmony_ci        // calling get calls from_json, for now, we cannot do this in custom
567c5f01b2fSopenharmony_ci        // serializers
568c5f01b2fSopenharmony_ci        nlohmann::from_json(j, value);
569c5f01b2fSopenharmony_ci        auto* bytes = static_cast<char*>(static_cast<void*>(&value));
570c5f01b2fSopenharmony_ci        std::memcpy(&t, bytes, sizeof(value));
571c5f01b2fSopenharmony_ci    }
572c5f01b2fSopenharmony_ci
573c5f01b2fSopenharmony_ci    template <
574c5f01b2fSopenharmony_ci        typename BasicJsonType, typename U = T,
575c5f01b2fSopenharmony_ci        typename std::enable_if <
576c5f01b2fSopenharmony_ci            !(std::is_pod<U>::value && std::is_class<U>::value), int >::type = 0 >
577c5f01b2fSopenharmony_ci    static void to_json(BasicJsonType& j, const  T& t)
578c5f01b2fSopenharmony_ci    {
579c5f01b2fSopenharmony_ci        using nlohmann::to_json;
580c5f01b2fSopenharmony_ci        to_json(j, t);
581c5f01b2fSopenharmony_ci    }
582c5f01b2fSopenharmony_ci
583c5f01b2fSopenharmony_ci    template < typename BasicJsonType, typename U = T,
584c5f01b2fSopenharmony_ci               typename std::enable_if <
585c5f01b2fSopenharmony_ci                   std::is_pod<U>::value && std::is_class<U>::value, int >::type = 0 >
586c5f01b2fSopenharmony_ci    static void to_json(BasicJsonType& j, const  T& t) noexcept
587c5f01b2fSopenharmony_ci    {
588c5f01b2fSopenharmony_ci        const auto* bytes = static_cast< const unsigned char*>(static_cast<const void*>(&t));
589c5f01b2fSopenharmony_ci        std::uint64_t value = 0;
590c5f01b2fSopenharmony_ci        std::memcpy(&value, bytes, sizeof(value));
591c5f01b2fSopenharmony_ci        nlohmann::to_json(j, value);
592c5f01b2fSopenharmony_ci    }
593c5f01b2fSopenharmony_ci};
594c5f01b2fSopenharmony_ci
595c5f01b2fSopenharmony_cinamespace udt
596c5f01b2fSopenharmony_ci{
597c5f01b2fSopenharmony_cistruct small_pod
598c5f01b2fSopenharmony_ci{
599c5f01b2fSopenharmony_ci    int begin;
600c5f01b2fSopenharmony_ci    char middle;
601c5f01b2fSopenharmony_ci    short end;
602c5f01b2fSopenharmony_ci};
603c5f01b2fSopenharmony_ci
604c5f01b2fSopenharmony_cistruct non_pod
605c5f01b2fSopenharmony_ci{
606c5f01b2fSopenharmony_ci    std::string s{};
607c5f01b2fSopenharmony_ci    non_pod() = default;
608c5f01b2fSopenharmony_ci    non_pod(std::string S) : s(std::move(S)) {}
609c5f01b2fSopenharmony_ci};
610c5f01b2fSopenharmony_ci
611c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
612c5f01b2fSopenharmony_cistatic void to_json(BasicJsonType& j, const non_pod& np)
613c5f01b2fSopenharmony_ci{
614c5f01b2fSopenharmony_ci    j = np.s;
615c5f01b2fSopenharmony_ci}
616c5f01b2fSopenharmony_ci
617c5f01b2fSopenharmony_citemplate <typename BasicJsonType>
618c5f01b2fSopenharmony_cistatic void from_json(const BasicJsonType& j, non_pod& np)
619c5f01b2fSopenharmony_ci{
620c5f01b2fSopenharmony_ci    np.s = j.template get<std::string>();
621c5f01b2fSopenharmony_ci}
622c5f01b2fSopenharmony_ci
623c5f01b2fSopenharmony_cistatic bool operator==(small_pod lhs, small_pod rhs) noexcept
624c5f01b2fSopenharmony_ci{
625c5f01b2fSopenharmony_ci    return std::tie(lhs.begin, lhs.middle, lhs.end) ==
626c5f01b2fSopenharmony_ci           std::tie(rhs.begin, rhs.middle, rhs.end);
627c5f01b2fSopenharmony_ci}
628c5f01b2fSopenharmony_ci
629c5f01b2fSopenharmony_cistatic bool operator==(const  non_pod& lhs, const  non_pod& rhs) noexcept
630c5f01b2fSopenharmony_ci{
631c5f01b2fSopenharmony_ci    return lhs.s == rhs.s;
632c5f01b2fSopenharmony_ci}
633c5f01b2fSopenharmony_ci
634c5f01b2fSopenharmony_cistatic std::ostream& operator<<(std::ostream& os, small_pod l)
635c5f01b2fSopenharmony_ci{
636c5f01b2fSopenharmony_ci    return os << "begin: " << l.begin << ", middle: " << l.middle << ", end: " << l.end;
637c5f01b2fSopenharmony_ci}
638c5f01b2fSopenharmony_ci} // namespace udt
639c5f01b2fSopenharmony_ci
640c5f01b2fSopenharmony_ciTEST_CASE("custom serializer for pods" * doctest::test_suite("udt"))
641c5f01b2fSopenharmony_ci{
642c5f01b2fSopenharmony_ci    using custom_json =
643c5f01b2fSopenharmony_ci        nlohmann::basic_json<std::map, std::vector, std::string, bool,
644c5f01b2fSopenharmony_ci        std::int64_t, std::uint64_t, double, std::allocator, pod_serializer>;
645c5f01b2fSopenharmony_ci
646c5f01b2fSopenharmony_ci    auto p = udt::small_pod{42, '/', 42};
647c5f01b2fSopenharmony_ci    custom_json j = p;
648c5f01b2fSopenharmony_ci
649c5f01b2fSopenharmony_ci    auto p2 = j.get<udt::small_pod>();
650c5f01b2fSopenharmony_ci
651c5f01b2fSopenharmony_ci    CHECK(p == p2);
652c5f01b2fSopenharmony_ci
653c5f01b2fSopenharmony_ci    auto np = udt::non_pod{{"non-pod"}};
654c5f01b2fSopenharmony_ci    custom_json j2 = np;
655c5f01b2fSopenharmony_ci    auto np2 = j2.get<udt::non_pod>();
656c5f01b2fSopenharmony_ci    CHECK(np == np2);
657c5f01b2fSopenharmony_ci}
658c5f01b2fSopenharmony_ci
659c5f01b2fSopenharmony_citemplate <typename T, typename>
660c5f01b2fSopenharmony_cistruct another_adl_serializer;
661c5f01b2fSopenharmony_ci
662c5f01b2fSopenharmony_ciusing custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, another_adl_serializer>;
663c5f01b2fSopenharmony_ci
664c5f01b2fSopenharmony_citemplate <typename T, typename>
665c5f01b2fSopenharmony_cistruct another_adl_serializer
666c5f01b2fSopenharmony_ci{
667c5f01b2fSopenharmony_ci    static void from_json(const custom_json& j, T& t)
668c5f01b2fSopenharmony_ci    {
669c5f01b2fSopenharmony_ci        using nlohmann::from_json;
670c5f01b2fSopenharmony_ci        from_json(j, t);
671c5f01b2fSopenharmony_ci    }
672c5f01b2fSopenharmony_ci
673c5f01b2fSopenharmony_ci    static void to_json(custom_json& j, const T& t)
674c5f01b2fSopenharmony_ci    {
675c5f01b2fSopenharmony_ci        using nlohmann::to_json;
676c5f01b2fSopenharmony_ci        to_json(j, t);
677c5f01b2fSopenharmony_ci    }
678c5f01b2fSopenharmony_ci};
679c5f01b2fSopenharmony_ci
680c5f01b2fSopenharmony_ciTEST_CASE("custom serializer that does adl by default" * doctest::test_suite("udt"))
681c5f01b2fSopenharmony_ci{
682c5f01b2fSopenharmony_ci    auto me = udt::person{{23}, {"theo"}, udt::country::france};
683c5f01b2fSopenharmony_ci
684c5f01b2fSopenharmony_ci    json j = me;
685c5f01b2fSopenharmony_ci    custom_json cj = me;
686c5f01b2fSopenharmony_ci
687c5f01b2fSopenharmony_ci    CHECK(j.dump() == cj.dump());
688c5f01b2fSopenharmony_ci
689c5f01b2fSopenharmony_ci    CHECK(me == j.get<udt::person>());
690c5f01b2fSopenharmony_ci    CHECK(me == cj.get<udt::person>());
691c5f01b2fSopenharmony_ci}
692c5f01b2fSopenharmony_ci
693c5f01b2fSopenharmony_ciTEST_CASE("different basic_json types conversions")
694c5f01b2fSopenharmony_ci{
695c5f01b2fSopenharmony_ci    SECTION("null")
696c5f01b2fSopenharmony_ci    {
697c5f01b2fSopenharmony_ci        json j;
698c5f01b2fSopenharmony_ci        custom_json cj = j;
699c5f01b2fSopenharmony_ci        CHECK(cj == nullptr);
700c5f01b2fSopenharmony_ci    }
701c5f01b2fSopenharmony_ci
702c5f01b2fSopenharmony_ci    SECTION("boolean")
703c5f01b2fSopenharmony_ci    {
704c5f01b2fSopenharmony_ci        json j = true;
705c5f01b2fSopenharmony_ci        custom_json cj = j;
706c5f01b2fSopenharmony_ci        CHECK(cj == true);
707c5f01b2fSopenharmony_ci    }
708c5f01b2fSopenharmony_ci
709c5f01b2fSopenharmony_ci    SECTION("discarded")
710c5f01b2fSopenharmony_ci    {
711c5f01b2fSopenharmony_ci        json j(json::value_t::discarded);
712c5f01b2fSopenharmony_ci        custom_json cj;
713c5f01b2fSopenharmony_ci        CHECK_NOTHROW(cj = j);
714c5f01b2fSopenharmony_ci        CHECK(cj.type() == custom_json::value_t::discarded);
715c5f01b2fSopenharmony_ci    }
716c5f01b2fSopenharmony_ci
717c5f01b2fSopenharmony_ci    SECTION("array")
718c5f01b2fSopenharmony_ci    {
719c5f01b2fSopenharmony_ci        json j = {1, 2, 3};
720c5f01b2fSopenharmony_ci        custom_json cj = j;
721c5f01b2fSopenharmony_ci        CHECK((cj == std::vector<int> {1, 2, 3}));
722c5f01b2fSopenharmony_ci    }
723c5f01b2fSopenharmony_ci
724c5f01b2fSopenharmony_ci    SECTION("integer")
725c5f01b2fSopenharmony_ci    {
726c5f01b2fSopenharmony_ci        json j = 42;
727c5f01b2fSopenharmony_ci        custom_json cj = j;
728c5f01b2fSopenharmony_ci        CHECK(cj == 42);
729c5f01b2fSopenharmony_ci    }
730c5f01b2fSopenharmony_ci
731c5f01b2fSopenharmony_ci    SECTION("float")
732c5f01b2fSopenharmony_ci    {
733c5f01b2fSopenharmony_ci        json j = 42.0;
734c5f01b2fSopenharmony_ci        custom_json cj = j;
735c5f01b2fSopenharmony_ci        CHECK(cj == 42.0);
736c5f01b2fSopenharmony_ci    }
737c5f01b2fSopenharmony_ci
738c5f01b2fSopenharmony_ci    SECTION("unsigned")
739c5f01b2fSopenharmony_ci    {
740c5f01b2fSopenharmony_ci        json j = 42u;
741c5f01b2fSopenharmony_ci        custom_json cj = j;
742c5f01b2fSopenharmony_ci        CHECK(cj == 42u);
743c5f01b2fSopenharmony_ci    }
744c5f01b2fSopenharmony_ci
745c5f01b2fSopenharmony_ci    SECTION("string")
746c5f01b2fSopenharmony_ci    {
747c5f01b2fSopenharmony_ci        json j = "forty-two";
748c5f01b2fSopenharmony_ci        custom_json cj = j;
749c5f01b2fSopenharmony_ci        CHECK(cj == "forty-two");
750c5f01b2fSopenharmony_ci    }
751c5f01b2fSopenharmony_ci
752c5f01b2fSopenharmony_ci    SECTION("binary")
753c5f01b2fSopenharmony_ci    {
754c5f01b2fSopenharmony_ci        json j = json::binary({1, 2, 3}, 42);
755c5f01b2fSopenharmony_ci        custom_json cj = j;
756c5f01b2fSopenharmony_ci        CHECK(cj.get_binary().subtype() == 42);
757c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> cv = cj.get_binary();
758c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> v = j.get_binary();
759c5f01b2fSopenharmony_ci        CHECK(cv == v);
760c5f01b2fSopenharmony_ci    }
761c5f01b2fSopenharmony_ci
762c5f01b2fSopenharmony_ci    SECTION("object")
763c5f01b2fSopenharmony_ci    {
764c5f01b2fSopenharmony_ci        json j = {{"forty", "two"}};
765c5f01b2fSopenharmony_ci        custom_json cj = j;
766c5f01b2fSopenharmony_ci        auto m = j.get<std::map<std::string, std::string>>();
767c5f01b2fSopenharmony_ci        CHECK(cj == m);
768c5f01b2fSopenharmony_ci    }
769c5f01b2fSopenharmony_ci
770c5f01b2fSopenharmony_ci    SECTION("get<custom_json>")
771c5f01b2fSopenharmony_ci    {
772c5f01b2fSopenharmony_ci        json j = 42;
773c5f01b2fSopenharmony_ci        custom_json cj = j.get<custom_json>();
774c5f01b2fSopenharmony_ci        CHECK(cj == 42);
775c5f01b2fSopenharmony_ci    }
776c5f01b2fSopenharmony_ci}
777c5f01b2fSopenharmony_ci
778c5f01b2fSopenharmony_cinamespace
779c5f01b2fSopenharmony_ci{
780c5f01b2fSopenharmony_cistruct incomplete;
781c5f01b2fSopenharmony_ci
782c5f01b2fSopenharmony_ci// std::is_constructible is broken on macOS' libc++
783c5f01b2fSopenharmony_ci// use the cppreference implementation
784c5f01b2fSopenharmony_ci
785c5f01b2fSopenharmony_citemplate <typename T, typename = void>
786c5f01b2fSopenharmony_cistruct is_constructible_patched : std::false_type {};
787c5f01b2fSopenharmony_ci
788c5f01b2fSopenharmony_citemplate <typename T>
789c5f01b2fSopenharmony_cistruct is_constructible_patched<T, decltype(void(json(std::declval<T>())))> : std::true_type {};
790c5f01b2fSopenharmony_ci} // namespace
791c5f01b2fSopenharmony_ci
792c5f01b2fSopenharmony_ciTEST_CASE("an incomplete type does not trigger a compiler error in non-evaluated context" * doctest::test_suite("udt"))
793c5f01b2fSopenharmony_ci{
794c5f01b2fSopenharmony_ci    static_assert(!is_constructible_patched<json, incomplete>::value, "");
795c5f01b2fSopenharmony_ci}
796c5f01b2fSopenharmony_ci
797c5f01b2fSopenharmony_cinamespace
798c5f01b2fSopenharmony_ci{
799c5f01b2fSopenharmony_ciclass Evil
800c5f01b2fSopenharmony_ci{
801c5f01b2fSopenharmony_ci  public:
802c5f01b2fSopenharmony_ci    Evil() = default;
803c5f01b2fSopenharmony_ci    template <typename T>
804c5f01b2fSopenharmony_ci    Evil(T t) : m_i(sizeof(t))
805c5f01b2fSopenharmony_ci    {
806c5f01b2fSopenharmony_ci        static_cast<void>(t); // fix MSVC's C4100 warning
807c5f01b2fSopenharmony_ci    }
808c5f01b2fSopenharmony_ci
809c5f01b2fSopenharmony_ci    int m_i = 0;
810c5f01b2fSopenharmony_ci};
811c5f01b2fSopenharmony_ci
812c5f01b2fSopenharmony_civoid from_json(const json& /*unused*/, Evil& /*unused*/) {}
813c5f01b2fSopenharmony_ci} // namespace
814c5f01b2fSopenharmony_ci
815c5f01b2fSopenharmony_ciTEST_CASE("Issue #924")
816c5f01b2fSopenharmony_ci{
817c5f01b2fSopenharmony_ci    // Prevent get<std::vector<Evil>>() to throw
818c5f01b2fSopenharmony_ci    auto j = json::array();
819c5f01b2fSopenharmony_ci
820c5f01b2fSopenharmony_ci    CHECK_NOTHROW(j.get<Evil>());
821c5f01b2fSopenharmony_ci    CHECK_NOTHROW(j.get<std::vector<Evil>>());
822c5f01b2fSopenharmony_ci
823c5f01b2fSopenharmony_ci    // silence Wunused-template warnings
824c5f01b2fSopenharmony_ci    Evil e(1);
825c5f01b2fSopenharmony_ci    CHECK(e.m_i >= 0);
826c5f01b2fSopenharmony_ci}
827c5f01b2fSopenharmony_ci
828c5f01b2fSopenharmony_ciTEST_CASE("Issue #1237")
829c5f01b2fSopenharmony_ci{
830c5f01b2fSopenharmony_ci    struct non_convertible_type {};
831c5f01b2fSopenharmony_ci    static_assert(!std::is_convertible<json, non_convertible_type>::value, "");
832c5f01b2fSopenharmony_ci}
833c5f01b2fSopenharmony_ci
834c5f01b2fSopenharmony_cinamespace
835c5f01b2fSopenharmony_ci{
836c5f01b2fSopenharmony_ciclass no_iterator_type
837c5f01b2fSopenharmony_ci{
838c5f01b2fSopenharmony_ci  public:
839c5f01b2fSopenharmony_ci    no_iterator_type(std::initializer_list<int> l)
840c5f01b2fSopenharmony_ci        : _v(l)
841c5f01b2fSopenharmony_ci    {}
842c5f01b2fSopenharmony_ci
843c5f01b2fSopenharmony_ci    std::vector<int>::const_iterator begin() const
844c5f01b2fSopenharmony_ci    {
845c5f01b2fSopenharmony_ci        return _v.begin();
846c5f01b2fSopenharmony_ci    }
847c5f01b2fSopenharmony_ci
848c5f01b2fSopenharmony_ci    std::vector<int>::const_iterator end() const
849c5f01b2fSopenharmony_ci    {
850c5f01b2fSopenharmony_ci        return _v.end();
851c5f01b2fSopenharmony_ci    }
852c5f01b2fSopenharmony_ci
853c5f01b2fSopenharmony_ci  private:
854c5f01b2fSopenharmony_ci    std::vector<int> _v;
855c5f01b2fSopenharmony_ci};
856c5f01b2fSopenharmony_ci}  // namespace
857c5f01b2fSopenharmony_ci
858c5f01b2fSopenharmony_ciTEST_CASE("compatible array type, without iterator type alias")
859c5f01b2fSopenharmony_ci{
860c5f01b2fSopenharmony_ci    no_iterator_type vec{1, 2, 3};
861c5f01b2fSopenharmony_ci    json j = vec;
862c5f01b2fSopenharmony_ci}
863c5f01b2fSopenharmony_ci
864c5f01b2fSopenharmony_ciDOCTEST_GCC_SUPPRESS_WARNING_POP
865