Source: ../../libxorp/test_main.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2009 XORP, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License, Version
// 2.1, June 1999 as published by the Free Software Foundation.
// Redistribution and/or modification of this program under the terms of
// any other version of the GNU Lesser General Public License is not
// permitted.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
// see the GNU Lesser General Public License, Version 2.1, a copy of
// which can be found in the XORP LICENSE.lgpl file.
//
// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
// http://xorp.net
// $XORP: xorp/libxorp/test_main.hh,v 1.22 2009/01/05 18:30:58 jtc Exp $
#ifndef __LIBXORP_TEST_MAIN_HH__
#define __LIBXORP_TEST_MAIN_HH__
#include <string>
#include <list>
#include "xorp.h"
#include "callback.hh"
/**
* Macro to use to generate debugging output when the verbose flag is
* enabled.
*/
#define DOUT(info) \
if (info.verbose()) \
info.out() << __FUNCTION__ << ":" \
<< __LINE__ << ":" \
<< info.test_name() << ": "
/**
* Only generate debugging output if the verbose_level is equal to or above
* threshold.
*/
#define DOUT_LEVEL(info, level) \
if (info.verbose() && info.verbose_level() >= level) \
info.out() << __FUNCTION__ << ":" \
<< __LINE__ << ":" \
<< info.test_name() << ": "
/**
* This class is passed as the first argument to each test function/method.
*/
class TestInfo {
public:
TestInfo(string myname, bool verbose, int verbose_level, ostream& o) :
_myname(myname), _verbose(verbose), _verbose_level(verbose_level),
_ostream(o)
{
}
TestInfo(const TestInfo& rhs)
: _myname(rhs._myname), _verbose(rhs._verbose),
_verbose_level(rhs._verbose_level), _ostream(rhs._ostream)
{
}
/*
* @return The name of the current test.
*/
string test_name()
{
return _myname;
}
/*
* @return True if the verbose flag has been enabled.
*/
bool
verbose()
{
return _verbose;
}
/*
* @return The verbose level.
*/
int
verbose_level()
{
return _verbose_level;
}
/*
* @return The stream to which output should be sent.
*/
ostream& out()
{
return _ostream;
}
private:
string _myname;
bool _verbose;
int _verbose_level;
ostream& _ostream;
};
/**
* A helper class for test programs.
*
* This class is used to parse the command line arguments and return
* the exit status from the test functions/methods. An example of how
* to use this class can be found in test_test_main.cc.
*
*/
class TestMain {
public:
/**
* Start the parsing of command line arguments.
*/
TestMain(int argc, char * const argv[]) :
_verbose(false), _verbose_level(0), _exit_status(true)
{
_progname = argv[0];
for (int i = 1; i < argc; i++) {
string argname;
string argvalue = "";
Arg a;
// Argument flag
if (argv[i][0] == '-') {
// Long form argument.
if (argv[i][1] == '-') {
argname = argv[i];
} else {
argname = argv[i][1];
argname = "-" + argname;
if ('\0' != argv[i][2]) {
argvalue = &argv[i][2];
}
}
// Try and get the argument value if we don't already
// have it.
if ("" == argvalue && (i + 1) < argc) {
if (argv[i + 1][0] != '-') {
i++;
argvalue = argv[i];
}
}
if ("" == argvalue)
a = Arg(Arg::FLAG, argname);
else
a = Arg(Arg::VALUE, argname, argvalue);
} else {
a = Arg(Arg::REST, argv[i]);
}
_args.push_back(a);
}
}
/**
* Get an optional argument from the command line.
*
* @param short_form The short form of the argument e.g. "-t".
* @param long_form The long form of the argument
* e.g. "--testing".
* @param description The description of this argument that will
* be used in the usage message.
* @return the argument or "" if not found or an error occured in
* previous parsing of the arguments.
*/
string
get_optional_args(const string &short_form, const string &long_form,
const string &description)
{
_usage += short_form + "|" + long_form + " arg\t" + description + "\n";
if (false == _exit_status)
return "";
list<Arg>::iterator i;
for (i = _args.begin(); i != _args.end(); i++) {
if (short_form == i->name() || long_form == i->name()) {
bool has_value;
string value;
value = i->value(has_value);
if (!has_value) {
_exit_status = false;
return "";
}
_args.erase(i);
return value;
}
}
return "";
}
/**
* Get an optional flag from the command line.
*
* @param short_form The short form of the argument e.g. "-t".
* @param long_form The long form of the argument
* e.g. "--testing".
* @param description The description of this argument that will
* be used in the usage message.
* @return true if the flag is present or false found or an error
* occured in previous parsing of the arguments.
*/
bool
get_optional_flag(const string &short_form, const string &long_form,
const string &description)
{
_usage += short_form + "|" + long_form + " arg\t" + description + "\n";
if (false == _exit_status)
return false;
list<Arg>::iterator i;
for (i = _args.begin(); i != _args.end(); i++) {
if (short_form == i->name() || long_form == i->name()) {
_args.erase(i);
return true;
}
}
return false;
}
/**
* Complete parsing the arguments.
*
* Process generic arguments and verify that there are no
* arguments left unprocessed.
*/
void
complete_args_parsing()
{
_verbose = get_optional_flag("-v", "--verbose", "Verbose");
string level = get_optional_args("-l",
"--verbose-level","Verbose level");
if ("" != level)
_verbose_level = atoi(level.c_str());
bool h = get_optional_flag("-h", "--help","Print help information");
bool q = get_optional_flag("-?", "--help","Print help information");
if (h || q) {
cerr << usage();
::exit(-1);
}
if (!_args.empty()) {
list<Arg>::iterator i;
for (i = _args.begin(); i != _args.end(); i++) {
cerr << "Unused argument: " << i->name() << endl;
}
cerr << usage();
_exit_status = false;
}
}
/**
* Get the state of the verbose flag. Used by test programs that
* don't use the run method to run tests.
*/
bool get_verbose() const { return _verbose; }
/**
* Get the the verbose level, should only be used if get_verbose()
* is true. Used by test programs that don't use the run method to
* run the tests.
*/
int get_verbose_level() const { return _verbose_level; }
/**
* Run a test function/method. The test function/method is passed
* a TestInfo. The test function/method should return
* true for success and "false for
* failure.
*
* To run a function call "test":
* run("test", callback(test));
*
* @param test_name The name of the test.
* @param cb Callback object.
*/
void
run(string test_name, XorpCallback1<bool, TestInfo&>::RefPtr cb)
{
if (false == _exit_status)
return;
// if (_verbose)
cout << "Running: " << test_name << endl;
TestInfo info(test_name, _verbose, _verbose_level, cout);
switch (cb->dispatch(info)) {
case true:
break;
case false:
_exit_status = false;
cerr << "Failed: " << test_name << endl;
break;
}
}
/**
* @return The usage string.
*/
const string
usage()
{
return "Usage " + _progname + ":\n" + _usage;
}
/**
* Mark the tests as having failed. Used for setting an error
* condition from outside a test.
*
* @param error Error string.
*/
void
failed(string error)
{
_error_string += error;
_exit_status = false;
}
/**
* Must be called at the end of the tests.
*
* @return The status of the tests. Should be passed to exit().
*/
int
exit()
{
if ("" != _error_string)
cerr << _error_string;
return _exit_status ? 0 : -1;
}
private:
class Arg;
string _progname;
list<Arg> _args;
bool _verbose;
int _verbose_level;
bool _exit_status;
string _error_string;
string _usage;
class Arg {
public:
typedef enum {FLAG, VALUE, REST} arg_type;
Arg() {}
Arg(arg_type a, string name, string value = "")
: _arg_type(a), _name(name), _value(value)
{
// debug_msg("Argument type = %d flag name = %s value = %s\n",
// a, name.c_str(), value.c_str());
}
Arg(const Arg& rhs)
{
copy(rhs);
}
Arg& operator=(const Arg& rhs)
{
if (&rhs == this)
return *this;
copy(rhs);
return *this;
}
void
copy(const Arg& rhs)
{
_arg_type = rhs._arg_type;
_name = rhs._name;
_value = rhs._value;
}
const string&
name()
{
return _name;
}
const string&
value(bool& has_value)
{
if (VALUE != _arg_type) {
cerr << "Argument " << _name <<
" was not provided with a value\n";
has_value = false;
} else
has_value = true;
return _value;
}
private:
arg_type _arg_type;
string _name;
string _value;
};
};
#endif // __LIBXORP_TEST_MAIN_HH__
Generated by: pavlin on kobe.xorp.net on Wed Jan 7 19:10:36 2009, using kdoc 2.0a54+XORP.