Fixes Issue #24

This commit is contained in:
Pranav Srinivas Kumar 2019-06-06 21:24:32 -04:00
parent 2125f34d35
commit 73f6aa7538
5 changed files with 117 additions and 12 deletions

View File

@ -217,9 +217,30 @@ public:
} }
private: private:
static bool is_integer(const std::string& aValue) {
if(aValue.empty() ||
((!isdigit(aValue[0])) && (aValue[0] != '-') && (aValue[0] != '+')))
return false;
char * tPtr;
strtol(aValue.c_str(), &tPtr, 10);
return (*tPtr == 0);
}
static bool is_float(const std::string& aValue) {
std::istringstream tStream(aValue);
float tFloat;
// noskipws considers leading whitespace invalid
tStream >> std::noskipws >> tFloat;
// Check the entire string was consumed
// and if either failbit or badbit is set
return tStream.eof() && !tStream.fail();
}
// If an argument starts with "-" or "--", then it's optional // If an argument starts with "-" or "--", then it's optional
static bool is_optional(const std::string& aName) { static bool is_optional(const std::string& aName) {
return (!aName.empty() && aName[0] == '-'); return (!aName.empty() && aName[0] == '-' &&
!is_integer(aName) && !is_float(aName));
} }
static bool is_positional(const std::string& aName) { static bool is_positional(const std::string& aName) {
@ -464,9 +485,10 @@ class ArgumentParser {
*/ */
void parse_args_validate() { void parse_args_validate() {
// Check if all arguments are parsed // Check if all arguments are parsed
std::for_each(std::begin(mArgumentMap), std::end(mArgumentMap), [](const auto& argPair) { std::for_each(std::begin(mArgumentMap), std::end(mArgumentMap),
const auto& [key, arg] = argPair; [](const auto& argPair) {
arg->validate(); const auto& tArgument = argPair.second;
tArgument->validate();
}); });
} }
@ -475,11 +497,13 @@ class ArgumentParser {
if (mArgumentMap.empty()) if (mArgumentMap.empty())
return 0; return 0;
std::vector<size_t> argumentLengths(mArgumentMap.size()); std::vector<size_t> argumentLengths(mArgumentMap.size());
std::transform(std::begin(mArgumentMap), std::end(mArgumentMap), std::begin(argumentLengths), [](const auto& argPair) { std::transform(std::begin(mArgumentMap), std::end(mArgumentMap),
const auto& [key, arg] = argPair; std::begin(argumentLengths), [](const auto& argPair) {
return arg->get_arguments_length(); const auto& tArgument = argPair.second;
return tArgument->get_arguments_length();
}); });
return *std::max_element(std::begin(argumentLengths), std::end(argumentLengths)); return *std::max_element(std::begin(argumentLengths),
std::end(argumentLengths));
} }
std::string mProgramName; std::string mProgramName;

View File

@ -1,6 +1,18 @@
cmake_minimum_required(VERSION 3.6) cmake_minimum_required(VERSION 3.6)
project(ARGPARSE) project(ARGPARSE)
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
# Update if necessary
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
endif()
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
endif() endif()

View File

@ -9,3 +9,4 @@
#include <test_container_arguments.hpp> #include <test_container_arguments.hpp>
#include <test_parent_parsers.hpp> #include <test_parent_parsers.hpp>
#include <test_invalid_arguments.hpp> #include <test_invalid_arguments.hpp>
#include <test_negative_numbers.hpp>

View File

@ -100,6 +100,9 @@ TEST_CASE("Parse out-of-order compound arguments", "[compound_arguments]") {
auto a = program.get<bool>("-a"); // true auto a = program.get<bool>("-a"); // true
auto b = program.get<bool>("-b"); // true auto b = program.get<bool>("-b"); // true
auto c = program.get<std::vector<float>>("-c"); // {3.14f, 2.718f} auto c = program.get<std::vector<float>>("-c"); // {3.14f, 2.718f}
REQUIRE(a == true);
REQUIRE(b == true);
REQUIRE(program["-c"] == std::vector<float>{3.14f, 2.718f});
} }
TEST_CASE("Parse out-of-order compound arguments. Second variation", "[compound_arguments]") { TEST_CASE("Parse out-of-order compound arguments. Second variation", "[compound_arguments]") {

View File

@ -0,0 +1,65 @@
#pragma once
#include <catch.hpp>
#include <argparse.hpp>
TEST_CASE("Parse negative integer", "[positional_arguments]") {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.action([](const std::string& value) { return std::stoi(value); });
program.parse_args({"./main", "-1"});
REQUIRE(program.get<int>("number") == -1);
}
TEST_CASE("Parse negative integers into a vector", "[positional_arguments]") {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.nargs(3)
.action([](const std::string& value) { return std::stoi(value); });
program.parse_args({"./main", "-1", "-2", "3"});
REQUIRE(program["number"] == std::vector<int>{-1, -2, 3});
}
TEST_CASE("Parse negative float", "[positional_arguments]") {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.action([](const std::string& value) { return std::stof(value); });
program.parse_args({"./main", "-1.0"});
REQUIRE(program.get<float>("number") == -1.0);
}
TEST_CASE("Parse negative floats into a vector", "[positional_arguments]") {
argparse::ArgumentParser program;
program.add_argument("--verbose", "-v")
.help("enable verbose logging")
.default_value(false)
.implicit_value(true);
program.add_argument("number")
.help("Input number")
.nargs(3)
.action([](const std::string& value) { return std::stod(value); });
program.parse_args({"./main", "-1.001", "-2.002", "3.003"});
REQUIRE(program["number"] == std::vector<double>{-1.001, -2.002, 3.003});
}