poafloc

poafloc - Parser Of Arguments For Lines Of Commands
git clone git://git.dimitrijedobrota.com/poafloc.git
Log | Files | Refs | README | LICENSE

commit 0dfc1d32da3d539129533341c4a2eb45a3848b78
parent 42b158159fc1188afc6b1afecf30ac0184fb0c52
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sat, 29 Jun 2024 12:32:41 +0200

Add test suite, bug fixing

Diffstat:
MCMakeLists.txt | 2+-
Msource/poafloc.cpp | 26+++++++++++++++++---------
Msource/trie.cpp | 15+++------------
Mtest/CMakeLists.txt | 51++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtest/source/poafloc_test.cpp | 60+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 130 insertions(+), 24 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -4,7 +4,7 @@ include(cmake/prelude.cmake) project( poafloc - VERSION 1.0.1 + VERSION 1.0.2 DESCRIPTION "Parser Of Arguments For Lines Of Commands" HOMEPAGE_URL "https://git.dimitrijedobrota.com/poafloc.git" LANGUAGES C CXX diff --git a/source/poafloc.cpp b/source/poafloc.cpp @@ -103,7 +103,7 @@ Parser::Parser(const arg_t* argp, unsigned flags, void* input) else { // duplicate key, silently ignoring - if (!m_options.contains(opt.key)) continue; + if (m_options.contains(opt.key)) continue; if (opt.name != nullptr) m_trie.insert(opt.name, opt.key); m_options[key_last = opt.key] = &opt; @@ -204,26 +204,33 @@ int Parser::parse(std::size_t argc, char* argv[]) const auto* option = m_options[key]; bool const is_opt = (option->flags & ARG_OPTIONAL) != 0; + if (option->arg == nullptr) { m_argp->parse(key, nullptr, this); + continue; } + if (opt[j + 1] != 0) { m_argp->parse(key, opt.substr(j + 1).c_str(), this); break; } - if (is_opt) m_argp->parse(key, nullptr, this); - else if (idx + 1 != argc) + + if (is_opt) { - m_argp->parse(key, args[++idx], this); - break; + m_argp->parse(key, nullptr, this); + continue; } - else + + if (idx + 1 != argc) { - err_code = handle_missing(true, args[idx]); - goto error; + m_argp->parse(key, args[++idx], this); + break; } + + err_code = handle_missing(true, args[idx]); + goto error; } } else @@ -320,6 +327,7 @@ int Parser::parse(std::size_t argc, char* argv[]) return 0; error: + m_argp->parse(Key::ERROR, nullptr, this); return err_code; } @@ -329,7 +337,7 @@ int Parser::handle_unknown(bool shrt, const char* argv) return m_argp->parse(Key::ERROR, nullptr, this); static const char* const unknown_fmt[2] = { - "unrem_argpized option '-%s'\n", + "unrecognized option '-%s'\n", "invalid option -- '%s'\n", }; diff --git a/source/trie.cpp b/source/trie.cpp @@ -9,10 +9,7 @@ bool Parser::trie_t::insert(const std::string& option, int key) { trie_t* crnt = this; - if (!is_valid(option)) - { - return false; - } + if (!is_valid(option)) return false; for (const char chr : option) { @@ -36,10 +33,7 @@ int Parser::trie_t::get(const std::string& option) const { const trie_t* crnt = this; - if (!is_valid(option)) - { - return 0; - } + if (!is_valid(option)) return 0; for (const char chr : option) { @@ -49,10 +43,7 @@ int Parser::trie_t::get(const std::string& option) const crnt = crnt->m_children.at(idx).get(); } - if (!crnt->m_terminal && crnt->m_count > 1) - { - return 0; - } + if (!crnt->m_terminal && crnt->m_count > 1) return 0; return crnt->m_key; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt @@ -18,7 +18,56 @@ add_executable(poafloc_test source/poafloc_test.cpp) target_link_libraries(poafloc_test PRIVATE poafloc::poafloc) target_compile_features(poafloc_test PRIVATE cxx_std_20) -add_test(NAME poafloc_test COMMAND poafloc_test) +add_test(NAME poafloc_test_empty COMMAND poafloc_test) +set_tests_properties(poafloc_test_empty PROPERTIES PASS_REGULAR_EXPRESSION "init\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_arg_one COMMAND poafloc_test a1) +set_tests_properties(poafloc_test_arg_one PROPERTIES PASS_REGULAR_EXPRESSION "init\narg:a1\nend\nsuccess") + +add_test(NAME poafloc_test_arg_two COMMAND poafloc_test a1 a2) +set_tests_properties(poafloc_test_arg_two PROPERTIES PASS_REGULAR_EXPRESSION "init\narg:a1\narg:a2\nend\nsuccess") + +add_test(NAME poafloc_test_short COMMAND poafloc_test -s) +set_tests_properties(poafloc_test_short PROPERTIES PASS_REGULAR_EXPRESSION "init\ns\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_long COMMAND poafloc_test --long) +set_tests_properties(poafloc_test_long PROPERTIES PASS_REGULAR_EXPRESSION "init\nl\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_short_arg COMMAND poafloc_test -a a1) +set_tests_properties(poafloc_test_short_arg PROPERTIES PASS_REGULAR_EXPRESSION "init\na:a1\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_long_arg COMMAND poafloc_test --arg a1) +set_tests_properties(poafloc_test_long_arg PROPERTIES PASS_REGULAR_EXPRESSION "init\na:a1\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_short_arg_equal COMMAND poafloc_test -aa1) +set_tests_properties(poafloc_test_short_arg_equal PROPERTIES PASS_REGULAR_EXPRESSION "init\na:a1\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_long_arg_equal COMMAND poafloc_test --arg=a1) +set_tests_properties(poafloc_test_long_arg_equal PROPERTIES PASS_REGULAR_EXPRESSION "init\na:a1\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_short_arg_without COMMAND poafloc_test -a) +set_tests_properties(poafloc_test_short_arg_without PROPERTIES WILL_FAIL TRUE) + +add_test(NAME poafloc_test_long_arg_without COMMAND poafloc_test --arg) +set_tests_properties(poafloc_test_long_arg_without PROPERTIES WILL_FAIL TRUE) + +add_test(NAME poafloc_test_short_opt COMMAND poafloc_test -oa1) +set_tests_properties(poafloc_test_short_opt PROPERTIES PASS_REGULAR_EXPRESSION "init\no:a1\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_long_opt COMMAND poafloc_test --opt=a1) +set_tests_properties(poafloc_test_long_opt PROPERTIES PASS_REGULAR_EXPRESSION "init\no:a1\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_short_opt_without COMMAND poafloc_test -o) +set_tests_properties(poafloc_test_short_opt_without PROPERTIES PASS_REGULAR_EXPRESSION "init\no:default\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_long_opt_without COMMAND poafloc_test --opt) +set_tests_properties(poafloc_test_long_opt_without PROPERTIES PASS_REGULAR_EXPRESSION "init\no:default\nnoargs\nend\nsuccess") + +add_test(NAME poafloc_test_short_opt_after COMMAND poafloc_test -o a1) +set_tests_properties(poafloc_test_short_opt_after PROPERTIES PASS_REGULAR_EXPRESSION "init\no:default\narg:a1\nend\nsuccess") + +add_test(NAME poafloc_test_long_opt_after COMMAND poafloc_test --opt a1) +set_tests_properties(poafloc_test_long_opt_after PROPERTIES PASS_REGULAR_EXPRESSION "init\no:default\narg:a1\nend\nsuccess") # ---- End-of-file commands ---- diff --git a/test/source/poafloc_test.cpp b/test/source/poafloc_test.cpp @@ -1,8 +1,66 @@ +#include <iostream> #include <string> #include "poafloc/poafloc.hpp" -int main() +using namespace poafloc; // NOLINT + // +int parse_opt(int key, const char* arg, Parser* parser) { + std::ignore = parser; + + switch (key) + { + case 's': + std::cout << 's' << std::endl; + break; + case 'l': + std::cout << 'l' << std::endl; + break; + case 'a': + std::cout << "a:" << arg << std::endl; + break; + case 'o': + std::cout << "o:" << (arg != nullptr ? arg : "default") << std::endl; + break; + case ARG: + std::cout << "arg:" << arg << std::endl; + break; + case INIT: + std::cout << "init" << std::endl; + break; + case END: + std::cout << "end" << std::endl; + break; + case SUCCESS: + std::cout << "success" << std::endl; + break; + case ERROR: + std::cout << "error" << std::endl; + break; + case NO_ARGS: + std::cout << "noargs" << std::endl; + break; + default: + break; + } + return 0; } + +// clang-format off +static const option_t options[] = { + {nullptr, 's', nullptr, 0, ""}, + { "long", 'l', nullptr, 0, ""}, + { "arg", 'a', "arg", 0, ""}, + { "opt", 'o', "arg", ARG_OPTIONAL, ""}, + {}, +}; +// clang-format on + +static const arg_t argp = {options, parse_opt, "", ""}; + +int main(int argc, char* argv[]) +{ + return parse(&argp, argc, argv, 0, nullptr); +}