From 750d035337cd7ec464f4125e8e522bd9d399b199 Mon Sep 17 00:00:00 2001 From: Cesare Ferrari Date: Thu, 21 May 2026 15:25:32 +0100 Subject: [PATCH] Updated ArgumentList to support retrieving both single and double dash options by not specifying either when using the get methods. e.g getValueFor ("foo") will return "bar" if the arguments include either --foo=bar or -foo bar --- choc/containers/choc_ArgumentList.h | 24 +++- tests/CMakeLists.txt | 2 +- tests/choc_tests.h | 183 ++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 3 deletions(-) diff --git a/choc/containers/choc_ArgumentList.h b/choc/containers/choc_ArgumentList.h index 3219c9d..1822e90 100644 --- a/choc/containers/choc_ArgumentList.h +++ b/choc/containers/choc_ArgumentList.h @@ -48,6 +48,7 @@ struct ArgumentList { ArgumentList() = default; ArgumentList (int argc, const char* const* argv); + ArgumentList (std::vector tokens); /// Returns the number of tokens in the list size_t size() const; @@ -181,6 +182,10 @@ inline ArgumentList::ArgumentList (int argc, const char* const* argv) #endif } +inline ArgumentList::ArgumentList (std::vector tokens_) : tokens (tokens_) +{ +} + inline size_t ArgumentList::size() const { return tokens.size(); @@ -218,6 +223,15 @@ inline bool ArgumentList::removeIfFound (std::string_view arg) inline int ArgumentList::indexOf (std::string_view arg) const { CHOC_ASSERT (! choc::text::trim (arg).empty()); + + if (! isOption (arg)) + { + if (auto singleIndex = indexOf ("-" + std::string (arg)); singleIndex != -1) + return singleIndex; + + return indexOf ("--" + std::string (arg)); + } + bool isDoubleDash = isDoubleDashOption (arg); for (size_t i = 0; i < tokens.size(); ++i) @@ -241,11 +255,17 @@ inline void ArgumentList::throwIfNotFound (std::string_view arg) const inline std::optional ArgumentList::getValueFor (std::string_view argToFind, bool remove) { + if (! isOption (argToFind)) + { + if (auto v = getValueFor ("-" + std::string (argToFind), remove); v.has_value()) + return v; + + return getValueFor ("--" + std::string (argToFind), remove); + } + bool isDoubleDash = isDoubleDashOption (argToFind); bool isSingleDash = isSingleDashOption (argToFind); - CHOC_ASSERT (isDoubleDash || isSingleDash); // the arg you pass in needs to be a "--option" or "-option" - if (auto i = indexOf (argToFind); i >= 0) { auto index = static_cast (i); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 897cdcc..a0d5ba8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16) project(choc_tests) -add_executable(choc_tests choc_tests.cpp) +add_executable(choc_tests choc_tests.cpp choc_tests.h) # To test V8, there needs to be a suitable folder somewhere with a build # set(V8_LOCATION "/path_to_your_v8_folder/v8") diff --git a/tests/choc_tests.h b/tests/choc_tests.h index 454f088..0fae3c3 100644 --- a/tests/choc_tests.h +++ b/tests/choc_tests.h @@ -76,6 +76,7 @@ #include "../choc/javascript/choc_javascript.h" #include "../choc/javascript/choc_javascript_Timer.h" #include "../choc/javascript/choc_javascript_Console.h" +#include "../choc/containers/choc_ArgumentList.h" #if CHOC_ENABLE_HTTP_SERVER_TEST #include "../choc/network/choc_HTTPServer.h" @@ -1383,6 +1384,187 @@ inline void testMIDI (choc::test::TestProgress& progress) } } +//============================================================================== +inline void testArgumentList (choc::test::TestProgress& progress) +{ + CHOC_CATEGORY (ArgumentList); + + { + CHOC_TEST (ArgcvParsingDoubleDash) + + const char* argv[] = { "executableName", "other1", "--flag1", "other2", "--param1=foo", "--flag2", "--param2=bar", "--param3=42", "other3" }; + + choc::ArgumentList args (9, argv); + + CHOC_EXPECT_TRUE (args.contains ("--flag1")); + CHOC_EXPECT_TRUE (args.contains ("--param1")); + CHOC_EXPECT_TRUE (args.contains ("--flag2")); + CHOC_EXPECT_TRUE (args.contains ("--param2")); + CHOC_EXPECT_TRUE (args.contains ("--param3")); + CHOC_EXPECT_FALSE (args.contains ("--flag3")); + + CHOC_EXPECT_EQ (args.indexOf ("--flag1"), 1); + CHOC_EXPECT_EQ (args.indexOf ("--param1"), 3); + CHOC_EXPECT_EQ (args.indexOf ("--flag2"), 4); + CHOC_EXPECT_EQ (args.indexOf ("--param2"), 5); + CHOC_EXPECT_EQ (args.indexOf ("--param3"), 6); + CHOC_EXPECT_EQ (args.indexOf ("--flag3"), -1); + + CHOC_EXPECT_EQ (args.getValueFor ("--param1", false).value(), "foo"); + CHOC_EXPECT_EQ (args.getValueFor ("--param2", false).value(), "bar"); + CHOC_EXPECT_EQ (args.getValueFor ("--param3", false).value(), "42"); + + CHOC_EXPECT_TRUE (args.removeIfFound ("--flag1")); + CHOC_EXPECT_TRUE (args.removeIfFound ("--param1")); + + CHOC_EXPECT_FALSE (args.getValueFor ("--param1", false).has_value()); + CHOC_EXPECT_EQ (args.getValueFor ("--param2", false).value(), "bar"); + CHOC_EXPECT_EQ (args.getValueFor ("--param3", false).value(), "42"); + + CHOC_EXPECT_EQ (args.removeValueFor ("--param2", "default"), "bar"); + CHOC_EXPECT_EQ (args.removeValueFor ("--param2", "default"), "default"); + CHOC_EXPECT_FALSE (args.removeValueFor ("--param2").has_value()); + CHOC_EXPECT_FALSE (args.getValueFor ("--param2", false).has_value()); + + CHOC_EXPECT_EQ (args.removeIntValue ("--param3", 101), 42); + CHOC_EXPECT_EQ (args.removeIntValue ("--param3", 101), 101); + + CHOC_EXPECT_EQ (args.indexOf ("--flag1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--param1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--flag2"), 2); + CHOC_EXPECT_EQ (args.indexOf ("--param2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--flag3"), -1); + + args.removeIndex (2); + + CHOC_EXPECT_EQ (args.indexOf ("--flag1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--param1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--flag2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--param2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("--flag3"), -1); + } + + { + CHOC_TEST (ArgcvParsingSingleDash) + + const char* argv[] = { "executableName", "other1", "-flag1", "other2", "-param1", "foo", "-flag2", "-param2", "bar", "-param3", "42", "other3" }; + + choc::ArgumentList args (12, argv); + + CHOC_EXPECT_TRUE (args.contains ("-flag1")); + CHOC_EXPECT_TRUE (args.contains ("-param1")); + CHOC_EXPECT_TRUE (args.contains ("-flag2")); + CHOC_EXPECT_TRUE (args.contains ("-param2")); + CHOC_EXPECT_TRUE (args.contains ("-param3")); + CHOC_EXPECT_FALSE (args.contains ("-flag3")); + + CHOC_EXPECT_EQ (args.indexOf ("-flag1"), 1); + CHOC_EXPECT_EQ (args.indexOf ("-param1"), 3); + CHOC_EXPECT_EQ (args.indexOf ("-flag2"), 5); + CHOC_EXPECT_EQ (args.indexOf ("-param2"), 6); + CHOC_EXPECT_EQ (args.indexOf ("-param3"), 8); + CHOC_EXPECT_EQ (args.indexOf ("-flag3"), -1); + + CHOC_EXPECT_EQ (args.getValueFor ("-param1", false).value(), "foo"); + CHOC_EXPECT_EQ (args.getValueFor ("-param2", false).value(), "bar"); + CHOC_EXPECT_EQ (args.getValueFor ("-param3", false).value(), "42"); + + CHOC_EXPECT_TRUE (args.removeIfFound ("-flag1")); + CHOC_EXPECT_TRUE (args.removeIfFound ("-param1")); + + CHOC_EXPECT_FALSE (args.getValueFor ("-param1", false).has_value()); + CHOC_EXPECT_EQ (args.getValueFor ("-param2", false).value(), "bar"); + CHOC_EXPECT_EQ (args.getValueFor ("-param3", false).value(), "42"); + + CHOC_EXPECT_EQ (args.removeValueFor ("-param2", "default"), "bar"); + CHOC_EXPECT_EQ (args.removeValueFor ("-param2", "default"), "default"); + CHOC_EXPECT_FALSE (args.removeValueFor ("-param2").has_value()); + CHOC_EXPECT_FALSE (args.getValueFor ("-param2", false).has_value()); + + CHOC_EXPECT_EQ (args.removeIntValue ("-param3", 101), 42); + CHOC_EXPECT_EQ (args.removeIntValue ("-param3", 101), 101); + + CHOC_EXPECT_EQ (args.indexOf ("-flag1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-param1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-flag2"), 3); + CHOC_EXPECT_EQ (args.indexOf ("-param2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-flag3"), -1); + + args.removeIndex (3); + + CHOC_EXPECT_EQ (args.indexOf ("-flag1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-param1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-flag2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-param2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("-flag3"), -1); + } + + + { + CHOC_TEST (ArgcvParsingMixed) + + const char* argv[] = { "executableName", "other1", "-flag1", "other2", "-param1", "foo", "--flag2", "--param2=bar", "-param3", "42", "other3" }; + + choc::ArgumentList args (12, argv); + + CHOC_EXPECT_TRUE (args.contains ("flag1")); + CHOC_EXPECT_TRUE (args.contains ("param1")); + CHOC_EXPECT_TRUE (args.contains ("flag2")); + CHOC_EXPECT_TRUE (args.contains ("param2")); + CHOC_EXPECT_TRUE (args.contains ("param3")); + CHOC_EXPECT_FALSE (args.contains ("flag3")); + + CHOC_EXPECT_EQ (args.indexOf ("flag1"), 1); + CHOC_EXPECT_EQ (args.indexOf ("param1"), 3); + CHOC_EXPECT_EQ (args.indexOf ("flag2"), 5); + CHOC_EXPECT_EQ (args.indexOf ("param2"), 6); + CHOC_EXPECT_EQ (args.indexOf ("param3"), 7); + CHOC_EXPECT_EQ (args.indexOf ("flag3"), -1); + + CHOC_EXPECT_EQ (args.getValueFor ("param1", false).value(), "foo"); + CHOC_EXPECT_EQ (args.getValueFor ("param2", false).value(), "bar"); + CHOC_EXPECT_EQ (args.getValueFor ("param3", false).value(), "42"); + + CHOC_EXPECT_TRUE (args.removeIfFound ("flag1")); + CHOC_EXPECT_TRUE (args.removeIfFound ("param1")); + + CHOC_EXPECT_FALSE (args.getValueFor ("param1", false).has_value()); + CHOC_EXPECT_EQ (args.getValueFor ("param2", false).value(), "bar"); + CHOC_EXPECT_EQ (args.getValueFor ("param3", false).value(), "42"); + + CHOC_EXPECT_EQ (args.removeValueFor ("param2", "default"), "bar"); + CHOC_EXPECT_EQ (args.removeValueFor ("param2", "default"), "default"); + CHOC_EXPECT_FALSE (args.removeValueFor ("param2").has_value()); + CHOC_EXPECT_FALSE (args.getValueFor ("param2", false).has_value()); + + CHOC_EXPECT_EQ (args.removeIntValue ("param3", 101), 42); + CHOC_EXPECT_EQ (args.removeIntValue ("param3", 101), 101); + + CHOC_EXPECT_EQ (args.indexOf ("flag1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("param1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("flag2"), 3); + CHOC_EXPECT_EQ (args.indexOf ("param2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("flag3"), -1); + + args.removeIndex (3); + + CHOC_EXPECT_EQ (args.indexOf ("flag1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("param1"), -1); + CHOC_EXPECT_EQ (args.indexOf ("flag2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("param2"), -1); + CHOC_EXPECT_EQ (args.indexOf ("flag3"), -1); + } + + { + CHOC_TEST (ArgcvParsingStringArgs) + + choc::ArgumentList args (choc::text::splitAtWhitespace ("-flag1 --flag2 --param1=foo other stuff")); + + CHOC_EXPECT_TRUE (args.contains ("flag1")); + CHOC_EXPECT_EQ (args.removeValueFor ("param1", "default"), "foo"); + } +} + //============================================================================== inline void testAudioBuffers (choc::test::TestProgress& progress) { @@ -4135,6 +4317,7 @@ inline bool runAllTests (choc::test::TestProgress& progress, bool multithread) std::function testFunctions[] = { + testArgumentList, testExecute, testHTTPServer, testZLIB,