Riyyi
3 years ago
commit
8a1fb689bd
10 changed files with 764 additions and 0 deletions
@ -0,0 +1,38 @@
|
||||
# -*- yaml -*- |
||||
|
||||
--- |
||||
BasedOnStyle: WebKit |
||||
IndentWidth: 4 |
||||
--- |
||||
Language: Cpp |
||||
|
||||
AlignAfterOpenBracket: Align |
||||
AlignEscapedNewlines: Left |
||||
AlignOperands: Align |
||||
AlignTrailingComments: true |
||||
|
||||
AllowAllArgumentsOnNextLine: false |
||||
AllowAllConstructorInitializersOnNextLine: true |
||||
AllowAllParametersOfDeclarationOnNextLine: false |
||||
AllowShortLambdasOnASingleLine: All |
||||
|
||||
AlwaysBreakTemplateDeclarations: Yes |
||||
|
||||
BraceWrapping: |
||||
AfterEnum: false |
||||
AfterFunction: true |
||||
BeforeCatch: true |
||||
BeforeElse: true |
||||
BeforeLambdaBody: false |
||||
SplitEmptyRecord: false |
||||
BreakBeforeBraces: Custom |
||||
BreakInheritanceList: BeforeComma |
||||
|
||||
SpaceAfterTemplateKeyword: false |
||||
SpaceInEmptyBlock: false |
||||
NamespaceIndentation: None |
||||
FixNamespaceComments: true |
||||
Standard: c++17 |
||||
TabWidth: 4 |
||||
UseTab: AlignWithSpaces |
||||
... |
@ -0,0 +1,7 @@
|
||||
# Directories |
||||
|
||||
.cache/ |
||||
.clangd/ |
||||
build/ |
||||
|
||||
# Files |
@ -0,0 +1,74 @@
|
||||
# User config between these lines |
||||
# ------------------------------------------ |
||||
|
||||
# Set project name |
||||
set(PROJECT "stowage") |
||||
# Set debugging, ON/OFF |
||||
set(DEBUG "ON") |
||||
|
||||
# ------------------------------------------ |
||||
|
||||
# Add 'make run' target |
||||
add_custom_target(run |
||||
COMMAND ${PROJECT} |
||||
) |
||||
|
||||
# ------------------------------------------ |
||||
|
||||
cmake_minimum_required(VERSION 3.16) |
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) |
||||
|
||||
# Check if the build should include debugging symbols |
||||
option(DEBUG "" ${DEBUG}) |
||||
if(DEBUG) |
||||
# cmake -DDEBUG=on .. && make |
||||
message("--- Debug ---") |
||||
set(CMAKE_BUILD_TYPE "Debug") |
||||
|
||||
# -Og = Optimizations that do not interfere with debugging |
||||
# -Wall = All warnings about contructions that are easily avoidable |
||||
# -Wextra = Extra warning flags not covered by -Wall |
||||
# -g = Produce debugging information in OS's native format |
||||
# -pg = Generate profile information for analysis with gprof |
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -Wall -Wextra -g -pg") |
||||
# gprof <PROJECT> gmon.out > profile-data.txt |
||||
else() |
||||
# cmake -DDEBUG=off .. && make |
||||
message("--- Release ---") |
||||
set(CMAKE_BUILD_TYPE "Release") |
||||
|
||||
# -O3 = Optimizations that increases compilation time and performance |
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") |
||||
endif() |
||||
|
||||
# Include all headers |
||||
include_directories( |
||||
"src" |
||||
"test" |
||||
) |
||||
|
||||
# Define source files |
||||
file(GLOB_RECURSE PROJECT_SOURCES "src/*.cpp") |
||||
set(PROJECT_SOURCES ${PROJECT_SOURCES}) |
||||
|
||||
# Define test source files |
||||
file(GLOB_RECURSE TEST_SOURCES "test/*.cpp") |
||||
file(GLOB_RECURSE MAIN_SOURCES "src/*/*.cpp") |
||||
set(TEST_SOURCES ${TEST_SOURCES} ${MAIN_SOURCES}) |
||||
|
||||
# ------------------------------------------ |
||||
|
||||
project(${PROJECT}) |
||||
set(CMAKE_CXX_STANDARD 17) |
||||
|
||||
add_executable(${PROJECT} ${PROJECT_SOURCES}) |
||||
target_link_libraries(${PROJECT}) |
||||
|
||||
# ------------------------------------------ |
||||
|
||||
project(test) |
||||
set(CMAKE_CXX_STANDARD 17) |
||||
|
||||
add_executable(test ${TEST_SOURCES}) |
||||
target_link_libraries(test) |
@ -0,0 +1,74 @@
|
||||
* Stowage |
||||
|
||||
Needed information for generation: |
||||
- short option |
||||
- long option |
||||
- short description (for usage ouput) |
||||
- long description (for manpage output) |
||||
|
||||
* Option Parsing |
||||
|
||||
Parsed from left to right. |
||||
|
||||
** Types |
||||
|
||||
- Short option |
||||
- Long option |
||||
- Argument to option |
||||
- Non-option parameter (default argument) |
||||
|
||||
*** Short Option |
||||
|
||||
'-' followed by short option character. |
||||
If option has required argument, directly after OR separated by white-space. |
||||
Optional argument must be directly after the option character. |
||||
|
||||
Possible to write several short options after one '-', |
||||
if all (except last) do not have *required* or *optional* arguments. |
||||
|
||||
*** Long Option |
||||
|
||||
'--' followed by long option name. |
||||
If option has a required argument, directly after, separated by '=' OR white-space. |
||||
Optional argument must be directly after the option, separated by '='. |
||||
|
||||
*** Non-option Parameter |
||||
|
||||
Each parameter not starting with '-' and not a required argument of a previous option, |
||||
is a non-option parameter. |
||||
|
||||
Each parameter after a '--' parameter is always interpreted as a non-option parameter. |
||||
|
||||
* Examples |
||||
|
||||
#+BEGIN_SRC shell-script |
||||
./stowage -Fals |
||||
./stowage -F -a -l -s |
||||
|
||||
./stowage --file --add --pull --push |
||||
|
||||
./stowage -r filename |
||||
./stowage -rfilename |
||||
./stowage --remove=filename |
||||
./stowage --remove filename |
||||
|
||||
./stowage --remove filename other stuff |
||||
./stowage --remove filename -- other stuff |
||||
#+END_SRC |
||||
|
||||
** Multiple of the same options |
||||
|
||||
#+BEGIN_SRC shell-script |
||||
./stowage -e pattern1 -epattern2 --regexp=pattern3 --regexp pattern4 |
||||
#+END_SRC |
||||
|
||||
* TODO |
||||
|
||||
- after first non option, go into no-option mode |
||||
- support '--' to go into no-option mode |
||||
- add multi-option support, vectors! |
||||
- support argument parsing + storing |
||||
- add addOption overloads |
||||
- generate usage string |
||||
- generate man page string |
||||
- parse() function to return bool true if any error has occured |
@ -0,0 +1,39 @@
|
||||
// #include <cstddef> // size_t
|
||||
// #include <cstdlib> // maloc, free
|
||||
#include <string> |
||||
|
||||
#include "util/argparser.h" |
||||
|
||||
// void* operator new(size_t size)
|
||||
// {
|
||||
// std::cout << "Allocating '" << size << "' bytes" << std::endl;
|
||||
// return std::malloc(size);
|
||||
// }
|
||||
|
||||
// void operator delete(void* pointer, size_t size)
|
||||
// {
|
||||
// std::cout << "Freeing '" << size << "' bytes" << std::endl;
|
||||
// free(pointer);
|
||||
// }
|
||||
|
||||
int main(int argc, const char* argv[]) |
||||
{ |
||||
bool pattern = false; |
||||
std::string stringArg1 = "default value"; |
||||
std::string stringArg2 = "nothing"; |
||||
|
||||
Util::ArgParser parser; |
||||
// parser.setExitOnFirstError(false);
|
||||
// parser.setErrorMessages(false);
|
||||
|
||||
parser.addOption(pattern, 'e', "regexp", "search pattern", "Use ${U}PATTERNS${N} as the patterns."); |
||||
parser.addOption(stringArg1, 'a', "arg1", "test argument", "Test argument manpage description.", "TEST", Util::ArgParser::Required::Yes); |
||||
parser.addOption(stringArg2, 'b', "arg2", "optional argument", "Option with optional argument", "TEST", Util::ArgParser::Required::Optional); |
||||
parser.parse(argc, argv); |
||||
|
||||
printf(" Pattern: {%d}\n", pattern); |
||||
printf(" Arg1: {%s}\n", stringArg1.data()); |
||||
printf(" Arg2: {%s}\n", stringArg2.data()); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,281 @@
|
||||
#include <algorithm> // std::find_if |
||||
#include <cstdio> // printf |
||||
#include <string_view> |
||||
|
||||
#include "util/argparser.h" |
||||
|
||||
namespace Util { |
||||
|
||||
ArgParser::ArgParser() |
||||
{ |
||||
} |
||||
|
||||
ArgParser::~ArgParser() |
||||
{ |
||||
} |
||||
|
||||
void ArgParser::printOptionError(char name, Error error) |
||||
{ |
||||
char tmp[] { name, '\0' }; |
||||
printOptionError(tmp, error, false); |
||||
} |
||||
|
||||
void ArgParser::printOptionError(const char* name, Error error, bool longName) |
||||
{ |
||||
if (!m_errorMessages) { |
||||
return; |
||||
} |
||||
|
||||
if (error == Error::InvalidOption) { |
||||
printf("%s: invalid option -- '%s'\n", m_name, name); |
||||
} |
||||
else if (error == Error::UnrecognizedOption) { |
||||
printf("%s: unrecognized option -- '%s'\n", m_name, name); |
||||
} |
||||
else if (error == Error::DoesntAllowArgument) { |
||||
printf("%s: option '--%s' doesn't allow an argument\n", m_name, name); |
||||
} |
||||
else if (error == Error::RequiresArgument) { |
||||
if (longName) { |
||||
printf("%s: option '--%s' requires an argument", m_name, name); |
||||
} |
||||
else { |
||||
printf("%s: option requires an argument -- '%s'\n", m_name, name); |
||||
} |
||||
} |
||||
|
||||
// TODO: Print command usage, if it's enabled.
|
||||
} |
||||
|
||||
// Required: directly after || separated by space
|
||||
// Optional: directly after
|
||||
bool ArgParser::parseShortOption(std::string_view option, std::string_view next) |
||||
{ |
||||
bool result = true; |
||||
|
||||
printf("Parsing short option: '%s'\n", option.data()); |
||||
|
||||
char c; |
||||
std::string_view value; |
||||
for (std::string_view::size_type i = 0; i < option.size(); ++i) { |
||||
c = option.at(i); |
||||
printf("short '%c'\n", c); |
||||
|
||||
auto foundOption = std::find_if(m_options.begin(), m_options.end(), [&c](Option& it) -> bool { |
||||
return it.shortName == c; |
||||
}); |
||||
|
||||
// Option does not exist
|
||||
if (foundOption == m_options.cend()) { |
||||
printOptionError(c, Error::InvalidOption); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
|
||||
if (foundOption->requiresArgument == Required::No) { |
||||
// FIXME: Figure out why providing a nullptr breaks the lambda here.
|
||||
foundOption->acceptValue(""); |
||||
} |
||||
else if (foundOption->requiresArgument == Required::Yes) { |
||||
value = option.substr(i + 1); |
||||
if (value.empty() && next.empty()) { |
||||
foundOption->error = Error::RequiresArgument; |
||||
printOptionError(c, Error::RequiresArgument); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
else if (!value.empty()) { |
||||
foundOption->acceptValue(value.data()); |
||||
} |
||||
else if (next[0] == '-') { |
||||
foundOption->error = Error::RequiresArgument; |
||||
printOptionError(c, Error::RequiresArgument); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
else { |
||||
foundOption->acceptValue(next.data()); |
||||
m_optionIndex++; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
else if (foundOption->requiresArgument == Required::Optional) { |
||||
value = option.substr(i + 1); |
||||
if (!value.empty()) { |
||||
foundOption->acceptValue(value.data()); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
// Required: directly after, separated by '=' || separated by space
|
||||
// Optional: directly after, separated by '='
|
||||
bool ArgParser::parseLongOption(std::string_view option, std::string_view next) |
||||
{ |
||||
bool result = true; |
||||
|
||||
std::string_view name = option.substr(0, option.find_first_of('=')); |
||||
std::string_view value = option.substr(option.find_first_of('=') + 1); |
||||
|
||||
bool argumentProvided = true; |
||||
if (name.compare(value) == 0 && option.find('=') == std::string_view::npos) { |
||||
argumentProvided = false; |
||||
} |
||||
|
||||
printf("Parsing long option: '%s' with value '%s'\n", name.data(), argumentProvided ? value.data() : ""); |
||||
|
||||
auto foundOption = std::find_if(m_options.begin(), m_options.end(), [&name](Option& it) -> bool { |
||||
return it.longName == name; |
||||
}); |
||||
|
||||
if (foundOption == m_options.cend()) { |
||||
foundOption->error = Error::UnrecognizedOption; |
||||
printOptionError(name.data(), Error::UnrecognizedOption); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
|
||||
if (argumentProvided) { |
||||
if (foundOption->requiresArgument == Required::No) { |
||||
foundOption->error = Error::DoesntAllowArgument; |
||||
printOptionError(name.data(), Error::DoesntAllowArgument); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
else if (foundOption->requiresArgument == Required::Yes) { |
||||
foundOption->acceptValue(value.data()); |
||||
} |
||||
else if (foundOption->requiresArgument == Required::Optional) { |
||||
foundOption->acceptValue(value.data()); |
||||
} |
||||
} |
||||
else if (!next.empty() && foundOption->requiresArgument == Required::Yes) { |
||||
if (next[0] == '-') { |
||||
foundOption->error = Error::RequiresArgument; |
||||
printOptionError(name.data(), Error::RequiresArgument); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
else { |
||||
foundOption->acceptValue(next.data()); |
||||
m_optionIndex++; |
||||
} |
||||
} |
||||
else if (foundOption->requiresArgument == Required::Yes) { |
||||
foundOption->error = Error::RequiresArgument; |
||||
printOptionError(name.data(), Error::RequiresArgument); |
||||
|
||||
result = false; |
||||
if (m_exitOnFirstError) { |
||||
return result; |
||||
} |
||||
} |
||||
else { |
||||
// FIXME: Figure out why providing a nullptr breaks the lambda here.
|
||||
foundOption->acceptValue(""); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
bool ArgParser::parse(int argc, const char* argv[]) |
||||
{ |
||||
// Get program name
|
||||
m_name = argv[0] + std::string_view(argv[0]).find_last_of('/') + 1; |
||||
|
||||
printf("name: %s\n", m_name); |
||||
|
||||
std::string_view argument; |
||||
std::string_view next; |
||||
for (; m_optionIndex < argc; ++m_optionIndex) { |
||||
printf("argv[%d]: %s\n", m_optionIndex, argv[m_optionIndex]); |
||||
|
||||
argument = argv[m_optionIndex]; |
||||
if (m_optionIndex + 1 < argc && argv[m_optionIndex + 1][0] != '-') { |
||||
next = argv[m_optionIndex + 1]; |
||||
} |
||||
else { |
||||
next = {}; |
||||
} |
||||
|
||||
// Long Option
|
||||
if (argument[0] == '-' && argument[1] == '-') { |
||||
argument = argument.substr(argument.find_first_not_of('-')); |
||||
parseLongOption(argument, next); |
||||
} |
||||
// Short Option
|
||||
else if (argument[0] == '-') { |
||||
argument = argument.substr(argument.find_first_not_of('-')); |
||||
parseShortOption(argument, next); |
||||
} |
||||
// Argument
|
||||
else { |
||||
printf("-> argu: '%s'", argument.data()); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void ArgParser::addOption(Option&& option) |
||||
{ |
||||
m_options.push_back(option); |
||||
} |
||||
|
||||
void ArgParser::addOption(bool& value, char shortName, const char* longName, const char* usageString, const char* manString) |
||||
{ |
||||
Option option { |
||||
shortName, |
||||
longName, |
||||
nullptr, |
||||
usageString, |
||||
manString, |
||||
Required::No, |
||||
[&value](const char*) -> bool { |
||||
value = true; |
||||
return true; |
||||
} |
||||
}; |
||||
addOption(std::move(option)); |
||||
} |
||||
|
||||
void ArgParser::addOption(std::string& value, char shortName, const char* longName, const char* usageString, const char* manString, const char* argumentName, Required requiresArgument) |
||||
{ |
||||
Option option { |
||||
shortName, |
||||
longName, |
||||
argumentName, |
||||
usageString, |
||||
manString, |
||||
requiresArgument, |
||||
[&value](const char* a) -> bool { |
||||
value = a; |
||||
return true; |
||||
} |
||||
}; |
||||
addOption(std::move(option)); |
||||
} |
||||
|
||||
} // namespace Util
|
@ -0,0 +1,75 @@
|
||||
#ifndef ARG_PARSER_H |
||||
#define ARG_PARSER_H |
||||
|
||||
#include <functional> |
||||
#include <string> |
||||
#include <string_view> |
||||
#include <vector> |
||||
|
||||
namespace Util { |
||||
|
||||
class ArgParser final { |
||||
public: |
||||
ArgParser(); |
||||
virtual ~ArgParser(); |
||||
|
||||
enum class Required { |
||||
No, |
||||
Yes, |
||||
Optional, |
||||
}; |
||||
|
||||
enum class Error { |
||||
None, |
||||
InvalidOption, // For short options
|
||||
UnrecognizedOption, // For long options
|
||||
DoesntAllowArgument, |
||||
RequiresArgument, |
||||
}; |
||||
|
||||
struct Option { |
||||
char shortName { 0 }; |
||||
const char* longName { nullptr }; |
||||
const char* argumentName { nullptr }; |
||||
const char* usageString { nullptr }; |
||||
const char* manString { nullptr }; |
||||
Required requiresArgument; |
||||
std::function<bool(const char*)> acceptValue; |
||||
|
||||
Error error = Error::None; |
||||
}; |
||||
|
||||
struct Argument { |
||||
}; |
||||
|
||||
bool parse(int argc, const char* argv[]); |
||||
|
||||
void addOption(Option&& option); |
||||
void addOption(bool& value, char shortName, const char* longName, const char* usageString, const char* manString); |
||||
void addOption(std::string& value, char shortName, const char* longName, const char* usageString, const char* manString, const char* argumentName = "", Required requiresArgument = Required::No); |
||||
|
||||
void setOptionIndex(int index) { m_optionIndex = index; } |
||||
void setExitOnFirstError(bool state) { m_exitOnFirstError = state; } |
||||
void setErrorMessages(bool state) { m_errorMessages = state; } |
||||
void setNonOptionAfterFirst(bool state) { m_nonOptionAfterFirst = state; } |
||||
|
||||
private: |
||||
void printOptionError(char name, Error error); |
||||
void printOptionError(const char* name, Error error, bool longName = true); |
||||
bool parseShortOption(std::string_view option, std::string_view next); |
||||
bool parseLongOption(std::string_view option, std::string_view next); |
||||
|
||||
int m_optionIndex { 1 }; |
||||
bool m_exitOnFirstError { true }; |
||||
bool m_errorMessages { true }; |
||||
// TODO: Implement this, maybe combine with error messages flag, enum class? or bitfield
|
||||
bool m_nonOptionAfterFirst { false }; |
||||
|
||||
const char* m_name; |
||||
std::vector<Option> m_options; |
||||
std::vector<Argument> m_arguments; |
||||
}; |
||||
|
||||
} // namespace Util
|
||||
|
||||
#endif // ARG_PARSER_H
|
@ -0,0 +1,18 @@
|
||||
#ifndef TEST_H |
||||
#define TEST_H |
||||
|
||||
#include <cstdio> // printf |
||||
#include <iostream> // cout |
||||
|
||||
#define EXPECT(x) \ |
||||
if (!(x)) { \
|
||||
printf("FAIL: %s:%d: EXPECT(%s) failed\n", __FILE__, __LINE__, #x); \
|
||||
} |
||||
|
||||
#define EXPECT_EQ(a, b) \ |
||||
if (a != b) { \
|
||||
std::cout << "FAIL: " << __FILE__ << ":" << __LINE__ \
|
||||
<< ": EXPECT_EQ(" << #a << ", " << #b ") failed with lhs=" << a << " and rhs=" << b << std::endl; \
|
||||
} |
||||
|
||||
#endif // TEST_H
|
@ -0,0 +1,157 @@
|
||||
#include <cstdio> // fopen, printf, stdout |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "macro.h" |
||||
#include "util/argparser.h" |
||||
|
||||
FILE* output; |
||||
FILE* null; |
||||
|
||||
bool runParser(std::vector<const char*> arguments, std::function<void(Util::ArgParser&)> initializer = {}) |
||||
{ |
||||
stdout = null; |
||||
|
||||
Util::ArgParser parser; |
||||
if (initializer) { |
||||
initializer(parser); |
||||
} |
||||
|
||||
arguments.insert(arguments.begin(), "app"); |
||||
auto result = parser.parse(arguments.size(), arguments.data()); |
||||
|
||||
stdout = output; |
||||
return result; |
||||
} |
||||
|
||||
int main(int, const char*[]) |
||||
{ |
||||
output = stdout; |
||||
null = fopen("/dev/null", "w"); // Windows: nul
|
||||
|
||||
printf("Test project\n"); |
||||
|
||||
// No arguments
|
||||
{ |
||||
auto result = runParser({}); |
||||
EXPECT_EQ(result, true); |
||||
} |
||||
|
||||
// Bool options
|
||||
{ |
||||
// Short option
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({ "-b" }, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, 'b', nullptr, nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, true); |
||||
} |
||||
{ |
||||
// Short option, not given
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({}, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, 'b', nullptr, nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, false); |
||||
} |
||||
{ |
||||
// Long option
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({ "--bool" }, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, '\0', "bool", nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, true); |
||||
} |
||||
{ |
||||
// Long option, not given
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({}, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, '\0', "bool", nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, false); |
||||
} |
||||
{ |
||||
// Allow both short and long option, provide short
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({ "-b" }, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, 'b', "bool", nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, true); |
||||
} |
||||
{ |
||||
// Allow both short and long option, provide long
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({ "--bool" }, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, 'b', "bool", nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, true); |
||||
} |
||||
{ |
||||
// Allow both short and long option, provide both
|
||||
bool boolOpt1 = false; |
||||
auto result = runParser({ "-b", "--bool" }, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, 'b', "bool", nullptr, nullptr); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, true); |
||||
} |
||||
|
||||
// ..
|
||||
{ |
||||
//
|
||||
bool boolOpt1 = false; |
||||
std::string stringOpt1 = ""; |
||||
auto result = runParser({ "-b", "something", "-s", "my-value" }, [&](auto& parser) { |
||||
parser.addOption(boolOpt1, 'b', nullptr, nullptr, nullptr); |
||||
parser.addOption(stringOpt1, 's', nullptr, nullptr, nullptr, nullptr, Util::ArgParser::Required::Yes); |
||||
}); |
||||
EXPECT_EQ(result, true); |
||||
EXPECT_EQ(boolOpt1, true); |
||||
EXPECT_EQ(stringOpt1, ""); |
||||
} |
||||
|
||||
// // bool tests
|
||||
// test('o', "option", { "-o" }, true);
|
||||
// test('o', "option", { "-n" }, false);
|
||||
// test('o', "option", { "--option" }, true);
|
||||
// test('o', "option", { "--noexist" }, false);
|
||||
|
||||
// // string tests
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "-o", "my-argument" }, "my-argument", 0);
|
||||
// test('o', "option", Util::ArgParser::Required::Optional, { "-o", "my-argument" }, {}, 0);
|
||||
// test('o', "option", Util::ArgParser::Required::No, { "-o", "my-argument" }, {}, 0);
|
||||
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "-omy-argument" }, "my-argument", 0);
|
||||
// test('o', "option", Util::ArgParser::Required::Optional, { "-omy-argument" }, "my-argument", 0);
|
||||
// test('o', "option", Util::ArgParser::Required::No, { "-omy-argument" }, {}, 0);
|
||||
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "--option", "my-argument" }, "my-argument", 0);
|
||||
// test('o', "option", Util::ArgParser::Required::Optional, { "--option", "my-argument" }, {}, 0);
|
||||
// test('o', "option", Util::ArgParser::Required::No, { "--option", "my-argument" }, {}, 0);
|
||||
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "--option=my-argument" }, "my-argument", 0);
|
||||
// test('o', "option", Util::ArgParser::Required::Optional, { "--option=my-argument" }, "my-argument", 0);
|
||||
// test('o', "option", Util::ArgParser::Required::No , { "--option=my-argument" }, {}, 0);
|
||||
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "-o", "my-argument" }, "not-same", -1);
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "-omy-argument" }, "not-same", -1);
|
||||
// test('o', "option", Util::ArgParser::Required::Optional, { "-omy-argument" }, "not-same", -1);
|
||||
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "--option", "my-argument" }, "not-same", -1);
|
||||
// test('o', "option", Util::ArgParser::Required::Yes, { "--option=my-argument" }, "not-same", -1);
|
||||
// test('o', "option", Util::ArgParser::Required::Optional, { "--option=my-argument" }, "not-same", -1);
|
||||
|
||||
// ./help -o something -a my-value
|
||||
// -a has required argument, but something should stop option parsing
|
||||
|
||||
printf("Completed running tests\n"); |
||||
|
||||
fclose(null); |
||||
return 0; |
||||
} |
Loading…
Reference in new issue