build: remove unused options code

This commit is contained in:
Danny Robson 2015-07-02 17:24:49 +10:00
parent 536284a56d
commit 991558fc7f
4 changed files with 0 additions and 1185 deletions

View File

@ -248,11 +248,6 @@ UTIL_FILES = \
view.cpp \
view.hpp
# zlib.cpp
# zlib.hpp
# options.cpp
# options.hpp
if PLATFORM_LINUX
UTIL_FILES += \
backtrace_execinfo.cpp \

View File

@ -1,605 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#include "options.hpp"
#include "debug.hpp"
#include "string.hpp"
#include "types.hpp"
#include "types/casts.hpp"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <cstring>
#include <iostream>
#include <stdexcept>
using util::option;
using util::nulloption;
using util::presentoption;
using util::valueoption;
using util::bytesoption;
using util::processor;
///////////////////////////////////////////////////////////////////////////////
/// Generic option operations, failure or default modes
option::option (char _letter,
const char *_name,
const char *_desc,
bool _required):
m_shortopt (_letter),
m_longopt (_name),
m_description(_desc),
m_required (_required),
m_found (false)
{ reset(); }
//-----------------------------------------------------------------------------
void
option::execute (void)
{
throw std::runtime_error(
"Cannot provide no value for the option '" + m_longopt + "'"
);
}
//-----------------------------------------------------------------------------
void
option::execute (const std::string& data)
{
assert(data.size() > 0);
throw std::runtime_error(
"Cannot provide a value for the option '" + m_longopt + "'"
);
}
//-----------------------------------------------------------------------------
std::ostream&
operator<< (std::ostream & os, const option& opt)
{
os << (opt.is_required () ? " -" : "[-" ) << opt.shortopt ()
<< (opt.is_required () ? " \t" : "]\t") << opt.longopt ()
<< "\t" << opt.description ();
return os;
}
//-----------------------------------------------------------------------------
void
option::finish (void)
{
if (m_required && !m_found)
throw std::runtime_error ("Required argument not found: " + m_longopt);
}
///////////////////////////////////////////////////////////////////////////////
nulloption::nulloption (char _letter,
const char *_name,
const char *_desc,
bool _required):
option (_letter, _name, _desc, _required)
{ ; }
///////////////////////////////////////////////////////////////////////////////
presentoption::presentoption (char _letter,
const char *_name,
const char *_desc,
bool *_data,
bool _required):
option (_letter, _name, _desc, _required),
m_data (_data)
{ ; }
//-----------------------------------------------------------------------------
void
presentoption::execute (void)
{
*m_data = true;
m_found = true;
}
///////////////////////////////////////////////////////////////////////////////
namespace util {
template<>
bool&
valueoption<bool>::get_arg(const std::string& arg, bool *val)
{
if (arg == "true" || arg == "yes" || arg == "1")
return *val = true;
else if (arg == "false" || arg == "no" || arg == "0")
return *val = false;
else
throw std::domain_error("Invalid form for boolean argument");
}
template <typename T>
T&
valueoption<T>::get_arg(const std::string &arg,
T *val)
{
std::istringstream stream (arg, std::istringstream::in);
stream.exceptions (
std::istringstream::failbit
| std::istringstream::badbit
);
stream >> *val;
return *val;
}
}
//-----------------------------------------------------------------------------
template std::string& util::valueoption<std::string>::get_arg (const std::string&, std::string*);
template int16_t& util::valueoption< int16_t>::get_arg (const std::string&, int16_t*);
template int32_t& util::valueoption< int32_t>::get_arg (const std::string&, int32_t*);
template int64_t& util::valueoption< int64_t>::get_arg (const std::string&, int64_t*);
template uint16_t& util::valueoption<uint16_t>::get_arg (const std::string&, uint16_t*);
template uint32_t& util::valueoption<uint32_t>::get_arg (const std::string&, uint32_t*);
template uint64_t& util::valueoption<uint64_t>::get_arg (const std::string&, uint64_t*);
///////////////////////////////////////////////////////////////////////////////
bytesoption::bytesoption (char _letter,
const char *_name,
const char *_desc,
size_t *_data,
bytestype _type,
bytesmodifier _modifier,
bool _required):
valueoption<size_t> (_letter, _name, _desc, _data, _required),
m_type (_type),
m_modifier (_modifier)
{ ; }
//-----------------------------------------------------------------------------
bytesoption::bytestype
bytesoption::type_from_character (char c)
{
switch (c) {
case 'e':
case 'E':
return BYTES_EXA;
case 'p':
case 'P':
return BYTES_PETA;
case 't':
case 'T':
return BYTES_TERA;
case 'g':
case 'G':
return BYTES_GIGA;
case 'm':
case 'M':
return BYTES_MEGA;
case 'k':
case 'K':
return BYTES_KILO;
default:
throw std::domain_error("Invalid magnitude specifier");
}
}
//-----------------------------------------------------------------------------
void
bytesoption::execute (const std::string& data)
{
// We shouldn't get this far into processing with a zero sized argument,
// that's what the null data execute function is for.
assert (data.size () > 0);
size_t defaultvalue = *m_data;
try {
bytesmodifier modifier = m_modifier;
size_t cursor = data.size () - 1;
// Consume an optional trailing `byte' type
if (data[cursor] == 'B' || data[cursor] == 'b') {
if (cursor == 0)
throw std::invalid_argument ("Size is too short");
--cursor;
}
// Check if we explicitly request base2
if (data[cursor] == 'i') {
modifier = BYTES_BASE2;
if (cursor == 0)
throw std::invalid_argument("Size is too short");
--cursor;
}
// Determine what constant factor is needed for the raw size
uint64_t multiplier = 1;
uint64_t modifier_factor;
switch (modifier) {
case BYTES_BASE2:
modifier_factor = 1024;
break;
case BYTES_BASE10:
modifier_factor = 1000;
break;
default:
unreachable ();
}
// Find the difference in magnitude between what is desired, and what
// is specified by the user. Raise the multiplier by that magnitude.
bytestype specified = m_type;
try {
specified = type_from_character (data[cursor]);
// If the character is a digit, it just means the user skipped the
// size specifier, which is ok.
} catch (std::domain_error &x) {
if (!isdigit (data[cursor]))
throw std::invalid_argument ("Not a size");
// Falsely increment the cursor if there's no size specifier...
++cursor;
}
// ... so that we can easily decrement the cursor without special logic
// after reading the specifiers.
--cursor;
multiplier = static_cast<uintmax_t> (std::pow (modifier_factor, (int)specified));
get_arg (data.substr(0, cursor + 1), m_data);
*m_data *= multiplier;
} catch (...) {
// Ensure that we haven't nuked a default value due to a half
// completed calculation followed by an exception.
*m_data = defaultvalue;
throw;
}
m_found = true;
}
///////////////////////////////////////////////////////////////////////////////
///
/// Internal helper options. Print help and usage.
/// A callback to the processor which triggers output of the help message.
///
/// This should never be instanced by a user of the system. The processor will
/// automatically adds this to its available options where needed.
class helpoption : public option
{
protected:
static const char HELP_CHARACTER;
static const char *HELP_NAME;
static const char *HELP_DESCRIPTION;
processor * m_processor;
public:
helpoption (processor * _processor):
option (HELP_CHARACTER, HELP_NAME, HELP_DESCRIPTION, false),
m_processor (_processor)
{ ; }
virtual void execute (void);
virtual void execute (const std::string& data)
{ option::execute (data); }
};
//-----------------------------------------------------------------------------
const char helpoption::HELP_CHARACTER = 'h';
const char *helpoption::HELP_NAME = "help";
const char *helpoption::HELP_DESCRIPTION =
"display help and usage information";
//-----------------------------------------------------------------------------
void
helpoption::execute (void)
{
m_processor->print_usage ();
exit (EXIT_SUCCESS);
}
///////////////////////////////////////////////////////////////////////////////
processor::processor ()
{
add_option (std::make_unique<helpoption> (this));
}
//-----------------------------------------------------------------------------
processor::~processor ()
{ ; }
//-----------------------------------------------------------------------------
void
processor::print_usage (void)
{
std::cout << "Usage: " << m_command << " [options]\n";
for (const auto &i: m_options)
std::cout << '\t' << *i << '\n';
}
///----------------------------------------------------------------------------
/// Parse a single argument in short form. We are given an offset into the
/// argument array, and arguments. Establishes whether a value is present and
/// passes control over to the option.
///
/// The format of the options are "-f [b]" || "-abcde"
///
/// @param pos the current offset into the argument array
/// @param argc the size of the argument array
/// @param argv the argument array given to the application
///
/// @return the number of tokens consumed for this option; must be at least 1.
unsigned int
processor::parse_short (int pos, int argc, const char **argv)
{
assert (pos > 0);
assert (pos < argc);
assert (argv[pos] != NULL);
const char *arg = argv[pos];
// Must begin with a dash, then have at least one non-dash character
assert (arg[0] == '-');
assert (arg[1] != '-');
assert (strlen(arg) >= 2);
// Check if we have a value option, Ie `-a [val]`
// First: must be of form '-[a-zA-Z]'.
if (strlen (arg) == 2) {
// Second: the next segment (which contains the value) shouldn't begin
// with a dash.
if (pos + 1 < argc && argv[pos+1][0] != '-') {
option * o = m_shortopt[arg[1]];
if (!o)
throw std::runtime_error ("Cannot match option");
o->execute (argv[pos+1]);
return 2;
}
}
// We must have a string of no-value flags, `-abcdef...`, execute each
// option in the list after the dash.
for(unsigned int i = 1; i < strlen (arg); ++i) {
option * o = m_shortopt[arg[i]];
if (!o)
throw std::runtime_error ("Cannot match option");
o->execute ();
}
return 1;
}
///----------------------------------------------------------------------------
///
/// Parse a single argument in long form. We are given an offset into the
/// argument array, and arguments. Establishes whether a value is present and
/// passes control over to the option.
///
/// The format of the options are "--foo[=bar]"
///
/// @param pos the current offset into the argument array
/// @param argc the size of the argument array
/// @param argv the argument array given to the application`--foo[=bar]`
///
/// @return the number of tokens consumed for this option; must be 1.
unsigned int
processor::parse_long (int pos, int argc, const char ** argv)
{
assert (pos > 0);
assert (pos < argc);
assert (argv[pos] != NULL);
const char *arg = argv[pos];
// We must have at least two hyphens, and two letters (else a short opt)
assert (arg[0] == '-');
assert (arg[1] == '-');
assert (strlen (arg) >= 4);
// Skip past the dashes to the argument name
arg += 2;
// If there's an equals it has a value to extract
const char *data = strchr (arg, '=');
option *o = data ? m_longopt[std::string (arg, data++)]
: m_longopt[arg];
if (!o)
throw std::runtime_error ("Cannot match option");
if (data)
o->execute (data);
else
o->execute ();
return 1;
}
///----------------------------------------------------------------------------
///
/// Pass long and short options to specific parsing handlers.
///
/// Establishes enough context to determine if the argument is long, short, or
/// none. The functions parse_long and parse_short are given the task of
/// dispatching control to the relevant option handlers.
///
/// @param argc the raw parameter from the application main
/// @param argv the raw parameter from the application main
void
processor::parse_args (int argc, const char ** argv)
{
// While technically we can have zero arguments, for practical purposes
// this is a reasonable method at catching odd errors in the library.
assert (argc > 0);
assert (argv[0]);
m_command.assign (argv[0]);
// Must make sure each option has a chance to reset state (clear flags,
// etc) between parses
for (auto &i: m_options)
i->reset ();
const int FIRST_ARGUMENT = 1;
try {
for (int i = FIRST_ARGUMENT; i < argc; ++i) {
// An argument must begin with a dash, if not we've reached the
// end of the argument lists or we have a parsing error.
if (argv[i][0] != '-')
return;
// An argument must consist of at least one non-dash character
if (strlen (argv[i]) <= 1)
throw std::runtime_error ("Invalid argument");
// Actually hand off args to be parsed. Subtract one from the
// tokens consumed, as the for loop increments tokens too.
unsigned int consumed;
if (argv[i][1] != '-')
consumed = parse_short (i, argc, argv);
else
consumed = parse_long (i, argc, argv);
assert (consumed >= 1);
i += sign_cast<int> (consumed - 1);
}
} catch (std::runtime_error &x) {
print_usage ();
exit (EXIT_FAILURE);
}
for (auto &i: m_options)
i->finish ();
}
//-----------------------------------------------------------------------------
void
processor::add_option (std::unique_ptr<option> opt)
{
if (m_shortopt.find (opt->shortopt ()) != m_shortopt.end ())
throw std::logic_error ("Short option already exists");
if (m_longopt.find (opt->longopt ()) != m_longopt.end ())
throw std::logic_error ("Long option already exists");
m_shortopt[opt->shortopt ()] = opt.get ();
m_longopt [opt->longopt ()] = opt.get ();
m_options.push_back (move (opt));
}
//-----------------------------------------------------------------------------
std::unique_ptr<option>
processor::remove_option (char letter)
{
// Locate the option by short name
const auto s_candidate = m_shortopt.find (letter);
if (s_candidate == m_shortopt.end ())
throw std::logic_error ("Cannot remove an option which is not present");
option *target = (*s_candidate).second;
// Locate the long option entry
const auto l_candidate = m_longopt.find (target->longopt ());
assert (l_candidate != m_longopt.end ());
// Remove all references and return
auto prime = std::find_if (
m_options.begin (),
m_options.end (),
[&target] (std::unique_ptr<option> &rhs) { return rhs.get () == target; }
);
std::unique_ptr<option> opt = move (*prime);
m_shortopt.erase (s_candidate);
m_longopt.erase (l_candidate);
m_options.erase (prime);
return opt;
}
//-----------------------------------------------------------------------------
std::unique_ptr<option>
processor::remove_option (const char *name)
{
// Locate the option by long name
const auto l_candidate = m_longopt.find (name);
if (l_candidate == m_longopt.end ())
throw std::logic_error ("Cannot remove an option which is not present");
option *target = (*l_candidate).second;
// Locate the short option entry
const auto s_candidate = m_shortopt.find (target->shortopt ());
assert (s_candidate != m_shortopt.end ());
// Remove all references and return
auto prime = std::find_if (
m_options.begin (),
m_options.end (),
[&target] (std::unique_ptr<option> &rhs) { return rhs.get () == target; }
);
std::unique_ptr<option> opt = move (*prime);
m_shortopt.erase (s_candidate);
m_longopt.erase (l_candidate);
m_options.erase (prime);
return opt;
}

