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. 56 explicit int_wrapper(int value_) : 57 _value(value_) 58 { 59 } 60 61 /// \return The integer value stored by the object. 62 int 63 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* 77 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 88 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 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 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 120 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); 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); 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); 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); 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); 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 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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 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