diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 81d32323a..96af16937 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -31,7 +31,7 @@ jobs: strategy: matrix: visual_studio_arm64: - vmImage: "windows-2022" + vmImage: "windows-2025" cli11.std: 17 cli11.build_type: Debug cli11.options: -G "Visual Studio 17 2022" -A ARM64 @@ -66,21 +66,21 @@ jobs: cli11.std: 14 cli11.precompile: ON Windows17: - vmImage: "windows-2019" + vmImage: "windows-2022" cli11.std: 17 Windows17PC: - vmImage: "windows-2019" + vmImage: "windows-2022" cli11.std: 17 cli11.precompile: ON Windows11: - vmImage: "windows-2019" + vmImage: "windows-2022" cli11.std: 11 Windows20: - vmImage: "windows-2022" + vmImage: "windows-2025" cli11.std: 20 cli11.options: -DCMAKE_CXX_FLAGS="/EHsc" WindowsLatest: - vmImage: "windows-2022" + vmImage: "windows-2025" cli11.std: 23 cli11.options: -DCMAKE_CXX_FLAGS="/EHsc" Linux17nortti: diff --git a/include/CLI/impl/App_inl.hpp b/include/CLI/impl/App_inl.hpp index cd382a6fd..80ff4c171 100644 --- a/include/CLI/impl/App_inl.hpp +++ b/include/CLI/impl/App_inl.hpp @@ -206,6 +206,12 @@ CLI11_INLINE Option *App::add_option(std::string option_name, if(op != nullptr && op->get_configurable()) { throw(OptionAlreadyAdded("added option matches existing option: --" + ln)); } + if(ln.size() == 1 || top_level_parent->get_allow_non_standard_option_names()) { + op = top_level_parent->get_option_no_throw("-" + ln); + if(op != nullptr && op->get_configurable()) { + throw(OptionAlreadyAdded("added option matches existing option: -" + ln)); + } + } } for(auto &sn : myopt.snames_) { const auto *op = top_level_parent->get_option_no_throw(sn); @@ -216,6 +222,10 @@ CLI11_INLINE Option *App::add_option(std::string option_name, if(op != nullptr && op->get_configurable()) { throw(OptionAlreadyAdded("added option matches existing option: -" + sn)); } + op = top_level_parent->get_option_no_throw("--" + sn); + if(op != nullptr && op->get_configurable()) { + throw(OptionAlreadyAdded("added option matches existing option: --" + sn)); + } } } if(allow_non_standard_options_ && !myopt.snames_.empty()) { diff --git a/tests/OptionTypeTest.cpp b/tests/OptionTypeTest.cpp index 346c3ac32..8ea57262d 100644 --- a/tests/OptionTypeTest.cpp +++ b/tests/OptionTypeTest.cpp @@ -951,6 +951,12 @@ TEST_CASE_METHOD(TApp, "vectorEmptyArg", "[optiontype]") { run(); CHECK(cv.size() == 2); CHECK(cv[1] == "[]"); + + args = {"-c", "test1", "[[aa]]"}; + + run(); + CHECK(cv.size() == 2); + CHECK(cv[1] == "[a]"); } TEST_CASE_METHOD(TApp, "vectorDoubleArg", "[optiontype]") { diff --git a/tests/SubcommandTest.cpp b/tests/SubcommandTest.cpp index 337750d8b..4b1bd0f6d 100644 --- a/tests/SubcommandTest.cpp +++ b/tests/SubcommandTest.cpp @@ -1851,6 +1851,25 @@ TEST_CASE_METHOD(TApp, "subcommand_help", "[subcom]") { CHECK(called); } +TEST_CASE_METHOD(TApp, "DuplicateErrors", "[subcom]") { + app.allow_non_standard_option_names(); + app.add_option("-t"); + app.add_option("m"); + app.add_option("--quit"); + auto *sub1 = app.add_option_group("sub1"); + + CHECK_THROWS_AS(sub1->add_option("-t"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("--t"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("t"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("-m"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("--m"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("m"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("quit"), CLI::OptionAlreadyAdded); + CHECK_THROWS_AS(sub1->add_option("--quit"), CLI::OptionAlreadyAdded); + sub1->allow_non_standard_option_names(); + CHECK_THROWS_AS(sub1->add_option("-quit"), CLI::OptionAlreadyAdded); +} + TEST_CASE_METHOD(TApp, "AliasErrors", "[subcom]") { auto *sub1 = app.add_subcommand("sub1"); auto *sub2 = app.add_subcommand("sub2");