xorp

test_main.hh

00001 // -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
00002 // vim:set sts=4 ts=8:
00003 
00004 // Copyright (c) 2001-2011 XORP, Inc and Others
00005 //
00006 // This program is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU Lesser General Public License, Version
00008 // 2.1, June 1999 as published by the Free Software Foundation.
00009 // Redistribution and/or modification of this program under the terms of
00010 // any other version of the GNU Lesser General Public License is not
00011 // permitted.
00012 // 
00013 // This program is distributed in the hope that it will be useful, but
00014 // WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
00016 // see the GNU Lesser General Public License, Version 2.1, a copy of
00017 // which can be found in the XORP LICENSE.lgpl file.
00018 // 
00019 // XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
00020 // http://xorp.net
00021 
00022 // $XORP: xorp/libxorp/test_main.hh,v 1.21 2008/10/02 21:57:34 bms Exp $
00023 
00024 #ifndef __LIBXORP_TEST_MAIN_HH__
00025 #define __LIBXORP_TEST_MAIN_HH__
00026 
00027 
00028 
00029 
00030 #include "xorp.h"
00031 #include "callback.hh"
00032 
00037 #define DOUT(info)                      \
00038         if (info.verbose())                 \
00039             info.out() << __FUNCTION__ << ":"   \
00040                    << __LINE__ << ":"       \
00041                    << info.test_name() << ": "
00042 
00043 
00048 #define DOUT_LEVEL(info, level)                     \
00049         if (info.verbose() && info.verbose_level() >= level)    \
00050             info.out() << __FUNCTION__ << ":"       \
00051                    << __LINE__ << ":"           \
00052                    << info.test_name() << ": "
00053 
00057 class TestInfo {
00058 public:
00059     TestInfo(string myname, bool verbose, int verbose_level, ostream& o) :
00060     _myname(myname), _verbose(verbose), _verbose_level(verbose_level),
00061     _ostream(o)
00062     {
00063     }
00064 
00065     TestInfo(const TestInfo& rhs)
00066     : _myname(rhs._myname),  _verbose(rhs._verbose),
00067       _verbose_level(rhs._verbose_level), _ostream(rhs._ostream)
00068     {
00069     }
00070 
00071     /*
00072      * @return The name of the current test.
00073      */
00074     string test_name()
00075     {
00076     return _myname;
00077     }
00078 
00079     /*
00080      * @return True if the verbose flag has been enabled.
00081      */
00082     bool
00083     verbose()
00084     {
00085     return _verbose;
00086     }
00087     
00088     /*
00089      * @return The verbose level.
00090      */
00091     int
00092     verbose_level()
00093     {
00094     return _verbose_level;
00095     }
00096 
00097     /*
00098      * @return The stream to which output should be sent.
00099      */
00100     ostream& out()
00101     {
00102     return _ostream;
00103     }
00104 private:
00105     string _myname;
00106     bool _verbose;
00107     int _verbose_level;
00108     ostream& _ostream;
00109 };
00110 
00119 class TestMain {
00120 public:
00124     TestMain(int argc, char * const argv[]) :
00125     _verbose(false), _verbose_level(0), _exit_status(true)
00126     {
00127     _progname = argv[0];
00128 
00129     for (int i = 1; i < argc; i++) {
00130         string argname;
00131         string argvalue = "";
00132         Arg a;
00133         // Argument flag
00134         if (argv[i][0] == '-') {
00135         // Long form argument.
00136         if (argv[i][1] == '-') {
00137             argname = argv[i];
00138         } else {
00139             argname = argv[i][1];
00140             argname = "-" + argname;
00141             if ('\0' != argv[i][2]) {
00142             argvalue = &argv[i][2];
00143             }
00144         }
00145         // Try and get the argument value if we don't already
00146         // have it.
00147         if ("" == argvalue && (i + 1) < argc) {
00148             if (argv[i + 1][0] != '-') {
00149             i++;
00150             argvalue = argv[i];
00151             }
00152         }
00153         if ("" == argvalue)
00154             a = Arg(Arg::FLAG, argname);
00155         else
00156             a = Arg(Arg::VALUE, argname, argvalue);
00157         } else {
00158         a = Arg(Arg::REST, argv[i]);
00159         }
00160         _args.push_back(a);
00161     }
00162     }
00163 
00175     string
00176     get_optional_args(const string &short_form, const string &long_form,
00177               const string &description)
00178     {
00179     _usage += short_form + "|" + long_form + " arg\t" + description + "\n";
00180 
00181     if (false == _exit_status)
00182         return "";
00183     list<Arg>::iterator i;
00184     for (i = _args.begin(); i != _args.end(); i++) {
00185         if (short_form == i->name() || long_form == i->name()) {
00186         bool has_value;
00187         string value;
00188         value = i->value(has_value);
00189         if (!has_value) {
00190             _exit_status = false;
00191             return "";
00192         }
00193         _args.erase(i);
00194         return value;
00195         }
00196     }
00197     return "";
00198     }
00199 
00211     bool
00212     get_optional_flag(const string &short_form, const string &long_form,
00213               const string &description)
00214     {
00215     _usage += short_form + "|" + long_form + " arg\t" + description + "\n";
00216 
00217     if (false == _exit_status)
00218         return false;
00219     list<Arg>::iterator i;
00220     for (i = _args.begin(); i != _args.end(); i++) {
00221         if (short_form == i->name() || long_form == i->name()) {
00222         _args.erase(i);
00223         return true;
00224         }
00225     }
00226     return false;
00227     }
00228 
00235     void
00236     complete_args_parsing()
00237     {
00238     _verbose = get_optional_flag("-v", "--verbose", "Verbose");
00239 
00240     string level = get_optional_args("-l",
00241                      "--verbose-level","Verbose level");
00242     if ("" != level)
00243         _verbose_level = atoi(level.c_str());
00244 
00245     bool h = get_optional_flag("-h", "--help","Print help information");
00246     bool q = get_optional_flag("-?", "--help","Print help information");
00247 
00248     if (h || q) {
00249         cerr << usage();
00250 	    ::exit(-1);
00251     }
00252 
00253     if (!_args.empty()) {
00254         list<Arg>::iterator i;
00255         for (i = _args.begin(); i != _args.end(); i++) {
00256         cerr << "Unused argument: " << i->name() << endl;
00257         }
00258         cerr << usage();
00259         _exit_status = false;
00260     }
00261     }
00262 
00267     bool get_verbose() const { return _verbose; }
00268 
00274     int get_verbose_level() const { return _verbose_level; }
00275 
00288     void
00289     run(string test_name, XorpCallback1<bool, TestInfo&>::RefPtr cb)
00290     {
00291     if (false == _exit_status)
00292         return;
00293 //      if (_verbose)
00294         cout << "Running: " << test_name << endl;
00295     TestInfo info(test_name, _verbose, _verbose_level, cout);
00296     if (!cb->dispatch(info)) {
00297         _exit_status = false;
00298         cerr << "Test Failed: " << test_name << endl;
00299     }
00300     else {
00301         cout << "Test Passed: " << test_name << endl;
00302     }
00303     }
00304 
00308     const string
00309     usage()
00310     {
00311     return "Usage " + _progname + ":\n" + _usage;
00312     }
00313 
00320     void
00321     failed(string error)
00322     {
00323     _error_string += error;
00324     _exit_status = false;
00325     }
00326 
00332     int
00333     exit()
00334     {
00335     if ("" != _error_string)
00336         cerr << _error_string;
00337 
00338     return _exit_status ? 0 : -1;
00339     }
00340 
00341 private:
00342     class Arg;
00343     string _progname;
00344     list<Arg> _args;
00345     bool _verbose;
00346     int _verbose_level;
00347     bool _exit_status;
00348     string _error_string;
00349     string _usage;
00350 
00351     class Arg {
00352     public:
00353     typedef enum {FLAG, VALUE, REST} arg_type;
00354     Arg() {}
00355 
00356     Arg(arg_type a, string name, string value = "")
00357         : _arg_type(a), _name(name), _value(value)
00358     {
00359         //  debug_msg("Argument type = %d flag name = %s value = %s\n",
00360         //        a, name.c_str(), value.c_str());
00361     }
00362 
00363     Arg(const Arg& rhs)
00364     {
00365         copy(rhs);
00366     }
00367 
00368     Arg& operator=(const Arg& rhs)
00369     {
00370         if (&rhs == this)
00371         return *this;
00372         copy(rhs);
00373 
00374         return *this;
00375     }
00376     
00377     void
00378     copy(const Arg& rhs)
00379     {
00380         _arg_type = rhs._arg_type;
00381         _name = rhs._name;
00382         _value = rhs._value;
00383     }
00384 
00385     const string&
00386     name()
00387     {
00388         return _name;
00389     }
00390 
00391     const string&
00392     value(bool& has_value)
00393     {
00394         if (VALUE != _arg_type) {
00395         cerr << "Argument " << _name <<
00396             " was not provided with a value\n";
00397         has_value = false;
00398         } else
00399         has_value = true;
00400 
00401         return _value;
00402     }
00403 
00404     private:
00405     arg_type _arg_type;
00406     string _name;
00407     string _value;
00408     };
00409 };
00410 
00411 #endif // __LIBXORP_TEST_MAIN_HH__
 All Classes Namespaces Functions Variables Typedefs Enumerations