// -*- c++ -*- // Generated by assa-genesis //------------------------------------------------------------------------------ // $Id: glops_test.cpp,v 1.3 2005/10/10 02:27:48 vlg Exp $ //------------------------------------------------------------------------------ // glops.cpp //------------------------------------------------------------------------------ // // Author : Vladislav Grinchenko // Date : Nov 29 2001 //------------------------------------------------------------------------------ static const char help_msg[]= " \n" " NAME: \n" " glops_test - test for CmdLineOpts class \n" " \n" " DESCRIPTION: \n" " \n" " This test exercises usage of CmdLineOpts class to considerable \n" " extend. If you want to separate log messages from test report messages, \n" " use {-D, --log-file NAME} option. \n" " \n" " USAGE: \n" " \n" " shell> glops [OPTIONS] \n" " \n" " OPTIONS: \n" " \n" " -D, --log-file NAME logging messages file \n" " --log-stdout BOOL Write debug messages to the terminal \n" " -i, --instance NUM process instance \n" " -s, --set NAME configuration set \n" " -z, --size SIZE log file size \n" " -t, --timeout TIMEOUT connection timeout \n" " -c, --comm-timeout TIMEOUT commlib timeout \n" " -b, --daemon BOOL run in background \n" " -m, --mask MASK debug mask (defalt: ALL_OFF) \n" " -h, --help print this message \n" " -V version \n" " --date compilation date \n" " \n" " Options with long option argument \n" " can also be given in the form {-z, --size=SIZE} \n" " \n" " To get CMDLIEOPTS log messages only, use --mask=0x800082 \n" " \n" " shell> glops_test --mask=0x800082 --log-file=glops.log \n" " \n" " Written by Vladislav Grinchenko \n"; //------------------------------------------------------------------------------ #include // getpid () #include #include #include #include #include using namespace std; #include "assa/GenServer.h" #include "assa/Singleton.h" #include "assa/TimeVal.h" #include "assa/Logger.h" #include "assa/IniFile.h" using namespace ASSA; class A : public CmdLineOpts { public: A (); virtual ~A() {} virtual bool init (char* argv[], const char* h); virtual void pos_arg (const char* arg_); virtual void dump () const; void help () { clog << "\n\n" << m_help_msg << "\n\n"; } bool validate_data_from_ini (); bool validate_data_from_args (); private: static void version () { cout << "\n\tVersion: 1.0\n"; } static void date () { cout << "\n\tBuilt on: " << __DATE__ << ", " << __TIME__ << endl; } protected: int m_instance; string m_set_burst; long m_size; const char* m_help_msg; bool m_help_flag; long m_mask; string m_logfname; }; A::A () : m_instance (0), m_set_burst ("no"), m_size (5), m_help_msg (NULL), m_help_flag (false), m_mask (0) { add_opt ('i', "instance", &m_instance); add_opt ('s', "set-burst",&m_set_burst); add_opt ('m', "mask", &m_mask); add_opt ('z', "size", &m_size); add_opt ('V', "", &version); add_opt ( 0, "date", &date); add_opt ('D', "log-file", &m_logfname); add_flag_opt ('h', "help", &m_help_flag); } bool A::init (char* argv_[], const char* h_) { trace("A::init"); m_help_msg = h_; DL((APP,"Parsing command-line arguments ...\n")); bool ret = parse_args ((const char**)argv_); if (ret) { DL((APP,"parse_args() = true\n")); // if (m_help_flag) { // help (); // exit (0); // } } return (ret); } void A::pos_arg (const char* arg_) { trace("A::pos_arg"); DL((APP,"Positional argument: \"%s\"\n", arg_)); } void A::dump () const { CmdLineOpts::dump (); DL((APP,"A::[instance ] = %d\n", m_instance)); DL((APP,"A::[set-burst ] = \"%s\"\n", m_set_burst.c_str ())); DL((APP,"A::[mask ] = 0x%X\n", m_mask)); DL((APP,"A::[size ] = %ld\n", m_size)); DL((APP,"A::[help-flag ] = %s\n", (m_help_flag ? "true" : "false"))); DL((APP,"A::[log-file ] = %s\n", m_logfname.c_str ())); } bool A::validate_data_from_ini () { if (m_instance != 2 || m_mask != 0x2f || m_logfname != "foobar.log" || m_set_burst != "yes" || m_help_flag != true) { return false; } return true; } bool A::validate_data_from_args () { if (m_instance != 2 || m_mask != 0x2f || m_logfname != "meomeo.log" || m_set_burst != "no" || m_help_flag != true ) { return false; } return true; } void func0 () { trace("func0"); DL((APP,"Global OPTS_FUNC is being called.\n")); } void func1 (const string& opt_) { trace("func1"); DL((APP,"Global OPTS_FUNC_ONE is being called with arg \"%s\"\n", opt_.c_str ())); } class B : public A { public: B (); ~B () {} virtual void pos_arg (const char* arg_); virtual void dump () const; void set_log_fname (const char* fname_) { m_logfname = fname_; } private: double b_d; float b_f; bool b_b; string b_log_stdout; }; B::B () : b_d (.33), b_f (33.2), b_b (false), b_log_stdout ("no") { add_opt ('t', "timeout", &b_d); add_opt ('c', "comm-timeout", &b_f); add_flag_opt ('b', "daemon", &b_b); add_opt (0, "log-stdout", &b_log_stdout); } void B::dump () const { A::dump (); DL((APP,"B::t [timeout ] = %5.2f\n", b_d)); DL((APP,"B::c [comm-timeout] = %5.2f\n", b_f)); DL((APP,"B::b [daemon ] = %s\n", (b_b ? "true" : "false"))); DL((APP,"B::h [help ] = \n")); } void B::pos_arg (const char* arg_) { trace("B::pos_arg"); DL((APP,"Positional argument: \"%s\"\n", arg_)); } void print_args (char* argv[]) { DL((APP,"Array of arguments:\n")); for (int i=0; argv[i]; i++) { DL((APP,"[%02d] = \"%s\"\n", i, argv [i])); } } class Args : public CmdLineOpts { public: Args (); bool init (char* argv_[]); private: long m_mask; string m_log_file; string m_log_stdout; }; Args::Args () : m_mask (0x8000a2), // APP | ERROR | CMDLINEOPTS | INIFILE m_log_file ("glops_test.log"), m_log_stdout ("no") { add_opt ('D', "log-file", &m_log_file); add_opt ('m', "mask", &m_mask); add_opt ( 0, "log-stdout", &m_log_stdout); } bool Args::init (char* argv_[]) { if (parse_args ((const char**)argv_)) { if (m_log_stdout == "yes") { Log::open_log_stdout (m_mask); } else if (m_log_file.size () > 0) { ::unlink (m_log_file.c_str ()); Log::open_log_file (m_log_file.c_str (), m_mask); } return true; } return false; } void record_header (ostringstream& msg_) { DL((APP,"%s",msg_.str ().c_str ())); msg_.str (""); } int main (int argc, char* argv[]) { const char self[] = "clops"; ostringstream msg; string init_args; string new_cmd_line; char** new_argv; int new_argc; Args args; if (!args.init (argv)) { return (1); } trace_with_mask("main",APP); cout << "= Running glops_test Test =\n"; DL((APP,"*** Command line arguments:\n")); print_args (argv); msg << "\n*******************************************************" << "\n*** Test 1 : processing command-line arguments." << "\n*******************************************************\n\n"; record_header (msg); B bee; if (! bee.init (argv, help_msg)) { cerr << "Option error: " << bee.get_opt_error () << endl; bee.help (); cout << "\nTest 1 : Failed\n"; return (1); } else { DL((APP,"* State of object B after initialization\n")); DL((APP," --------------------------------------\n")); bee.dump (); DL((APP," --------------------------------------\n")); cout << "\nTest 1 : OK\n"; } msg << "\n*******************************************************" << "\n*** Test 2 : handling invalid command-line arguments." << "\n*******************************************************\n\n"; record_header (msg); new_cmd_line = "glops --summer -L"; CmdLineOpts::str_to_argv (new_cmd_line, new_argc, new_argv); DL((APP,"Command line: \"%s\"\n", new_cmd_line.c_str ())); print_args (new_argv); if (! bee.init (new_argv, help_msg)) { cout << "\nTest 2 : OK " << "(Error reported: " << bee.get_opt_error () << ')' << endl; } else { cout << "\nTest 2 : Failed\n"; return (1); } CmdLineOpts::free_argv (new_argv); msg << "\n*******************************************************" << "\n*** Test 3 : demonstrating function hookups." << "\n*******************************************************\n\n"; record_header (msg); new_cmd_line = "glops --func --func-one arg1"; CmdLineOpts::str_to_argv (new_cmd_line, new_argc, new_argv); DL((APP,"Command line: \"%s\"\n", new_cmd_line.c_str ())); print_args (new_argv); if (!bee.add_opt ('f', "func", &func0)) { cerr << "Error on adding '-f, --func' argument : " << bee.get_opt_error () << endl; return (1); } if (!bee.add_opt ('F', "func-one", &func1)) { cerr << "Error on adding '-F, --func-one' argument : " << bee.get_opt_error () << endl; return (1); } bee.dump (); if (!bee.init (new_argv, help_msg)) { cout << "\nTest 3 : Failed (Error reported: " << bee.get_opt_error () << ")\n"; return (1); } else { cout << "\nTest 3 : OK\n"; } CmdLineOpts::free_argv (new_argv); //---------------------------------------------------------------------- msg << "\n*******************************************************" << "\n*** Test 4 : Remove option and test its availabitily." << "\n*******************************************************\n\n"; record_header (msg); new_cmd_line = "glops --comm-timeout"; CmdLineOpts::str_to_argv (new_cmd_line, new_argc, new_argv); DL((APP,"Command line: \"%s\"\n", new_cmd_line.c_str ())); print_args (new_argv); if (!bee.rm_opt ('c', "comm-timeout")) { cerr << "Error removing '-c, --comm-timeout' argument : " << bee.get_opt_error () << endl; return (1); } DL((APP,"Options after \"--comm-timeout\" has been removed:\n")); bee.dump (); if (!bee.init (new_argv, help_msg)) { cout << "\nTest 4 : OK " << "(Would be error reported: " << bee.get_opt_error () << ')' << endl; } else { cout << "\nTest 4 : Failed\n"; return (1); } CmdLineOpts::free_argv (new_argv); //---------------------------------------------------------------------- msg << "\n*******************************************************" << "\n*** Test 5 : Grouped short binary options" << "\n*******************************************************\n\n"; record_header (msg); new_cmd_line = "glops -xy -kzee l bootleg -"; CmdLineOpts::str_to_argv (new_cmd_line, new_argc, new_argv); DL((APP,"Command line: \"%s\"\n", new_cmd_line.c_str ())); print_args (new_argv); bool x = false; bool y = false; string k; if (!bee.add_flag_opt ('x', "hex", &x)) { cerr << "Error on adding '-x, --hex' argument : " << bee.get_opt_error () << endl; return (1); } if (!bee.add_flag_opt ('y', "yoke", &y)) { cerr << "Error on adding '-y, --yoke' argument : " << bee.get_opt_error () << endl; return (1); } if (!bee.add_opt ('k', "zebra", &k)) { cerr << "Error on adding '-k, --zebra' argument : " << bee.get_opt_error () << endl; return (1); } bee.dump (); if (!bee.init (new_argv, help_msg)) { cout << "\nTest 5 : Failed (Error reported: " << bee.get_opt_error () << ")\n"; return (1); } else { if (x && y && k == "zee") { cout << "\nTest 5 : OK\n"; } else { cout << "\nTest 5 : Falied\n" << "x = " << x << " (expected: true)\n" << "y = " << y << " (expected: true)\n" << "k = '" << k << "' (expected: 'zee')\n"; return (1); } } CmdLineOpts::free_argv (new_argv); //---------------------------------------------------------------------- msg << "\n*******************************************************" << "\n*** Test 6 : Wrong arguments order" << "\n*******************************************************" << "\n\n"; record_header (msg); new_cmd_line = "glops -xy bootleg -kzee -"; CmdLineOpts::str_to_argv (new_cmd_line, new_argc, new_argv); DL((APP,"Command line: \"%s\"\n", new_cmd_line.c_str ())); print_args (new_argv); if (!bee.init (new_argv, help_msg)) { cout << "\nTest 6 : OK " << "(Would be error reported: " << bee.get_opt_error () << ")\n"; } else { cout << "\nTest 6 : Failed\n"; return (1); } CmdLineOpts::free_argv (new_argv); /*---------------------------------------------------------------------- * The goal of this test is to validate the correctness of option * assgnments from various sources. An option's value is frist * initialized by the constructor of an object derived from CmdLineOpts. * The value is then changed by parsing INI file. At last, the value * can be altered with command-line arguments. * * m_set_burst m_help_flag * ============================== * "no" false Ctor * ------------- ------------- * "yes" true INI File * ------------- ------------- * "no" true Command-line arguments * ------------------------------ * * NOTE: Value of bool flag cannot be changed once it is set to 'true' * somewhere along the path. *----------------------------------------------------------------------*/ msg << "\n*******************************************************" << "\n*** Test 7 : Reading [options] section of config file " << "\n*******************************************************" << "\n\n"; record_header (msg); /** Create a configuration file */ ofstream cfg_file; char cfg_name [256]; int opts_sz = 5; A apple; int ret; sprintf (cfg_name, "/tmp/glops_test.%d", getpid ()); ::unlink (cfg_name); cfg_file.open (cfg_name, std::ios::out); if (!cfg_file) { cout << "\nTest 7 : Failed to create cfg file \"" << cfg_name << "\"\n"; return (1); } cfg_file << "# This is the input test file for \n" << "# inifile_test driver\n" << "#\n" << "\n" << "[options] \n" << "instance=2\n" << "mask=0x2f\n" << "log_file=foobar.log\n" << "set_burst=yes\n" << "help=true\n"; cfg_file.close (); /** Load configuration file with IniFile */ IniFile ini_file (cfg_name); if (ini_file.load () < 0) { cout << "\nTest 7 : Failed to load ini file (\"" << cfg_name << "\"\n"; unlink (cfg_name); return (1); } ret = apple.parse_config_file (ini_file); if (ret < 0) { cout << "\nTest 7 : Failed (" << apple.get_opt_error () << ")\n"; unlink (cfg_name); return (1); } if (ret != opts_sz) { cout << "\nTest 7 : Failed to fetch " << opts_sz << " options from INI file (got only " << ret << " options)\n"; ::unlink (cfg_name); return (1); } DL ((APP,"Options after reading INI file:\n")); apple.dump (); if (!apple.validate_data_from_ini ()) { cout << "\nTest 7 : Failed to match data\n"; ::unlink (cfg_name); return (1); } ::unlink (cfg_name); /** Now, flip the options again with command-line arguments */ new_cmd_line = "glops --set-burst=no --help --log-file=meomeo.log"; CmdLineOpts::str_to_argv (new_cmd_line, new_argc, new_argv); DL((APP,"Command line: \"%s\"\n", new_cmd_line.c_str ())); print_args (new_argv); if (!apple.init (new_argv, help_msg)) { cout << "\nTest 7 : Failed to init() A with args\n"; return (1); } DL ((APP,"Options after parsing command-line arguments:\n")); apple.dump (); if (!apple.validate_data_from_args ()) { cout << "\nTest 7 : Failed to validate data from args\n"; return (1); } //---------------------------------------------------------------------- cout << "\n" << "'" << self << "' : Passed the test!\n"; return (0); }