Use ArgTraits instead of ValueExtractor specialization Bug 1711487

This commit is contained in:
macbishop 2007-06-14 21:02:01 +00:00
parent 847b8c9478
commit 00f07eb977
18 changed files with 488 additions and 416 deletions

View File

@ -1,5 +1,6 @@
noinst_PROGRAMS = test1 test2 test3 test4 test5 test6 test7 test8 test9 test10
noinst_PROGRAMS = test1 test2 test3 test4 test5 test6 test7 test8 test9 \
test10 test11 test12
test1_SOURCES = test1.cpp
test2_SOURCES = test2.cpp
@ -11,6 +12,8 @@ test7_SOURCES = test7.cpp
test8_SOURCES = test8.cpp
test9_SOURCES = test9.cpp
test10_SOURCES = test10.cpp
test11_SOURCES = test11.cpp
test12_SOURCES = test12.cpp
INCLUDES = -I$(top_srcdir)/include

52
examples/test11.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "tclap/CmdLine.h"
#include <iterator>
using namespace TCLAP;
// Define a simple 3D vector type
struct Vect3D {
double v[3];
// operator= will be used to assign to the vector
Vect3D& operator=(const std::string &str)
{
std::istringstream iss(str);
if (!(iss >> v[0] >> v[1] >> v[2]))
throw TCLAP::ArgParseException(str + " is not a 3D vector");
return *this;
}
std::ostream& print(std::ostream &os) const
{
std::copy(v, v + 3, std::ostream_iterator<double>(os, " "));
return os;
}
};
// Create an ArgTraits for the 3D vector type that declares it to be
// of string like type
namespace TCLAP {
template<>
struct ArgTraits<Vect3D> {
typedef StringLike ValueCategory;
};
}
int main(int argc, char *argv[])
{
CmdLine cmd("Command description message", ' ', "0.9");
ValueArg<Vect3D> vec("v", "vect", "vector",
true, Vect3D(), "3D vector", cmd);
try {
cmd.parse(argc, argv);
} catch(std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
vec.getValue().print(std::cout);
std::cout << std::endl;
}

68
examples/test12.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "tclap/CmdLine.h"
#include <iterator>
#include <algorithm>
using namespace TCLAP;
// Define a simple 3D vector type
struct Vect3D {
double v[3];
// operator= will be used to assign to the vector
Vect3D& operator=(const std::string &str)
{
std::istringstream iss(str);
if (!(iss >> v[0] >> v[1] >> v[2]))
throw TCLAP::ArgParseException(str + " is not a 3D vector");
return *this;
}
std::ostream& print(std::ostream &os) const
{
std::copy(v, v + 3, std::ostream_iterator<double>(os, " "));
return os;
}
};
std::ostream& operator<<(std::ostream &os, const Vect3D &v)
{
return v.print(os);
}
// Create an ArgTraits for the 3D vector type that declares it to be
// of string like type
namespace TCLAP {
template<>
struct ArgTraits<Vect3D> {
typedef StringLike ValueCategory;
};
}
int main(int argc, char *argv[])
{
CmdLine cmd("Command description message", ' ', "0.9");
MultiArg<Vect3D> vec("v", "vect", "vector",
true, "3D vector", cmd);
try {
cmd.parse(argc, argv);
} catch(std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
std::copy(vec.begin(), vec.end(),
std::ostream_iterator<Vect3D>(std::cout, "\n"));
std::cout << "REVERSED" << std::endl;
// use alt. form getValue()
std::vector<Vect3D> v(vec.getValue());
std::reverse(v.begin(), v.end());
std::copy(v.begin(), v.end(),
std::ostream_iterator<Vect3D>(std::cout, "\n"));
}

View File

@ -24,11 +24,27 @@
#ifndef TCLAP_ARGUMENT_H
#define TCLAP_ARGUMENT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#else
#define HAVE_SSTREAM
#endif
#include <string>
#include <vector>
#include <list>
#include <iostream>
#if defined(HAVE_SSTREAM)
#include <sstream>
typedef std::istringstream istringstream;
#elif defined(HAVE_STRSTREAM)
#include <strstream>
typedef std::istrstream istringstream;
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
#include <tclap/ArgException.h>
#include <tclap/Visitor.h>
#include <tclap/CmdLineInterface.h>
@ -350,6 +366,84 @@ typedef std::vector<Arg*>::iterator ArgVectorIterator;
*/
typedef std::list<Visitor*>::iterator VisitorListIterator;
// We use two empty structs to get compile type specialization
// function to work
/**
* A value like argument value type is a value that can be set using
* operator>>. This is the default value type.
*/
struct ValueLike {};
/**
* A string like argument value type is a value that can be set using
* operator=(string). Usefull if the value type contains spaces which
* will be broken up into individual tokens by operator>>.
*/
struct StringLike {};
/**
* Arg traits are used to get compile type specialization when parsing
* argument values. Using an ArgTraits you can specify the way that
* values gets assigned to any particular type during parsing. The two
* supported types are string like and value like.
*/
template<typename T>
struct ArgTraits {
typedef ValueLike ValueCategory;
};
/**
* Strings have string like argument traits.
*/
template<>
struct ArgTraits<std::string> {
typedef StringLike ValueCategory;
};
/*
* Extract a value of type T from it's string representation contained
* in strVal. The ValueLike parameter used to select the correct
* specialization of ExtractValue depending on the value traits of T.
* ValueLike traits use operator>> to assign the value from strVal.
*/
template<typename T> void
ExtractValue(T &destVal, const std::string& strVal, ValueLike vl)
{
std::istringstream is(strVal);
int valuesRead = 0;
while ( is.good() ) {
if ( is.peek() != EOF )
is >> destVal;
else
break;
valuesRead++;
}
if ( is.fail() )
throw( ArgParseException("Couldn't read argument value "
"from string '" + strVal + "'"));
if ( valuesRead > 1 )
throw( ArgParseException("More than one valid value parsed from "
"string '" + strVal + "'"));
}
/*
* Extract a value of type T from it's string representation contained
* in strVal. The ValueLike parameter used to select the correct
* specialization of ExtractValue depending on the value traits of T.
* StringLike uses assignment (operator=) to assign from strVal.
*/
template<typename T> void
ExtractValue(T &destVal, const std::string& strVal, StringLike sl)
{
destVal = strVal;
}
//////////////////////////////////////////////////////////////////////
//BEGIN Arg.cpp

View File

@ -29,135 +29,7 @@
#include <tclap/Arg.h>
#include <tclap/Constraint.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#else
#define HAVE_SSTREAM
#endif
#if defined(HAVE_SSTREAM)
#include <sstream>
#elif defined(HAVE_STRSTREAM)
#include <strstream>
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
namespace TCLAP {
template<class T> class MultiArg;
namespace MULTI_ARG_HELPER {
enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };
/**
* This class is used to extract a value from an argument.
* It is used because we need a special implementation to
* deal with std::string and making a specialiced function
* puts it in the T segment, thus generating link errors.
* Having a specialiced class makes the symbols weak.
* This is not pretty but I don't know how to make it
* work any other way.
*/
template<class T>
class ValueExtractor
{
friend class MultiArg<T>;
private:
/**
* Reference to the vector of values where the result of the
* extraction will be put.
*/
std::vector<T> &_values;
/**
* Constructor.
* \param values - Where the values extracted will be put.
*/
ValueExtractor(std::vector<T> &values) : _values(values) {}
/**
* Method that will attempt to parse the input stream for values
* of type T.
* \param val - Where the values parsed will be put.
*/
int extractValue( const std::string& val )
{
T temp;
#if defined(HAVE_SSTREAM)
std::istringstream is(val);
#elif defined(HAVE_STRSTREAM)
std::istrstream is(val.c_str());
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
int valuesRead = 0;
while ( is.good() )
{
if ( is.peek() != EOF )
is >> temp;
else
break;
valuesRead++;
}
if ( is.fail() )
return EXTRACT_FAILURE;
if ( valuesRead > 1 )
return EXTRACT_TOO_MANY;
_values.push_back(temp);
return 0;
}
};
/**
* Specialization for string. This is necessary because istringstream
* operator>> is not able to ignore spaces... meaning -x "X Y" will only
* read 'X'... and thus the specialization.
*/
template<>
class ValueExtractor<std::string>
{
friend class MultiArg<std::string>;
private:
/**
* Reference to the vector of strings where the result of the
* extraction will be put.
*/
std::vector<std::string> &_values;
/**
* Constructor.
* \param values - Where the strings extracted will be put.
*/
ValueExtractor(std::vector<std::string> &values) : _values(values) {}
/**
* Method that will attempt to parse the input stream for values
* of type std::string.
* \param val - Where the values parsed will be put.
*/
int extractValue( const std::string& val )
{
_values.push_back( val );
return 0;
}
};
} //namespace MULTI_ARG_HELPER
/**
* An argument that allows multiple values of type T to be specified. Very
* similar to a ValueArg, except a vector of values will be returned
@ -166,78 +38,83 @@ class ValueExtractor<std::string>
template<class T>
class MultiArg : public Arg
{
protected:
public:
typedef std::vector<T> container_type;
typedef typename container_type::iterator iterator;
typedef typename container_type::const_iterator const_iterator;
/**
* The list of values parsed from the CmdLine.
*/
std::vector<T> _values;
protected:
/**
* The description of type T to be used in the usage.
*/
std::string _typeDesc;
/**
* The list of values parsed from the CmdLine.
*/
std::vector<T> _values;
/**
* A list of constraint on this Arg.
*/
Constraint<T>* _constraint;
/**
* The description of type T to be used in the usage.
*/
std::string _typeDesc;
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - The string to be read.
*/
void _extractValue( const std::string& val );
/**
* A list of constraint on this Arg.
*/
Constraint<T>* _constraint;
bool _allowMore;
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - The string to be read.
*/
void _extractValue( const std::string& val );
public:
bool _allowMore;
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
public:
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
@ -245,45 +122,45 @@ class MultiArg : public Arg
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
@ -291,41 +168,53 @@ class MultiArg : public Arg
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns a vector of type T containing the values parsed from
* the command line.
*/
const std::vector<T>& getValue();
/**
* Returns a vector of type T containing the values parsed from
* the command line.
*/
const std::vector<T>& getValue();
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns an iterator over the values parsed from the command
* line.
*/
const_iterator begin() const { return _values.begin(); }
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Returns the end of the values parsed from the command
* line.
*/
const_iterator end() const { return _values.end(); }
/**
* Once we've matched the first value, then the arg is no longer
* required.
*/
virtual bool isRequired() const;
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
virtual bool allowMore();
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Once we've matched the first value, then the arg is no longer
* required.
*/
virtual bool isRequired() const;
virtual bool allowMore();
};
@ -492,24 +381,20 @@ bool MultiArg<T>::isRequired() const
template<class T>
void MultiArg<T>::_extractValue( const std::string& val )
{
MULTI_ARG_HELPER::ValueExtractor<T> ve(_values);
try {
T tmp;
ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
_values.push_back(tmp);
} catch( ArgParseException &e) {
throw ArgParseException(e.error(), toString());
}
int err = ve.extractValue(val);
if ( err == MULTI_ARG_HELPER::EXTRACT_FAILURE )
throw( ArgParseException("Couldn't read argument value "
"from string '" + val + "'", toString() ) );
if(err == MULTI_ARG_HELPER::EXTRACT_TOO_MANY)
throw( ArgParseException("More than one valid value "
"parsed from string '" + val + "'",
toString() ) );
if ( _constraint != NULL )
if ( ! _constraint->check( _values.back() ) )
throw( CmdLineParseException( "Value '" + val +
"' does not meet constraint: " +
_constraint->description(),
toString() ) );
if ( _constraint != NULL )
if ( ! _constraint->check( _values.back() ) )
throw( CmdLineParseException( "Value '" + val +
"' does not meet constraint: " +
_constraint->description(),
toString() ) );
}
template<class T>

View File

@ -29,135 +29,8 @@
#include <tclap/Arg.h>
#include <tclap/Constraint.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#else
#define HAVE_SSTREAM
#endif
#if defined(HAVE_SSTREAM)
#include <sstream>
#elif defined(HAVE_STRSTREAM)
#include <strstream>
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
namespace TCLAP {
template<class T> class ValueArg;
namespace VALUE_ARG_HELPER {
enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };
/**
* This class is used to extract a value from an argument.
* It is used because we need a special implementation to
* deal with std::string and making a specialiced function
* puts it in the T segment, thus generating link errors.
* Having a specialiced class makes the symbols weak.
* This is not pretty but I don't know how to make it
* work any other way.
*/
template<class T> class ValueExtractor
{
/**
*
*/
friend class ValueArg<T>;
private:
/**
* Reference to the value where the result of the extraction will
* be put.
*/
T &_value;
/**
* Constructor.
* \param value - Where the value extracted will be put.
*/
ValueExtractor(T &value) : _value(value) { }
/**
* Method that will attempt to parse the input stream for a value
* of type T.
* \param val - Where the value parsed will be put.
*/
int extractValue( const std::string& val )
{
#if defined(HAVE_SSTREAM)
std::istringstream is(val);
#elif defined(HAVE_STRSTREAM)
std::istrstream is(val.c_str());
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
int valuesRead = 0;
while ( is.good() )
{
if ( is.peek() != EOF )
is >> _value;
else
break;
valuesRead++;
}
if ( is.fail() )
return EXTRACT_FAILURE;
if ( valuesRead > 1 )
return EXTRACT_TOO_MANY;
return 0;
}
};
/**
* Specialization for string. This is necessary because istringstream
* operator>> is not able to ignore spaces... meaning -x "X Y" will only
* read 'X'... and thus the specialization.
*/
template<> class ValueExtractor<std::string>
{
/**
*
*/
friend class ValueArg<std::string>;
private:
/**
* Reference to the value where the result of the extraction will
* be put.
*/
std::string &_value;
/**
* Constructor.
* \param value - Where the value extracted will be put.
*/
ValueExtractor(std::string &value) : _value(value) {}
/**
* Method that will attempt to parse the input stream for a value
* of type std::string.
* \param val - Where the string parsed will be put.
*/
int extractValue( const std::string& val )
{
_value = val;
return 0;
}
};
} //namespace VALUE_ARG_HELPER
/**
* The basic labeled argument that parses a value.
* This is a template class, which means the type T defines the type
@ -500,25 +373,18 @@ std::string ValueArg<T>::longID(const std::string& val) const
template<class T>
void ValueArg<T>::_extractValue( const std::string& val )
{
VALUE_ARG_HELPER::ValueExtractor<T> ve(_value);
try {
ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
} catch( ArgParseException &e) {
throw ArgParseException(e.error(), toString());
}
int err = ve.extractValue(val);
if ( err == VALUE_ARG_HELPER::EXTRACT_FAILURE )
throw( ArgParseException("Couldn't read argument value from string '" +
val + "'", toString() ) );
if ( err == VALUE_ARG_HELPER::EXTRACT_TOO_MANY )
throw( ArgParseException(
"More than one valid value parsed from string '" +
val + "'", toString() ) );
if ( _constraint != NULL )
if ( ! _constraint->check( _value ) )
throw( CmdLineParseException( "Value '" + val +
"' does not meet constraint: " +
_constraint->description(),
toString() ) );
if ( _constraint != NULL )
if ( ! _constraint->check( _value ) )
throw( CmdLineParseException( "Value '" + val +
+ "' does not meet constraint: "
+ _constraint->description(),
toString() ) );
}
} // namespace TCLAP

View File

@ -2,8 +2,9 @@
let "suc = 0"
let "fail = 0"
NUMTEST=67
for (( tno = 1 ; $tno < 62 ; tno = $tno + 1 )); do
for (( tno = 1 ; $tno <= $NUMTEST ; tno = $tno + 1 )); do
./testCheck.sh $tno
if [ "$?" -eq "0" ]; then
echo "OK"

9
tests/test63.out Normal file
View File

@ -0,0 +1,9 @@
PARSE ERROR:
Required argument missing: vect
Brief USAGE:
../examples/test11 -v <3D vector> [--] [--version] [-h]
For complete USAGE and HELP type:
../examples/test11 --help

13
tests/test63.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# this tests whether all required args are listed as
# missing when no arguments are specified
# failure
../examples/test11 > tmp.out 2>&1
if cmp -s tmp.out $srcdir/test63.out; then
exit 0
else
exit 1
fi

1
tests/test64.out Normal file
View File

@ -0,0 +1 @@
1 2 3

13
tests/test64.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# this tests whether all required args are listed as
# missing when no arguments are specified
# failure
../examples/test11 -v "1 2 3" > tmp.out 2>&1
if cmp -s tmp.out $srcdir/test64.out; then
exit 0
else
exit 1
fi

9
tests/test65.out Normal file
View File

@ -0,0 +1,9 @@
1 2 3
4 5 6
7 8 9
-1 0.2 0.4
REVERSED
-1 0.2 0.4
7 8 9
4 5 6
1 2 3

14
tests/test65.sh Normal file
View File

@ -0,0 +1,14 @@
#!/bin/sh
# this tests whether all required args are listed as
# missing when no arguments are specified
# failure
../examples/test12 -v "1 2 3" -v "4 5 6" -v "7 8 9" -v "-1 0.2 0.4" \
> tmp.out 2>&1
if cmp -s tmp.out $srcdir/test65.out; then
exit 0
else
exit 1
fi

9
tests/test66.out Normal file
View File

@ -0,0 +1,9 @@
PARSE ERROR:
Required argument missing: vect
Brief USAGE:
../examples/test12 -v <3D vector> ... [--] [--version] [-h]
For complete USAGE and HELP type:
../examples/test12 --help

13
tests/test66.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# this tests whether all required args are listed as
# missing when no arguments are specified
# failure
../examples/test12 > tmp.out 2>&1
if cmp -s tmp.out $srcdir/test66.out; then
exit 0
else
exit 1
fi

9
tests/test67.out Normal file
View File

@ -0,0 +1,9 @@
PARSE ERROR: Argument: -v (--vect)
a 1 0.3 is not a 3D vector
Brief USAGE:
../examples/test12 -v <3D vector> ... [--] [--version] [-h]
For complete USAGE and HELP type:
../examples/test12 --help

13
tests/test67.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# this tests whether all required args are listed as
# missing when no arguments are specified
# failure
../examples/test12 -v "a 1 0.3" > tmp.out 2>&1
if cmp -s tmp.out $srcdir/test67.out; then
exit 0
else
exit 1
fi

View File

@ -7,7 +7,7 @@ if [ "$1" == "" ]
then
echo "USAGE: testCheck.sh <test num>"
else
cmd="./test$1.sh"
cmd="sh ./test$1.sh"
out="test$1.out"
$cmd
if cmp -s tmp.out $out