first commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build
|
15
.travis.yml
Normal file
15
.travis.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
dist: bionic
|
||||||
|
language: minimal
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
$HOME/cmake
|
||||||
|
|
||||||
|
install:
|
||||||
|
- ci/install_deps.sh || travis_terminate 1;
|
||||||
|
|
||||||
|
script:
|
||||||
|
- mkdir -p build && cd build
|
||||||
|
- cmake ..
|
||||||
|
- make
|
||||||
|
- test/test_all
|
11
CMakeLists.txt
Normal file
11
CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 3.0: version
|
||||||
|
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
|
||||||
|
|
||||||
|
project(argparse LANGUAGES CXX VERSION 0.1.0.0)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
|
# "this command should be in the source directory root for CTest to find the test file"
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(test)
|
31
README.md
Normal file
31
README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# argparse
|
||||||
|
|
||||||
|
Simple single-file header-only CLI option parsing for C++.
|
||||||
|
No subcommands, grouped commands.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Download the latest [`argparse.hpp`](www.google.com) and include it in your project.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [x] allow (default) / disallow (`Parser::no_unrecognize()`) unrecognized options and flags
|
||||||
|
- [x] optional/required (`PosnlBase::required()`) positional arguments
|
||||||
|
- [x] flags with `-s`, `--long-flag` formats
|
||||||
|
- [x] options with `--long-opt val` format
|
||||||
|
- [x] positional arguments
|
||||||
|
- [x] `--` to stop parsing options and flags
|
||||||
|
- [x] modify `argc`/`argv` (disable with `Parser::no_consume()`)
|
||||||
|
- Option Types
|
||||||
|
- [x] `int`
|
||||||
|
- [x] `size_t`
|
||||||
|
- [x] `float`
|
||||||
|
- [x] `double`
|
||||||
|
- [x] `std::string`
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
- [ ] examples
|
||||||
|
- [ ] Help string output
|
||||||
|
- [ ] support --long-option=value
|
||||||
|
- [ ] have the last positional argument fill a vector with remaining
|
19
ci/build.sh
Executable file
19
ci/build.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
set -x -e
|
||||||
|
|
||||||
|
source ci/env.sh
|
||||||
|
|
||||||
|
which g++
|
||||||
|
which nvcc
|
||||||
|
which cmake
|
||||||
|
|
||||||
|
g++ --version
|
||||||
|
nvcc --version
|
||||||
|
cmake --version
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. \
|
||||||
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
|
-DCMAKE_PREFIX_PATH=$OPENMPI_PATH \
|
||||||
|
-DMPI_HOME=/usr/lib/x86_64-linux-gnu/openmpi/
|
||||||
|
make VERBOSE=1
|
8
ci/env.sh
Normal file
8
ci/env.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
OPENMPI_PREFIX=$HOME/openmpi
|
||||||
|
CMAKE_PREFIX=$HOME/cmake
|
||||||
|
|
||||||
|
export PATH=/usr/local/cuda/bin:$PATH
|
||||||
|
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
export PATH=$OPENMPI_PREFIX/bin:$PATH
|
||||||
|
export PATH=$CMAKE_PREFIX/bin:$PATH
|
40
ci/install_deps.sh
Executable file
40
ci/install_deps.sh
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
set -x -e
|
||||||
|
|
||||||
|
source ci/env.sh
|
||||||
|
|
||||||
|
# Install Cmake if it doesn't exist
|
||||||
|
mkdir -p $CMAKE_PREFIX
|
||||||
|
if [[ ! -f $CMAKE_PREFIX/bin/cmake ]]; then
|
||||||
|
if [[ $TRAVIS_CPU_ARCH == "ppc64le" ]]; then
|
||||||
|
wget -qSL https://cmake.org/files/v3.13/cmake-3.13.5.tar.gz -O cmake.tar.gz
|
||||||
|
tar -xf cmake.tar.gz --strip-components=1 -C $CMAKE_PREFIX
|
||||||
|
rm cmake.tar.gz
|
||||||
|
cd $CMAKE_PREFIX
|
||||||
|
./bootstrap --prefix=$CMAKE_PREFIX
|
||||||
|
make -j `nproc` install
|
||||||
|
elif [[ $TRAVIS_CPU_ARCH == "amd64" ]]; then
|
||||||
|
wget -qSL https://cmake.org/files/v3.13/cmake-3.13.5-Linux-x86_64.tar.gz -O cmake.tar.gz
|
||||||
|
tar -xf cmake.tar.gz --strip-components=1 -C $CMAKE_PREFIX
|
||||||
|
rm cmake.tar.gz
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
cd $HOME
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
libopenmpi-dev openmpi-bin
|
||||||
|
|
||||||
|
## install CUDA
|
||||||
|
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
|
||||||
|
|
||||||
|
if [[ $TRAVIS_CPU_ARCH == "ppc64le" ]]; then
|
||||||
|
CUDA102="https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/ppc64el/cuda-repo-ubuntu1804_10.2.89-1_ppc64el.deb"
|
||||||
|
elif [[ $TRAVIS_CPU_ARCH == "amd64" ]]; then
|
||||||
|
CUDA102="http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.2.89-1_amd64.deb"
|
||||||
|
fi
|
||||||
|
|
||||||
|
wget -SL $CUDA102 -O cuda.deb
|
||||||
|
sudo dpkg -i cuda.deb
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
cuda-toolkit-10-2
|
4
ci/test.sh
Executable file
4
ci/test.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
set -x
|
||||||
|
|
||||||
|
cd build
|
||||||
|
make test
|
274
include/argparse/argparse.hpp
Normal file
274
include/argparse/argparse.hpp
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OptionBase {
|
||||||
|
public:
|
||||||
|
virtual void set_val(const std::string &valStr) = 0;
|
||||||
|
virtual const std::string &long_str() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class Option : public OptionBase {
|
||||||
|
std::string long_;
|
||||||
|
T *val_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Option(T &val, const std::string &l) : long_(l), val_(&val) {}
|
||||||
|
void set_val(const std::string &val) override { set_val((T *)nullptr, val); }
|
||||||
|
const std::string &long_str() override {
|
||||||
|
return long_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_val(size_t *, const std::string &val) { // convert to size_t
|
||||||
|
*val_ = std::stoull(val);
|
||||||
|
}
|
||||||
|
void set_val(double *, const std::string &val) { // convert to double
|
||||||
|
*val_ = std::stod(val);
|
||||||
|
}
|
||||||
|
void set_val(float *, const std::string &val) { // convert to float
|
||||||
|
*val_ = std::stof(val);
|
||||||
|
}
|
||||||
|
void set_val(int *, const std::string &val) { // convert to int
|
||||||
|
*val_ = std::stoi(val);
|
||||||
|
}
|
||||||
|
void set_val(std::string *, const std::string &val) { // convert to string
|
||||||
|
*val_ = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Flag {
|
||||||
|
std::string long_;
|
||||||
|
std::string short_;
|
||||||
|
std::string help_;
|
||||||
|
bool *val_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Flag(bool &val, const std::string &l, const std::string &s) : long_(l), short_(s), val_(&val) {}
|
||||||
|
|
||||||
|
const std::string &long_str() const noexcept { return long_; }
|
||||||
|
const std::string &short_str() const noexcept { return short_; }
|
||||||
|
|
||||||
|
void set() const noexcept { *val_ = true; }
|
||||||
|
|
||||||
|
void help(const std::string &s) {
|
||||||
|
help_ = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &help_str() const noexcept {
|
||||||
|
return help_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PosnlBase {
|
||||||
|
public:
|
||||||
|
virtual bool is_required() = 0;
|
||||||
|
virtual PosnlBase *required() = 0;
|
||||||
|
virtual void set_val(const std::string &val) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class Positional : public PosnlBase {
|
||||||
|
bool required_;
|
||||||
|
T *val_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Positional(T &val) : required_(false), val_(&val) {}
|
||||||
|
|
||||||
|
PosnlBase *required() override {
|
||||||
|
required_ = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_required() override { return required_; }
|
||||||
|
|
||||||
|
// use nullpointer type to disambiguate call
|
||||||
|
// https://stackoverflow.com/questions/5512910/explicit-specialization-of-template-class-member-function
|
||||||
|
void set_val(const std::string &val) { set_val((T *)nullptr, val); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// https://stackoverflow.com/questions/5512910/explicit-specialization-of-template-class-member-function
|
||||||
|
template <typename C>
|
||||||
|
void get_as(C *, const std::string &val) { // to be overridden
|
||||||
|
}
|
||||||
|
void set_val(size_t *, const std::string &val) { // convert to size_t
|
||||||
|
*val_ = std::stoull(val);
|
||||||
|
}
|
||||||
|
void set_val(double *, const std::string &val) { // convert to double
|
||||||
|
*val_ = std::stod(val);
|
||||||
|
}
|
||||||
|
void set_val(float *, const std::string &val) { // convert to float
|
||||||
|
*val_ = std::stof(val);
|
||||||
|
}
|
||||||
|
void set_val(int *, const std::string &val) { // convert to int
|
||||||
|
*val_ = std::stoi(val);
|
||||||
|
}
|
||||||
|
void set_val(std::string *, const std::string &val) { // convert to string
|
||||||
|
*val_ = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Parser {
|
||||||
|
|
||||||
|
std::string description_;
|
||||||
|
bool noUnrecognized_; // error on unrecognized flags / opts
|
||||||
|
bool help_; // help has been requested
|
||||||
|
bool consume_; // remove consumed values from argc, argv
|
||||||
|
|
||||||
|
std::vector<OptionBase *> opts_;
|
||||||
|
std::vector<Flag> flags_;
|
||||||
|
std::vector<PosnlBase *> posnls_;
|
||||||
|
|
||||||
|
static bool starts_with(const std::string &s, const std::string &prefix) {
|
||||||
|
if (s.rfind(prefix, 0) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionBase *match_opt(const char *arg) const {
|
||||||
|
std::string sarg(arg);
|
||||||
|
for (int64_t i = int64_t(opts_.size()) - 1; i >= 0; --i) {
|
||||||
|
if (opts_[i]->long_str() == sarg) {
|
||||||
|
return opts_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag *match_flag(const char *arg) {
|
||||||
|
std::string sarg(arg);
|
||||||
|
for (int64_t i = int64_t(flags_.size()) - 1; i >= 0; --i) {
|
||||||
|
if (flags_[i].long_str() == sarg || flags_[i].short_str() == sarg) {
|
||||||
|
return &flags_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Parser() : noUnrecognized_(false), help_(false), consume_(true) {
|
||||||
|
add_flag(help_, "--help", "-h")->help("Print help message");
|
||||||
|
}
|
||||||
|
Parser(const std::string &description) : description_(description), noUnrecognized_(false), help_(false), consume_(true) {
|
||||||
|
add_flag(help_, "--help", "-h")->help("Print help message");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse(int &argc, char ** argv) {
|
||||||
|
|
||||||
|
std::vector<char*> newArgv;
|
||||||
|
if (argc > 0) {
|
||||||
|
newArgv.push_back(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pi = 0; // positional argument position
|
||||||
|
bool optsOkay = true; // okay to interpret as opt/flag
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
|
||||||
|
// '--' indicates only positional arguments follow
|
||||||
|
if (argv[i] == std::string("--")) {
|
||||||
|
optsOkay = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// try interpreting as a flag or option if it looks like one
|
||||||
|
if (optsOkay && starts_with(argv[i], "-")) {
|
||||||
|
OptionBase *opt = match_opt(argv[i]);
|
||||||
|
if (opt) {
|
||||||
|
opt->set_val(argv[i + 1]);
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Flag *flag = match_flag(argv[i]);
|
||||||
|
if (flag) {
|
||||||
|
flag->set();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
newArgv.push_back(argv[i]);
|
||||||
|
if (noUnrecognized_) {
|
||||||
|
std::cerr << "unrecognized " << argv[i] << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else { // otherwise try it as positional
|
||||||
|
if (pi < posnls_.size()) {
|
||||||
|
posnls_[pi]->set_val(argv[i]);
|
||||||
|
++pi;
|
||||||
|
} else {
|
||||||
|
newArgv.push_back(argv[i]);
|
||||||
|
std::cerr << "encountered unexpected positional argument " << pi << ": " << argv[i]
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; pi < posnls_.size(); ++pi) {
|
||||||
|
if (posnls_[pi]->is_required()) {
|
||||||
|
std::cerr << "missing required positional argument " << pi << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consume_) {
|
||||||
|
argc = newArgv.size();
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
argv[i] = newArgv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> void add_option(T &val, const std::string &l) {
|
||||||
|
opts_.push_back(new Option<T>(val, l));
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag *add_flag(bool &val, const std::string &l, const std::string &s = "") {
|
||||||
|
flags_.push_back(Flag(val, l, s));
|
||||||
|
return &(flags_.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> PosnlBase *add_positional(T &val) {
|
||||||
|
posnls_.push_back(new Positional<T>(val));
|
||||||
|
return posnls_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string help() const {
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
ss << description_ << "\n";
|
||||||
|
|
||||||
|
for (auto &o : opts_) {
|
||||||
|
ss << o->long_str() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &f : flags_) {
|
||||||
|
ss << " " << f.short_str() << ", " << f.long_str();
|
||||||
|
ss << "\t\t" << f.help_str();
|
||||||
|
ss << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief error on unrecognized flags and options
|
||||||
|
*/
|
||||||
|
void no_unrecognized() {
|
||||||
|
noUnrecognized_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief don't modify argc/argv
|
||||||
|
*/
|
||||||
|
void no_consume() {
|
||||||
|
consume_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool need_help() const noexcept {
|
||||||
|
return help_;
|
||||||
|
}
|
||||||
|
};
|
32
test/CMakeLists.txt
Normal file
32
test/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
macro(add_args tgt)
|
||||||
|
target_compile_options(
|
||||||
|
${tgt}
|
||||||
|
PUBLIC
|
||||||
|
-Wall;
|
||||||
|
-Wextra;
|
||||||
|
-Wpedantic;
|
||||||
|
-Wcast-align;
|
||||||
|
-Wdisabled-optimization;
|
||||||
|
-Winit-self;
|
||||||
|
-Wlogical-op;
|
||||||
|
-Wmissing-include-dirs;
|
||||||
|
-Woverloaded-virtual;
|
||||||
|
-Wpointer-arith;
|
||||||
|
-Wshadow;
|
||||||
|
-Wstrict-aliasing;
|
||||||
|
-Wswitch-enum;
|
||||||
|
-Wundef;
|
||||||
|
-Wvla;
|
||||||
|
-Wformat=2;
|
||||||
|
)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
|
||||||
|
add_executable(test_all test_main.cpp
|
||||||
|
test_argparse.cpp
|
||||||
|
)
|
||||||
|
add_args(test_all)
|
||||||
|
target_include_directories(test_all SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
||||||
|
target_include_directories(test_all SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty)
|
||||||
|
add_test(NAME test_all COMMAND test_all -a)
|
||||||
|
|
132
test/test_argparse.cpp
Normal file
132
test/test_argparse.cpp
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
#include "catch2/catch.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "argparse/argparse.hpp"
|
||||||
|
|
||||||
|
TEST_CASE("argparse") {
|
||||||
|
|
||||||
|
SECTION("types") {
|
||||||
|
char *argv[] = {
|
||||||
|
"some-exe", "--campi", "--f", "10", "1.7", "1.8",
|
||||||
|
"--", // stop looking for options
|
||||||
|
"--a string",
|
||||||
|
"-6",
|
||||||
|
};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
|
||||||
|
bool campi = false;
|
||||||
|
size_t x;
|
||||||
|
double d;
|
||||||
|
float f;
|
||||||
|
int i;
|
||||||
|
std::string s;
|
||||||
|
p.add_flag(campi, "--campi");
|
||||||
|
p.add_positional(x);
|
||||||
|
p.add_positional(d);
|
||||||
|
p.add_positional(f);
|
||||||
|
p.add_positional(s);
|
||||||
|
p.add_positional(i);
|
||||||
|
REQUIRE(p.parse(argc, argv));
|
||||||
|
|
||||||
|
REQUIRE(campi == true);
|
||||||
|
REQUIRE(x == 10);
|
||||||
|
REQUIRE(d == 1.7);
|
||||||
|
REQUIRE(f == 1.8f);
|
||||||
|
REQUIRE(s == "--a string");
|
||||||
|
REQUIRE(i == -6);
|
||||||
|
REQUIRE(p.need_help() == false);
|
||||||
|
|
||||||
|
REQUIRE(argc == 2); // does not use --f or some-exe
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("no args") {
|
||||||
|
char *argv[] = {nullptr};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
Parser p;
|
||||||
|
REQUIRE(p.parse(argc, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTION("description") {
|
||||||
|
char *argv[] = {
|
||||||
|
"some-exe",
|
||||||
|
};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
Parser p("a test program");
|
||||||
|
REQUIRE(p.parse(argc, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("skip-first") {
|
||||||
|
char *argv[] = {"some-exe"};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
p.no_unrecognized();
|
||||||
|
REQUIRE(p.parse(argc, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("no-unrecognized") {
|
||||||
|
char *argv[] = {"some-exe", "-f"};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
p.no_unrecognized();
|
||||||
|
REQUIRE(false == p.parse(argc, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("missing-reqd-posnl") {
|
||||||
|
char *argv[] = {"some-exe", "a"};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
std::string a;
|
||||||
|
std::string b;
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
p.add_positional(a)->required();
|
||||||
|
p.add_positional(b)->required();
|
||||||
|
REQUIRE(false == p.parse(argc, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("-h") {
|
||||||
|
char *argv[] = {"some-exe", "-h"};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
std::string a;
|
||||||
|
std::string b;
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
REQUIRE(true == p.parse(argc, argv));
|
||||||
|
REQUIRE(p.need_help());
|
||||||
|
|
||||||
|
std::cerr << p.help() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("--help") {
|
||||||
|
char *argv[] = {"some-exe", "--help"};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
std::string a;
|
||||||
|
std::string b;
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
REQUIRE(true == p.parse(argc, argv));
|
||||||
|
REQUIRE(p.need_help());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("--help") {
|
||||||
|
char *argv[] = {"some-exe", "--help", "--"};
|
||||||
|
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||||
|
|
||||||
|
std::string a;
|
||||||
|
std::string b;
|
||||||
|
|
||||||
|
Parser p;
|
||||||
|
REQUIRE(true == p.parse(argc, argv));
|
||||||
|
REQUIRE(p.need_help());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
2
test/test_main.cpp
Normal file
2
test/test_main.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||||
|
#include "catch2/catch.hpp"
|
17596
thirdparty/catch2/catch.hpp
vendored
Normal file
17596
thirdparty/catch2/catch.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user