Commit 15bb724e06af9f4699a657643720d9ed80bb6972

Authored by Philip Top
Committed by GitHub
1 parent ee2b7250

fix: make the IncorrectConstruction errors on bad subcommand name more comprehensible. (#602)

include/CLI/App.hpp
... ... @@ -368,7 +368,20 @@ class App {
368 368 /// Set an alias for the app
369 369 App *alias(std::string app_name) {
370 370 if(!detail::valid_name_string(app_name)) {
371   - throw(IncorrectConstruction("alias is not a valid name string"));
  371 + if(app_name.empty()) {
  372 + throw IncorrectConstruction("Empty aliases are not allowed");
  373 + }
  374 + if(!detail::valid_first_char(app_name[0])) {
  375 + throw IncorrectConstruction(
  376 + "Alias starts with invalid character, allowed characters are [a-zA-z0-9]+'_','?','@' ");
  377 + }
  378 + for(auto c : app_name) {
  379 + if(!detail::valid_later_char(c)) {
  380 + throw IncorrectConstruction(std::string("Alias contains invalid character ('") + c +
  381 + "'), allowed characters are "
  382 + "[a-zA-z0-9]+'_','?','@','.','-' ");
  383 + }
  384 + }
372 385 }
373 386  
374 387 if(parent_ != nullptr) {
... ... @@ -963,7 +976,17 @@ class App {
963 976 /// Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag
964 977 App *add_subcommand(std::string subcommand_name = "", std::string subcommand_description = "") {
965 978 if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
966   - throw IncorrectConstruction("subcommand name is not valid");
  979 + if(!detail::valid_first_char(subcommand_name[0])) {
  980 + throw IncorrectConstruction(
  981 + "Subcommand name starts with invalid character, allowed characters are [a-zA-z0-9]+'_','?','@' ");
  982 + }
  983 + for(auto c : subcommand_name) {
  984 + if(!detail::valid_later_char(c)) {
  985 + throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
  986 + "'), allowed characters are "
  987 + "[a-zA-z0-9]+'_','?','@','.','-' ");
  988 + }
  989 + }
967 990 }
968 991 CLI::App_p subcom = std::shared_ptr<App>(new App(std::move(subcommand_description), subcommand_name, this));
969 992 return add_subcommand(std::move(subcom));
... ...
tests/SubcommandTest.cpp
... ... @@ -811,6 +811,18 @@ TEST_CASE_METHOD(TApp, &quot;RequiredPosInSubcommand&quot;, &quot;[subcom]&quot;) {
811 811 CHECK_THROWS_AS(run(), CLI::RequiredError);
812 812 }
813 813  
  814 +TEST_CASE_METHOD(TApp, "invalidSubcommandName", "[subcom]") {
  815 +
  816 + bool gotError{false};
  817 + try {
  818 + app.add_subcommand("foo/foo", "Foo a bar");
  819 + } catch(const CLI::IncorrectConstruction &e) {
  820 + gotError = true;
  821 + CHECK_THAT(e.what(), Contains("/"));
  822 + }
  823 + CHECK(gotError);
  824 +}
  825 +
814 826 struct SubcommandProgram : public TApp {
815 827  
816 828 CLI::App *start{nullptr};
... ...