Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Config.ut.cpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#include "Config.hpp"
18
19#include <boost/test/unit_test.hpp>
20
21#include <map>
22#include <stdexcept>
23
24using namespace std;
25using namespace toolbox;
26
28
30{
31 const string text{R"(
32# comment
33 # indented comment
34ab
35cd=
36ef=gh
37=ij
38
39kl = mn
40 op = qr
41st = = uv =
42
43)"};
44
45 istringstream is{text};
47 parse_section(is, [&conf](const auto& key, const auto& val) { conf.emplace(key, val); });
48 BOOST_CHECK_EQUAL(conf.size(), 7U);
49 BOOST_CHECK_EQUAL(conf["ab"], "");
50 BOOST_CHECK_EQUAL(conf["cd"], "");
51 BOOST_CHECK_EQUAL(conf["ef"], "gh");
52 BOOST_CHECK_EQUAL(conf[""], "ij");
53 BOOST_CHECK_EQUAL(conf["kl"], "mn");
54 BOOST_CHECK_EQUAL(conf["op"], "qr");
55 BOOST_CHECK_EQUAL(conf["st"], "= uv =");
56 BOOST_CHECK(is.eof());
57}
58
60{
61 const string text{R"(
62# comment
63 # indented comment
64ab
65cd=
66
67[foo]
68ef=gh
69=ij
70
71 [ bar ]
72kl = mn
73 op = qr
74st = = uv =
75
76)"};
77
78 istringstream is{text};
81 string next;
82 parse_section(is, [&conf](const auto& key, const auto& val) { conf.emplace(key, val); }, &next);
83 BOOST_CHECK_EQUAL(conf.size(), 2U);
84 BOOST_CHECK_EQUAL(conf["ab"], "");
85 BOOST_CHECK_EQUAL(conf["cd"], "");
86 BOOST_CHECK_EQUAL(next, "foo");
87 BOOST_CHECK(!is.fail());
88
89 conf.clear();
90 parse_section(is, [&conf](const auto& key, const auto& val) { conf.emplace(key, val); }, &next);
91 BOOST_CHECK_EQUAL(conf.size(), 2U);
92 BOOST_CHECK_EQUAL(conf["ef"], "gh");
93 BOOST_CHECK_EQUAL(conf[""], "ij");
94 BOOST_CHECK_EQUAL(next, "bar");
95 BOOST_CHECK(!is.fail());
96
97 conf.clear();
98 parse_section(is, [&conf](const auto& key, const auto& val) { conf.emplace(key, val); }, &next);
100 BOOST_CHECK_EQUAL(conf["kl"], "mn");
101 BOOST_CHECK_EQUAL(conf["op"], "qr");
102 BOOST_CHECK_EQUAL(conf["st"], "= uv =");
103 BOOST_CHECK(next.empty());
104 BOOST_CHECK(is.eof());
105}
106
108{
110
111 BOOST_CHECK_EQUAL(config.get<int>("foo", 101), 101);
112 BOOST_CHECK_EQUAL(config.get<int>("bar", 202), 202);
113
114 config.set("foo", "101");
115 config.set("bar", "202");
116
117 BOOST_CHECK_EQUAL(config.get<int>("foo", 0), 101);
118 BOOST_CHECK_EQUAL(config.get<int>("bar", 0), 202);
119
120 config.set("foo", "303");
121
122 BOOST_CHECK_EQUAL(config.get<int>("foo", 0), 303);
123 BOOST_CHECK_EQUAL(config.get<int>("bar", 0), 202);
124}
125
127{
128 const string text{R"(
129foo=101
130bar=202
131
132[session]
133
134bar=303
135baz=404
136)"};
137
138 istringstream is{text};
139 string next;
140
142 parent.read_section(is, next);
143
144 BOOST_CHECK_EQUAL(parent.size(), 2U);
145 BOOST_CHECK_EQUAL(parent.get<int>("foo", 0), 101);
146 BOOST_CHECK_EQUAL(parent.get<int>("bar", 0), 202);
147 BOOST_CHECK_EQUAL(next, "session");
148 BOOST_CHECK(!is.fail());
150 // Verify that getter with nullptr default compiles.
151 BOOST_CHECK(parent.get("foo", nullptr));
152
153 // Conversion from internal std::string to std::string_view is a special case.
154 BOOST_CHECK_EQUAL(parent.get<string_view>("foo"), "101"sv);
155
157 child.read_section(is, next);
158 child.set_parent(parent);
159
160 BOOST_CHECK_EQUAL(child.size(), 2U);
161 BOOST_CHECK_EQUAL(child.get<int>("foo", 0), 101);
162 BOOST_CHECK_EQUAL(child.get<int>("bar", 0), 303);
163 BOOST_CHECK_EQUAL(child.get<int>("baz", 0), 404);
164 BOOST_CHECK(next.empty());
165 BOOST_CHECK(is.eof());
167 BOOST_CHECK_THROW(child.get("bad"), runtime_error);
168 BOOST_CHECK_THROW(child.get<int>("bad"), runtime_error);
169}
170
172{
173 const string text{R"(
174foo=\a\b\c
175)"};
176
177 istringstream is{text};
178
181
182 BOOST_CHECK_EQUAL(config.size(), 1U);
183 BOOST_CHECK_EQUAL(config.get("foo"), "abc");
184}
185
187{
188 const string text{R"(
189foo = test=++=test
190foo + = test=++=test
191baz1
192baz2=
193baz3 +=
194)"};
195
196 istringstream is{text};
197
201 BOOST_CHECK_EQUAL(config.size(), 5U);
202 BOOST_CHECK_EQUAL(config.get("foo"), "test=++=test");
203 BOOST_CHECK_EQUAL(config.get("foo +"), "test=++=test");
204 BOOST_CHECK_EQUAL(config.get("baz1"), "");
205 BOOST_CHECK_EQUAL(config.get("baz2"), "");
206 BOOST_CHECK_EQUAL(config.get("baz3"), "");
207}
208
210{
211 const string text{R"(
212foo += test=++=test
213foo +==abcd
214)"};
215
216 istringstream is{text};
217
220
222
223 auto rng = config.get_multi("foo");
224 BOOST_CHECK_EQUAL(rng.size(), 2);
225
226 auto it = rng.begin();
227 BOOST_CHECK_EQUAL(*it++, "test=++=test");
228 BOOST_CHECK_EQUAL(*it++, "=abcd");
229 BOOST_CHECK_EQUAL(it == rng.end(), true);
230}
231
233{
234 const string text{R"(
235foo=101
236foo=202
237)"};
238
239 istringstream is{text};
240
243
244 BOOST_CHECK_EQUAL(config.size(), 2U);
245 BOOST_CHECK_EQUAL(config.get("foo"), "202");
246 BOOST_CHECK_EQUAL(config.get<int>("foo"), 202);
247}
248
250{
251 const string text{R"(
252foo+=101
253foo+=202
254)"};
255
256 istringstream is{text};
257
260
261 BOOST_CHECK_EQUAL(config.size(), 2U);
262 BOOST_CHECK_EQUAL(config.get("foo"), "202");
264 auto rng = config.get_multi("foo");
265 BOOST_CHECK_EQUAL(rng.size(), 2);
266
267 auto it = rng.begin();
268 BOOST_CHECK_EQUAL(*it++, "101");
269 BOOST_CHECK_EQUAL(*it++, "202");
270 BOOST_CHECK_EQUAL(it == rng.end(), true);
271}
272
274{
275 const string text{R"(
276foo+=101
277foo+=202
278)"};
279
280 istringstream is{text};
281
284
285 BOOST_CHECK_EQUAL(config.size(), 2U);
286 BOOST_CHECK_EQUAL(config.get<int>("foo"), 202);
287
288 auto rng = config.get_multi<int>("foo");
289 BOOST_CHECK_EQUAL(rng.size(), 2);
290
291 auto it = rng.begin();
292 BOOST_CHECK_EQUAL(*it++, 101);
294 BOOST_CHECK_EQUAL(it == rng.end(), true);
295}
296
298{
299 const string text{R"(
300foo+=101
301foo+=202
302)"};
303
304 istringstream is{text};
305
308
310 BOOST_CHECK_EQUAL(config.get<string_view>("foo"), "202"sv);
311
312 auto rng = config.get_multi<string_view>("foo");
313 BOOST_CHECK_EQUAL(rng.size(), 2);
314
315 auto it = rng.begin();
316 BOOST_CHECK_EQUAL(*it++, "101"sv);
317 BOOST_CHECK_EQUAL(*it++, "202"sv);
318 BOOST_CHECK_EQUAL(it == rng.end(), true);
319}
320
322{
323 const string text{R"(
324foo=101
325foo=202
326)"};
327
328 istringstream is{text};
329
331 BOOST_CHECK_NO_THROW(config.read_section(is));
332}
333
335{
336 const string text{R"(
337foo=101
338foo+=202
339)"};
340
341 istringstream is{text};
342
344 BOOST_CHECK_THROW(config.read_section(is), runtime_error);
345}
346
348{
349 const string text{R"(
350foo+=101
351foo=202
352)"};
353
354 istringstream is{text};
355
357 BOOST_CHECK_THROW(config.read_section(is), runtime_error);
358}
359
361{
362 const string text{R"()"};
363 istringstream is{text};
364
367
368 BOOST_CHECK_EQUAL(config.size(), 0U);
369
370 auto rng = config.get_multi<string_view>("foo");
371 BOOST_CHECK_EQUAL(rng.empty(), true);
372 BOOST_CHECK_EQUAL(rng.size(), 0U);
373 BOOST_CHECK_EQUAL(rng.begin() == rng.end(), true);
374}
375
377{
378 const string text{R"(
379foo=101
380)"};
381
382 istringstream is{text};
383
386
387 BOOST_CHECK_EQUAL(config.size(), 1U);
388
389 auto rng = config.get_multi<string_view>("foo");
390 BOOST_CHECK_EQUAL(rng.size(), 1);
391
392 BOOST_CHECK_EQUAL(*rng.begin(), "101"sv);
393}
394
396{
397 const string text{R"(
398foo=101
399)"};
400
401 istringstream is{text};
402
405
406 BOOST_CHECK_EQUAL(config.size(), 1U);
407 BOOST_CHECK_EQUAL(config.get<int>("foo"), 101);
408
409 config.insert("bar", "202");
410 config.insert("foo", "102");
411
412 BOOST_CHECK_EQUAL(config.get("bar"), "202");
413 BOOST_CHECK_EQUAL(config.get<int>("bar"), 202);
414 BOOST_CHECK_EQUAL(config.get<int>("foo"), 102);
415
416 auto foo_rng = config.get_multi<int>("foo");
417 BOOST_CHECK_EQUAL(foo_rng.size(), 2);
418
419 auto foo_it = foo_rng.begin();
420 BOOST_CHECK_EQUAL(*foo_it++, 101);
421 BOOST_CHECK_EQUAL(*foo_it++, 102);
422 BOOST_CHECK_EQUAL(foo_it == foo_rng.end(), true);
423}
424
426{
427 const string text{R"(
428foo=101
429)"};
430
431 istringstream is{text};
432
435
436 BOOST_CHECK_EQUAL(config.size(), 1U);
437 BOOST_CHECK_EQUAL(config.get<int>("foo"), 101);
438
439 config.set("bar", "100");
440 config.set("foo", "111", "222", "333", "444");
441
442 BOOST_CHECK_EQUAL(config.get("bar"), "100");
443 BOOST_CHECK_EQUAL(config.get<int>("bar"), 100);
444 BOOST_CHECK_EQUAL(config.get<int>("foo"), 444);
445
446 auto foo_rng = config.get_multi<int>("foo");
447 BOOST_CHECK_EQUAL(foo_rng.size(), 4);
448
449 auto foo_it = foo_rng.begin();
450 BOOST_CHECK_EQUAL(*foo_it++, 111);
451 BOOST_CHECK_EQUAL(*foo_it++, 222);
452 BOOST_CHECK_EQUAL(*foo_it++, 333);
453 BOOST_CHECK_EQUAL(*foo_it++, 444);
454 BOOST_CHECK_EQUAL(foo_it == foo_rng.end(), true);
455}
456
458{
459 const string text{R"(
460[First]
461key_abc=value_abc
462
463[Second]
464key_xyz=value_xyz
465)"};
466
467 std::map<std::string, util::Config> sections;
468
470 istringstream is{text};
471 c.read(is);
472 c.for_each_section([&sections](const std::string& name, const util::Config& config) {
473 sections.emplace(name, config);
474 });
475 auto first{sections.find("First")};
476 auto second{sections.find("Second")};
477 if (first == sections.end()) {
478 BOOST_FAIL("Missing section 'First'");
479 }
480 if (second == sections.end()) {
481 BOOST_FAIL("Missing section 'Second'");
482 }
483 BOOST_CHECK_EQUAL(first->second.get<std::string_view>("key_abc"), "value_abc"sv);
484 BOOST_CHECK_EQUAL(second->second.get<std::string_view>("key_xyz"), "value_xyz"sv);
485}
486
BOOST_AUTO_TEST_CASE(ParseSectionSingleCase)
Definition Config.ut.cpp:29
BOOST_CHECK_EQUAL(v.size(), 10U)
Simple config reader with environment variable substitution.
Definition Config.hpp:102
std::istream & read_section(std::istream &is)
Definition Config.hpp:167
void read(std::istream &is)
Definition Config.cpp:81
STL namespace.
std::istream & parse_section(std::istream &is, FnT fn, std::string *name=nullptr)
Definition Config.hpp:35
std::string_view sv
Definition Tokeniser.hpp:26
constexpr auto bind() noexcept
Definition Slot.hpp:97
BOOST_CHECK(isnan(stod(""sv, numeric_limits< double >::quiet_NaN())))