1//     __ _____ _____ _____
2//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3// |  |  |__   |  |  | | | |  version 3.11.2
4// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#include "doctest_compatibility.h"
10
11#include <nlohmann/json.hpp>
12using nlohmann::json;
13
14TEST_CASE("reference access")
15{
16    // create a JSON value with different types
17    json json_types =
18    {
19        {"boolean", true},
20        {
21            "number", {
22                {"integer", 42},
23                {"floating-point", 17.23}
24            }
25        },
26        {"string", "Hello, world!"},
27        {"array", {1, 2, 3, 4, 5}},
28        {"null", nullptr}
29    };
30
31    SECTION("reference access to object_t")
32    {
33        using test_type = json::object_t;
34        json value = {{"one", 1}, {"two", 2}};
35
36        // check if references are returned correctly
37        auto& p1 = value.get_ref<test_type&>();
38        CHECK(&p1 == value.get_ptr<test_type*>());
39        CHECK(p1 == value.get<test_type>());
40
41        const auto& p2 = value.get_ref<const test_type&>();
42        CHECK(&p2 == value.get_ptr<const test_type*>());
43        CHECK(p2 == value.get<test_type>());
44
45        // check if mismatching references throw correctly
46        CHECK_NOTHROW(value.get_ref<json::object_t&>());
47        CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
48                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
49        CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
50                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
51        CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
52                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
53        CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
54                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
55        CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
56                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
57        CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
58                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
59    }
60
61    SECTION("const reference access to const object_t")
62    {
63        using test_type = json::object_t;
64        const json value = {{"one", 1}, {"two", 2}};
65
66        // this should not compile
67        // test_type& p1 = value.get_ref<test_type&>();
68
69        // check if references are returned correctly
70        const auto& p2 = value.get_ref<const test_type&>();
71        CHECK(&p2 == value.get_ptr<const test_type*>());
72        CHECK(p2 == value.get<test_type>());
73    }
74
75    SECTION("reference access to array_t")
76    {
77        using test_type = json::array_t;
78        json value = {1, 2, 3, 4};
79
80        // check if references are returned correctly
81        auto& p1 = value.get_ref<test_type&>();
82        CHECK(&p1 == value.get_ptr<test_type*>());
83        CHECK(p1 == value.get<test_type>());
84
85        const auto& p2 = value.get_ref<const test_type&>();
86        CHECK(&p2 == value.get_ptr<const test_type*>());
87        CHECK(p2 == value.get<test_type>());
88
89        // check if mismatching references throw correctly
90        CHECK_THROWS_WITH_AS(value.get_ref<json::object_t&>(),
91                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
92        CHECK_NOTHROW(value.get_ref<json::array_t&>());
93        CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
94                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
95        CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
96                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
97        CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
98                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
99        CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
100                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
101        CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
102                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
103    }
104
105    SECTION("reference access to string_t")
106    {
107        using test_type = json::string_t;
108        json value = "hello";
109
110        // check if references are returned correctly
111        auto& p1 = value.get_ref<test_type&>();
112        CHECK(&p1 == value.get_ptr<test_type*>());
113        CHECK(p1 == value.get<test_type>());
114
115        const auto& p2 = value.get_ref<const test_type&>();
116        CHECK(&p2 == value.get_ptr<const test_type*>());
117        CHECK(p2 == value.get<test_type>());
118
119        // check if mismatching references throw correctly
120        CHECK_THROWS_WITH_AS(value.get_ref<json::object_t&>(),
121                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
122        CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
123                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
124        CHECK_NOTHROW(value.get_ref<json::string_t&>());
125        CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
126                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
127        CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
128                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
129        CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
130                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
131        CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
132                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
133    }
134
135    SECTION("reference access to boolean_t")
136    {
137        using test_type = json::boolean_t;
138        json value = false;
139
140        // check if references are returned correctly
141        auto& p1 = value.get_ref<test_type&>();
142        CHECK(&p1 == value.get_ptr<test_type*>());
143        CHECK(p1 == value.get<test_type>());
144
145        const auto& p2 = value.get_ref<const test_type&>();
146        CHECK(&p2 == value.get_ptr<const test_type*>());
147        CHECK(p2 == value.get<test_type>());
148
149        // check if mismatching references throw correctly
150        CHECK_THROWS_WITH_AS(value.get_ref<json::object_t&>(),
151                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
152        CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
153                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
154        CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
155                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
156        CHECK_NOTHROW(value.get_ref<json::boolean_t&>());
157        CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
158                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
159        CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
160                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
161        CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
162                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
163    }
164
165    SECTION("reference access to number_integer_t")
166    {
167        using test_type = json::number_integer_t;
168        json value = -23;
169
170        // check if references are returned correctly
171        auto& p1 = value.get_ref<test_type&>();
172        CHECK(&p1 == value.get_ptr<test_type*>());
173        CHECK(p1 == value.get<test_type>());
174
175        const auto& p2 = value.get_ref<const test_type&>();
176        CHECK(&p2 == value.get_ptr<const test_type*>());
177        CHECK(p2 == value.get<test_type>());
178
179        // check if mismatching references throw correctly
180        CHECK_THROWS_WITH_AS(value.get_ref<json::object_t&>(),
181                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
182        CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
183                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
184        CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
185                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
186        CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
187                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
188        CHECK_NOTHROW(value.get_ref<json::number_integer_t&>());
189        CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
190                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
191        CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
192                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
193    }
194
195    SECTION("reference access to number_unsigned_t")
196    {
197        using test_type = json::number_unsigned_t;
198        json value = 23u;
199
200        // check if references are returned correctly
201        auto& p1 = value.get_ref<test_type&>();
202        CHECK(&p1 == value.get_ptr<test_type*>());
203        CHECK(p1 == value.get<test_type>());
204
205        const auto& p2 = value.get_ref<const test_type&>();
206        CHECK(&p2 == value.get_ptr<const test_type*>());
207        CHECK(p2 == value.get<test_type>());
208
209        // check if mismatching references throw correctly
210        CHECK_THROWS_WITH_AS(value.get_ref<json::object_t&>(),
211                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
212        CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
213                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
214        CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
215                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
216        CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
217                             "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
218        //CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
219        //    "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
220        CHECK_NOTHROW(value.get_ref<json::number_unsigned_t&>());
221        CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
222    }
223
224    SECTION("reference access to number_float_t")
225    {
226        using test_type = json::number_float_t;
227        json value = 42.23;
228
229        // check if references are returned correctly
230        auto& p1 = value.get_ref<test_type&>();
231        CHECK(&p1 == value.get_ptr<test_type*>());
232        CHECK(p1 == value.get<test_type>());
233
234        const auto& p2 = value.get_ref<const test_type&>();
235        CHECK(&p2 == value.get_ptr<const test_type*>());
236        CHECK(p2 == value.get<test_type>());
237
238        // check if mismatching references throw correctly
239        CHECK_THROWS_WITH_AS(value.get_ref<json::object_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
240        CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
241        CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
242        CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
243        CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
244        CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
245        CHECK_NOTHROW(value.get_ref<json::number_float_t&>());
246    }
247}
248