Compare commits
No commits in common. "master" and "fix_iter_access" have entirely different histories.
master
...
fix_iter_a
24
.github/workflows/cifuzz.yml
vendored
24
.github/workflows/cifuzz.yml
vendored
@ -1,24 +0,0 @@
|
|||||||
name: CIFuzz
|
|
||||||
on: [pull_request]
|
|
||||||
jobs:
|
|
||||||
Fuzzing:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Build Fuzzers
|
|
||||||
id: build
|
|
||||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
|
||||||
with:
|
|
||||||
oss-fuzz-project-name: 'cxxopts'
|
|
||||||
language: c++
|
|
||||||
- name: Run Fuzzers
|
|
||||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
|
||||||
with:
|
|
||||||
oss-fuzz-project-name: 'cxxopts'
|
|
||||||
language: c++
|
|
||||||
fuzz-seconds: 300
|
|
||||||
- name: Upload Crash
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: failure() && steps.build.outcome == 'success'
|
|
||||||
with:
|
|
||||||
name: artifacts
|
|
||||||
path: ./out/artifacts
|
|
||||||
6
.github/workflows/cmake.yml
vendored
6
.github/workflows/cmake.yml
vendored
@ -20,9 +20,11 @@ jobs:
|
|||||||
build-ubuntu:
|
build-ubuntu:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-20.04, ubuntu-22.04 ]
|
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ]
|
||||||
compiler: [ g++-9, g++-10, clang++ ]
|
compiler: [ g++-9, g++-10, clang++ ]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-18.04
|
||||||
|
compiler: g++-7
|
||||||
name: Build and Test on Ubuntu
|
name: Build and Test on Ubuntu
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@ -6,11 +6,3 @@ cc_library(
|
|||||||
strip_include_prefix = "include",
|
strip_include_prefix = "include",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
|
|
||||||
|
|
||||||
cc_fuzz_test(
|
|
||||||
name = "cxxopts_fuzz_test",
|
|
||||||
srcs = ["test/fuzz.cpp"],
|
|
||||||
deps = [":cxxopts"],
|
|
||||||
)
|
|
||||||
36
CHANGELOG.md
36
CHANGELOG.md
@ -3,51 +3,17 @@
|
|||||||
This is the changelog for `cxxopts`, a C++11 library for parsing command line
|
This is the changelog for `cxxopts`, a C++11 library for parsing command line
|
||||||
options. The project adheres to semantic versioning.
|
options. The project adheres to semantic versioning.
|
||||||
|
|
||||||
## 3.2.1
|
## Unreleased
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
* Fix compilation with optional on C++20.
|
|
||||||
|
|
||||||
## 3.2
|
|
||||||
|
|
||||||
### Bug fixes
|
|
||||||
|
|
||||||
* Fix unannotated fallthrough.
|
|
||||||
* Fix sign conversion with Unicode output.
|
|
||||||
* Don't initialize regex in static initialiser.
|
|
||||||
* Fix incorrect integer overflow checks.
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
* Add fuzzing to CI
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
* Change quote output to '' to match Windows.
|
|
||||||
* Don't split positional arguments by the list delimiter.
|
|
||||||
* Order help groups by the order they were added.
|
|
||||||
|
|
||||||
## 3.1.1
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fixed version number in header.
|
|
||||||
* Fixed cast warning in Unicode function.
|
|
||||||
|
|
||||||
## 3.1
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* Support for multiple long names for the same option (= multiple long aliases)
|
* Support for multiple long names for the same option (= multiple long aliases)
|
||||||
* Add a `program()` function to retrieve the program name.
|
* Add a `program()` function to retrieve the program name.
|
||||||
* Added a .clang-format file.
|
* Added a .clang-format file.
|
||||||
* Added iterator and printing for a ParseResult.
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Cleanup exception code, add cxxopts::exceptions namespace.
|
* Cleanup exception code, add cxxopts::exceptions namespace.
|
||||||
* Renamed several exceptions to be more descriptive, and added to a nested namespace.
|
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
|||||||
11
README.md
11
README.md
@ -85,6 +85,9 @@ result["opt"].as<type>()
|
|||||||
to get its value. If "opt" doesn't exist, or isn't of the right type, then an
|
to get its value. If "opt" doesn't exist, or isn't of the right type, then an
|
||||||
exception will be thrown.
|
exception will be thrown.
|
||||||
|
|
||||||
|
Note that the result of `options.parse` should only be used as long as the
|
||||||
|
`options` object that created it is in scope.
|
||||||
|
|
||||||
## Unrecognised arguments
|
## Unrecognised arguments
|
||||||
|
|
||||||
You can allow unrecognised arguments to be skipped. This applies to both
|
You can allow unrecognised arguments to be skipped. This applies to both
|
||||||
@ -193,8 +196,8 @@ therefore, `-o false` does not work.
|
|||||||
|
|
||||||
## `std::vector<T>` values
|
## `std::vector<T>` values
|
||||||
|
|
||||||
Parsing a list of values into a `std::vector<T>` is also supported, as long as `T`
|
Parsing of list of values in form of an `std::vector<T>` is also supported, as long as `T`
|
||||||
can be parsed. To separate single values in a list the define symbol `CXXOPTS_VECTOR_DELIMITER`
|
can be parsed. To separate single values in a list the definition `CXXOPTS_VECTOR_DELIMITER`
|
||||||
is used, which is ',' by default. Ensure that you use no whitespaces between values because
|
is used, which is ',' by default. Ensure that you use no whitespaces between values because
|
||||||
those would be interpreted as the next command line option. Example for a command line option
|
those would be interpreted as the next command line option. Example for a command line option
|
||||||
that can be parsed as a `std::vector<double>`:
|
that can be parsed as a `std::vector<double>`:
|
||||||
@ -275,3 +278,7 @@ GCC >= 4.9 or clang >= 3.1 with libc++ are known to work.
|
|||||||
The following compilers are known not to work:
|
The following compilers are known not to work:
|
||||||
|
|
||||||
* MSVC 2013
|
* MSVC 2013
|
||||||
|
|
||||||
|
# TODO list
|
||||||
|
|
||||||
|
* Allow unrecognised options.
|
||||||
|
|||||||
16
WORKSPACE
16
WORKSPACE
@ -1,16 +0,0 @@
|
|||||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
|
||||||
|
|
||||||
http_archive(
|
|
||||||
name = "rules_fuzzing",
|
|
||||||
sha256 = "d9002dd3cd6437017f08593124fdd1b13b3473c7b929ceb0e60d317cb9346118",
|
|
||||||
strip_prefix = "rules_fuzzing-0.3.2",
|
|
||||||
urls = ["https://github.com/bazelbuild/rules_fuzzing/archive/v0.3.2.zip"],
|
|
||||||
)
|
|
||||||
|
|
||||||
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
|
|
||||||
|
|
||||||
rules_fuzzing_dependencies()
|
|
||||||
|
|
||||||
load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")
|
|
||||||
|
|
||||||
rules_fuzzing_init()
|
|
||||||
@ -27,7 +27,6 @@ THE SOFTWARE.
|
|||||||
#ifndef CXXOPTS_HPP_INCLUDED
|
#ifndef CXXOPTS_HPP_INCLUDED
|
||||||
#define CXXOPTS_HPP_INCLUDED
|
#define CXXOPTS_HPP_INCLUDED
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@ -41,7 +40,6 @@ THE SOFTWARE.
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <locale>
|
|
||||||
|
|
||||||
#ifdef CXXOPTS_NO_EXCEPTIONS
|
#ifdef CXXOPTS_NO_EXCEPTIONS
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -56,8 +54,8 @@ THE SOFTWARE.
|
|||||||
#define CXXOPTS_LINKONCE_CONST __declspec(selectany) extern
|
#define CXXOPTS_LINKONCE_CONST __declspec(selectany) extern
|
||||||
#define CXXOPTS_LINKONCE __declspec(selectany) extern
|
#define CXXOPTS_LINKONCE __declspec(selectany) extern
|
||||||
#else
|
#else
|
||||||
#define CXXOPTS_LINKONCE_CONST
|
#define CXXOPTS_LINKONCE_CONST
|
||||||
#define CXXOPTS_LINKONCE
|
#define CXXOPTS_LINKONCE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CXXOPTS_NO_REGEX
|
#ifndef CXXOPTS_NO_REGEX
|
||||||
@ -74,14 +72,6 @@ THE SOFTWARE.
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CXXOPTS_FALLTHROUGH
|
|
||||||
#ifdef __has_cpp_attribute
|
|
||||||
#if __has_cpp_attribute(fallthrough)
|
|
||||||
#undef CXXOPTS_FALLTHROUGH
|
|
||||||
#define CXXOPTS_FALLTHROUGH [[fallthrough]]
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cplusplus >= 201603L
|
#if __cplusplus >= 201603L
|
||||||
#define CXXOPTS_NODISCARD [[nodiscard]]
|
#define CXXOPTS_NODISCARD [[nodiscard]]
|
||||||
#else
|
#else
|
||||||
@ -93,8 +83,8 @@ THE SOFTWARE.
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CXXOPTS__VERSION_MAJOR 3
|
#define CXXOPTS__VERSION_MAJOR 3
|
||||||
#define CXXOPTS__VERSION_MINOR 2
|
#define CXXOPTS__VERSION_MINOR 0
|
||||||
#define CXXOPTS__VERSION_PATCH 1
|
#define CXXOPTS__VERSION_PATCH 0
|
||||||
|
|
||||||
#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6
|
#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6
|
||||||
#define CXXOPTS_NULL_DEREF_IGNORE
|
#define CXXOPTS_NULL_DEREF_IGNORE
|
||||||
@ -239,10 +229,10 @@ stringAppend(String& s, Iterator begin, Iterator end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
size_t
|
std::size_t
|
||||||
stringLength(const String& s)
|
stringLength(const String& s)
|
||||||
{
|
{
|
||||||
return static_cast<size_t>(s.length());
|
return s.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@ -346,8 +336,13 @@ empty(const std::string& s)
|
|||||||
namespace cxxopts {
|
namespace cxxopts {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
#ifdef _WIN32
|
||||||
CXXOPTS_LINKONCE_CONST std::string LQUOTE("\'");
|
CXXOPTS_LINKONCE_CONST std::string LQUOTE("\'");
|
||||||
CXXOPTS_LINKONCE_CONST std::string RQUOTE("\'");
|
CXXOPTS_LINKONCE_CONST std::string RQUOTE("\'");
|
||||||
|
#else
|
||||||
|
CXXOPTS_LINKONCE_CONST std::string LQUOTE("‘");
|
||||||
|
CXXOPTS_LINKONCE_CONST std::string RQUOTE("’");
|
||||||
|
#endif
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we
|
// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we
|
||||||
@ -369,9 +364,6 @@ class Value : public std::enable_shared_from_this<Value>
|
|||||||
std::shared_ptr<Value>
|
std::shared_ptr<Value>
|
||||||
clone() const = 0;
|
clone() const = 0;
|
||||||
|
|
||||||
virtual void
|
|
||||||
add(const std::string& text) const = 0;
|
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
parse(const std::string& text) const = 0;
|
parse(const std::string& text) const = 0;
|
||||||
|
|
||||||
@ -765,31 +757,29 @@ inline ArguDesc ParseArgument(const char *arg, bool &matched)
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
CXXOPTS_LINKONCE
|
CXXOPTS_LINKONCE
|
||||||
const char* const integer_pattern =
|
std::basic_regex<char> integer_pattern
|
||||||
"(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)";
|
("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
|
||||||
CXXOPTS_LINKONCE
|
CXXOPTS_LINKONCE
|
||||||
const char* const truthy_pattern =
|
std::basic_regex<char> truthy_pattern
|
||||||
"(t|T)(rue)?|1";
|
("(t|T)(rue)?|1");
|
||||||
CXXOPTS_LINKONCE
|
CXXOPTS_LINKONCE
|
||||||
const char* const falsy_pattern =
|
std::basic_regex<char> falsy_pattern
|
||||||
"(f|F)(alse)?|0";
|
("(f|F)(alse)?|0");
|
||||||
CXXOPTS_LINKONCE
|
CXXOPTS_LINKONCE
|
||||||
const char* const option_pattern =
|
std::basic_regex<char> option_matcher
|
||||||
"--([[:alnum:]][-_[:alnum:]\\.]+)(=(.*))?|-([[:alnum:]].*)";
|
("--([[:alnum:]][-_[:alnum:]\\.]+)(=(.*))?|-([[:alnum:]].*)");
|
||||||
CXXOPTS_LINKONCE
|
CXXOPTS_LINKONCE
|
||||||
const char* const option_specifier_pattern =
|
std::basic_regex<char> option_specifier
|
||||||
"([[:alnum:]][-_[:alnum:]\\.]*)(,[ ]*[[:alnum:]][-_[:alnum:]]*)*";
|
("([[:alnum:]][-_[:alnum:]\\.]*)(,[ ]*[[:alnum:]][-_[:alnum:]]*)*");
|
||||||
CXXOPTS_LINKONCE
|
CXXOPTS_LINKONCE
|
||||||
const char* const option_specifier_separator_pattern = ", *";
|
std::basic_regex<char> option_specifier_separator(", *");
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
inline IntegerDesc SplitInteger(const std::string &text)
|
inline IntegerDesc SplitInteger(const std::string &text)
|
||||||
{
|
{
|
||||||
static const std::basic_regex<char> integer_matcher(integer_pattern);
|
|
||||||
|
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
std::regex_match(text, match, integer_matcher);
|
std::regex_match(text, match, integer_pattern);
|
||||||
|
|
||||||
if (match.length() == 0)
|
if (match.length() == 0)
|
||||||
{
|
{
|
||||||
@ -813,17 +803,15 @@ inline IntegerDesc SplitInteger(const std::string &text)
|
|||||||
|
|
||||||
inline bool IsTrueText(const std::string &text)
|
inline bool IsTrueText(const std::string &text)
|
||||||
{
|
{
|
||||||
static const std::basic_regex<char> truthy_matcher(truthy_pattern);
|
|
||||||
std::smatch result;
|
std::smatch result;
|
||||||
std::regex_match(text, result, truthy_matcher);
|
std::regex_match(text, result, truthy_pattern);
|
||||||
return !result.empty();
|
return !result.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsFalseText(const std::string &text)
|
inline bool IsFalseText(const std::string &text)
|
||||||
{
|
{
|
||||||
static const std::basic_regex<char> falsy_matcher(falsy_pattern);
|
|
||||||
std::smatch result;
|
std::smatch result;
|
||||||
std::regex_match(text, result, falsy_matcher);
|
std::regex_match(text, result, falsy_pattern);
|
||||||
return !result.empty();
|
return !result.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -832,25 +820,22 @@ inline bool IsFalseText(const std::string &text)
|
|||||||
// (without considering which or how many are single-character)
|
// (without considering which or how many are single-character)
|
||||||
inline OptionNames split_option_names(const std::string &text)
|
inline OptionNames split_option_names(const std::string &text)
|
||||||
{
|
{
|
||||||
static const std::basic_regex<char> option_specifier_matcher(option_specifier_pattern);
|
if (!std::regex_match(text.c_str(), option_specifier))
|
||||||
if (!std::regex_match(text.c_str(), option_specifier_matcher))
|
|
||||||
{
|
{
|
||||||
throw_or_mimic<exceptions::invalid_option_format>(text);
|
throw_or_mimic<exceptions::invalid_option_format>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionNames split_names;
|
OptionNames split_names;
|
||||||
|
|
||||||
static const std::basic_regex<char> option_specifier_separator_matcher(option_specifier_separator_pattern);
|
|
||||||
constexpr int use_non_matches { -1 };
|
constexpr int use_non_matches { -1 };
|
||||||
auto token_iterator = std::sregex_token_iterator(
|
auto token_iterator = std::sregex_token_iterator(
|
||||||
text.begin(), text.end(), option_specifier_separator_matcher, use_non_matches);
|
text.begin(), text.end(), option_specifier_separator, use_non_matches);
|
||||||
std::copy(token_iterator, std::sregex_token_iterator(), std::back_inserter(split_names));
|
std::copy(token_iterator, std::sregex_token_iterator(), std::back_inserter(split_names));
|
||||||
return split_names;
|
return split_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ArguDesc ParseArgument(const char *arg, bool &matched)
|
inline ArguDesc ParseArgument(const char *arg, bool &matched)
|
||||||
{
|
{
|
||||||
static const std::basic_regex<char> option_matcher(option_pattern);
|
|
||||||
std::match_results<const char*> result;
|
std::match_results<const char*> result;
|
||||||
std::regex_match(arg, result, option_matcher);
|
std::regex_match(arg, result, option_matcher);
|
||||||
matched = !result.empty();
|
matched = !result.empty();
|
||||||
@ -973,26 +958,13 @@ integer_parser(const std::string& text, T& value)
|
|||||||
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
US limit = 0;
|
const US next = static_cast<US>(result * base + digit);
|
||||||
if (negative)
|
if (result > next)
|
||||||
{
|
|
||||||
limit = static_cast<US>(std::abs(static_cast<intmax_t>(std::numeric_limits<T>::min())));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
limit = std::numeric_limits<T>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base != 0 && result > limit / base)
|
|
||||||
{
|
|
||||||
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
|
||||||
}
|
|
||||||
if (result * base > limit - digit)
|
|
||||||
{
|
{
|
||||||
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
throw_or_mimic<exceptions::incorrect_argument_type>(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = static_cast<US>(result * base + digit);
|
result = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::check_signed_range<T>(negative, result, text);
|
detail::check_signed_range<T>(negative, result, text);
|
||||||
@ -1062,6 +1034,25 @@ parse_value(const std::string& text, T& value) {
|
|||||||
stringstream_parser(text, value);
|
stringstream_parser(text, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
parse_value(const std::string& text, std::vector<T>& value)
|
||||||
|
{
|
||||||
|
if (text.empty()) {
|
||||||
|
T v;
|
||||||
|
parse_value(text, v);
|
||||||
|
value.emplace_back(std::move(v));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::stringstream in(text);
|
||||||
|
std::string token;
|
||||||
|
while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
|
||||||
|
T v;
|
||||||
|
parse_value(token, v);
|
||||||
|
value.emplace_back(std::move(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CXXOPTS_HAS_OPTIONAL
|
#ifdef CXXOPTS_HAS_OPTIONAL
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void
|
void
|
||||||
@ -1084,41 +1075,6 @@ void parse_value(const std::string& text, char& c)
|
|||||||
c = text[0];
|
c = text[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void
|
|
||||||
parse_value(const std::string& text, std::vector<T>& value)
|
|
||||||
{
|
|
||||||
if (text.empty()) {
|
|
||||||
T v;
|
|
||||||
parse_value(text, v);
|
|
||||||
value.emplace_back(std::move(v));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::stringstream in(text);
|
|
||||||
std::string token;
|
|
||||||
while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
|
|
||||||
T v;
|
|
||||||
parse_value(token, v);
|
|
||||||
value.emplace_back(std::move(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void
|
|
||||||
add_value(const std::string& text, T& value)
|
|
||||||
{
|
|
||||||
parse_value(text, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void
|
|
||||||
add_value(const std::string& text, std::vector<T>& value)
|
|
||||||
{
|
|
||||||
T v;
|
|
||||||
add_value(text, v);
|
|
||||||
value.emplace_back(std::move(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct type_is_container
|
struct type_is_container
|
||||||
{
|
{
|
||||||
@ -1170,12 +1126,6 @@ class abstract_value : public Value
|
|||||||
m_implicit_value = rhs.m_implicit_value;
|
m_implicit_value = rhs.m_implicit_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
add(const std::string& text) const override
|
|
||||||
{
|
|
||||||
add_value(text, *m_store);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parse(const std::string& text) const override
|
parse(const std::string& text) const override
|
||||||
{
|
{
|
||||||
@ -1461,19 +1411,6 @@ struct HelpGroupDetails
|
|||||||
class OptionValue
|
class OptionValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void
|
|
||||||
add
|
|
||||||
(
|
|
||||||
const std::shared_ptr<const OptionDetails>& details,
|
|
||||||
const std::string& text
|
|
||||||
)
|
|
||||||
{
|
|
||||||
ensure_value(details);
|
|
||||||
++m_count;
|
|
||||||
m_value->add(text);
|
|
||||||
m_long_names = &details->long_names();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parse
|
parse
|
||||||
(
|
(
|
||||||
@ -1538,15 +1475,6 @@ CXXOPTS_DIAGNOSTIC_POP
|
|||||||
return CXXOPTS_RTTI_CAST<const values::standard_value<T>&>(*m_value).get();
|
return CXXOPTS_RTTI_CAST<const values::standard_value<T>&>(*m_value).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CXXOPTS_HAS_OPTIONAL
|
|
||||||
template <typename T>
|
|
||||||
std::optional<T>
|
|
||||||
as_optional() const
|
|
||||||
{
|
|
||||||
return as<T>();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void
|
||||||
ensure_value(const std::shared_ptr<const OptionDetails>& details)
|
ensure_value(const std::shared_ptr<const OptionDetails>& details)
|
||||||
@ -1569,7 +1497,7 @@ CXXOPTS_DIAGNOSTIC_POP
|
|||||||
class KeyValue
|
class KeyValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KeyValue(std::string key_, std::string value_) noexcept
|
KeyValue(std::string key_, std::string value_)
|
||||||
: m_key(std::move(key_))
|
: m_key(std::move(key_))
|
||||||
, m_value(std::move(value_))
|
, m_value(std::move(value_))
|
||||||
{
|
{
|
||||||
@ -1622,8 +1550,7 @@ class ParseResult
|
|||||||
Iterator(const Iterator&) = default;
|
Iterator(const Iterator&) = default;
|
||||||
|
|
||||||
// GCC complains about m_iter not being initialised in the member
|
// GCC complains about m_iter not being initialised in the member
|
||||||
// initializer list
|
// initializer list
|
||||||
CXXOPTS_DIAGNOSTIC_PUSH
|
|
||||||
CXXOPTS_IGNORE_WARNING("-Weffc++")
|
CXXOPTS_IGNORE_WARNING("-Weffc++")
|
||||||
Iterator(const ParseResult *pr, bool end=false)
|
Iterator(const ParseResult *pr, bool end=false)
|
||||||
: m_pr(pr)
|
: m_pr(pr)
|
||||||
@ -1759,24 +1686,6 @@ CXXOPTS_DIAGNOSTIC_POP
|
|||||||
return viter->second;
|
return viter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CXXOPTS_HAS_OPTIONAL
|
|
||||||
template <typename T>
|
|
||||||
std::optional<T>
|
|
||||||
as_optional(const std::string& option) const
|
|
||||||
{
|
|
||||||
auto iter = m_keys.find(option);
|
|
||||||
if (iter != m_keys.end())
|
|
||||||
{
|
|
||||||
auto viter = m_values.find(iter->second);
|
|
||||||
if (viter != m_values.end())
|
|
||||||
{
|
|
||||||
return viter->second.as_optional<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const std::vector<KeyValue>&
|
const std::vector<KeyValue>&
|
||||||
arguments() const
|
arguments() const
|
||||||
{
|
{
|
||||||
@ -1871,7 +1780,7 @@ class OptionParser
|
|||||||
);
|
);
|
||||||
|
|
||||||
void
|
void
|
||||||
add_to_option(const std::shared_ptr<OptionDetails>& value, const std::string& arg);
|
add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg);
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_option
|
parse_option
|
||||||
@ -2074,7 +1983,6 @@ class Options
|
|||||||
std::unordered_set<std::string> m_positional_set{};
|
std::unordered_set<std::string> m_positional_set{};
|
||||||
|
|
||||||
//mapping from groups to help options
|
//mapping from groups to help options
|
||||||
std::vector<std::string> m_group{};
|
|
||||||
std::map<std::string, HelpGroupDetails> m_help{};
|
std::map<std::string, HelpGroupDetails> m_help{};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2327,7 +2235,6 @@ OptionAdder::operator()
|
|||||||
case 1:
|
case 1:
|
||||||
short_name = *first_short_name_iter;
|
short_name = *first_short_name_iter;
|
||||||
option_names.erase(first_short_name_iter);
|
option_names.erase(first_short_name_iter);
|
||||||
CXXOPTS_FALLTHROUGH;
|
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2419,13 +2326,9 @@ OptionParser::checked_parse_arg
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
OptionParser::add_to_option(const std::shared_ptr<OptionDetails>& value, const std::string& arg)
|
OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg)
|
||||||
{
|
{
|
||||||
auto hash = value->hash();
|
parse_option(iter->second, option, arg);
|
||||||
auto& result = m_parsed[hash];
|
|
||||||
result.add(value, arg);
|
|
||||||
|
|
||||||
m_sequential.emplace_back(value->essential_name(), arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@ -2442,14 +2345,14 @@ OptionParser::consume_positional(const std::string& a, PositionalListIterator& n
|
|||||||
auto& result = m_parsed[iter->second->hash()];
|
auto& result = m_parsed[iter->second->hash()];
|
||||||
if (result.count() == 0)
|
if (result.count() == 0)
|
||||||
{
|
{
|
||||||
add_to_option(iter->second, a);
|
add_to_option(iter, *next, a);
|
||||||
++next;
|
++next;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
++next;
|
++next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
add_to_option(iter->second, a);
|
add_to_option(iter, *next, a);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
throw_or_mimic<exceptions::no_such_option>(*next);
|
throw_or_mimic<exceptions::no_such_option>(*next);
|
||||||
@ -2713,12 +2616,6 @@ Options::add_option
|
|||||||
}
|
}
|
||||||
|
|
||||||
//add the help details
|
//add the help details
|
||||||
|
|
||||||
if (m_help.find(group) == m_help.end())
|
|
||||||
{
|
|
||||||
m_group.push_back(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& options = m_help[group];
|
auto& options = m_help[group];
|
||||||
|
|
||||||
options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
|
options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
|
||||||
@ -2850,7 +2747,19 @@ inline
|
|||||||
void
|
void
|
||||||
Options::generate_all_groups_help(String& result) const
|
Options::generate_all_groups_help(String& result) const
|
||||||
{
|
{
|
||||||
generate_group_help(result, m_group);
|
std::vector<std::string> all_groups;
|
||||||
|
|
||||||
|
std::transform(
|
||||||
|
m_help.begin(),
|
||||||
|
m_help.end(),
|
||||||
|
std::back_inserter(all_groups),
|
||||||
|
[] (const std::map<std::string, HelpGroupDetails>::value_type& group)
|
||||||
|
{
|
||||||
|
return group.first;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
generate_group_help(result, all_groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@ -2890,7 +2799,19 @@ inline
|
|||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
Options::groups() const
|
Options::groups() const
|
||||||
{
|
{
|
||||||
return m_group;
|
std::vector<std::string> g;
|
||||||
|
|
||||||
|
std::transform(
|
||||||
|
m_help.begin(),
|
||||||
|
m_help.end(),
|
||||||
|
std::back_inserter(g),
|
||||||
|
[] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
|
||||||
|
{
|
||||||
|
return pair.first;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
|
|||||||
@ -51,10 +51,3 @@ add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
|
|||||||
|
|
||||||
add_executable(link_test link_a.cpp link_b.cpp)
|
add_executable(link_test link_a.cpp link_b.cpp)
|
||||||
target_link_libraries(link_test cxxopts)
|
target_link_libraries(link_test cxxopts)
|
||||||
|
|
||||||
if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") AND ("${CMAKE_SYSTEM}" MATCHES "Linux"))
|
|
||||||
add_executable(fuzzer fuzz.cpp)
|
|
||||||
target_link_libraries(fuzzer PRIVATE cxxopts)
|
|
||||||
target_compile_options(fuzzer PRIVATE -fsanitize=fuzzer)
|
|
||||||
target_link_options(fuzzer PRIVATE -fsanitize=fuzzer)
|
|
||||||
endif()
|
|
||||||
|
|||||||
24782
test/catch.hpp
24782
test/catch.hpp
File diff suppressed because it is too large
Load Diff
107
test/fuzz.cpp
107
test/fuzz.cpp
@ -1,107 +0,0 @@
|
|||||||
#include <cassert>
|
|
||||||
#include <cxxopts.hpp>
|
|
||||||
#include <fuzzer/FuzzedDataProvider.h>
|
|
||||||
|
|
||||||
constexpr int kMaxOptions = 1024;
|
|
||||||
constexpr int kMaxArgSize = 1024;
|
|
||||||
|
|
||||||
enum class ParseableTypes
|
|
||||||
{
|
|
||||||
kInt,
|
|
||||||
kString,
|
|
||||||
kVectorString,
|
|
||||||
kFloat,
|
|
||||||
kDouble,
|
|
||||||
|
|
||||||
// Marker for fuzzer.
|
|
||||||
kMaxValue,
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void
|
|
||||||
add_fuzzed_option(cxxopts::Options* options, FuzzedDataProvider* provider)
|
|
||||||
{
|
|
||||||
assert(options);
|
|
||||||
assert(provider);
|
|
||||||
|
|
||||||
options->add_options()(provider->ConsumeRandomLengthString(kMaxArgSize),
|
|
||||||
provider->ConsumeRandomLengthString(kMaxArgSize),
|
|
||||||
cxxopts::value<T>());
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int
|
|
||||||
LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FuzzedDataProvider provider(data, size);
|
|
||||||
|
|
||||||
// Randomly generate a usage string.
|
|
||||||
cxxopts::Options options(provider.ConsumeRandomLengthString(kMaxArgSize),
|
|
||||||
provider.ConsumeRandomLengthString(kMaxArgSize));
|
|
||||||
|
|
||||||
// Randomly generate a set of flags configurations.
|
|
||||||
for (int i = 0; i < provider.ConsumeIntegralInRange<int>(0, kMaxOptions);
|
|
||||||
i++)
|
|
||||||
{
|
|
||||||
switch (provider.ConsumeEnum<ParseableTypes>())
|
|
||||||
{
|
|
||||||
case ParseableTypes::kInt:
|
|
||||||
add_fuzzed_option<int>(&options, &provider);
|
|
||||||
break;
|
|
||||||
case ParseableTypes::kString:
|
|
||||||
add_fuzzed_option<std::string>(&options, &provider);
|
|
||||||
break;
|
|
||||||
case ParseableTypes::kVectorString:
|
|
||||||
add_fuzzed_option<std::vector<std::string>>(&options, &provider);
|
|
||||||
break;
|
|
||||||
case ParseableTypes::kFloat:
|
|
||||||
add_fuzzed_option<float>(&options, &provider);
|
|
||||||
break;
|
|
||||||
case ParseableTypes::kDouble:
|
|
||||||
add_fuzzed_option<double>(&options, &provider);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sometimes allow unrecognised options.
|
|
||||||
if (provider.ConsumeBool())
|
|
||||||
{
|
|
||||||
options.allow_unrecognised_options();
|
|
||||||
}
|
|
||||||
// Sometimes allow trailing positional arguments.
|
|
||||||
if (provider.ConsumeBool())
|
|
||||||
{
|
|
||||||
std::string positional_option_name =
|
|
||||||
provider.ConsumeRandomLengthString(kMaxArgSize);
|
|
||||||
options.add_options()(positional_option_name,
|
|
||||||
provider.ConsumeRandomLengthString(kMaxArgSize),
|
|
||||||
cxxopts::value<std::vector<std::string>>());
|
|
||||||
options.parse_positional({positional_option_name});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build command line input.
|
|
||||||
const int argc = provider.ConsumeIntegralInRange<int>(1, kMaxOptions);
|
|
||||||
|
|
||||||
std::vector<std::string> command_line_container;
|
|
||||||
command_line_container.reserve(argc);
|
|
||||||
|
|
||||||
std::vector<const char*> argv;
|
|
||||||
argv.reserve(argc);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
command_line_container.push_back(
|
|
||||||
provider.ConsumeRandomLengthString(kMaxArgSize));
|
|
||||||
argv.push_back(command_line_container[i].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse command line;
|
|
||||||
auto result = options.parse(argc, argv.data());
|
|
||||||
} catch (...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
149
test/options.cpp
149
test/options.cpp
@ -112,7 +112,7 @@ TEST_CASE("Basic options", "[options]")
|
|||||||
CHECK(arguments[2].key() == "value");
|
CHECK(arguments[2].key() == "value");
|
||||||
CHECK(arguments[3].key() == "av");
|
CHECK(arguments[3].key() == "av");
|
||||||
|
|
||||||
CHECK_THROWS_AS(result["nothing"].as<std::string>(), cxxopts::exceptions::option_has_no_value);
|
CHECK_THROWS_AS(result["nothing"].as<std::string>(), cxxopts::exceptions::option_has_no_value&);
|
||||||
|
|
||||||
CHECK(options.program() == "tester");
|
CHECK(options.program() == "tester");
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ TEST_CASE("Short options", "[options]")
|
|||||||
CHECK(result["c"].as<std::string>() == "foo=something");
|
CHECK(result["c"].as<std::string>() == "foo=something");
|
||||||
|
|
||||||
REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
|
REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
|
||||||
cxxopts::exceptions::invalid_option_format);
|
cxxopts::exceptions::invalid_option_format&);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("No positional", "[positional]")
|
TEST_CASE("No positional", "[positional]")
|
||||||
@ -238,6 +238,9 @@ TEST_CASE("No positional with extras", "[positional]")
|
|||||||
auto** argv = av.argv();
|
auto** argv = av.argv();
|
||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
|
auto old_argv = argv;
|
||||||
|
auto old_argc = argc;
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
auto result = options.parse(argc, argv);
|
||||||
|
|
||||||
auto& unmatched = result.unmatched();
|
auto& unmatched = result.unmatched();
|
||||||
@ -257,7 +260,7 @@ TEST_CASE("Positional not valid", "[positional]") {
|
|||||||
auto** argv = av.argv();
|
auto** argv = av.argv();
|
||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::no_such_option);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::no_such_option&);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Positional with empty arguments", "[positional]") {
|
TEST_CASE("Positional with empty arguments", "[positional]") {
|
||||||
@ -285,37 +288,6 @@ TEST_CASE("Positional with empty arguments", "[positional]") {
|
|||||||
REQUIRE(actual == expected);
|
REQUIRE(actual == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Positional with list delimiter", "[positional]") {
|
|
||||||
std::string single;
|
|
||||||
std::vector<std::string> positional;
|
|
||||||
|
|
||||||
cxxopts::Options options("test_all_positional_list_delimiter", " - test all positional with list delimiters");
|
|
||||||
options.add_options()
|
|
||||||
("single", "Single positional param",
|
|
||||||
cxxopts::value<std::string>(single))
|
|
||||||
("positional", "Positional parameters vector",
|
|
||||||
cxxopts::value<std::vector<std::string>>(positional))
|
|
||||||
;
|
|
||||||
|
|
||||||
Argv av({"tester", "a,b", "c,d", "e"});
|
|
||||||
|
|
||||||
auto argc = av.argc();
|
|
||||||
auto argv = av.argv();
|
|
||||||
|
|
||||||
std::vector<std::string> pos_names = {"single", "positional"};
|
|
||||||
|
|
||||||
options.parse_positional(pos_names.begin(), pos_names.end());
|
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
|
||||||
|
|
||||||
CHECK(result.unmatched().size() == 0);
|
|
||||||
REQUIRE(positional.size() == 2);
|
|
||||||
|
|
||||||
CHECK(single == "a,b");
|
|
||||||
CHECK(positional[0] == "c,d");
|
|
||||||
CHECK(positional[1] == "e");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Empty with implicit value", "[implicit]")
|
TEST_CASE("Empty with implicit value", "[implicit]")
|
||||||
{
|
{
|
||||||
cxxopts::Options options("empty_implicit", "doesn't handle empty");
|
cxxopts::Options options("empty_implicit", "doesn't handle empty");
|
||||||
@ -347,7 +319,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
|
|||||||
auto** argv = av.argv();
|
auto** argv = av.argv();
|
||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::missing_argument);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::missing_argument&);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("With equal-separated true") {
|
SECTION("With equal-separated true") {
|
||||||
@ -517,7 +489,7 @@ TEST_CASE("Unsigned integers", "[options]")
|
|||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
options.parse_positional("positional");
|
options.parse_positional("positional");
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Integer bounds", "[integer]")
|
TEST_CASE("Integer bounds", "[integer]")
|
||||||
@ -552,32 +524,14 @@ TEST_CASE("Overflow on boundary", "[integer]")
|
|||||||
using namespace cxxopts::values;
|
using namespace cxxopts::values;
|
||||||
|
|
||||||
int8_t si;
|
int8_t si;
|
||||||
int16_t si16;
|
|
||||||
int64_t si64;
|
|
||||||
uint8_t ui;
|
uint8_t ui;
|
||||||
uint16_t ui16;
|
|
||||||
uint64_t ui64;
|
|
||||||
|
|
||||||
CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
|
|
||||||
CHECK_THROWS_AS((integer_parser("65536", ui16)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("75536", ui16)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("32768", si16)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("-32769", si16)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("-42769", si16)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("-75536", si16)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
|
|
||||||
CHECK_THROWS_AS((integer_parser("18446744073709551616", ui64)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("28446744073709551616", ui64)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("9223372036854775808", si64)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("-9223372036854775809", si64)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("-10223372036854775809", si64)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
CHECK_THROWS_AS((integer_parser("-28446744073709551616", si64)), cxxopts::exceptions::incorrect_argument_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Integer overflow", "[options]")
|
TEST_CASE("Integer overflow", "[options]")
|
||||||
@ -594,11 +548,11 @@ TEST_CASE("Integer overflow", "[options]")
|
|||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
options.parse_positional("positional");
|
options.parse_positional("positional");
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
|
|
||||||
int integer = 0;
|
int integer = 0;
|
||||||
CHECK_THROWS_AS((integer_parser("23423423423", integer)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("23423423423", integer)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
CHECK_THROWS_AS((integer_parser("234234234234", integer)), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS((integer_parser("234234234234", integer)), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Floats", "[options]")
|
TEST_CASE("Floats", "[options]")
|
||||||
@ -639,7 +593,7 @@ TEST_CASE("Invalid integers", "[integer]") {
|
|||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
options.parse_positional("positional");
|
options.parse_positional("positional");
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::incorrect_argument_type);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::incorrect_argument_type&);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Booleans", "[boolean]") {
|
TEST_CASE("Booleans", "[boolean]") {
|
||||||
@ -709,13 +663,11 @@ TEST_CASE("std::vector", "[vector]") {
|
|||||||
#ifdef CXXOPTS_HAS_OPTIONAL
|
#ifdef CXXOPTS_HAS_OPTIONAL
|
||||||
TEST_CASE("std::optional", "[optional]") {
|
TEST_CASE("std::optional", "[optional]") {
|
||||||
std::optional<std::string> optional;
|
std::optional<std::string> optional;
|
||||||
std::optional<bool> opt_bool;
|
|
||||||
cxxopts::Options options("optional", " - tests optional");
|
cxxopts::Options options("optional", " - tests optional");
|
||||||
options.add_options()
|
options.add_options()
|
||||||
("optional", "an optional option", cxxopts::value<std::optional<std::string>>(optional))
|
("optional", "an optional option", cxxopts::value<std::optional<std::string>>(optional));
|
||||||
("optional_bool", "an boolean optional", cxxopts::value<std::optional<bool>>(opt_bool)->default_value("false"));
|
|
||||||
|
|
||||||
Argv av({"optional", "--optional", "foo", "--optional_bool", "true"});
|
Argv av({"optional", "--optional", "foo"});
|
||||||
|
|
||||||
auto** argv = av.argv();
|
auto** argv = av.argv();
|
||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
@ -724,8 +676,6 @@ TEST_CASE("std::optional", "[optional]") {
|
|||||||
|
|
||||||
REQUIRE(optional.has_value());
|
REQUIRE(optional.has_value());
|
||||||
CHECK(*optional == "foo");
|
CHECK(*optional == "foo");
|
||||||
CHECK(opt_bool.has_value());
|
|
||||||
CHECK(*opt_bool);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -749,7 +699,7 @@ TEST_CASE("Unrecognised options", "[options]") {
|
|||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
SECTION("Default behaviour") {
|
SECTION("Default behaviour") {
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::no_such_option);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::no_such_option&);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("After allowing unrecognised options") {
|
SECTION("After allowing unrecognised options") {
|
||||||
@ -776,7 +726,7 @@ TEST_CASE("Allow bad short syntax", "[options]") {
|
|||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
SECTION("Default behaviour") {
|
SECTION("Default behaviour") {
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::invalid_option_syntax);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::invalid_option_syntax&);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("After allowing unrecognised options") {
|
SECTION("After allowing unrecognised options") {
|
||||||
@ -799,7 +749,7 @@ TEST_CASE("Invalid option syntax", "[options]") {
|
|||||||
auto argc = av.argc();
|
auto argc = av.argc();
|
||||||
|
|
||||||
SECTION("Default behaviour") {
|
SECTION("Default behaviour") {
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::invalid_option_syntax);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::invalid_option_syntax&);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,60 +768,9 @@ TEST_CASE("Options empty", "[options]") {
|
|||||||
auto** argv = argv_.argv();
|
auto** argv = argv_.argv();
|
||||||
|
|
||||||
CHECK(options.groups().empty());
|
CHECK(options.groups().empty());
|
||||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::no_such_option);
|
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::exceptions::no_such_option&);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CXXOPTS_HAS_OPTIONAL
|
|
||||||
TEST_CASE("Optional value", "[optional]")
|
|
||||||
{
|
|
||||||
cxxopts::Options options("options", "query as std::optional");
|
|
||||||
options.add_options()
|
|
||||||
("int", "Integer", cxxopts::value<int>())
|
|
||||||
("float", "Float", cxxopts::value<float>())
|
|
||||||
("string", "String", cxxopts::value<std::string>())
|
|
||||||
;
|
|
||||||
|
|
||||||
SECTION("Available") {
|
|
||||||
Argv av({
|
|
||||||
"--int",
|
|
||||||
"42",
|
|
||||||
"--float",
|
|
||||||
"3.141",
|
|
||||||
"--string",
|
|
||||||
"Hello"
|
|
||||||
});
|
|
||||||
|
|
||||||
auto** argv = av.argv();
|
|
||||||
auto argc = av.argc();
|
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
|
||||||
|
|
||||||
CHECK(result.as_optional<int>("int"));
|
|
||||||
CHECK(result.as_optional<float>("float"));
|
|
||||||
CHECK(result.as_optional<string>("string"));
|
|
||||||
|
|
||||||
CHECK(*result.as_optional<int>("int") == 42);
|
|
||||||
CHECK(*result.as_optional<float>("float") == 3.141);
|
|
||||||
CHECK(*result.as_optional<string>("string") == "Hello");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Unavailable") {
|
|
||||||
Argv av({
|
|
||||||
});
|
|
||||||
|
|
||||||
auto** argv = av.argv();
|
|
||||||
auto argc = av.argc();
|
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
|
||||||
|
|
||||||
CHECK(!result.as_optional<int>("int"));
|
|
||||||
CHECK(!result.as_optional<float>("float"));
|
|
||||||
CHECK(!result.as_optional<string>("string"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST_CASE("Initializer list with group", "[options]") {
|
TEST_CASE("Initializer list with group", "[options]") {
|
||||||
cxxopts::Options options("Initializer list group", " - test initializer list with group");
|
cxxopts::Options options("Initializer list group", " - test initializer list with group");
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user