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,