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::ordered_map;
13
14
15TEST_CASE("ordered_map")
16{
17    SECTION("constructor")
18    {
19        SECTION("constructor from iterator range")
20        {
21            std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
22            ordered_map<std::string, std::string> om(m.begin(), m.end());
23            CHECK(om.size() == 3);
24        }
25
26        SECTION("copy assignment")
27        {
28            std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
29            ordered_map<std::string, std::string> om(m.begin(), m.end());
30            const auto com = om;
31            om.clear(); // silence a warning by forbidding having "const auto& com = om;"
32            CHECK(com.size() == 3);
33        }
34    }
35
36    SECTION("at")
37    {
38        std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
39        ordered_map<std::string, std::string> om(m.begin(), m.end());
40        const auto com = om;
41
42        SECTION("with Key&&")
43        {
44            CHECK(om.at(std::string("eins")) == std::string("one"));
45            CHECK(com.at(std::string("eins")) == std::string("one"));
46            CHECK_THROWS_AS(om.at(std::string("vier")), std::out_of_range);
47            CHECK_THROWS_AS(com.at(std::string("vier")), std::out_of_range);
48        }
49
50        SECTION("with const Key&&")
51        {
52            const std::string eins = "eins";
53            const std::string vier = "vier";
54            CHECK(om.at(eins) == std::string("one"));
55            CHECK(com.at(eins) == std::string("one"));
56            CHECK_THROWS_AS(om.at(vier), std::out_of_range);
57            CHECK_THROWS_AS(com.at(vier), std::out_of_range);
58        }
59
60        SECTION("with string literal")
61        {
62            CHECK(om.at("eins") == std::string("one"));
63            CHECK(com.at("eins") == std::string("one"));
64            CHECK_THROWS_AS(om.at("vier"), std::out_of_range);
65            CHECK_THROWS_AS(com.at("vier"), std::out_of_range);
66        }
67    }
68
69    SECTION("operator[]")
70    {
71        std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
72        ordered_map<std::string, std::string> om(m.begin(), m.end());
73        const auto com = om;
74
75        SECTION("with Key&&")
76        {
77            CHECK(om[std::string("eins")] == std::string("one"));
78            CHECK(com[std::string("eins")] == std::string("one"));
79
80            CHECK(om[std::string("vier")] == std::string(""));
81            CHECK(om.size() == 4);
82        }
83
84        SECTION("with const Key&&")
85        {
86            const std::string eins = "eins";
87            const std::string vier = "vier";
88
89            CHECK(om[eins] == std::string("one"));
90            CHECK(com[eins] == std::string("one"));
91
92            CHECK(om[vier] == std::string(""));
93            CHECK(om.size() == 4);
94        }
95
96        SECTION("with string literal")
97        {
98            CHECK(om["eins"] == std::string("one"));
99            CHECK(com["eins"] == std::string("one"));
100
101            CHECK(om["vier"] == std::string(""));
102            CHECK(om.size() == 4);
103        }
104    }
105
106    SECTION("erase")
107    {
108        ordered_map<std::string, std::string> om;
109        om["eins"] = "one";
110        om["zwei"] = "two";
111        om["drei"] = "three";
112
113        {
114            auto it = om.begin();
115            CHECK(it->first == "eins");
116            ++it;
117            CHECK(it->first == "zwei");
118            ++it;
119            CHECK(it->first == "drei");
120            ++it;
121            CHECK(it == om.end());
122        }
123
124        SECTION("with Key&&")
125        {
126            CHECK(om.size() == 3);
127            CHECK(om.erase(std::string("eins")) == 1);
128            CHECK(om.size() == 2);
129            CHECK(om.erase(std::string("vier")) == 0);
130            CHECK(om.size() == 2);
131
132            auto it = om.begin();
133            CHECK(it->first == "zwei");
134            ++it;
135            CHECK(it->first == "drei");
136            ++it;
137            CHECK(it == om.end());
138        }
139
140        SECTION("with const Key&&")
141        {
142            const std::string eins = "eins";
143            const std::string vier = "vier";
144            CHECK(om.size() == 3);
145            CHECK(om.erase(eins) == 1);
146            CHECK(om.size() == 2);
147            CHECK(om.erase(vier) == 0);
148            CHECK(om.size() == 2);
149
150            auto it = om.begin();
151            CHECK(it->first == "zwei");
152            ++it;
153            CHECK(it->first == "drei");
154            ++it;
155            CHECK(it == om.end());
156        }
157
158        SECTION("with string literal")
159        {
160            CHECK(om.size() == 3);
161            CHECK(om.erase("eins") == 1);
162            CHECK(om.size() == 2);
163            CHECK(om.erase("vier") == 0);
164            CHECK(om.size() == 2);
165
166            auto it = om.begin();
167            CHECK(it->first == "zwei");
168            ++it;
169            CHECK(it->first == "drei");
170            ++it;
171            CHECK(it == om.end());
172        }
173
174        SECTION("with iterator")
175        {
176            CHECK(om.size() == 3);
177            CHECK(om.begin()->first == "eins");
178            CHECK(std::next(om.begin(), 1)->first == "zwei");
179            CHECK(std::next(om.begin(), 2)->first == "drei");
180
181            auto it = om.erase(om.begin());
182            CHECK(it->first == "zwei");
183            CHECK(om.size() == 2);
184
185            auto it2 = om.begin();
186            CHECK(it2->first == "zwei");
187            ++it2;
188            CHECK(it2->first == "drei");
189            ++it2;
190            CHECK(it2 == om.end());
191        }
192
193        SECTION("with iterator pair")
194        {
195            SECTION("range in the middle")
196            {
197                // need more elements
198                om["vier"] = "four";
199                om["fünf"] = "five";
200
201                // delete "zwei" and "drei"
202                auto it = om.erase(om.begin() + 1, om.begin() + 3);
203                CHECK(it->first == "vier");
204                CHECK(om.size() == 3);
205            }
206
207            SECTION("range at the beginning")
208            {
209                // need more elements
210                om["vier"] = "four";
211                om["fünf"] = "five";
212
213                // delete "eins" and "zwei"
214                auto it = om.erase(om.begin(), om.begin() + 2);
215                CHECK(it->first == "drei");
216                CHECK(om.size() == 3);
217            }
218
219            SECTION("range at the end")
220            {
221                // need more elements
222                om["vier"] = "four";
223                om["fünf"] = "five";
224
225                // delete "vier" and "fünf"
226                auto it = om.erase(om.begin() + 3, om.end());
227                CHECK(it == om.end());
228                CHECK(om.size() == 3);
229            }
230        }
231    }
232
233    SECTION("count")
234    {
235        ordered_map<std::string, std::string> om;
236        om["eins"] = "one";
237        om["zwei"] = "two";
238        om["drei"] = "three";
239
240        const std::string eins("eins");
241        const std::string vier("vier");
242        CHECK(om.count("eins") == 1);
243        CHECK(om.count(std::string("eins")) == 1);
244        CHECK(om.count(eins) == 1);
245        CHECK(om.count("vier") == 0);
246        CHECK(om.count(std::string("vier")) == 0);
247        CHECK(om.count(vier) == 0);
248    }
249
250    SECTION("find")
251    {
252        ordered_map<std::string, std::string> om;
253        om["eins"] = "one";
254        om["zwei"] = "two";
255        om["drei"] = "three";
256        const auto com = om;
257
258        const std::string eins("eins");
259        const std::string vier("vier");
260        CHECK(om.find("eins") == om.begin());
261        CHECK(om.find(std::string("eins")) == om.begin());
262        CHECK(om.find(eins) == om.begin());
263        CHECK(om.find("vier") == om.end());
264        CHECK(om.find(std::string("vier")) == om.end());
265        CHECK(om.find(vier) == om.end());
266
267        CHECK(com.find("eins") == com.begin());
268        CHECK(com.find(std::string("eins")) == com.begin());
269        CHECK(com.find(eins) == com.begin());
270        CHECK(com.find("vier") == com.end());
271        CHECK(com.find(std::string("vier")) == com.end());
272        CHECK(com.find(vier) == com.end());
273    }
274
275    SECTION("insert")
276    {
277        ordered_map<std::string, std::string> om;
278        om["eins"] = "one";
279        om["zwei"] = "two";
280        om["drei"] = "three";
281
282        SECTION("const value_type&")
283        {
284            ordered_map<std::string, std::string>::value_type vt1 {"eins", "1"};
285            ordered_map<std::string, std::string>::value_type vt4 {"vier", "four"};
286
287            auto res1 = om.insert(vt1);
288            CHECK(res1.first == om.begin());
289            CHECK(res1.second == false);
290            CHECK(om.size() == 3);
291
292            auto res4 = om.insert(vt4);
293            CHECK(res4.first == om.begin() + 3);
294            CHECK(res4.second == true);
295            CHECK(om.size() == 4);
296        }
297
298        SECTION("value_type&&")
299        {
300            auto res1 = om.insert({"eins", "1"});
301            CHECK(res1.first == om.begin());
302            CHECK(res1.second == false);
303            CHECK(om.size() == 3);
304
305            auto res4 = om.insert({"vier", "four"});
306            CHECK(res4.first == om.begin() + 3);
307            CHECK(res4.second == true);
308            CHECK(om.size() == 4);
309        }
310    }
311}
312