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>
12 using nlohmann::json;
13 
14 TEST_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