Path: blob/main/contrib/kyua/utils/config/lua_module_test.cpp
48081 views
// Copyright 2012 The Kyua Authors.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728#include "utils/config/lua_module.hpp"2930#include <atf-c++.hpp>3132#include <lutok/exceptions.hpp>33#include <lutok/operations.hpp>34#include <lutok/state.ipp>3536#include "utils/config/tree.ipp"37#include "utils/defs.hpp"3839namespace config = utils::config;404142namespace {434445/// Non-native type to use as a leaf node.46struct custom_type {47/// The value recorded in the object.48int value;4950/// Constructs a new object.51///52/// \param value_ The value to store in the object.53explicit custom_type(const int value_) :54value(value_)55{56}57};585960/// Custom implementation of a node type for testing purposes.61class custom_node : public config::typed_leaf_node< custom_type > {62public:63/// Copies the node.64///65/// \return A dynamically-allocated node.66virtual base_node*67deep_copy(void) const68{69std::unique_ptr< custom_node > new_node(new custom_node());70new_node->_value = _value;71return new_node.release();72}7374/// Pushes the node's value onto the Lua stack.75///76/// \param state The Lua state onto which to push the value.77void78push_lua(lutok::state& state) const79{80state.push_integer(value().value * 5);81}8283/// Sets the value of the node from an entry in the Lua stack.84///85/// \param state The Lua state from which to get the value.86/// \param value_index The stack index in which the value resides.87void88set_lua(lutok::state& state, const int value_index)89{90ATF_REQUIRE(state.is_number(value_index));91set(custom_type(state.to_integer(value_index) * 2));92}9394/// Sets the value of the node from a raw string representation.95///96/// \post The test case is marked as failed, as this function is not97/// supposed to be invoked by the lua_module code.98void99set_string(const std::string& /* raw_value */)100{101ATF_FAIL("Should not be used");102}103104/// Converts the contents of the node to a string.105///106/// \post The test case is marked as failed, as this function is not107/// supposed to be invoked by the lua_module code.108///109/// \return Nothing.110std::string111to_string(void) const112{113ATF_FAIL("Should not be used");114}115};116117118} // anonymous namespace119120121ATF_TEST_CASE_WITHOUT_HEAD(top__valid_types);122ATF_TEST_CASE_BODY(top__valid_types)123{124config::tree tree;125tree.define< config::bool_node >("top_boolean");126tree.define< config::int_node >("top_integer");127tree.define< config::string_node >("top_string");128129{130lutok::state state;131config::redirect(state, tree);132lutok::do_string(state,133"top_boolean = true\n"134"top_integer = 12345\n"135"top_string = 'a foo'\n",1360, 0, 0);137}138139ATF_REQUIRE_EQ(true, tree.lookup< config::bool_node >("top_boolean"));140ATF_REQUIRE_EQ(12345, tree.lookup< config::int_node >("top_integer"));141ATF_REQUIRE_EQ("a foo", tree.lookup< config::string_node >("top_string"));142}143144145ATF_TEST_CASE_WITHOUT_HEAD(top__invalid_types);146ATF_TEST_CASE_BODY(top__invalid_types)147{148config::tree tree;149tree.define< config::bool_node >("top_boolean");150tree.define< config::int_node >("top_integer");151152{153lutok::state state;154config::redirect(state, tree);155ATF_REQUIRE_THROW_RE(156lutok::error,157"Invalid value for property 'top_boolean': Not a boolean",158lutok::do_string(state,159"top_boolean = true\n"160"top_integer = 8\n"161"top_boolean = 'foo'\n",1620, 0, 0));163}164165ATF_REQUIRE_EQ(true, tree.lookup< config::bool_node >("top_boolean"));166ATF_REQUIRE_EQ(8, tree.lookup< config::int_node >("top_integer"));167}168169170ATF_TEST_CASE_WITHOUT_HEAD(top__reuse);171ATF_TEST_CASE_BODY(top__reuse)172{173config::tree tree;174tree.define< config::int_node >("first");175tree.define< config::int_node >("second");176177{178lutok::state state;179config::redirect(state, tree);180lutok::do_string(state, "first = 100; second = first * 2", 0, 0, 0);181}182183ATF_REQUIRE_EQ(100, tree.lookup< config::int_node >("first"));184ATF_REQUIRE_EQ(200, tree.lookup< config::int_node >("second"));185}186187188ATF_TEST_CASE_WITHOUT_HEAD(top__reset);189ATF_TEST_CASE_BODY(top__reset)190{191config::tree tree;192tree.define< config::int_node >("first");193194{195lutok::state state;196config::redirect(state, tree);197lutok::do_string(state, "first = 100; first = 200", 0, 0, 0);198}199200ATF_REQUIRE_EQ(200, tree.lookup< config::int_node >("first"));201}202203204ATF_TEST_CASE_WITHOUT_HEAD(top__already_set_on_entry);205ATF_TEST_CASE_BODY(top__already_set_on_entry)206{207config::tree tree;208tree.define< config::int_node >("first");209tree.set< config::int_node >("first", 100);210211{212lutok::state state;213config::redirect(state, tree);214lutok::do_string(state, "first = first * 15", 0, 0, 0);215}216217ATF_REQUIRE_EQ(1500, tree.lookup< config::int_node >("first"));218}219220221ATF_TEST_CASE_WITHOUT_HEAD(subtree__valid_types);222ATF_TEST_CASE_BODY(subtree__valid_types)223{224config::tree tree;225tree.define< config::bool_node >("root.boolean");226tree.define< config::int_node >("root.a.integer");227tree.define< config::string_node >("root.string");228229{230lutok::state state;231config::redirect(state, tree);232lutok::do_string(state,233"root.boolean = true\n"234"root.a.integer = 12345\n"235"root.string = 'a foo'\n",2360, 0, 0);237}238239ATF_REQUIRE_EQ(true, tree.lookup< config::bool_node >("root.boolean"));240ATF_REQUIRE_EQ(12345, tree.lookup< config::int_node >("root.a.integer"));241ATF_REQUIRE_EQ("a foo", tree.lookup< config::string_node >("root.string"));242}243244245ATF_TEST_CASE_WITHOUT_HEAD(subtree__reuse);246ATF_TEST_CASE_BODY(subtree__reuse)247{248config::tree tree;249tree.define< config::int_node >("a.first");250tree.define< config::int_node >("a.second");251252{253lutok::state state;254config::redirect(state, tree);255lutok::do_string(state, "a.first = 100; a.second = a.first * 2",2560, 0, 0);257}258259ATF_REQUIRE_EQ(100, tree.lookup< config::int_node >("a.first"));260ATF_REQUIRE_EQ(200, tree.lookup< config::int_node >("a.second"));261}262263264ATF_TEST_CASE_WITHOUT_HEAD(subtree__reset);265ATF_TEST_CASE_BODY(subtree__reset)266{267config::tree tree;268tree.define< config::int_node >("a.first");269270{271lutok::state state;272config::redirect(state, tree);273lutok::do_string(state, "a.first = 100; a.first = 200", 0, 0, 0);274}275276ATF_REQUIRE_EQ(200, tree.lookup< config::int_node >("a.first"));277}278279280ATF_TEST_CASE_WITHOUT_HEAD(subtree__already_set_on_entry);281ATF_TEST_CASE_BODY(subtree__already_set_on_entry)282{283config::tree tree;284tree.define< config::int_node >("a.first");285tree.set< config::int_node >("a.first", 100);286287{288lutok::state state;289config::redirect(state, tree);290lutok::do_string(state, "a.first = a.first * 15", 0, 0, 0);291}292293ATF_REQUIRE_EQ(1500, tree.lookup< config::int_node >("a.first"));294}295296297ATF_TEST_CASE_WITHOUT_HEAD(subtree__override_inner);298ATF_TEST_CASE_BODY(subtree__override_inner)299{300config::tree tree;301tree.define_dynamic("root");302303{304lutok::state state;305config::redirect(state, tree);306lutok::do_string(state, "root.test = 'a'", 0, 0, 0);307ATF_REQUIRE_THROW_RE(lutok::error, "Invalid value for property 'root'",308lutok::do_string(state, "root = 'b'", 0, 0, 0));309// Ensure that the previous assignment to 'root' did not cause any310// inconsistencies in the environment that would prevent a new311// assignment from working.312lutok::do_string(state, "root.test2 = 'c'", 0, 0, 0);313}314315ATF_REQUIRE_EQ("a", tree.lookup< config::string_node >("root.test"));316ATF_REQUIRE_EQ("c", tree.lookup< config::string_node >("root.test2"));317}318319320ATF_TEST_CASE_WITHOUT_HEAD(dynamic_subtree__strings);321ATF_TEST_CASE_BODY(dynamic_subtree__strings)322{323config::tree tree;324tree.define_dynamic("root");325326lutok::state state;327config::redirect(state, tree);328lutok::do_string(state,329"root.key1 = 1234\n"330"root.a.b.key2 = 'foo bar'\n",3310, 0, 0);332333ATF_REQUIRE_EQ("1234", tree.lookup< config::string_node >("root.key1"));334ATF_REQUIRE_EQ("foo bar",335tree.lookup< config::string_node >("root.a.b.key2"));336}337338339ATF_TEST_CASE_WITHOUT_HEAD(dynamic_subtree__invalid_types);340ATF_TEST_CASE_BODY(dynamic_subtree__invalid_types)341{342config::tree tree;343tree.define_dynamic("root");344345lutok::state state;346config::redirect(state, tree);347ATF_REQUIRE_THROW_RE(lutok::error,348"Invalid value for property 'root.boolean': "349"Not a string",350lutok::do_string(state, "root.boolean = true",3510, 0, 0));352ATF_REQUIRE_THROW_RE(lutok::error,353"Invalid value for property 'root.table': "354"Not a string",355lutok::do_string(state, "root.table = {}",3560, 0, 0));357ATF_REQUIRE(!tree.is_set("root.boolean"));358ATF_REQUIRE(!tree.is_set("root.table"));359}360361362ATF_TEST_CASE_WITHOUT_HEAD(locals);363ATF_TEST_CASE_BODY(locals)364{365config::tree tree;366tree.define< config::int_node >("the_key");367368{369lutok::state state;370config::redirect(state, tree);371lutok::do_string(state,372"local function generate()\n"373" return 15\n"374"end\n"375"local test_var = 20\n"376"the_key = generate() + test_var\n",3770, 0, 0);378}379380ATF_REQUIRE_EQ(35, tree.lookup< config::int_node >("the_key"));381}382383384ATF_TEST_CASE_WITHOUT_HEAD(custom_node);385ATF_TEST_CASE_BODY(custom_node)386{387config::tree tree;388tree.define< custom_node >("key1");389tree.define< custom_node >("key2");390tree.set< custom_node >("key2", custom_type(10));391392{393lutok::state state;394config::redirect(state, tree);395lutok::do_string(state, "key1 = 512\n", 0, 0, 0);396lutok::do_string(state, "key2 = key2 * 2\n", 0, 0, 0);397}398399ATF_REQUIRE_EQ(1024, tree.lookup< custom_node >("key1").value);400ATF_REQUIRE_EQ(200, tree.lookup< custom_node >("key2").value);401}402403404ATF_TEST_CASE_WITHOUT_HEAD(invalid_key);405ATF_TEST_CASE_BODY(invalid_key)406{407config::tree tree;408409lutok::state state;410config::redirect(state, tree);411ATF_REQUIRE_THROW_RE(lutok::error, "Empty component in key 'root.'",412lutok::do_string(state, "root['']['a'] = 12345\n",4130, 0, 0));414}415416417ATF_TEST_CASE_WITHOUT_HEAD(unknown_key);418ATF_TEST_CASE_BODY(unknown_key)419{420config::tree tree;421tree.define< config::bool_node >("static.bool");422423lutok::state state;424config::redirect(state, tree);425ATF_REQUIRE_THROW_RE(lutok::error,426"Unknown configuration property 'static.int'",427lutok::do_string(state,428"static.int = 12345\n",4290, 0, 0));430}431432433ATF_TEST_CASE_WITHOUT_HEAD(value_error);434ATF_TEST_CASE_BODY(value_error)435{436config::tree tree;437tree.define< config::bool_node >("a.b");438439lutok::state state;440config::redirect(state, tree);441ATF_REQUIRE_THROW_RE(lutok::error,442"Invalid value for property 'a.b': Not a boolean",443lutok::do_string(state, "a.b = 12345\n", 0, 0, 0));444ATF_REQUIRE_THROW_RE(lutok::error,445"Invalid value for property 'a': ",446lutok::do_string(state, "a = 1\n", 0, 0, 0));447}448449450ATF_INIT_TEST_CASES(tcs)451{452ATF_ADD_TEST_CASE(tcs, top__valid_types);453ATF_ADD_TEST_CASE(tcs, top__invalid_types);454ATF_ADD_TEST_CASE(tcs, top__reuse);455ATF_ADD_TEST_CASE(tcs, top__reset);456ATF_ADD_TEST_CASE(tcs, top__already_set_on_entry);457458ATF_ADD_TEST_CASE(tcs, subtree__valid_types);459ATF_ADD_TEST_CASE(tcs, subtree__reuse);460ATF_ADD_TEST_CASE(tcs, subtree__reset);461ATF_ADD_TEST_CASE(tcs, subtree__already_set_on_entry);462ATF_ADD_TEST_CASE(tcs, subtree__override_inner);463464ATF_ADD_TEST_CASE(tcs, dynamic_subtree__strings);465ATF_ADD_TEST_CASE(tcs, dynamic_subtree__invalid_types);466467ATF_ADD_TEST_CASE(tcs, locals);468ATF_ADD_TEST_CASE(tcs, custom_node);469470ATF_ADD_TEST_CASE(tcs, invalid_key);471ATF_ADD_TEST_CASE(tcs, unknown_key);472ATF_ADD_TEST_CASE(tcs, value_error);473}474475476