1 // Copyright 2012 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "utils/config/tree.ipp"
30
31 #include <atf-c++.hpp>
32
33 #include "utils/config/nodes.ipp"
34 #include "utils/format/macros.hpp"
35 #include "utils/text/operations.ipp"
36
37 namespace config = utils::config;
38 namespace text = utils::text;
39
40
41 namespace {
42
43
44 /// Simple wrapper around an integer value without default constructors.
45 ///
46 /// The purpose of this type is to have a simple class without default
47 /// constructors to validate that we can use it as a leaf of a tree.
48 class int_wrapper {
49 /// The wrapped integer value.
50 int _value;
51
52 public:
53 /// Constructs a new wrapped integer.
54 ///
55 /// \param value_ The value to store in the object.
int_wrapper(int value_)56 explicit int_wrapper(int value_) :
57 _value(value_)
58 {
59 }
60
61 /// \return The integer value stored by the object.
62 int
value(void) const63 value(void) const
64 {
65 return _value;
66 }
67 };
68
69
70 /// Custom tree leaf type for an object without defualt constructors.
71 class wrapped_int_node : public config::typed_leaf_node< int_wrapper > {
72 public:
73 /// Copies the node.
74 ///
75 /// \return A dynamically-allocated node.
76 virtual base_node*
deep_copy(void) const77 deep_copy(void) const
78 {
79 std::auto_ptr< wrapped_int_node > new_node(new wrapped_int_node());
80 new_node->_value = _value;
81 return new_node.release();
82 }
83
84 /// Pushes the node's value onto the Lua stack.
85 ///
86 /// \param state The Lua state onto which to push the value.
87 void
push_lua(lutok::state & state) const88 push_lua(lutok::state& state) const
89 {
90 state.push_integer(
91 config::typed_leaf_node< int_wrapper >::value().value());
92 }
93
94 /// Sets the value of the node from an entry in the Lua stack.
95 ///
96 /// \param state The Lua state from which to get the value.
97 /// \param value_index The stack index in which the value resides.
98 void
set_lua(lutok::state & state,const int value_index)99 set_lua(lutok::state& state, const int value_index)
100 {
101 ATF_REQUIRE(state.is_number(value_index));
102 int_wrapper new_value(state.to_integer(value_index));
103 config::typed_leaf_node< int_wrapper >::set(new_value);
104 }
105
106 /// Sets the value of the node from a raw string representation.
107 ///
108 /// \param raw_value The value to set the node to.
109 void
set_string(const std::string & raw_value)110 set_string(const std::string& raw_value)
111 {
112 int_wrapper new_value(text::to_type< int >(raw_value));
113 config::typed_leaf_node< int_wrapper >::set(new_value);
114 }
115
116 /// Converts the contents of the node to a string.
117 ///
118 /// \return A string representation of the value held by the node.
119 std::string
to_string(void) const120 to_string(void) const
121 {
122 return F("%s") %
123 config::typed_leaf_node< int_wrapper >::value().value();
124 }
125 };
126
127
128 } // anonymous namespace
129
130
131 ATF_TEST_CASE_WITHOUT_HEAD(define_set_lookup__one_level);
ATF_TEST_CASE_BODY(define_set_lookup__one_level)132 ATF_TEST_CASE_BODY(define_set_lookup__one_level)
133 {
134 config::tree tree;
135
136 tree.define< config::int_node >("var1");
137 tree.define< config::string_node >("var2");
138 tree.define< config::bool_node >("var3");
139
140 tree.set< config::int_node >("var1", 42);
141 tree.set< config::string_node >("var2", "hello");
142 tree.set< config::bool_node >("var3", false);
143
144 ATF_REQUIRE_EQ(42, tree.lookup< config::int_node >("var1"));
145 ATF_REQUIRE_EQ("hello", tree.lookup< config::string_node >("var2"));
146 ATF_REQUIRE(!tree.lookup< config::bool_node >("var3"));
147 }
148
149
150 ATF_TEST_CASE_WITHOUT_HEAD(define_set_lookup__multiple_levels);
ATF_TEST_CASE_BODY(define_set_lookup__multiple_levels)151 ATF_TEST_CASE_BODY(define_set_lookup__multiple_levels)
152 {
153 config::tree tree;
154
155 tree.define< config::int_node >("foo.bar.1");
156 tree.define< config::string_node >("foo.bar.2");
157 tree.define< config::bool_node >("foo.3");
158 tree.define_dynamic("sub.tree");
159
160 tree.set< config::int_node >("foo.bar.1", 42);
161 tree.set< config::string_node >("foo.bar.2", "hello");
162 tree.set< config::bool_node >("foo.3", true);
163 tree.set< config::string_node >("sub.tree.1", "bye");
164 tree.set< config::int_node >("sub.tree.2", 4);
165 tree.set< config::int_node >("sub.tree.3.4", 123);
166
167 ATF_REQUIRE_EQ(42, tree.lookup< config::int_node >("foo.bar.1"));
168 ATF_REQUIRE_EQ("hello", tree.lookup< config::string_node >("foo.bar.2"));
169 ATF_REQUIRE(tree.lookup< config::bool_node >("foo.3"));
170 ATF_REQUIRE_EQ(4, tree.lookup< config::int_node >("sub.tree.2"));
171 ATF_REQUIRE_EQ(123, tree.lookup< config::int_node >("sub.tree.3.4"));
172 }
173
174
175 ATF_TEST_CASE_WITHOUT_HEAD(deep_copy__empty);
ATF_TEST_CASE_BODY(deep_copy__empty)176 ATF_TEST_CASE_BODY(deep_copy__empty)
177 {
178 config::tree tree1;
179 config::tree tree2 = tree1.deep_copy();
180
181 tree1.define< config::bool_node >("var1");
182 // This would crash if the copy shared the internal data.
183 tree2.define< config::int_node >("var1");
184 }
185
186
187 ATF_TEST_CASE_WITHOUT_HEAD(deep_copy__some);
ATF_TEST_CASE_BODY(deep_copy__some)188 ATF_TEST_CASE_BODY(deep_copy__some)
189 {
190 config::tree tree1;
191 tree1.define< config::bool_node >("this.is.a.var");
192 tree1.set< config::bool_node >("this.is.a.var", true);
193 tree1.define< config::int_node >("this.is.another.var");
194 tree1.set< config::int_node >("this.is.another.var", 34);
195 tree1.define< config::int_node >("and.another");
196 tree1.set< config::int_node >("and.another", 123);
197
198 config::tree tree2 = tree1.deep_copy();
199 tree2.set< config::bool_node >("this.is.a.var", false);
200 tree2.set< config::int_node >("this.is.another.var", 43);
201
202 ATF_REQUIRE( tree1.lookup< config::bool_node >("this.is.a.var"));
203 ATF_REQUIRE(!tree2.lookup< config::bool_node >("this.is.a.var"));
204
205 ATF_REQUIRE_EQ(34, tree1.lookup< config::int_node >("this.is.another.var"));
206 ATF_REQUIRE_EQ(43, tree2.lookup< config::int_node >("this.is.another.var"));
207
208 ATF_REQUIRE_EQ(123, tree1.lookup< config::int_node >("and.another"));
209 ATF_REQUIRE_EQ(123, tree2.lookup< config::int_node >("and.another"));
210 }
211
212
213 ATF_TEST_CASE_WITHOUT_HEAD(combine__empty);
ATF_TEST_CASE_BODY(combine__empty)214 ATF_TEST_CASE_BODY(combine__empty)
215 {
216 const config::tree t1, t2;
217 const config::tree combined = t1.combine(t2);
218
219 const config::tree expected;
220 ATF_REQUIRE(expected == combined);
221 }
222
223
224 static void
init_tree_for_combine_test(config::tree & tree)225 init_tree_for_combine_test(config::tree& tree)
226 {
227 tree.define< config::int_node >("int-node");
228 tree.define< config::string_node >("string-node");
229 tree.define< config::int_node >("unused.node");
230 tree.define< config::int_node >("deeper.int.node");
231 tree.define_dynamic("deeper.dynamic");
232 }
233
234
235 ATF_TEST_CASE_WITHOUT_HEAD(combine__same_layout__no_overrides);
ATF_TEST_CASE_BODY(combine__same_layout__no_overrides)236 ATF_TEST_CASE_BODY(combine__same_layout__no_overrides)
237 {
238 config::tree t1, t2;
239 init_tree_for_combine_test(t1);
240 init_tree_for_combine_test(t2);
241 t1.set< config::int_node >("int-node", 3);
242 t1.set< config::string_node >("string-node", "foo");
243 t1.set< config::int_node >("deeper.int.node", 15);
244 t1.set_string("deeper.dynamic.first", "value1");
245 t1.set_string("deeper.dynamic.second", "value2");
246 const config::tree combined = t1.combine(t2);
247
248 ATF_REQUIRE(t1 == combined);
249 }
250
251
252 ATF_TEST_CASE_WITHOUT_HEAD(combine__same_layout__no_base);
ATF_TEST_CASE_BODY(combine__same_layout__no_base)253 ATF_TEST_CASE_BODY(combine__same_layout__no_base)
254 {
255 config::tree t1, t2;
256 init_tree_for_combine_test(t1);
257 init_tree_for_combine_test(t2);
258 t2.set< config::int_node >("int-node", 3);
259 t2.set< config::string_node >("string-node", "foo");
260 t2.set< config::int_node >("deeper.int.node", 15);
261 t2.set_string("deeper.dynamic.first", "value1");
262 t2.set_string("deeper.dynamic.second", "value2");
263 const config::tree combined = t1.combine(t2);
264
265 ATF_REQUIRE(t2 == combined);
266 }
267
268
269 ATF_TEST_CASE_WITHOUT_HEAD(combine__same_layout__mix);
ATF_TEST_CASE_BODY(combine__same_layout__mix)270 ATF_TEST_CASE_BODY(combine__same_layout__mix)
271 {
272 config::tree t1, t2;
273 init_tree_for_combine_test(t1);
274 init_tree_for_combine_test(t2);
275 t1.set< config::int_node >("int-node", 3);
276 t2.set< config::int_node >("int-node", 5);
277 t1.set< config::string_node >("string-node", "foo");
278 t2.set< config::int_node >("deeper.int.node", 15);
279 t1.set_string("deeper.dynamic.first", "value1");
280 t1.set_string("deeper.dynamic.second", "value2.1");
281 t2.set_string("deeper.dynamic.second", "value2.2");
282 t2.set_string("deeper.dynamic.third", "value3");
283 const config::tree combined = t1.combine(t2);
284
285 config::tree expected;
286 init_tree_for_combine_test(expected);
287 expected.set< config::int_node >("int-node", 5);
288 expected.set< config::string_node >("string-node", "foo");
289 expected.set< config::int_node >("deeper.int.node", 15);
290 expected.set_string("deeper.dynamic.first", "value1");
291 expected.set_string("deeper.dynamic.second", "value2.2");
292 expected.set_string("deeper.dynamic.third", "value3");
293 ATF_REQUIRE(expected == combined);
294 }
295
296
297 ATF_TEST_CASE_WITHOUT_HEAD(combine__different_layout);
ATF_TEST_CASE_BODY(combine__different_layout)298 ATF_TEST_CASE_BODY(combine__different_layout)
299 {
300 config::tree t1;
301 t1.define< config::int_node >("common.base1");
302 t1.define< config::int_node >("common.base2");
303 t1.define_dynamic("dynamic.base");
304 t1.define< config::int_node >("unset.base");
305
306 config::tree t2;
307 t2.define< config::int_node >("common.base2");
308 t2.define< config::int_node >("common.base3");
309 t2.define_dynamic("dynamic.other");
310 t2.define< config::int_node >("unset.other");
311
312 t1.set< config::int_node >("common.base1", 1);
313 t1.set< config::int_node >("common.base2", 2);
314 t1.set_string("dynamic.base.first", "foo");
315 t1.set_string("dynamic.base.second", "bar");
316
317 t2.set< config::int_node >("common.base2", 4);
318 t2.set< config::int_node >("common.base3", 3);
319 t2.set_string("dynamic.other.first", "FOO");
320 t2.set_string("dynamic.other.second", "BAR");
321
322 config::tree combined = t1.combine(t2);
323
324 config::tree expected;
325 expected.define< config::int_node >("common.base1");
326 expected.define< config::int_node >("common.base2");
327 expected.define< config::int_node >("common.base3");
328 expected.define_dynamic("dynamic.base");
329 expected.define_dynamic("dynamic.other");
330 expected.define< config::int_node >("unset.base");
331 expected.define< config::int_node >("unset.other");
332
333 expected.set< config::int_node >("common.base1", 1);
334 expected.set< config::int_node >("common.base2", 4);
335 expected.set< config::int_node >("common.base3", 3);
336 expected.set_string("dynamic.base.first", "foo");
337 expected.set_string("dynamic.base.second", "bar");
338 expected.set_string("dynamic.other.first", "FOO");
339 expected.set_string("dynamic.other.second", "BAR");
340
341 ATF_REQUIRE(expected == combined);
342
343 // The combined tree should have respected existing but unset nodes. Check
344 // that these calls do not crash.
345 combined.set< config::int_node >("unset.base", 5);
346 combined.set< config::int_node >("unset.other", 5);
347 }
348
349
350 ATF_TEST_CASE_WITHOUT_HEAD(combine__dynamic_wins);
ATF_TEST_CASE_BODY(combine__dynamic_wins)351 ATF_TEST_CASE_BODY(combine__dynamic_wins)
352 {
353 config::tree t1;
354 t1.define< config::int_node >("inner.leaf1");
355 t1.set< config::int_node >("inner.leaf1", 3);
356
357 config::tree t2;
358 t2.define_dynamic("inner");
359 t2.set_string("inner.leaf2", "4");
360
361 config::tree combined = t1.combine(t2);
362
363 config::tree expected;
364 expected.define_dynamic("inner");
365 expected.set_string("inner.leaf1", "3");
366 expected.set_string("inner.leaf2", "4");
367
368 ATF_REQUIRE(expected == combined);
369
370 // The combined inner node should have become dynamic so this call should
371 // not fail.
372 combined.set_string("inner.leaf3", "5");
373 }
374
375
376 ATF_TEST_CASE_WITHOUT_HEAD(combine__inner_leaf_mismatch);
ATF_TEST_CASE_BODY(combine__inner_leaf_mismatch)377 ATF_TEST_CASE_BODY(combine__inner_leaf_mismatch)
378 {
379 config::tree t1;
380 t1.define< config::int_node >("top.foo.bar");
381
382 config::tree t2;
383 t2.define< config::int_node >("top.foo");
384
385 ATF_REQUIRE_THROW_RE(config::bad_combination_error,
386 "'top.foo' is an inner node in the base tree but a "
387 "leaf node in the overrides tree",
388 t1.combine(t2));
389
390 ATF_REQUIRE_THROW_RE(config::bad_combination_error,
391 "'top.foo' is a leaf node in the base tree but an "
392 "inner node in the overrides tree",
393 t2.combine(t1));
394 }
395
396
397 ATF_TEST_CASE_WITHOUT_HEAD(lookup__invalid_key);
ATF_TEST_CASE_BODY(lookup__invalid_key)398 ATF_TEST_CASE_BODY(lookup__invalid_key)
399 {
400 config::tree tree;
401
402 ATF_REQUIRE_THROW(config::invalid_key_error,
403 tree.lookup< config::int_node >("."));
404 }
405
406
407 ATF_TEST_CASE_WITHOUT_HEAD(lookup__unknown_key);
ATF_TEST_CASE_BODY(lookup__unknown_key)408 ATF_TEST_CASE_BODY(lookup__unknown_key)
409 {
410 config::tree tree;
411
412 tree.define< config::int_node >("foo.bar");
413 tree.define< config::int_node >("a.b.c");
414 tree.define_dynamic("a.d");
415 tree.set< config::int_node >("a.b.c", 123);
416 tree.set< config::int_node >("a.d.100", 0);
417
418 ATF_REQUIRE_THROW(config::unknown_key_error,
419 tree.lookup< config::int_node >("abc"));
420
421 ATF_REQUIRE_THROW(config::unknown_key_error,
422 tree.lookup< config::int_node >("foo"));
423 ATF_REQUIRE_THROW(config::unknown_key_error,
424 tree.lookup< config::int_node >("foo.bar"));
425 ATF_REQUIRE_THROW(config::unknown_key_error,
426 tree.lookup< config::int_node >("foo.bar.baz"));
427
428 ATF_REQUIRE_THROW(config::unknown_key_error,
429 tree.lookup< config::int_node >("a"));
430 ATF_REQUIRE_THROW(config::unknown_key_error,
431 tree.lookup< config::int_node >("a.b"));
432 ATF_REQUIRE_THROW(config::unknown_key_error,
433 tree.lookup< config::int_node >("a.c"));
434 (void)tree.lookup< config::int_node >("a.b.c");
435 ATF_REQUIRE_THROW(config::unknown_key_error,
436 tree.lookup< config::int_node >("a.b.c.d"));
437 ATF_REQUIRE_THROW(config::unknown_key_error,
438 tree.lookup< config::int_node >("a.d"));
439 (void)tree.lookup< config::int_node >("a.d.100");
440 ATF_REQUIRE_THROW(config::unknown_key_error,
441 tree.lookup< config::int_node >("a.d.101"));
442 ATF_REQUIRE_THROW(config::unknown_key_error,
443 tree.lookup< config::int_node >("a.d.100.3"));
444 ATF_REQUIRE_THROW(config::unknown_key_error,
445 tree.lookup< config::int_node >("a.d.e"));
446 }
447
448
449 ATF_TEST_CASE_WITHOUT_HEAD(is_set__one_level);
ATF_TEST_CASE_BODY(is_set__one_level)450 ATF_TEST_CASE_BODY(is_set__one_level)
451 {
452 config::tree tree;
453
454 tree.define< config::int_node >("var1");
455 tree.define< config::string_node >("var2");
456 tree.define< config::bool_node >("var3");
457
458 tree.set< config::int_node >("var1", 42);
459 tree.set< config::bool_node >("var3", false);
460
461 ATF_REQUIRE( tree.is_set("var1"));
462 ATF_REQUIRE(!tree.is_set("var2"));
463 ATF_REQUIRE( tree.is_set("var3"));
464 }
465
466
467 ATF_TEST_CASE_WITHOUT_HEAD(is_set__multiple_levels);
ATF_TEST_CASE_BODY(is_set__multiple_levels)468 ATF_TEST_CASE_BODY(is_set__multiple_levels)
469 {
470 config::tree tree;
471
472 tree.define< config::int_node >("a.b.var1");
473 tree.define< config::string_node >("a.b.var2");
474 tree.define< config::bool_node >("e.var3");
475
476 tree.set< config::int_node >("a.b.var1", 42);
477 tree.set< config::bool_node >("e.var3", false);
478
479 ATF_REQUIRE(!tree.is_set("a"));
480 ATF_REQUIRE(!tree.is_set("a.b"));
481 ATF_REQUIRE( tree.is_set("a.b.var1"));
482 ATF_REQUIRE(!tree.is_set("a.b.var1.trailing"));
483
484 ATF_REQUIRE(!tree.is_set("a"));
485 ATF_REQUIRE(!tree.is_set("a.b"));
486 ATF_REQUIRE(!tree.is_set("a.b.var2"));
487 ATF_REQUIRE(!tree.is_set("a.b.var2.trailing"));
488
489 ATF_REQUIRE(!tree.is_set("e"));
490 ATF_REQUIRE( tree.is_set("e.var3"));
491 ATF_REQUIRE(!tree.is_set("e.var3.trailing"));
492 }
493
494
495 ATF_TEST_CASE_WITHOUT_HEAD(is_set__invalid_key);
ATF_TEST_CASE_BODY(is_set__invalid_key)496 ATF_TEST_CASE_BODY(is_set__invalid_key)
497 {
498 config::tree tree;
499
500 ATF_REQUIRE_THROW(config::invalid_key_error, tree.is_set(".abc"));
501 }
502
503
504 ATF_TEST_CASE_WITHOUT_HEAD(set__invalid_key);
ATF_TEST_CASE_BODY(set__invalid_key)505 ATF_TEST_CASE_BODY(set__invalid_key)
506 {
507 config::tree tree;
508
509 ATF_REQUIRE_THROW(config::invalid_key_error,
510 tree.set< config::int_node >("foo.", 54));
511 }
512
513
514 ATF_TEST_CASE_WITHOUT_HEAD(set__invalid_key_value);
ATF_TEST_CASE_BODY(set__invalid_key_value)515 ATF_TEST_CASE_BODY(set__invalid_key_value)
516 {
517 config::tree tree;
518
519 tree.define< config::int_node >("foo.bar");
520 tree.define_dynamic("a.d");
521
522 ATF_REQUIRE_THROW(config::invalid_key_value,
523 tree.set< config::int_node >("foo", 3));
524 ATF_REQUIRE_THROW(config::invalid_key_value,
525 tree.set< config::int_node >("a", -10));
526 }
527
528
529 ATF_TEST_CASE_WITHOUT_HEAD(set__unknown_key);
ATF_TEST_CASE_BODY(set__unknown_key)530 ATF_TEST_CASE_BODY(set__unknown_key)
531 {
532 config::tree tree;
533
534 tree.define< config::int_node >("foo.bar");
535 tree.define< config::int_node >("a.b.c");
536 tree.define_dynamic("a.d");
537 tree.set< config::int_node >("a.b.c", 123);
538 tree.set< config::string_node >("a.d.3", "foo");
539
540 ATF_REQUIRE_THROW(config::unknown_key_error,
541 tree.set< config::int_node >("abc", 2));
542
543 tree.set< config::int_node >("foo.bar", 15);
544 ATF_REQUIRE_THROW(config::unknown_key_error,
545 tree.set< config::int_node >("foo.bar.baz", 0));
546
547 ATF_REQUIRE_THROW(config::unknown_key_error,
548 tree.set< config::int_node >("a.c", 100));
549 tree.set< config::int_node >("a.b.c", -3);
550 ATF_REQUIRE_THROW(config::unknown_key_error,
551 tree.set< config::int_node >("a.b.c.d", 82));
552 tree.set< config::string_node >("a.d.3", "bar");
553 tree.set< config::string_node >("a.d.4", "bar");
554 ATF_REQUIRE_THROW(config::unknown_key_error,
555 tree.set< config::int_node >("a.d.4.5", 82));
556 tree.set< config::int_node >("a.d.5.6", 82);
557 }
558
559
560 ATF_TEST_CASE_WITHOUT_HEAD(set__unknown_key_not_strict);
ATF_TEST_CASE_BODY(set__unknown_key_not_strict)561 ATF_TEST_CASE_BODY(set__unknown_key_not_strict)
562 {
563 config::tree tree(false);
564
565 tree.define< config::int_node >("foo.bar");
566 tree.define< config::int_node >("a.b.c");
567 tree.define_dynamic("a.d");
568 tree.set< config::int_node >("a.b.c", 123);
569 tree.set< config::string_node >("a.d.3", "foo");
570
571 tree.set< config::int_node >("abc", 2);
572 ATF_REQUIRE(!tree.is_set("abc"));
573
574 tree.set< config::int_node >("foo.bar", 15);
575 tree.set< config::int_node >("foo.bar.baz", 0);
576 ATF_REQUIRE(!tree.is_set("foo.bar.baz"));
577
578 tree.set< config::int_node >("a.c", 100);
579 ATF_REQUIRE(!tree.is_set("a.c"));
580 }
581
582
583 ATF_TEST_CASE_WITHOUT_HEAD(push_lua__ok);
ATF_TEST_CASE_BODY(push_lua__ok)584 ATF_TEST_CASE_BODY(push_lua__ok)
585 {
586 config::tree tree;
587
588 tree.define< config::int_node >("top.integer");
589 tree.define< wrapped_int_node >("top.custom");
590 tree.define_dynamic("dynamic");
591 tree.set< config::int_node >("top.integer", 5);
592 tree.set< wrapped_int_node >("top.custom", int_wrapper(10));
593 tree.set_string("dynamic.first", "foo");
594
595 lutok::state state;
596 tree.push_lua("top.integer", state);
597 tree.push_lua("top.custom", state);
598 tree.push_lua("dynamic.first", state);
599 ATF_REQUIRE(state.is_number(-3));
600 ATF_REQUIRE_EQ(5, state.to_integer(-3));
601 ATF_REQUIRE(state.is_number(-2));
602 ATF_REQUIRE_EQ(10, state.to_integer(-2));
603 ATF_REQUIRE(state.is_string(-1));
604 ATF_REQUIRE_EQ("foo", state.to_string(-1));
605 state.pop(3);
606 }
607
608
609 ATF_TEST_CASE_WITHOUT_HEAD(set_lua__ok);
ATF_TEST_CASE_BODY(set_lua__ok)610 ATF_TEST_CASE_BODY(set_lua__ok)
611 {
612 config::tree tree;
613
614 tree.define< config::int_node >("top.integer");
615 tree.define< wrapped_int_node >("top.custom");
616 tree.define_dynamic("dynamic");
617
618 {
619 lutok::state state;
620 state.push_integer(5);
621 state.push_integer(10);
622 state.push_string("foo");
623 tree.set_lua("top.integer", state, -3);
624 tree.set_lua("top.custom", state, -2);
625 tree.set_lua("dynamic.first", state, -1);
626 state.pop(3);
627 }
628
629 ATF_REQUIRE_EQ(5, tree.lookup< config::int_node >("top.integer"));
630 ATF_REQUIRE_EQ(10, tree.lookup< wrapped_int_node >("top.custom").value());
631 ATF_REQUIRE_EQ("foo", tree.lookup< config::string_node >("dynamic.first"));
632 }
633
634
635 ATF_TEST_CASE_WITHOUT_HEAD(lookup_rw);
ATF_TEST_CASE_BODY(lookup_rw)636 ATF_TEST_CASE_BODY(lookup_rw)
637 {
638 config::tree tree;
639
640 tree.define< config::int_node >("var1");
641 tree.define< config::bool_node >("var3");
642
643 tree.set< config::int_node >("var1", 42);
644 tree.set< config::bool_node >("var3", false);
645
646 tree.lookup_rw< config::int_node >("var1") += 10;
647 ATF_REQUIRE_EQ(52, tree.lookup< config::int_node >("var1"));
648 ATF_REQUIRE(!tree.lookup< config::bool_node >("var3"));
649 }
650
651
652 ATF_TEST_CASE_WITHOUT_HEAD(lookup_string__ok);
ATF_TEST_CASE_BODY(lookup_string__ok)653 ATF_TEST_CASE_BODY(lookup_string__ok)
654 {
655 config::tree tree;
656
657 tree.define< config::int_node >("var1");
658 tree.define< config::string_node >("b.var2");
659 tree.define< config::bool_node >("c.d.var3");
660
661 tree.set< config::int_node >("var1", 42);
662 tree.set< config::string_node >("b.var2", "hello");
663 tree.set< config::bool_node >("c.d.var3", false);
664
665 ATF_REQUIRE_EQ("42", tree.lookup_string("var1"));
666 ATF_REQUIRE_EQ("hello", tree.lookup_string("b.var2"));
667 ATF_REQUIRE_EQ("false", tree.lookup_string("c.d.var3"));
668 }
669
670
671 ATF_TEST_CASE_WITHOUT_HEAD(lookup_string__invalid_key);
ATF_TEST_CASE_BODY(lookup_string__invalid_key)672 ATF_TEST_CASE_BODY(lookup_string__invalid_key)
673 {
674 config::tree tree;
675
676 ATF_REQUIRE_THROW(config::invalid_key_error, tree.lookup_string(""));
677 }
678
679
680 ATF_TEST_CASE_WITHOUT_HEAD(lookup_string__unknown_key);
ATF_TEST_CASE_BODY(lookup_string__unknown_key)681 ATF_TEST_CASE_BODY(lookup_string__unknown_key)
682 {
683 config::tree tree;
684
685 tree.define< config::int_node >("a.b.c");
686
687 ATF_REQUIRE_THROW(config::unknown_key_error, tree.lookup_string("a.b"));
688 ATF_REQUIRE_THROW(config::unknown_key_error, tree.lookup_string("a.b.c.d"));
689 }
690
691
692 ATF_TEST_CASE_WITHOUT_HEAD(set_string__ok);
ATF_TEST_CASE_BODY(set_string__ok)693 ATF_TEST_CASE_BODY(set_string__ok)
694 {
695 config::tree tree;
696
697 tree.define< config::int_node >("foo.bar.1");
698 tree.define< config::string_node >("foo.bar.2");
699 tree.define_dynamic("sub.tree");
700
701 tree.set_string("foo.bar.1", "42");
702 tree.set_string("foo.bar.2", "hello");
703 tree.set_string("sub.tree.2", "15");
704 tree.set_string("sub.tree.3.4", "bye");
705
706 ATF_REQUIRE_EQ(42, tree.lookup< config::int_node >("foo.bar.1"));
707 ATF_REQUIRE_EQ("hello", tree.lookup< config::string_node >("foo.bar.2"));
708 ATF_REQUIRE_EQ("15", tree.lookup< config::string_node >("sub.tree.2"));
709 ATF_REQUIRE_EQ("bye", tree.lookup< config::string_node >("sub.tree.3.4"));
710 }
711
712
713 ATF_TEST_CASE_WITHOUT_HEAD(set_string__invalid_key);
ATF_TEST_CASE_BODY(set_string__invalid_key)714 ATF_TEST_CASE_BODY(set_string__invalid_key)
715 {
716 config::tree tree;
717
718 ATF_REQUIRE_THROW(config::invalid_key_error, tree.set_string(".", "foo"));
719 }
720
721
722 ATF_TEST_CASE_WITHOUT_HEAD(set_string__invalid_key_value);
ATF_TEST_CASE_BODY(set_string__invalid_key_value)723 ATF_TEST_CASE_BODY(set_string__invalid_key_value)
724 {
725 config::tree tree;
726
727 tree.define< config::int_node >("foo.bar");
728
729 ATF_REQUIRE_THROW(config::invalid_key_value,
730 tree.set_string("foo", "abc"));
731 ATF_REQUIRE_THROW(config::invalid_key_value,
732 tree.set_string("foo.bar", " -3"));
733 ATF_REQUIRE_THROW(config::invalid_key_value,
734 tree.set_string("foo.bar", "3 "));
735 }
736
737
738 ATF_TEST_CASE_WITHOUT_HEAD(set_string__unknown_key);
ATF_TEST_CASE_BODY(set_string__unknown_key)739 ATF_TEST_CASE_BODY(set_string__unknown_key)
740 {
741 config::tree tree;
742
743 tree.define< config::int_node >("foo.bar");
744 tree.define< config::int_node >("a.b.c");
745 tree.define_dynamic("a.d");
746 tree.set_string("a.b.c", "123");
747 tree.set_string("a.d.3", "foo");
748
749 ATF_REQUIRE_THROW(config::unknown_key_error, tree.set_string("abc", "2"));
750
751 tree.set_string("foo.bar", "15");
752 ATF_REQUIRE_THROW(config::unknown_key_error,
753 tree.set_string("foo.bar.baz", "0"));
754
755 ATF_REQUIRE_THROW(config::unknown_key_error,
756 tree.set_string("a.c", "100"));
757 tree.set_string("a.b.c", "-3");
758 ATF_REQUIRE_THROW(config::unknown_key_error,
759 tree.set_string("a.b.c.d", "82"));
760 tree.set_string("a.d.3", "bar");
761 tree.set_string("a.d.4", "bar");
762 ATF_REQUIRE_THROW(config::unknown_key_error,
763 tree.set_string("a.d.4.5", "82"));
764 tree.set_string("a.d.5.6", "82");
765 }
766
767
768 ATF_TEST_CASE_WITHOUT_HEAD(set_string__unknown_key_not_strict);
ATF_TEST_CASE_BODY(set_string__unknown_key_not_strict)769 ATF_TEST_CASE_BODY(set_string__unknown_key_not_strict)
770 {
771 config::tree tree(false);
772
773 tree.define< config::int_node >("foo.bar");
774 tree.define< config::int_node >("a.b.c");
775 tree.define_dynamic("a.d");
776 tree.set_string("a.b.c", "123");
777 tree.set_string("a.d.3", "foo");
778
779 tree.set_string("abc", "2");
780 ATF_REQUIRE(!tree.is_set("abc"));
781
782 tree.set_string("foo.bar", "15");
783 tree.set_string("foo.bar.baz", "0");
784 ATF_REQUIRE(!tree.is_set("foo.bar.baz"));
785
786 tree.set_string("a.c", "100");
787 ATF_REQUIRE(!tree.is_set("a.c"));
788 }
789
790
791 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__none);
ATF_TEST_CASE_BODY(all_properties__none)792 ATF_TEST_CASE_BODY(all_properties__none)
793 {
794 const config::tree tree;
795 ATF_REQUIRE(tree.all_properties().empty());
796 }
797
798
799 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__all_set);
ATF_TEST_CASE_BODY(all_properties__all_set)800 ATF_TEST_CASE_BODY(all_properties__all_set)
801 {
802 config::tree tree;
803
804 tree.define< config::int_node >("plain");
805 tree.set< config::int_node >("plain", 1234);
806
807 tree.define< config::int_node >("static.first");
808 tree.set< config::int_node >("static.first", -3);
809 tree.define< config::string_node >("static.second");
810 tree.set< config::string_node >("static.second", "some text");
811
812 tree.define_dynamic("dynamic");
813 tree.set< config::string_node >("dynamic.first", "hello");
814 tree.set< config::string_node >("dynamic.second", "bye");
815
816 config::properties_map exp_properties;
817 exp_properties["plain"] = "1234";
818 exp_properties["static.first"] = "-3";
819 exp_properties["static.second"] = "some text";
820 exp_properties["dynamic.first"] = "hello";
821 exp_properties["dynamic.second"] = "bye";
822
823 const config::properties_map properties = tree.all_properties();
824 ATF_REQUIRE(exp_properties == properties);
825 }
826
827
828 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__some_unset);
ATF_TEST_CASE_BODY(all_properties__some_unset)829 ATF_TEST_CASE_BODY(all_properties__some_unset)
830 {
831 config::tree tree;
832
833 tree.define< config::int_node >("static.first");
834 tree.set< config::int_node >("static.first", -3);
835 tree.define< config::string_node >("static.second");
836
837 tree.define_dynamic("dynamic");
838
839 config::properties_map exp_properties;
840 exp_properties["static.first"] = "-3";
841
842 const config::properties_map properties = tree.all_properties();
843 ATF_REQUIRE(exp_properties == properties);
844 }
845
846
847 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__subtree__inner);
ATF_TEST_CASE_BODY(all_properties__subtree__inner)848 ATF_TEST_CASE_BODY(all_properties__subtree__inner)
849 {
850 config::tree tree;
851
852 tree.define< config::int_node >("root.a.b.c.first");
853 tree.define< config::int_node >("root.a.b.c.second");
854 tree.define< config::int_node >("root.a.d.first");
855
856 tree.set< config::int_node >("root.a.b.c.first", 1);
857 tree.set< config::int_node >("root.a.b.c.second", 2);
858 tree.set< config::int_node >("root.a.d.first", 3);
859
860 {
861 config::properties_map exp_properties;
862 exp_properties["root.a.b.c.first"] = "1";
863 exp_properties["root.a.b.c.second"] = "2";
864 exp_properties["root.a.d.first"] = "3";
865 ATF_REQUIRE(exp_properties == tree.all_properties("root"));
866 ATF_REQUIRE(exp_properties == tree.all_properties("root.a"));
867 }
868
869 {
870 config::properties_map exp_properties;
871 exp_properties["root.a.b.c.first"] = "1";
872 exp_properties["root.a.b.c.second"] = "2";
873 ATF_REQUIRE(exp_properties == tree.all_properties("root.a.b"));
874 ATF_REQUIRE(exp_properties == tree.all_properties("root.a.b.c"));
875 }
876
877 {
878 config::properties_map exp_properties;
879 exp_properties["root.a.d.first"] = "3";
880 ATF_REQUIRE(exp_properties == tree.all_properties("root.a.d"));
881 }
882 }
883
884
885 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__subtree__leaf);
ATF_TEST_CASE_BODY(all_properties__subtree__leaf)886 ATF_TEST_CASE_BODY(all_properties__subtree__leaf)
887 {
888 config::tree tree;
889
890 tree.define< config::int_node >("root.a.b.c.first");
891 tree.set< config::int_node >("root.a.b.c.first", 1);
892 ATF_REQUIRE_THROW_RE(config::value_error, "Cannot export.*leaf",
893 tree.all_properties("root.a.b.c.first"));
894 }
895
896
897 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__subtree__strip_key);
ATF_TEST_CASE_BODY(all_properties__subtree__strip_key)898 ATF_TEST_CASE_BODY(all_properties__subtree__strip_key)
899 {
900 config::tree tree;
901
902 tree.define< config::int_node >("root.a.b.c.first");
903 tree.define< config::int_node >("root.a.b.c.second");
904 tree.define< config::int_node >("root.a.d.first");
905
906 tree.set< config::int_node >("root.a.b.c.first", 1);
907 tree.set< config::int_node >("root.a.b.c.second", 2);
908 tree.set< config::int_node >("root.a.d.first", 3);
909
910 config::properties_map exp_properties;
911 exp_properties["b.c.first"] = "1";
912 exp_properties["b.c.second"] = "2";
913 exp_properties["d.first"] = "3";
914 ATF_REQUIRE(exp_properties == tree.all_properties("root.a", true));
915 }
916
917
918 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__subtree__invalid_key);
ATF_TEST_CASE_BODY(all_properties__subtree__invalid_key)919 ATF_TEST_CASE_BODY(all_properties__subtree__invalid_key)
920 {
921 config::tree tree;
922
923 ATF_REQUIRE_THROW(config::invalid_key_error, tree.all_properties("."));
924 }
925
926
927 ATF_TEST_CASE_WITHOUT_HEAD(all_properties__subtree__unknown_key);
ATF_TEST_CASE_BODY(all_properties__subtree__unknown_key)928 ATF_TEST_CASE_BODY(all_properties__subtree__unknown_key)
929 {
930 config::tree tree;
931
932 tree.define< config::int_node >("root.a.b.c.first");
933 tree.set< config::int_node >("root.a.b.c.first", 1);
934 tree.define< config::int_node >("root.a.b.c.unset");
935
936 ATF_REQUIRE_THROW(config::unknown_key_error,
937 tree.all_properties("root.a.b.c.first.foo"));
938 ATF_REQUIRE_THROW_RE(config::value_error, "Cannot export.*leaf",
939 tree.all_properties("root.a.b.c.unset"));
940 }
941
942
943 ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__empty);
ATF_TEST_CASE_BODY(operators_eq_and_ne__empty)944 ATF_TEST_CASE_BODY(operators_eq_and_ne__empty)
945 {
946 config::tree t1;
947 config::tree t2;
948 ATF_REQUIRE( t1 == t2);
949 ATF_REQUIRE(!(t1 != t2));
950 }
951
952
953 ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__shallow_copy);
ATF_TEST_CASE_BODY(operators_eq_and_ne__shallow_copy)954 ATF_TEST_CASE_BODY(operators_eq_and_ne__shallow_copy)
955 {
956 config::tree t1;
957 t1.define< config::int_node >("root.a.b.c.first");
958 t1.set< config::int_node >("root.a.b.c.first", 1);
959 config::tree t2 = t1;
960 ATF_REQUIRE( t1 == t2);
961 ATF_REQUIRE(!(t1 != t2));
962 }
963
964
965 ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__deep_copy);
ATF_TEST_CASE_BODY(operators_eq_and_ne__deep_copy)966 ATF_TEST_CASE_BODY(operators_eq_and_ne__deep_copy)
967 {
968 config::tree t1;
969 t1.define< config::int_node >("root.a.b.c.first");
970 t1.set< config::int_node >("root.a.b.c.first", 1);
971 config::tree t2 = t1.deep_copy();
972 ATF_REQUIRE( t1 == t2);
973 ATF_REQUIRE(!(t1 != t2));
974 }
975
976
977 ATF_TEST_CASE_WITHOUT_HEAD(operators_eq_and_ne__some_contents);
ATF_TEST_CASE_BODY(operators_eq_and_ne__some_contents)978 ATF_TEST_CASE_BODY(operators_eq_and_ne__some_contents)
979 {
980 config::tree t1, t2;
981
982 t1.define< config::int_node >("root.a.b.c.first");
983 t1.set< config::int_node >("root.a.b.c.first", 1);
984 ATF_REQUIRE(!(t1 == t2));
985 ATF_REQUIRE( t1 != t2);
986
987 t2.define< config::int_node >("root.a.b.c.first");
988 t2.set< config::int_node >("root.a.b.c.first", 1);
989 ATF_REQUIRE( t1 == t2);
990 ATF_REQUIRE(!(t1 != t2));
991
992 t1.set< config::int_node >("root.a.b.c.first", 2);
993 ATF_REQUIRE(!(t1 == t2));
994 ATF_REQUIRE( t1 != t2);
995
996 t2.set< config::int_node >("root.a.b.c.first", 2);
997 ATF_REQUIRE( t1 == t2);
998 ATF_REQUIRE(!(t1 != t2));
999
1000 t1.define< config::string_node >("another.key");
1001 t1.set< config::string_node >("another.key", "some text");
1002 ATF_REQUIRE(!(t1 == t2));
1003 ATF_REQUIRE( t1 != t2);
1004
1005 t2.define< config::string_node >("another.key");
1006 t2.set< config::string_node >("another.key", "some text");
1007 ATF_REQUIRE( t1 == t2);
1008 ATF_REQUIRE(!(t1 != t2));
1009 }
1010
1011
1012 ATF_TEST_CASE_WITHOUT_HEAD(custom_leaf__no_default_ctor);
ATF_TEST_CASE_BODY(custom_leaf__no_default_ctor)1013 ATF_TEST_CASE_BODY(custom_leaf__no_default_ctor)
1014 {
1015 config::tree tree;
1016
1017 tree.define< wrapped_int_node >("test1");
1018 tree.define< wrapped_int_node >("test2");
1019 tree.set< wrapped_int_node >("test1", int_wrapper(5));
1020 tree.set< wrapped_int_node >("test2", int_wrapper(10));
1021 const int_wrapper& test1 = tree.lookup< wrapped_int_node >("test1");
1022 ATF_REQUIRE_EQ(5, test1.value());
1023 const int_wrapper& test2 = tree.lookup< wrapped_int_node >("test2");
1024 ATF_REQUIRE_EQ(10, test2.value());
1025 }
1026
1027
ATF_INIT_TEST_CASES(tcs)1028 ATF_INIT_TEST_CASES(tcs)
1029 {
1030 ATF_ADD_TEST_CASE(tcs, define_set_lookup__one_level);
1031 ATF_ADD_TEST_CASE(tcs, define_set_lookup__multiple_levels);
1032
1033 ATF_ADD_TEST_CASE(tcs, deep_copy__empty);
1034 ATF_ADD_TEST_CASE(tcs, deep_copy__some);
1035
1036 ATF_ADD_TEST_CASE(tcs, combine__empty);
1037 ATF_ADD_TEST_CASE(tcs, combine__same_layout__no_overrides);
1038 ATF_ADD_TEST_CASE(tcs, combine__same_layout__no_base);
1039 ATF_ADD_TEST_CASE(tcs, combine__same_layout__mix);
1040 ATF_ADD_TEST_CASE(tcs, combine__different_layout);
1041 ATF_ADD_TEST_CASE(tcs, combine__dynamic_wins);
1042 ATF_ADD_TEST_CASE(tcs, combine__inner_leaf_mismatch);
1043
1044 ATF_ADD_TEST_CASE(tcs, lookup__invalid_key);
1045 ATF_ADD_TEST_CASE(tcs, lookup__unknown_key);
1046
1047 ATF_ADD_TEST_CASE(tcs, is_set__one_level);
1048 ATF_ADD_TEST_CASE(tcs, is_set__multiple_levels);
1049 ATF_ADD_TEST_CASE(tcs, is_set__invalid_key);
1050
1051 ATF_ADD_TEST_CASE(tcs, set__invalid_key);
1052 ATF_ADD_TEST_CASE(tcs, set__invalid_key_value);
1053 ATF_ADD_TEST_CASE(tcs, set__unknown_key);
1054 ATF_ADD_TEST_CASE(tcs, set__unknown_key_not_strict);
1055
1056 ATF_ADD_TEST_CASE(tcs, push_lua__ok);
1057 ATF_ADD_TEST_CASE(tcs, set_lua__ok);
1058
1059 ATF_ADD_TEST_CASE(tcs, lookup_rw);
1060
1061 ATF_ADD_TEST_CASE(tcs, lookup_string__ok);
1062 ATF_ADD_TEST_CASE(tcs, lookup_string__invalid_key);
1063 ATF_ADD_TEST_CASE(tcs, lookup_string__unknown_key);
1064
1065 ATF_ADD_TEST_CASE(tcs, set_string__ok);
1066 ATF_ADD_TEST_CASE(tcs, set_string__invalid_key);
1067 ATF_ADD_TEST_CASE(tcs, set_string__invalid_key_value);
1068 ATF_ADD_TEST_CASE(tcs, set_string__unknown_key);
1069 ATF_ADD_TEST_CASE(tcs, set_string__unknown_key_not_strict);
1070
1071 ATF_ADD_TEST_CASE(tcs, all_properties__none);
1072 ATF_ADD_TEST_CASE(tcs, all_properties__all_set);
1073 ATF_ADD_TEST_CASE(tcs, all_properties__some_unset);
1074 ATF_ADD_TEST_CASE(tcs, all_properties__subtree__inner);
1075 ATF_ADD_TEST_CASE(tcs, all_properties__subtree__leaf);
1076 ATF_ADD_TEST_CASE(tcs, all_properties__subtree__strip_key);
1077 ATF_ADD_TEST_CASE(tcs, all_properties__subtree__invalid_key);
1078 ATF_ADD_TEST_CASE(tcs, all_properties__subtree__unknown_key);
1079
1080 ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__empty);
1081 ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__shallow_copy);
1082 ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__deep_copy);
1083 ATF_ADD_TEST_CASE(tcs, operators_eq_and_ne__some_contents);
1084
1085 ATF_ADD_TEST_CASE(tcs, custom_leaf__no_default_ctor);
1086 }
1087