00001 #include <boost/test/auto_unit_test.hpp>
00002
00003 #include "testsuite.hh"
00004 #include <utilmm/configfile/configfile.hh>
00005 #include <utilmm/configfile/commandline.hh>
00006 #include <boost/filesystem/path.hpp>
00007 #include <utilmm/stringtools.hh>
00008 #include <algorithm>
00009
00010 using namespace utilmm;
00011 using namespace boost::filesystem;
00012 using namespace std;
00013
00014 auto_ptr<config_file> setup()
00015 {
00016 path testdir = path(__FILE__).branch_path();
00017 return auto_ptr<config_file>(new config_file( (testdir / "test_configfile.config").native_file_string().c_str() ));
00018 }
00019 #define SETUP auto_ptr<config_file> config( setup() )
00020
00021
00022 BOOST_AUTO_TEST_CASE( test_basic_properties )
00023 {
00024 SETUP;
00025
00026 BOOST_REQUIRE(! config->empty());
00027 config_set empty_set;
00028 BOOST_REQUIRE( empty_set.empty() );
00029 }
00030
00031 template<typename T>
00032 void test_get_scalar(config_set const& config, string const& name, T expected)
00033 {
00034 T val = config.get<T>(name);
00035 BOOST_REQUIRE_EQUAL(val, expected);
00036 }
00037 BOOST_AUTO_TEST_CASE( test_scalar )
00038 {
00039 SETUP;
00040
00041 BOOST_REQUIRE_EQUAL(config->get<string>("unknown_key", "defval"), "defval");
00042 BOOST_REQUIRE_EQUAL(config->get<string> ("str"), "a string");
00043 BOOST_REQUIRE_EQUAL(config->get<int>("int_one"), 1);
00044 BOOST_REQUIRE_EQUAL(config->get<bool>("bool_true"), true);
00045 BOOST_REQUIRE_EQUAL(config->get<bool>("bool_false"), false);
00046 BOOST_REQUIRE_THROW(config->get<bool>("bool_invalid"), boost::bad_lexical_cast);
00047 }
00048
00049 BOOST_AUTO_TEST_CASE( test_list )
00050 {
00051 SETUP;
00052
00053 list<int> values = config->get< list<int> >("list");
00054 BOOST_REQUIRE(!values.empty());
00055
00056 vector<int> expected(10, 0);
00057 for (list<int>::const_iterator it = values.begin(); it != values.end(); ++it)
00058 expected[*it] = 1;
00059
00060 BOOST_REQUIRE(find(expected.begin(), expected.end(), 0) == expected.end());
00061
00062 }
00063
00064 BOOST_AUTO_TEST_CASE( test_child )
00065 {
00066 SETUP;
00067
00068 std::list<config_set const*> children = config->children("child");
00069 BOOST_REQUIRE_EQUAL(children.size(), 1UL);
00070
00071 config_set const* child = children.front();
00072 BOOST_REQUIRE_EQUAL(child->get<string>("str"), "another string");
00073
00074 config_set const& only_child = config->child("child");
00075 BOOST_REQUIRE_EQUAL(child, &only_child);
00076
00077 config_set const& not_a_child = config->child("not_a_child");
00078 BOOST_REQUIRE(not_a_child.empty());
00079 }
00080
00081 BOOST_AUTO_TEST_CASE( test_cmdline_option_parsing )
00082 {
00083 SETUP;
00084
00085 { cmdline_option opt("*:include,I=string:include path");
00086 BOOST_REQUIRE(!opt.isRequired());
00087 BOOST_REQUIRE(opt.isMultiple());
00088 BOOST_REQUIRE_EQUAL("include", opt.getLong());
00089 BOOST_REQUIRE_EQUAL("include", opt.getConfigKey());
00090 BOOST_REQUIRE_EQUAL("I", opt.getShort());
00091 BOOST_REQUIRE(opt.hasArgument());
00092 BOOST_REQUIRE(!opt.isArgumentOptional());
00093 BOOST_REQUIRE(!opt.hasDefaultValue());
00094 BOOST_REQUIRE(opt.getArgumentFlags() & cmdline_option::StringArgument);
00095 BOOST_REQUIRE_EQUAL("include path", opt.getHelp());
00096 }
00097 { cmdline_option opt("!:required=bool:is a required argument");
00098 BOOST_REQUIRE(opt.isRequired());
00099 BOOST_REQUIRE(!opt.isMultiple());
00100 BOOST_REQUIRE_EQUAL("required", opt.getLong());
00101 BOOST_REQUIRE_EQUAL("required", opt.getConfigKey());
00102 BOOST_REQUIRE_EQUAL("", opt.getShort());
00103 BOOST_REQUIRE(opt.hasArgument());
00104 BOOST_REQUIRE(opt.getArgumentFlags() & cmdline_option::BoolArgument);
00105 BOOST_REQUIRE_EQUAL("is a required argument", opt.getHelp());
00106 }
00107 { cmdline_option opt("vkey:verbose,v?int,1:include path");
00108 BOOST_REQUIRE(!opt.isRequired());
00109 BOOST_REQUIRE(!opt.isMultiple());
00110 BOOST_REQUIRE_EQUAL("vkey", opt.getConfigKey());
00111 BOOST_REQUIRE_EQUAL("verbose", opt.getLong());
00112 BOOST_REQUIRE_EQUAL("v", opt.getShort());
00113 BOOST_REQUIRE(opt.hasArgument());
00114 BOOST_REQUIRE(opt.isArgumentOptional());
00115 BOOST_REQUIRE(opt.hasDefaultValue());
00116 BOOST_REQUIRE(opt.getArgumentFlags() & cmdline_option::IntArgument);
00117 BOOST_REQUIRE_EQUAL("1", opt.getDefaultValue());
00118 BOOST_REQUIRE_EQUAL("include path", opt.getHelp());
00119 }
00120 { cmdline_option opt(":quiet");
00121 BOOST_REQUIRE(!opt.isRequired());
00122 BOOST_REQUIRE(!opt.isMultiple());
00123 BOOST_REQUIRE_EQUAL("quiet", opt.getConfigKey());
00124 BOOST_REQUIRE_EQUAL("quiet", opt.getLong());
00125 BOOST_REQUIRE_EQUAL("", opt.getShort());
00126 BOOST_REQUIRE(!opt.hasArgument());
00127 BOOST_REQUIRE_EQUAL("", opt.getHelp());
00128 }
00129
00130
00131 BOOST_REQUIRE_THROW( cmdline_option option("*::bla"), bad_syntax );
00132
00133 BOOST_REQUIRE_THROW( cmdline_option option("*:invalid key:bla"), bad_syntax );
00134
00135 BOOST_REQUIRE_THROW( cmdline_option option(":blo=badtype"), bad_syntax );
00136
00137 BOOST_REQUIRE_THROW( cmdline_option option(":foo?int"), bad_syntax );
00138
00139 BOOST_REQUIRE_THROW( cmdline_option opt("!:required=bool,true:is a required argument"), bad_syntax );
00140
00141 BOOST_REQUIRE_NO_THROW( cmdline_option opt("!:required?bool,true:is a required argument") );
00142 }
00143
00144 void check_cmdline_properties(command_line& cmdline)
00145 {
00146 config_set config;
00147 const char* valid_argv[] = { "--required=false", "-I", "bla", "--include=test", "--quiet", "--verbose", "bla.cpp" };
00148
00149 cmdline.parse(7, valid_argv, config);
00150 BOOST_REQUIRE_EQUAL(1UL, cmdline.remaining().size() );
00151 BOOST_REQUIRE_EQUAL("bla.cpp", cmdline.remaining().front() );
00152
00153 list<string> includes = config.get< list<string> >("include");
00154 BOOST_REQUIRE_EQUAL(2UL, includes.size());
00155 BOOST_REQUIRE( "bla" == includes.back() || "bla" == includes.front() );
00156 BOOST_REQUIRE( "test" == includes.back() || "test" == includes.front() );
00157
00158 BOOST_REQUIRE_EQUAL( config.get<bool>("quiet"), true );
00159 BOOST_REQUIRE_EQUAL( config.get<bool>("vkey"), 1 );
00160 BOOST_REQUIRE_EQUAL( config.get<int>("defval"), 10 );
00161 }
00162
00163 BOOST_AUTO_TEST_CASE( test_commandline )
00164 {
00165 char const* valid_spec[] = {
00166 "*:include,I=string:include path",
00167 "!:required=bool:is a required argument",
00168 "vkey:verbose,v?int,1:include path",
00169 "defval:default-value=int,10:should be set to default value",
00170 ":quiet",
00171 0
00172 };
00173
00174 {
00175 list<string> strlist_spec;
00176 for (char const** specline = valid_spec; *specline; ++specline)
00177 strlist_spec.push_back(*specline);
00178
00179 command_line cmdline(valid_spec);
00180 check_cmdline_properties(cmdline);
00181 }
00182
00183 command_line cmdline(valid_spec);
00184 check_cmdline_properties(cmdline);
00185
00186 config_set config;
00187
00188 char const* missing_required[] = { "--quiet" };
00189 BOOST_REQUIRE_THROW( cmdline.parse(1, missing_required, config), commandline_error );
00190
00191 char const* missing_argument[] = { "--required=true", "--include" };
00192 BOOST_REQUIRE_THROW( cmdline.parse(2, missing_argument, config), commandline_error );
00193
00194 char const* missing_argument_short[] = { "--required=true", "-I", "--quiet" };
00195 BOOST_REQUIRE_THROW( cmdline.parse(3, missing_argument_short, config), commandline_error );
00196
00197 char const* invalid_argument_type[] = { "--required=true", "--verbose=bla" };
00198 BOOST_REQUIRE_THROW( cmdline.parse(2, invalid_argument_type, config), commandline_error );
00199
00200 char const* overriding_default_value[] = { "--required=true", "--default-value=20" };
00201 BOOST_REQUIRE_NO_THROW( cmdline.parse(2, overriding_default_value, config) );
00202 BOOST_REQUIRE_EQUAL(20, config.get<int>("defval"));
00203 }
00204