diff --git a/include/CLI/Validators.hpp b/include/CLI/Validators.hpp index 25e6704..e473c8a 100644 --- a/include/CLI/Validators.hpp +++ b/include/CLI/Validators.hpp @@ -150,6 +150,49 @@ struct NonexistentPathValidator : public Validator { }; } }; + +/// validate the given string is a legal ipv4 address +struct IPV4Validator : public Validator { + IPV4Validator() { + tname = "IPV4"; + func = [](const std::string &ip_addr) { + auto result = CLI::detail::split(ip_addr, '.'); + if(result.size() != 4) { + return "Invalid IPV4 address must have four parts " + ip_addr; + } + int num; + bool retval = true; + for(const auto &var : result) { + retval &= detail::lexical_cast(var, num); + if(!retval) { + return "Failed parsing number " + var; + } + if(num < 0 || num > 255) { + return "Each IP number must be between 0 and 255 " + var; + } + } + return std::string(); + }; + } +}; + +/// validate the argument is a number and equal greater then 0 +struct PositiveNumber : public Validator { + PositiveNumber() { + tname = "positive number"; + func = [](const std::string &number_str) { + int number; + if(!detail::lexical_cast(number_str, number)) { + return "Failed parsing number " + number_str; + } + if(number < 0) { + return "number less then 0 " + number_str; + } + return std::string(); + }; + } +}; + } // namespace detail // Static is not needed here, because global const implies static. @@ -166,6 +209,12 @@ const detail::ExistingPathValidator ExistingPath; /// Check for an non-existing path const detail::NonexistentPathValidator NonexistentPath; +/// Check for an existing path +const detail::IPV4Validator ValidIPV4; + +/// Check for an non-existing path +const detail::PositiveNumber PositiveNumber; + /// Produce a range (factory). Min and max are inclusive. struct Range : public Validator { /// This produces a range with min and max inclusive. diff --git a/tests/HelpersTest.cpp b/tests/HelpersTest.cpp index 6413e84..f8105c6 100644 --- a/tests/HelpersTest.cpp +++ b/tests/HelpersTest.cpp @@ -189,6 +189,38 @@ TEST(Validators, PathNotExistsDir) { EXPECT_NE(CLI::ExistingPath(mydir), ""); } +TEST(Validators, IPValidate1) { + std::string ip = "1.1.1.1"; + EXPECT_TRUE(CLI::ValidIPV4(ip).empty()); + ip = "224.255.0.1"; + EXPECT_TRUE(CLI::ValidIPV4(ip).empty()); + ip = "-1.255.0.1"; + EXPECT_FALSE(CLI::ValidIPV4(ip).empty()); + ip = "1.256.0.1"; + EXPECT_FALSE(CLI::ValidIPV4(ip).empty()); + ip = "1.256.0.1"; + EXPECT_FALSE(CLI::ValidIPV4(ip).empty()); + ip = "aaa"; + EXPECT_FALSE(CLI::ValidIPV4(ip).empty()); + ip = "11.22"; + EXPECT_FALSE(CLI::ValidIPV4(ip).empty()); +} + +TEST(Validators, PositiveValidator) { + std::string num = "1.1.1.1"; + EXPECT_FALSE(CLI::PositiveNumber(num).empty()); + num = "1"; + EXPECT_TRUE(CLI::PositiveNumber(num).empty()); + num = "10000"; + EXPECT_TRUE(CLI::PositiveNumber(num).empty()); + num = "0"; + EXPECT_TRUE(CLI::PositiveNumber(num).empty()); + num = "-1"; + EXPECT_FALSE(CLI::PositiveNumber(num).empty()); + num = "a"; + EXPECT_FALSE(CLI::PositiveNumber(num).empty()); +} + TEST(Validators, CombinedAndRange) { auto crange = CLI::Range(0, 12) & CLI::Range(4, 16); EXPECT_TRUE(crange("4").empty());