View File

@ -1,295 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2013-2014 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_OPTIONS_HPP
#define __UTIL_OPTIONS_HPP
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
/**
* Maximum length of an option, its value, and any supplementary characters
* required for interpreting them. Ie, strlen("--foo=bar")
*/
const size_t MAX_CHUNK_LENGTH = 1023;
namespace util {
/**
* The generic base class for all options.
*
* Stores enough information to determine whether a short or long style option
* has been specified. The `execute' methods performs an action if the option
* is either present, or present with a value.
*
* By default they will throw an exception and can be relied upon to provide
* some form of abort action.
*/
class option {
protected:
char m_shortopt;
const std::string m_longopt;
const std::string m_description;
bool m_required;
bool m_found;
public:
option (char _letter,
const char *_name,
const char *_desc,
bool _required);
virtual ~option() { ; }
virtual void execute (void) = 0;
virtual void execute (const std::string& _data) = 0;
virtual void finish (void);
virtual bool is_required (void) const
{ return m_required; }
virtual void reset(void)
{ m_found = false; }
virtual char shortopt(void) const
{ return m_shortopt; }
virtual const std::string& longopt(void) const
{ return m_longopt; }
virtual const std::string& description(void) const
{ return m_description; }
};
/**
* Specifies a debugging or deprecated option.
*
* The option will be recognised but no action will be performed when
* encountered. A description will still be visible when usage information is
* printed.
*/
class nulloption : public option {
public:
nulloption(char _letter,
const char *_name,
const char *_desc,
bool _required = false);
virtual void execute(void)
{ m_found = true; }
virtual void execute(const std::string&)
{ m_found = true; }
};
/**
* Sets a boolean value to reflect if the option has been specified.
*
* A provided boolean pointer will be set to false if the option isn't
* present, true if present.
* Assumes that the user will not modify the value for the duration of option
* processing.
* Throws an exception if a value is specified for the option.
*/
class presentoption : public option {
protected:
bool *m_data;
public:
presentoption(char _letter,
const char *_name,
const char *_desc,
bool *_data,
bool _required = false);
virtual void execute(void);
virtual void execute(const std::string& data)
{ option::execute(data); }
virtual void reset(void)
{ *m_data = false; }
};
/**
* Parses a value given on the command line into a specified type.
*
* Given a value, return it to the user via the specified pointer. Uses the
* istream operators to read the value, so it should be relatively generic.
* If the value is malformed then an exception will be thrown.
* If there is no value, then perform the default action.
*
* It is safe to assume that when no value has been extracted the data pointer
* provided will not be overwritten. Useful for pre-loading with default
* values.
*/
template<typename T>
class valueoption : public option {
protected:
T *m_data;
public:
valueoption(char _letter,
const char *_name,
const char *_desc,
T *_data,
bool _required = false):
option (_letter, _name, _desc, _required),
m_data (_data)
{ ; }
virtual void execute(void)
{ option::execute(); }
virtual void execute(const std::string& data) {
get_arg(data, m_data);
m_found = true;
}
protected:
// Retrieve string to value conversion
static
T& get_arg(const std::string &arg,
T *val);
static
T& get_arg(const std::string &_arg,
T *val,
const T &defaultval) {
try {
return get_arg(_arg, val);
} catch(...) {
return *val = defaultval;
}
}
};
/**
* Interpret a (possibly) numeric value as a data size.
*
* A developer specifies the default scale of the value and what base it is
* to be interpreted in - when not otherwise explicitly stated in the
* arguments.
*
* Recognises various postfixes and modifiers to a numeric value such as MiB.
*/
class bytesoption : public valueoption<size_t> {
public:
/* Description of types available for parsing
*/
enum bytestype {
BYTES_SINGLE = 0,
BYTES_KILO = 1,
BYTES_MEGA = 2,
BYTES_GIGA = 3,
BYTES_TERA = 4,
BYTES_PETA = 5,
BYTES_EXA = 6,
// Currently does not support yota or zeta as there can be
// trouble converting them without loss into 64bit quantities.
// That and they're fricking huge...
//
// BYTES_ZETA,
// BYTES_YOTA,
NUM_BYTESTYPE
};
enum bytesmodifier {
BYTES_BASE2,
BYTES_BASE10,
NUM_BYTESMODIFIER
};
protected:
bytestype m_type;
bytesmodifier m_modifier;
static bytestype type_from_character(char c);
public:
/* Constructors and methods
*/
bytesoption(char _letter,
const char *_name,
const char *_desc,
size_t *_data,
bytestype _type = BYTES_SINGLE,
bytesmodifier _modifier = BYTES_BASE2,
bool _required = false);
virtual void execute(const std::string &);
};
/**
* High level handler for option registration, dispatch, and interpretation.
*
* The processor is the central point of operation on a program's arguments.
* It contains a list of all options which will interpret and act upon any
* arguments. These must be registered by the user prior to argument parsing,
* each of which must be primed with data to act upon separately.
*
* parse_args will perform minimal interpretation of the arguments to allow
* dispatch to registered options. No direct actions upon any input is
* performed within this class, merely dispatch and tokenisation.
*/
class processor {
protected:
std::map<char, option *> m_shortopt;
std::map<std::string, option *> m_longopt;
std::list<std::unique_ptr<option>> m_options;
// The command to execute the application
std::string m_command;
protected:
unsigned int parse_short(int pos, int argc, const char ** argv);
unsigned int parse_long(int pos, int argc, const char ** argv);
public:
processor();
~processor();
void print_usage(void);
// TODO: Use function overloading here...
void parse_args(int argc, const char ** argv);
void parse_args(int argc, char ** argv)
{ parse_args(argc, const_cast<const char**>(argv)); }
void parse_stream(std::istream & is);
void add_option(std::unique_ptr<option>);
std::unique_ptr<option> remove_option(char letter);
std::unique_ptr<option> remove_option(const char * name);
std::unique_ptr<option> remove_option(const std::string& name)
{ return remove_option (name.c_str()); }
std::unique_ptr<option> remove_option(const option *opt)
{ return remove_option (opt->longopt ()); }
};
}
#endif

