Devendor cxxopts to submodule
parent
8aacc2d317
commit
3df4eaef2d
@ -0,0 +1 @@
|
||||
Subproject commit 6fa46a748838d5544ff8e9ab058906ba2c4bc0f3
|
@ -1,8 +0,0 @@
|
||||
*.swp
|
||||
build*
|
||||
CMakeCache.txt
|
||||
Makefile
|
||||
CMakeFiles/
|
||||
Testing/
|
||||
CTestTestfile.cmake
|
||||
cmake_install.cmake
|
@ -1,70 +0,0 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: COMPILER=g++-4.9
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.9
|
||||
sources: &sources
|
||||
- llvm-toolchain-trusty-3.8
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- ubuntu-toolchain-r-test
|
||||
- os: linux
|
||||
env: COMPILER=g++-4.9 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.9
|
||||
sources: *sources
|
||||
- os: linux
|
||||
env: COMPILER=g++-5
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
sources: *sources
|
||||
- os: linux
|
||||
env: COMPILER=g++-5 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
sources: *sources
|
||||
- os: linux
|
||||
env: COMPILER=clang++-3.8 CXXFLAGS=-stdlib=libc++
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
- libc++-dev
|
||||
sources: *sources
|
||||
- os: linux
|
||||
env: COMPILER=clang++-3.8 CXXFLAGS=-stdlib=libc++ UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
- libc++-dev
|
||||
sources: *sources
|
||||
- os: linux
|
||||
env: COMPILER=clang++-5.0 CMAKE_OPTIONS=-DCXXOPTS_CXX_STANDARD=17
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-5.0
|
||||
- g++-5
|
||||
sources: *sources
|
||||
script: >
|
||||
cmake -DCXXOPTS_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=$COMPILER
|
||||
-DCMAKE_CXX_FLAGS=$CXXFLAGS $UNICODE_OPTIONS $CMAKE_OPTIONS .
|
||||
&& make && make ARGS=--output-on-failure test
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install icu4c; fi
|
@ -1,96 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
This is the changelog for `cxxopts`, a C++11 library for parsing command line
|
||||
options. The project adheres to semantic versioning.
|
||||
|
||||
## Next version
|
||||
|
||||
### Changed
|
||||
|
||||
* Only search for a C++ compiler in CMakeLists.txt.
|
||||
* Allow for exceptions to be disabled.
|
||||
* Fix duplicate default options when there is a short and long option.
|
||||
* Add `CXXOPTS_NO_EXCEPTIONS` to disable exceptions.
|
||||
|
||||
## 2.2
|
||||
|
||||
### Changed
|
||||
|
||||
* Allow integers to have leading zeroes.
|
||||
* Build the tests by default.
|
||||
* Don't check for container when showing positional help.
|
||||
|
||||
### Added
|
||||
|
||||
* Iterator inputs to `parse_positional`.
|
||||
* Throw an exception if the option in `parse_positional` doesn't exist.
|
||||
* Parse a delimited list in a single argument for vector options.
|
||||
* Add an option to disable implicit value on booleans.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fix a warning about possible loss of data.
|
||||
* Fix version numbering in CMakeLists.txt
|
||||
* Remove unused declaration of the undefined `ParseResult::get_option`.
|
||||
* Throw on invalid option syntax when beginning with a `-`.
|
||||
* Throw in `as` when option wasn't present.
|
||||
* Fix catching exceptions by reference.
|
||||
* Fix out of bounds errors parsing integers.
|
||||
|
||||
## 2.1.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Revert the change adding `const` type for `argv`, because most users expect
|
||||
to pass a non-const `argv` from `main`.
|
||||
|
||||
## 2.1
|
||||
|
||||
### Changed
|
||||
|
||||
* Options with implicit arguments now require the `--option=value` form if
|
||||
they are to be specified with an option. This is to remove the ambiguity
|
||||
when a positional argument could follow an option with an implicit value.
|
||||
For example, `--foo value`, where `foo` has an implicit value, will be
|
||||
parsed as `--foo=implicit` and a positional argument `value`.
|
||||
* Boolean values are no longer special, but are just an option with a default
|
||||
and implicit value.
|
||||
|
||||
### Added
|
||||
|
||||
* Added support for `std::optional` as a storage type.
|
||||
* Allow the help string to be customised.
|
||||
* Use `const` for the type in the `argv` parameter, since the contents of the
|
||||
arguments is never modified.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Building against GCC 4.9 was broken due to overly strict shadow warnings.
|
||||
* Fixed an ambiguous overload in the `parse_positional` function when an
|
||||
`initializer_list` was directly passed.
|
||||
* Fixed precedence in the Boolean value regex.
|
||||
|
||||
## 2.0
|
||||
|
||||
### Changed
|
||||
|
||||
* `Options::parse` returns a ParseResult rather than storing the parse
|
||||
result internally.
|
||||
* Options with default values now get counted as appearing once if they
|
||||
were not specified by the user.
|
||||
|
||||
### Added
|
||||
|
||||
* A new `ParseResult` object that is the immutable result of parsing. It
|
||||
responds to the same `count` and `operator[]` as `Options` of 1.x did.
|
||||
* The function `ParseResult::arguments` returns a vector of the parsed
|
||||
arguments to iterate through in the order they were provided.
|
||||
* The symbol `cxxopts::version` for the version of the library.
|
||||
* Booleans can be specified with various strings and explicitly set false.
|
||||
|
||||
## 1.x
|
||||
|
||||
The 1.x series was the first major version of the library, with release numbers
|
||||
starting to follow semantic versioning, after 0.x being unstable. It never had
|
||||
a changelog maintained for it. Releases mostly contained bug fixes, with the
|
||||
occasional feature added.
|
@ -1,108 +0,0 @@
|
||||
# Copyright (c) 2014 Jarryd Beck
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
# parse the current version from the cxxopts header
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/cxxopts.hpp" cxxopts_version_defines
|
||||
REGEX "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH)")
|
||||
foreach(ver ${cxxopts_version_defines})
|
||||
if(ver MATCHES "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
|
||||
set(CXXOPTS__VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
|
||||
endif()
|
||||
endforeach()
|
||||
set(VERSION ${CXXOPTS__VERSION_MAJOR}.${CXXOPTS__VERSION_MINOR}.${CXXOPTS__VERSION_PATCH})
|
||||
message(STATUS "cxxopts version ${VERSION}")
|
||||
|
||||
project(cxxopts VERSION "${VERSION}" LANGUAGES CXX)
|
||||
|
||||
enable_testing()
|
||||
|
||||
option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON)
|
||||
option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" ON)
|
||||
option(CXXOPTS_ENABLE_INSTALL "Generate the install target" OFF)
|
||||
|
||||
# request c++11 without gnu extension for the whole project and enable more warnings
|
||||
if (CXXOPTS_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD ${CXXOPTS_CXX_STANDARD})
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2")
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow")
|
||||
endif()
|
||||
|
||||
add_library(cxxopts INTERFACE)
|
||||
add_library(cxxopts::cxxopts ALIAS cxxopts)
|
||||
|
||||
# optionally, enable unicode support using the ICU library
|
||||
set(CXXOPTS_USE_UNICODE_HELP FALSE CACHE BOOL "Use ICU Unicode library")
|
||||
if(CXXOPTS_USE_UNICODE_HELP)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(ICU REQUIRED icu-uc)
|
||||
|
||||
target_link_libraries(cxxopts INTERFACE ${ICU_LDFLAGS})
|
||||
target_compile_options(cxxopts INTERFACE ${ICU_CFLAGS})
|
||||
target_compile_definitions(cxxopts INTERFACE CXXOPTS_USE_UNICODE)
|
||||
endif()
|
||||
|
||||
target_include_directories(cxxopts INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
if(CXXOPTS_ENABLE_INSTALL)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(CXXOPTS_CMAKE_DIR "lib/cmake/cxxopts" CACHE STRING
|
||||
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
||||
set(version_config "${PROJECT_BINARY_DIR}/cxxopts-config-version.cmake")
|
||||
set(project_config "${PROJECT_BINARY_DIR}/cxxopts-config.cmake")
|
||||
set(targets_export_name cxxopts-targets)
|
||||
|
||||
# Generate the version, config and target files into the build directory.
|
||||
write_basic_package_version_file(
|
||||
${version_config}
|
||||
VERSION ${VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
configure_package_config_file(
|
||||
${PROJECT_SOURCE_DIR}/cxxopts-config.cmake.in
|
||||
${project_config}
|
||||
INSTALL_DESTINATION ${CXXOPTS_CMAKE_DIR})
|
||||
export(TARGETS cxxopts NAMESPACE cxxopts::
|
||||
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
|
||||
|
||||
# Install version, config and target files.
|
||||
install(
|
||||
FILES ${project_config} ${version_config}
|
||||
DESTINATION ${CXXOPTS_CMAKE_DIR})
|
||||
install(EXPORT ${targets_export_name} DESTINATION ${CXXOPTS_CMAKE_DIR}
|
||||
NAMESPACE cxxopts::)
|
||||
|
||||
# Install the header file and export the target
|
||||
install(TARGETS cxxopts EXPORT ${targets_export_name} DESTINATION lib)
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/include/cxxopts.hpp DESTINATION include)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(test)
|
@ -1,23 +0,0 @@
|
||||
== System installation ==
|
||||
|
||||
This library is header only. So you can either copy `include/cxxopts.hpp` to `/usr/include` or `/usr/local/include`, or add `include` to your search path.
|
||||
|
||||
== Building the examples and tests ==
|
||||
|
||||
It is preferable to build out of source. Make a build directory somewhere, and then
|
||||
do the following, where `${CXXOPTS_DIR}` is the path that you checked out `cxxopts`
|
||||
to:
|
||||
|
||||
cmake ${CXXOPTS_DIR}
|
||||
make
|
||||
|
||||
You can use another build tool, such as ninja.
|
||||
|
||||
cmake -G Ninja ${CXXOPTS_DIR}
|
||||
ninja
|
||||
|
||||
|
||||
To run the tests, you have to configure `cxxopts` with another flag:
|
||||
cmake -D CXXOPTS_BUILD_TESTS=On ${CXXOPTS_DIR}
|
||||
make
|
||||
make test
|
@ -1,19 +0,0 @@
|
||||
Copyright (c) 2014 Jarryd Beck
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@ -1,148 +0,0 @@
|
||||
[](https://travis-ci.org/jarro2783/cxxopts)
|
||||
|
||||
# Release versions
|
||||
|
||||
Note that `master` is generally a work in progress, and you probably want to use a
|
||||
tagged release version.
|
||||
|
||||
# Quick start
|
||||
|
||||
This is a lightweight C++ option parser library, supporting the standard GNU
|
||||
style syntax for options.
|
||||
|
||||
Options can be given as:
|
||||
|
||||
--long
|
||||
--long=argument
|
||||
--long argument
|
||||
-a
|
||||
-ab
|
||||
-abc argument
|
||||
|
||||
where c takes an argument, but a and b do not.
|
||||
|
||||
Additionally, anything after `--` will be parsed as a positional argument.
|
||||
|
||||
## Basics
|
||||
|
||||
#include <cxxopts.hpp>
|
||||
|
||||
Create a cxxopts::Options instance.
|
||||
|
||||
cxxopts::Options options("MyProgram", "One line description of MyProgram");
|
||||
|
||||
Then use `add_options`.
|
||||
|
||||
options.add_options()
|
||||
("d,debug", "Enable debugging")
|
||||
("f,file", "File name", cxxopts::value<std::string>())
|
||||
;
|
||||
|
||||
Options are declared with a long and an optional short option. A description
|
||||
must be provided. The third argument is the value, if omitted it is boolean.
|
||||
Any type can be given as long as it can be parsed, with operator>>.
|
||||
|
||||
To parse the command line do:
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
To retrieve an option use `result.count("option")` to get the number of times
|
||||
it appeared, and
|
||||
|
||||
result["opt"].as<type>()
|
||||
|
||||
to get its value. If "opt" doesn't exist, or isn't of the right type, then an
|
||||
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.
|
||||
|
||||
## Exceptions
|
||||
|
||||
Exceptional situations throw C++ exceptions. There are two types of
|
||||
exceptions: errors defining the options, and errors when parsing a list of
|
||||
arguments. All exceptions derive from `cxxopts::OptionException`. Errors
|
||||
defining options derive from `cxxopts::OptionSpecException` and errors
|
||||
parsing arguments derive from `cxxopts::OptionParseException`.
|
||||
|
||||
All exceptions define a `what()` function to get a printable string
|
||||
explaining the error.
|
||||
|
||||
## Help groups
|
||||
|
||||
Options can be placed into groups for the purposes of displaying help messages.
|
||||
To place options in a group, pass the group as a string to `add_options`. Then,
|
||||
when displaying the help, pass the groups that you would like displayed as a
|
||||
vector to the `help` function.
|
||||
|
||||
## Positional Arguments
|
||||
|
||||
Positional arguments can be optionally parsed into one or more options.
|
||||
To set up positional arguments, call
|
||||
|
||||
options.parse_positional({"first", "second", "last"})
|
||||
|
||||
where "last" should be the name of an option with a container type, and the
|
||||
others should have a single value.
|
||||
|
||||
## Default and implicit values
|
||||
|
||||
An option can be declared with a default or an implicit value, or both.
|
||||
|
||||
A default value is the value that an option takes when it is not specified
|
||||
on the command line. The following specifies a default value for an option:
|
||||
|
||||
cxxopts::value<std::string>()->default_value("value")
|
||||
|
||||
An implicit value is the value that an option takes when it is given on the
|
||||
command line without an argument. The following specifies an implicit value:
|
||||
|
||||
cxxopts::value<std::string>()->implicit_value("implicit")
|
||||
|
||||
If an option had both, then not specifying it would give the value `"value"`,
|
||||
writing it on the command line as `--option` would give the value `"implicit"`,
|
||||
and writing `--option=another` would give it the value `"another"`.
|
||||
|
||||
Note that the default and implicit value is always stored as a string,
|
||||
regardless of the type that you want to store it in. It will be parsed as
|
||||
though it was given on the command line.
|
||||
|
||||
## Boolean values
|
||||
|
||||
Boolean options have a default implicit value of `"true"`, which can be
|
||||
overridden. The effect is that writing `-o` by itself will set option `o` to
|
||||
`true`. However, they can also be written with various strings using `=value`.
|
||||
There is no way to disambiguate positional arguments from the value following
|
||||
a boolean, so we have chosen that they will be positional arguments, and
|
||||
therefore, `-o false` does not work.
|
||||
|
||||
## `std::vector<T>` values
|
||||
|
||||
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 definition `CXXOPTS_VECTOR_DELIMITER`
|
||||
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
|
||||
that can be parsed as a `std::vector<double>`:
|
||||
|
||||
~~~
|
||||
--my_list=1,-2.1,3,4.5
|
||||
~~~
|
||||
|
||||
## Custom help
|
||||
|
||||
The string after the program name on the first line of the help can be
|
||||
completely replaced by calling `options.custom_help`. Note that you might
|
||||
also want to override the positional help by calling `options.positional_help`.
|
||||
|
||||
# Linking
|
||||
|
||||
This is a header only library.
|
||||
|
||||
# Requirements
|
||||
|
||||
The only build requirement is a C++ compiler that supports C++11 regular
|
||||
expressions. For example GCC >= 4.9 or clang with libc++.
|
||||
|
||||
# TODO list
|
||||
|
||||
* Allow unrecognised options.
|
@ -1,4 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
|
||||
check_required_components(cxxopts)
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
example
|
@ -1,24 +0,0 @@
|
||||
# Copyright (c) 2014 Jarryd Beck
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
if(CXXOPTS_BUILD_EXAMPLES)
|
||||
add_executable(example example.cpp)
|
||||
target_link_libraries(example cxxopts)
|
||||
endif()
|
@ -1 +0,0 @@
|
||||
options_test
|
@ -1,35 +0,0 @@
|
||||
if (CXXOPTS_BUILD_TESTS)
|
||||
add_executable(options_test main.cpp options.cpp)
|
||||
target_link_libraries(options_test cxxopts)
|
||||
add_test(options options_test)
|
||||
|
||||
# test if the targets are findable from the build directory
|
||||
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
||||
-C ${CMAKE_BUILD_TYPE}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/find-package-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/find-package-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
|
||||
"-Dcxxopts_DIR=${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# test if the targets are findable when add_subdirectory is used
|
||||
add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
|
||||
-C ${CMAKE_BUILD_TYPE}
|
||||
--build-and-test
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test"
|
||||
--build-generator ${CMAKE_GENERATOR}
|
||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||
--build-options
|
||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
|
||||
)
|
||||
|
||||
add_executable(link_test link_a.cpp link_b.cpp)
|
||||
target_link_libraries(link_test cxxopts)
|
||||
endif()
|
@ -1,11 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(cxxopts-test)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
add_subdirectory(../.. cxxopts EXCLUDE_FROM_ALL)
|
||||
|
||||
add_executable(library-test "../../src/example.cpp")
|
||||
target_link_libraries(library-test cxxopts)
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(cxxopts-test)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
find_package(cxxopts REQUIRED)
|
||||
|
||||
add_executable(library-test "../../src/example.cpp")
|
||||
target_link_libraries(library-test cxxopts::cxxopts)
|
@ -1,6 +0,0 @@
|
||||
#include "cxxopts.hpp"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
#include <cxxopts.hpp>
|
@ -1,2 +0,0 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
@ -1,776 +0,0 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "cxxopts.hpp"
|
||||
|
||||
class Argv {
|
||||
public:
|
||||
|
||||
Argv(std::initializer_list<const char*> args)
|
||||
: m_argv(new char*[args.size()])
|
||||
, m_argc(static_cast<int>(args.size()))
|
||||
{
|
||||
int i = 0;
|
||||
auto iter = args.begin();
|
||||
while (iter != args.end()) {
|
||||
auto len = strlen(*iter) + 1;
|
||||
auto ptr = std::unique_ptr<char[]>(new char[len]);
|
||||
|
||||
strcpy(ptr.get(), *iter);
|
||||
m_args.push_back(std::move(ptr));
|
||||
m_argv.get()[i] = m_args.back().get();
|
||||
|
||||
++iter;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
char** argv() const {
|
||||
return m_argv.get();
|
||||
}
|
||||
|
||||
int argc() const {
|
||||
return m_argc;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<std::unique_ptr<char[]>> m_args;
|
||||
std::unique_ptr<char*[]> m_argv;
|
||||
int m_argc;
|
||||
};
|
||||
|
||||
TEST_CASE("Basic options", "[options]")
|
||||
{
|
||||
|
||||
cxxopts::Options options("tester", " - test basic options");
|
||||
|
||||
options.add_options()
|
||||
("long", "a long option")
|
||||
("s,short", "a short option")
|
||||
("value", "an option with a value", cxxopts::value<std::string>())
|
||||
("a,av", "a short option with a value", cxxopts::value<std::string>())
|
||||
("6,six", "a short number option")
|
||||
("p, space", "an option with space between short and long")
|
||||
("nothing", "won't exist", cxxopts::value<std::string>())
|
||||
;
|
||||
|
||||
Argv argv({
|
||||
"tester",
|
||||
"--long",
|
||||
"-s",
|
||||
"--value",
|
||||
"value",
|
||||
"-a",
|
||||
"b",
|
||||
"-6",
|
||||
"-p",
|
||||
"--space",
|
||||
});
|
||||
|
||||
char** actual_argv = argv.argv();
|
||||
auto argc = argv.argc();
|
||||
|
||||
auto result = options.parse(argc, actual_argv);
|
||||
|
||||
CHECK(result.count("long") == 1);
|
||||
CHECK(result.count("s") == 1);
|
||||
CHECK(result.count("value") == 1);
|
||||
CHECK(result.count("a") == 1);
|
||||
CHECK(result["value"].as<std::string>() == "value");
|
||||
CHECK(result["a"].as<std::string>() == "b");
|
||||
CHECK(result.count("6") == 1);
|
||||
CHECK(result.count("p") == 2);
|
||||
CHECK(result.count("space") == 2);
|
||||
|
||||
auto& arguments = result.arguments();
|
||||
REQUIRE(arguments.size() == 7);
|
||||
CHECK(arguments[0].key() == "long");
|
||||
CHECK(arguments[0].value() == "true");
|
||||
CHECK(arguments[0].as<bool>() == true);
|
||||
|
||||
CHECK(arguments[1].key() == "short");
|
||||
CHECK(arguments[2].key() == "value");
|
||||
CHECK(arguments[3].key() == "av");
|
||||
|
||||
CHECK_THROWS_AS(result["nothing"].as<std::string>(), std::domain_error&);
|
||||
}
|
||||
|
||||
TEST_CASE("Short options", "[options]")
|
||||
{
|
||||
cxxopts::Options options("test_short", " - test short options");
|
||||
|
||||
options.add_options()
|
||||
("a", "a short option", cxxopts::value<std::string>());
|
||||
|
||||
Argv argv({"test_short", "-a", "value"});
|
||||
|
||||
auto actual_argv = argv.argv();
|
||||
auto argc = argv.argc();
|
||||
|
||||
auto result = options.parse(argc, actual_argv);
|
||||
|
||||
CHECK(result.count("a") == 1);
|
||||
CHECK(result["a"].as<std::string>() == "value");
|
||||
|
||||
REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
|
||||
cxxopts::invalid_option_format_error&);
|
||||
}
|
||||
|
||||
TEST_CASE("No positional", "[positional]")
|
||||
{
|
||||
cxxopts::Options options("test_no_positional",
|
||||
" - test no positional options");
|
||||
|
||||
Argv av({"tester", "a", "b", "def"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(argc == 4);
|
||||
CHECK(strcmp(argv[1], "a") == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("All positional", "[positional]")
|
||||
{
|
||||
std::vector<std::string> positional;
|
||||
|
||||
cxxopts::Options options("test_all_positional", " - test all positional");
|
||||
options.add_options()
|
||||
("positional", "Positional parameters",
|
||||
cxxopts::value<std::vector<std::string>>(positional))
|
||||
;
|
||||
|
||||
Argv av({"tester", "a", "b", "c"});
|
||||
|
||||
auto argc = av.argc();
|
||||
auto argv = av.argv();
|
||||
|
||||
std::vector<std::string> pos_names = {"positional"};
|
||||
|
||||
options.parse_positional(pos_names.begin(), pos_names.end());
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(argc == 1);
|
||||
REQUIRE(positional.size() == 3);
|
||||
|
||||
CHECK(positional[0] == "a");
|
||||
CHECK(positional[1] == "b");
|
||||
CHECK(positional[2] == "c");
|
||||
}
|
||||
|
||||
TEST_CASE("Some positional explicit", "[positional]")
|
||||
{
|
||||
cxxopts::Options options("positional_explicit", " - test positional");
|
||||
|
||||
options.add_options()
|
||||
("input", "Input file", cxxopts::value<std::string>())
|
||||
("output", "Output file", cxxopts::value<std::string>())
|
||||
("positional", "Positional parameters",
|
||||
cxxopts::value<std::vector<std::string>>())
|
||||
;
|
||||
|
||||
options.parse_positional({"input", "output", "positional"});
|
||||
|
||||
Argv av({"tester", "--output", "a", "b", "c", "d"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
CHECK(argc == 1);
|
||||
CHECK(result.count("output"));
|
||||
CHECK(result["input"].as<std::string>() == "b");
|
||||
CHECK(result["output"].as<std::string>() == "a");
|
||||
|
||||
auto& positional = result["positional"].as<std::vector<std::string>>();
|
||||
|
||||
REQUIRE(positional.size() == 2);
|
||||
CHECK(positional[0] == "c");
|
||||
CHECK(positional[1] == "d");
|
||||
}
|
||||
|
||||
TEST_CASE("No positional with extras", "[positional]")
|
||||
{
|
||||
cxxopts::Options options("posargmaster", "shows incorrect handling");
|
||||
options.add_options()
|
||||
("dummy", "oh no", cxxopts::value<std::string>())
|
||||
;
|
||||
|
||||
Argv av({"extras", "--", "a", "b", "c", "d"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto old_argv = argv;
|
||||
auto old_argc = argc;
|
||||
|
||||
options.parse(argc, argv);
|
||||
|
||||
REQUIRE(argc == old_argc - 1);
|
||||
CHECK(argv[0] == std::string("extras"));
|
||||
CHECK(argv[1] == std::string("a"));
|
||||
}
|
||||
|
||||
TEST_CASE("Positional not valid", "[positional]") {
|
||||
cxxopts::Options options("positional_invalid", "invalid positional argument");
|
||||
options.add_options()
|
||||
("long", "a long option", cxxopts::value<std::string>())
|
||||
;
|
||||
|
||||
options.parse_positional("something");
|
||||
|
||||
Argv av({"foobar", "bar", "baz"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
|
||||
}
|
||||
|
||||
TEST_CASE("Empty with implicit value", "[implicit]")
|
||||
{
|
||||
cxxopts::Options options("empty_implicit", "doesn't handle empty");
|
||||
options.add_options()
|
||||
("implicit", "Has implicit", cxxopts::value<std::string>()
|
||||
->implicit_value("foo"));
|
||||
|
||||
Argv av({"implicit", "--implicit="});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(result.count("implicit") == 1);
|
||||
REQUIRE(result["implicit"].as<std::string>() == "");
|
||||
}
|
||||
|
||||
TEST_CASE("Boolean without implicit value", "[implicit]")
|
||||
{
|
||||
cxxopts::Options options("no_implicit", "bool without an implicit value");
|
||||
options.add_options()
|
||||
("bool", "Boolean without implicit", cxxopts::value<bool>()
|
||||
->no_implicit_value());
|
||||
|
||||
SECTION("When no value provided") {
|
||||
Argv av({"no_implicit", "--bool"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::missing_argument_exception&);
|
||||
}
|
||||
|
||||
SECTION("With equal-separated true") {
|
||||
Argv av({"no_implicit", "--bool=true"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("bool") == 1);
|
||||
CHECK(result["bool"].as<bool>() == true);
|
||||
}
|
||||
|
||||
SECTION("With equal-separated false") {
|
||||
Argv av({"no_implicit", "--bool=false"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("bool") == 1);
|
||||
CHECK(result["bool"].as<bool>() == false);
|
||||
}
|
||||
|
||||
SECTION("With space-separated true") {
|
||||
Argv av({"no_implicit", "--bool", "true"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("bool") == 1);
|
||||
CHECK(result["bool"].as<bool>() == true);
|
||||
}
|
||||
|
||||
SECTION("With space-separated false") {
|
||||
Argv av({"no_implicit", "--bool", "false"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("bool") == 1);
|
||||
CHECK(result["bool"].as<bool>() == false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Default values", "[default]")
|
||||
{
|
||||
cxxopts::Options options("defaults", "has defaults");
|
||||
options.add_options()
|
||||
("default", "Has implicit", cxxopts::value<int>()->default_value("42"))
|
||||
("v,vector", "Default vector", cxxopts::value<std::vector<int>>()
|
||||
->default_value("1,4"))
|
||||
;
|
||||
|
||||
SECTION("Sets defaults") {
|
||||
Argv av({"implicit"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("default") == 0);
|
||||
CHECK(result["default"].as<int>() == 42);
|
||||
|
||||
auto& v = result["vector"].as<std::vector<int>>();
|
||||
REQUIRE(v.size() == 2);
|
||||
CHECK(v[0] == 1);
|
||||
CHECK(v[1] == 4);
|
||||
}
|
||||
|
||||
SECTION("When values provided") {
|
||||
Argv av({"implicit", "--default", "5"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("default") == 1);
|
||||
CHECK(result["default"].as<int>() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse into a reference", "[reference]")
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
cxxopts::Options options("into_reference", "parses into a reference");
|
||||
options.add_options()
|
||||
("ref", "A reference", cxxopts::value(value));
|
||||
|
||||
Argv av({"into_reference", "--ref", "42"});
|
||||
|
||||
auto argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
CHECK(result.count("ref") == 1);
|
||||
CHECK(value == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("Integers", "[options]")
|
||||
{
|
||||
cxxopts::Options options("parses_integers", "parses integers correctly");
|
||||
options.add_options()
|
||||
("positional", "Integers", cxxopts::value<std::vector<int>>());
|
||||
|
||||
Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
options.parse_positional("positional");
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(result.count("positional") == 7);
|
||||
|
||||
auto& positional = result["positional"].as<std::vector<int>>();
|
||||
REQUIRE(positional.size() == 7);
|
||||
CHECK(positional[0] == 5);
|
||||
CHECK(positional[1] == 6);
|
||||
CHECK(positional[2] == -6);
|
||||
CHECK(positional[3] == 0);
|
||||
CHECK(positional[4] == 0xab);
|
||||
CHECK(positional[5] == 0xaf);
|
||||
CHECK(positional[6] == 0x0);
|
||||
}
|
||||
|
||||
TEST_CASE("Leading zero integers", "[options]")
|
||||
{
|
||||
cxxopts::Options options("parses_integers", "parses integers correctly");
|
||||
options.add_options()
|
||||
("positional", "Integers", cxxopts::value<std::vector<int>>());
|
||||
|
||||
Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
options.parse_positional("positional");
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(result.count("positional") == 4);
|
||||
|
||||
auto& positional = result["positional"].as<std::vector<int>>();
|
||||
REQUIRE(positional.size() == 4);
|
||||
CHECK(positional[0] == 5);
|
||||
CHECK(positional[1] == 6);
|
||||
CHECK(positional[2] == 0xab);
|
||||
CHECK(positional[3] == 0x1);
|
||||
}
|
||||
|
||||
TEST_CASE("Unsigned integers", "[options]")
|
||||
{
|
||||
cxxopts::Options options("parses_unsigned", "detects unsigned errors");
|
||||
options.add_options()
|
||||
("positional", "Integers", cxxopts::value<std::vector<unsigned int>>());
|
||||
|
||||
Argv av({"ints", "--", "-2"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
options.parse_positional("positional");
|
||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
|
||||
}
|
||||
|
||||
TEST_CASE("Integer bounds", "[integer]")
|
||||
{
|
||||
cxxopts::Options options("integer_boundaries", "check min/max integer");
|
||||
options.add_options()
|
||||
("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
|
||||
|
||||
SECTION("No overflow")
|
||||
{
|
||||
Argv av({"ints", "--", "127", "-128", "0x7f", "-0x80", "0x7e"});
|
||||
|
||||
auto argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
options.parse_positional("positional");
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(result.count("positional") == 5);
|
||||
|
||||
auto& positional = result["positional"].as<std::vector<int8_t>>();
|
||||
CHECK(positional[0] == 127);
|
||||
CHECK(positional[1] == -128);
|
||||
CHECK(positional[2] == 0x7f);
|
||||
CHECK(positional[3] == -0x80);
|
||||
CHECK(positional[4] == 0x7e);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Overflow on boundary", "[integer]")
|
||||
{
|
||||
using namespace cxxopts::values;
|
||||
|
||||
int8_t si;
|
||||
uint8_t ui;
|
||||
|
||||
CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::argument_incorrect_type&);
|
||||
CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::argument_incorrect_type&);
|
||||
CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::argument_incorrect_type&);
|
||||
CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::argument_incorrect_type&);
|
||||
CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::argument_incorrect_type&);
|
||||
CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::argument_incorrect_type&);
|
||||
}
|
||||
|
||||
TEST_CASE("Integer overflow", "[options]")
|
||||
{
|
||||
using namespace cxxopts::values;
|
||||
|
||||
cxxopts::Options options("reject_overflow", "rejects overflowing integers");
|
||||
options.add_options()
|
||||
("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
|
||||
|
||||
Argv av({"ints", "--", "128"});
|
||||
|
||||
auto argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
options.parse_positional("positional");
|
||||
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
|
||||
|
||||
int integer = 0;
|
||||
CHECK_THROWS_AS((integer_parser("23423423423", integer)), cxxopts::argument_incorrect_type&);
|
||||
CHECK_THROWS_AS((integer_parser("234234234234", integer)), cxxopts::argument_incorrect_type&);
|
||||
}
|
||||
|
||||
TEST_CASE("Floats", "[options]")
|
||||
{
|
||||
cxxopts::Options options("parses_floats", "parses floats correctly");
|
||||
options.add_options()
|
||||
("double", "Double precision", cxxopts::value<double>())
|
||||
("positional", "Floats", cxxopts::value<std::vector<float>>());
|
||||
|
||||
Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"});
|
||||
|
||||
char** argv = av.argv();
|
||||
auto argc = av.argc();
|
||||
|
||||
options.parse_positional("positional");
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
REQUIRE(result.count("double") == 1);
|
||||
REQUIRE(result.count("positional") == 4);
|
||||
|
||||
CHECK(result["double"].as<double>() == 0.5);
|
||||
|
||||
auto& positional = result["positional"].as<std::vector<float>>();
|
||||
CHECK(positional[0] == 4);
|
||||
CHECK(positional[1] == -4);
|
||||
CHECK(positional[2] == 1.5e6);
|
||||
CHECK(positional[3] == -1.5e6);
|
||||
}
|
||||
|
||||
TEST_CASE("Invalid integers", "[integer]") {
|
||||
cxxopts::Options options("invalid_integers", "rejects invalid integers");
|
||||
options.add_options()
|
||||
("positional", "Integers", cxxopts::value<std::vector<int>>());
|
||||
|
||||
Argv av({"ints", "--", "Ae"});
|
||||