View File

@ -1,280 +0,0 @@
#include "options.hpp"
#include "debug.hpp"
#include "tap.hpp"
#include "types.hpp"
#include <cassert>
#include <cstdlib>
#include <string>
#include <stdexcept>
#include <limits>
#include <sstream>
#include <cstdint>
#include <memory>
//-----------------------------------------------------------------------------
// Check that null options don't throw anything
void
test_null_opt (void) {
std::unique_ptr<util::processor> p(new util::processor());
p->add_option(std::make_unique<util::nulloption> ('n', "null", "testing null option"));
static const char *argv1[] = { "./foo", "-n", "foo" };
p->parse_args(elems(argv1), argv1);
static const char *argv2[] = { "./foo", "--null", "foo" };
p->parse_args(elems(argv2), argv2);
}
//-----------------------------------------------------------------------------
// Check if presence options can be used successfully
void
test_present_opt (void) {
std::unique_ptr<util::processor> p(new util::processor());
bool is_present;
p->add_option(std::make_unique<util::presentoption> ('p', "present", "option is present", &is_present));
// Short option form
static const char *argv1[] = { "./foo", "-p" };
is_present = false;
p->parse_args(elems(argv1), argv1);
CHECK (is_present);
// Long option form
static const char *argv2[] = { "./foo", "--present" };
is_present = false;
p->parse_args(elems(argv2), argv2);
CHECK (is_present);
// Check that value is reset from true if not present
static const char *argv3[] = { "./foo" };
is_present = true;
p->parse_args(elems(argv3), argv3);
CHECK (!is_present);
}
//-----------------------------------------------------------------------------
// Check all forms of boolean inputs
void
test_bool_opt (void) {
std::unique_ptr<util::processor> p(new util::processor());
bool value = false;
p->add_option (std::make_unique<util::valueoption<bool>> ('b', "bool", "testing boolean actions", &value));
// List all legal forms of positive or negative boolean values
std::array<const char*, 3> argv { "./foo", "-b", NULL };
static const char *positive[] = { "1", "true", "yes" };
static const char *negative[] = { "0", "false", "no" };
// For each boolean value, ensure that it returns as expected
for (auto i: positive) {
static size_t count;
std::cerr << "iter " << count++ << '\n';
argv[2] = i;
p->parse_args (argv.size (), argv.data ());
CHECK (value == true);
}
for (auto i: negative) {
argv[2] = i;
p->parse_args (argv.size (), argv.data ());
CHECK (value == false);
}
// Check that invalid forms of boolean all throw exceptions
const char* invalid[] = { "foo", "y", "null" };
for (auto i: invalid) {
argv[2] = i;
CHECK_THROWS (
std::domain_error,
p->parse_args (argv.size (), argv.data ())
);
}
}
//-----------------------------------------------------------------------------
template<typename T>
void
test_numeric_opt (void) {
std::unique_ptr<util::processor> p(new util::processor ());
T value;
p->add_option (std::make_unique<util::valueoption<T>> ('t', "type", "testing type option", &value));
T values[] = {
// TODO: Enable minimum value testing. Currently disabled as
// a negative numerical value looks just like a proceeding
// option.
//std::numeric_limits<T>::min(),
std::numeric_limits<T>::max (),
0
};
const char * argv_short[] = { "./foo", "-t", NULL };
const char * argv_long[] = { "./foo", NULL };
for(size_t i = 0; i < elems (values); ++i) {
std::ostringstream out_short, out_long;
std::string str_short, str_long;
out_short << values[i];
str_short = out_short.str ();
argv_short[2] = str_short.c_str ();
value = 2;
p->parse_args (elems (argv_short), argv_short);
CHECK (value == values[i]);
out_long << "--type=" << values[i];
str_long = out_long.str ();
argv_long[1] = str_long.c_str ();
value = 2;
p->parse_args (elems (argv_long), argv_long);
CHECK (value == values[i]);
}
}
//-----------------------------------------------------------------------------
void
test_bytes_opt(void) {
std::unique_ptr<util::processor> p(new util::processor ());
static const struct {
const char *param;
util::bytesoption::bytestype type;
util::bytesoption::bytesmodifier mod;
size_t size;
} commands[] = {
{ "1", util::bytesoption::BYTES_MEGA,
util::bytesoption::BYTES_BASE2,
1UL * 1024 * 1024 },
{ "1k", util::bytesoption::BYTES_KILO,
util::bytesoption::BYTES_BASE2,
1UL * 1024 },
{ "1M", util::bytesoption::BYTES_SINGLE,
util::bytesoption::BYTES_BASE2,
1UL * 1024 * 1024 },
{ "1G", util::bytesoption::BYTES_MEGA,
util::bytesoption::BYTES_BASE2,
1UL * 1024 * 1024 * 1024 },
{ "1M", util::bytesoption::BYTES_SINGLE,
util::bytesoption::BYTES_BASE10,
1UL * 1000 * 1000 },
{ "1MB", util::bytesoption::BYTES_SINGLE,
util::bytesoption::BYTES_BASE10,
1UL * 1000 * 1000 },
{ "1MiB", util::bytesoption::BYTES_SINGLE,
util::bytesoption::BYTES_BASE10,
1UL * 1024 * 1024 },
};
static const char *argv[] = {
"./foo",
"-b",
NULL
};
for (unsigned int i = 0; i < elems (commands); ++i) {
size_t size = 0;
p->add_option(std::make_unique<util::bytesoption> (
'b', "bytes",
"testing sizeof bytes", &size, commands[i].type,
commands[i].mod
));
argv[elems (argv) - 1] = commands[i].param;
p->parse_args (elems (argv), argv);
CHECK_EQ (commands[i].size, size);
p->remove_option ('b');
}
}
//-----------------------------------------------------------------------------
void
test_insert_remove_opt (void) {
{
std::unique_ptr<util::processor> p(new util::processor ());
auto opt = std::make_unique<util::nulloption> ('n', "null-option", "null testing action");
auto cmp = opt.get ();
p->add_option (move (opt));
CHECK_EQ (p->remove_option ('n').get (), (util::option*)cmp);
}
{
std::unique_ptr<util::processor> p(new util::processor ());
auto opt = std::make_unique<util::nulloption> ('n', "null-option", "null testing action");
auto cmp = opt.get ();
p->add_option (move (opt));
CHECK_EQ (p->remove_option ("null-option").get (), (util::option*)cmp);
}
{
std::unique_ptr<util::processor> p(new util::processor ());
auto opt1 = std::make_unique<util::nulloption> ('n', "null-option", "null testing action");
auto opt2 = std::make_unique<util::nulloption> ('n', "null-option", "null testing action");
p->add_option (move (opt1));
CHECK_THROWS (std::logic_error, p->add_option (move (opt2)));
}
}
//-----------------------------------------------------------------------------
void
test_required (void) {
std::unique_ptr<util::processor> p (new util::processor ());
p->add_option (std::make_unique <util::nulloption> (
'n',
"null",
"null testing",
true
));
static const char *argv[] = {
"./cpptest",
"-n",
"value"
};
CHECK_NOTHROW (p->parse_args (elems (argv), argv));
CHECK_THROWS (std::runtime_error, p->parse_args (1, argv));
}
//-----------------------------------------------------------------------------
int
main (int, char **) {
test_null_opt ();
test_present_opt ();
test_bool_opt ();
test_numeric_opt< int16_t> ();
test_numeric_opt< int32_t> ();
test_numeric_opt< int64_t> ();
test_numeric_opt<uint16_t> ();
test_numeric_opt<uint32_t> ();
test_numeric_opt<uint64_t> ();
test_bytes_opt ();
test_insert_remove_opt ();
test_required ();
util::TAP::logger tap;
tap.todo ("convert to TAP");
}