fix argparse help

main
Brett 2025-03-12 23:26:44 -04:00
parent 04a5c01704
commit 4fab2595bc
3 changed files with 1531 additions and 1597 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) include(cmake/color.cmake)
set(BLT_VERSION 5.2.21) set(BLT_VERSION 5.2.22)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

@ -1 +1 @@
Subproject commit 154c63489e84d5569d3b466342a2ae8fd99e4734 Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3

View File

@ -28,13 +28,11 @@
namespace blt::argparse namespace blt::argparse
{ {
constexpr static auto printer_primitive = [](const auto& v) constexpr static auto printer_primitive = [](const auto& v) {
{
std::cout << v; std::cout << v;
}; };
constexpr static auto printer_vector = [](const auto& v) constexpr static auto printer_vector = [](const auto& v) {
{
std::cout << "["; std::cout << "[";
for (const auto& [i, a] : enumerate(v)) for (const auto& [i, a] : enumerate(v))
{ {
@ -53,16 +51,13 @@ namespace blt::argparse
if constexpr (std::is_convertible_v<T, const char*>) if constexpr (std::is_convertible_v<T, const char*>)
{ {
return std::char_traits<char>::length(t); return std::char_traits<char>::length(t);
} } else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
{ {
return 1; return 1;
} } else if constexpr (std::is_same_v<T, std::string_view> || std::is_same_v<T, std::string>)
else if constexpr (std::is_same_v<T, std::string_view> || std::is_same_v<T, std::string>)
{ {
return t.size(); return t.size();
} } else
else
{ {
return 0; return 0;
} }
@ -74,14 +69,12 @@ namespace blt::argparse
if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string_view>) if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string_view>)
{ {
return std::string(t); return std::string(t);
} } else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
{ {
std::string str; std::string str;
str += t; str += t;
return str; return str;
} } else
else
{ {
return t; return t;
} }
@ -105,11 +98,12 @@ namespace blt::argparse
class aligned_internal_string_t class aligned_internal_string_t
{ {
public: public:
explicit aligned_internal_string_t(std::string& str, const size_t max_line_length, explicit aligned_internal_string_t(std::string& str, const size_t max_line_length, const size_t line_start_size): string(str),
const size_t line_start_size): string(str), max_line_size(max_line_length), max_line_size(
line_start_size(line_start_size) max_line_length),
{ line_start_size(
} line_start_size)
{}
void add(const std::string_view str) const void add(const std::string_view str) const
{ {
@ -149,8 +143,7 @@ namespace blt::argparse
{ {
size_t j = i; size_t j = i;
for (; j < str.size() && !std::isblank(str[j]); ++j) for (; j < str.size() && !std::isblank(str[j]); ++j)
{ {}
}
add(std::string_view(str.data() + i, j - i)); add(std::string_view(str.data() + i, j - i));
if (j < str.size()) if (j < str.size())
add(std::string_view(str.data() + j, 1)); add(std::string_view(str.data() + j, 1));
@ -173,10 +166,9 @@ namespace blt::argparse
class aligner_t class aligner_t
{ {
public: public:
aligner_t(std::vector<std::string>& buffer, const size_t start_index, const size_t max_line_size): aligner_t(std::vector<std::string>& buffer, const size_t start_index, const size_t max_line_size): buffer(buffer), start_index(start_index),
buffer(buffer), start_index(start_index), max_line_size(max_line_size) max_line_size(max_line_size)
{ {}
}
void align(const size_t spaces_between) const void align(const size_t spaces_between) const
{ {
@ -186,8 +178,7 @@ namespace blt::argparse
{ {
auto size = static_cast<i64>(v.size()); auto size = static_cast<i64>(v.size());
for (; size > 0 && std::isblank(v[size - 1]); size--) for (; size > 0 && std::isblank(v[size - 1]); size--)
{ {}
}
aligned_size = std::max(aligned_size, static_cast<size_t>(size)); aligned_size = std::max(aligned_size, static_cast<size_t>(size));
} }
const auto offset_size = aligned_size + spaces_between; const auto offset_size = aligned_size + spaces_between;
@ -201,16 +192,14 @@ namespace blt::argparse
[[nodiscard]] auto iter() [[nodiscard]] auto iter()
{ {
return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x) return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x) {
{
return aligned_internal_string_t{x, max_line_size, x.size()}; return aligned_internal_string_t{x, max_line_size, x.size()};
}); });
} }
[[nodiscard]] auto iter() const [[nodiscard]] auto iter() const
{ {
return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x) return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x) {
{
return aligned_internal_string_t{x, max_line_size, x.size()}; return aligned_internal_string_t{x, max_line_size, x.size()};
}); });
} }
@ -375,11 +364,8 @@ namespace blt::argparse
for (auto& [name, value] : positional_storage.remaining()) for (auto& [name, value] : positional_storage.remaining())
{ {
std::visit(lambda_visitor{ std::visit(lambda_visitor{
[](const nargs_t) [](const nargs_t) {},
{ [](const int argc) {
},
[](const int argc)
{
if (argc == 0) if (argc == 0)
throw detail::bad_positional("Positional Argument takes no values, this is invalid!"); throw detail::bad_positional("Positional Argument takes no values, this is invalid!");
} }
@ -434,6 +420,7 @@ namespace blt::argparse
{ {
help += "Positional Arguments:"; help += "Positional Arguments:";
help.newline(); help.newline();
auto mark = help.mark();
for (auto& [name, builder] : m_positional_arguments) for (auto& [name, builder] : m_positional_arguments)
{ {
help += '\t'; help += '\t';
@ -442,49 +429,55 @@ namespace blt::argparse
help += name; help += name;
if (!builder.m_required) if (!builder.m_required)
help += ']'; help += ']';
help.newline();
}
mark.align(4);
for (auto zipped_positionals : mark.iter().zip(m_positional_arguments))
{
auto& line = std::get<0>(zipped_positionals);
auto& [name, builder] = std::get<1>(zipped_positionals);
line += builder.m_help.value_or("");
if (builder.m_default_value && !(builder.m_action == action_t::STORE_TRUE || builder.m_action == action_t::STORE_FALSE)) if (builder.m_default_value && !(builder.m_action == action_t::STORE_TRUE || builder.m_action == action_t::STORE_FALSE))
{ {
if (!std::isblank(help.str().back())) if (!std::isblank(line.str().back()))
help += " "; line += " ";
help += "(Default: "; line += "(Default: ";
std::visit(detail::arg_meta_type_helper_t::make_visitor( std::visit(detail::arg_meta_type_helper_t::make_visitor(
[&](auto& value) [&](auto& value)
{ {
help += value; line += value;
}, },
[&](auto& vec) [&](auto& vec)
{ {
if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>) if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>)
{ {
help += '['; line += '[';
for (const auto& [i, v] : enumerate(vec)) for (const auto& [i, v] : enumerate(vec))
{ {
help += v; line += v;
if (i != vec.size() - 1) if (i != vec.size() - 1)
help += ", "; line += ", ";
} }
help += ']'; line += ']';
} }
}), *builder.m_default_value); }), *builder.m_default_value);
help += ")"; line += ")";
} }
if (builder.m_choices) if (builder.m_choices)
{ {
if (!std::isblank(help.str().back())) if (!std::isblank(line.str().back()))
help += " "; line += " ";
help += "(Choices: "; line += "(Choices: ";
for (const auto& [i, v] : enumerate(*builder.m_choices)) for (const auto& [i, v] : enumerate(*builder.m_choices))
{ {
help += '\''; line += '\'';
help += v; line += v;
help += '\''; line += '\'';
if (i != builder.m_choices->size() - 1) if (i != builder.m_choices->size() - 1)
help += ", "; line += ", ";
} }
help += ')'; line += ')';
} }
help.newline();
help.newline();
} }
} }
@ -508,14 +501,12 @@ namespace blt::argparse
} }
const argument_string_t arg{flag_list.front(), allowed_flag_prefixes}; const argument_string_t arg{flag_list.front(), allowed_flag_prefixes};
auto metavar = builder->m_metavar.value_or(string::toUpperCase(arg.get_name())); auto metavar = builder->m_metavar.value_or(string::toUpperCase(arg.get_name()));
auto lambda = [&]() auto lambda = [&]() {
{
help += ' '; help += ' ';
help += metavar; help += metavar;
}; };
std::visit(lambda_visitor{ std::visit(lambda_visitor{
[&](const nargs_t type) [&](const nargs_t type) {
{
lambda(); lambda();
switch (type) switch (type)
{ {
@ -527,8 +518,7 @@ namespace blt::argparse
break; break;
} }
}, },
[&](const int argc) [&](const int argc) {
{
if (argc == 0) if (argc == 0)
return; return;
lambda(); lambda();
@ -552,13 +542,9 @@ namespace blt::argparse
if (!std::isblank(str.str().back())) if (!std::isblank(str.str().back()))
str += " "; str += " ";
str += "(Default: '"; str += "(Default: '";
std::visit(detail::arg_meta_type_helper_t::make_visitor( std::visit(detail::arg_meta_type_helper_t::make_visitor([&](auto& value) {
[&](auto& value)
{
str += value; str += value;
}, }, [&](auto& vec) {
[&](auto& vec)
{
if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>) if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>)
{ {
str += '['; str += '[';
@ -639,8 +625,7 @@ namespace blt::argparse
singleFlags[arg.get_flag()].emplace_back(arg.get_name()); singleFlags[arg.get_flag()].emplace_back(arg.get_name());
else else
compoundFlags.emplace_back(arg, value); compoundFlags.emplace_back(arg, value);
} } else
else
compoundFlags.emplace_back(arg, value); compoundFlags.emplace_back(arg, value);
} }
@ -661,14 +646,12 @@ namespace blt::argparse
const auto& builder = kv.second; const auto& builder = kv.second;
aligner += builder->m_required ? '<' : '['; aligner += builder->m_required ? '<' : '[';
aligner += name.get_argument(); aligner += name.get_argument();
auto lambda = [&]() auto lambda = [&]() {
{
aligner += ' '; aligner += ' ';
aligner += builder->m_metavar.value_or(string::toUpperCase(name.get_name())); aligner += builder->m_metavar.value_or(string::toUpperCase(name.get_name()));
}; };
std::visit(lambda_visitor{ std::visit(lambda_visitor{
[&](const nargs_t type) [&](const nargs_t type) {
{
lambda(); lambda();
switch (type) switch (type)
{ {
@ -680,8 +663,7 @@ namespace blt::argparse
break; break;
} }
}, },
[&](const int argc) [&](const int argc) {
{
for (int j = 0; j < argc; j++) for (int j = 0; j < argc; j++)
lambda(); lambda();
} }
@ -710,8 +692,8 @@ namespace blt::argparse
std::cout << m_name.value_or("NO NAME") << " " << m_version.value_or("NO VERSION") << std::endl; std::cout << m_name.value_or("NO NAME") << " " << m_version.value_or("NO VERSION") << std::endl;
} }
void argument_parser_t::handle_compound_flags(hashset_t<std::string>& found_flags, argument_storage_t& parsed_args, void argument_parser_t::handle_compound_flags(hashset_t<std::string>& found_flags, argument_storage_t& parsed_args, argument_consumer_t& consumer,
argument_consumer_t& consumer, const argument_string_t& arg) const argument_string_t& arg)
{ {
// i kinda hate this, TODO? // i kinda hate this, TODO?
std::vector<std::string> compound_flags; std::vector<std::string> compound_flags;
@ -719,8 +701,7 @@ namespace blt::argparse
{ {
for (const auto c : arg.get_name()) for (const auto c : arg.get_name())
compound_flags.emplace_back(std::string{arg.get_flag()} + c); compound_flags.emplace_back(std::string{arg.get_flag()} + c);
} } else
else
{ {
if (arg.get_flag().size() > 2) if (arg.get_flag().size() > 2)
throw detail::bad_flag(make_string("Error: Flag '", arg.get_argument(), "' is too long!")); throw detail::bad_flag(make_string("Error: Flag '", arg.get_argument(), "' is too long!"));
@ -742,8 +723,7 @@ namespace blt::argparse
auto flag = m_flag_arguments.find(arg)->second; auto flag = m_flag_arguments.find(arg)->second;
const auto dest = flag->m_dest.value_or(std::string{arg}); const auto dest = flag->m_dest.value_or(std::string{arg});
std::visit(lambda_visitor{ std::visit(lambda_visitor{
[&parsed_args, &consumer, &dest, &flag, arg](const nargs_t arg_enum) [&parsed_args, &consumer, &dest, &flag, arg](const nargs_t arg_enum) {
{
switch (arg_enum) switch (arg_enum)
{ {
case nargs_t::IF_POSSIBLE: case nargs_t::IF_POSSIBLE:
@ -770,8 +750,7 @@ namespace blt::argparse
break; break;
} }
}, },
[&parsed_args, &consumer, &dest, &flag, arg, this](const i32 argc) [&parsed_args, &consumer, &dest, &flag, arg, this](const i32 argc) {
{
const auto args = consume_argc(argc, consumer, flag->m_choices ? &*flag->m_choices : nullptr, arg); const auto args = consume_argc(argc, consumer, flag->m_choices ? &*flag->m_choices : nullptr, arg);
switch (flag->m_action) switch (flag->m_action)
@ -800,22 +779,16 @@ namespace blt::argparse
make_string("Argument '", arg, "'s action is append const but takes in arguments.")); make_string("Argument '", arg, "'s action is append const but takes in arguments."));
if (!flag->m_const_value) if (!flag->m_const_value)
{ {
throw detail::missing_value_error( throw detail::missing_value_error(make_string(
make_string("Append const chosen as an action but const value not provided for argument '", arg, "Append const chosen as an action but const value not provided for argument '", arg, '\''));
'\''));
} }
if (parsed_args.contains(dest)) if (parsed_args.contains(dest))
{ {
auto& data = parsed_args.m_data[dest]; auto& data = parsed_args.m_data[dest];
std::visit(detail::arg_meta_type_helper_t::make_visitor( std::visit(detail::arg_meta_type_helper_t::make_visitor([arg](auto& primitive) {
[arg](auto& primitive) throw detail::type_error(make_string("Invalid type for argument '", arg, "' expected list type, found '",
{
throw detail::type_error(make_string(
"Invalid type for argument '", arg, "' expected list type, found '",
blt::type_string<decltype(primitive)>(), "' with value ", primitive)); blt::type_string<decltype(primitive)>(), "' with value ", primitive));
}, }, [&flag, arg](auto& vec) {
[&flag, arg](auto& vec)
{
using type = typename meta::remove_cvref_t<decltype(vec)>::value_type; using type = typename meta::remove_cvref_t<decltype(vec)>::value_type;
if (!std::holds_alternative<type>(*flag->m_const_value)) if (!std::holds_alternative<type>(*flag->m_const_value))
{ {
@ -825,18 +798,13 @@ namespace blt::argparse
} }
vec.push_back(std::get<type>(*flag->m_const_value)); vec.push_back(std::get<type>(*flag->m_const_value));
}), data); }), data);
} } else
else
{
std::visit(detail::arg_meta_type_helper_t::make_visitor(
[&parsed_args, &dest](auto& primitive)
{ {
std::visit(detail::arg_meta_type_helper_t::make_visitor([&parsed_args, &dest](auto& primitive) {
std::vector<meta::remove_cvref_t<decltype(primitive)>> vec; std::vector<meta::remove_cvref_t<decltype(primitive)>> vec;
vec.emplace_back(primitive); vec.emplace_back(primitive);
parsed_args.m_data.emplace(dest, std::move(vec)); parsed_args.m_data.emplace(dest, std::move(vec));
}, }, [](auto&) {
[](auto&)
{
throw detail::type_error("Append const should not be a list type!"); throw detail::type_error("Append const should not be a list type!");
}), *flag->m_const_value); }), *flag->m_const_value);
} }
@ -872,27 +840,20 @@ namespace blt::argparse
case action_t::COUNT: case action_t::COUNT:
if (parsed_args.m_data.contains(dest)) if (parsed_args.m_data.contains(dest))
{ {
auto visitor = detail::arg_meta_type_helper_t::make_visitor( auto visitor = detail::arg_meta_type_helper_t::make_visitor([](auto& primitive) -> detail::arg_data_t {
[](auto& primitive) -> detail::arg_data_t
{
using type = meta::remove_cvref_t<decltype(primitive)>; using type = meta::remove_cvref_t<decltype(primitive)>;
if constexpr (std::is_convertible_v<decltype(1), type>) if constexpr (std::is_convertible_v<decltype(1), type>)
{ {
return primitive + static_cast<type>(1); return primitive + static_cast<type>(1);
} } else
else throw detail::type_error("Error: count called but stored type is " + blt::type_string<type>());
}, [](auto&) -> detail::arg_data_t {
throw detail::type_error( throw detail::type_error(
"Error: count called but stored type is " + blt::type_string<type>()); "List present on count. This condition doesn't make any sense! "
},
[](auto&) -> detail::arg_data_t
{
throw detail::type_error("List present on count. This condition doesn't make any sense! "
"(How did we get here, please report this!)"); "(How did we get here, please report this!)");
} });
);
parsed_args.m_data[dest] = std::visit(visitor, parsed_args.m_data[dest]); parsed_args.m_data[dest] = std::visit(visitor, parsed_args.m_data[dest]);
} } else // I also hate this!
else // I also hate this!
flag->m_dest_func(dest, parsed_args, "1"); flag->m_dest_func(dest, parsed_args, "1");
break; break;
case action_t::HELP: case action_t::HELP:
@ -914,8 +875,7 @@ namespace blt::argparse
auto& positional = storage.next(); auto& positional = storage.next();
const auto dest = positional.m_dest.value_or(std::string{arg}); const auto dest = positional.m_dest.value_or(std::string{arg});
std::visit(lambda_visitor{ std::visit(lambda_visitor{
[&consumer, &positional, &dest, &parsed_args, arg](const nargs_t arg_enum) [&consumer, &positional, &dest, &parsed_args, arg](const nargs_t arg_enum) {
{
switch (arg_enum) switch (arg_enum)
{ {
case nargs_t::IF_POSSIBLE: case nargs_t::IF_POSSIBLE:
@ -927,8 +887,7 @@ namespace blt::argparse
make_string("Error expected at least one argument to be consumed by '", arg, '\'')); make_string("Error expected at least one argument to be consumed by '", arg, '\''));
[[fallthrough]]; [[fallthrough]];
case nargs_t::ALL: case nargs_t::ALL:
auto result = consume_until_flag_or_end( auto result = consume_until_flag_or_end(consumer, positional.m_choices ? &*positional.m_choices : nullptr);
consumer, positional.m_choices ? &*positional.m_choices : nullptr);
if (!result) if (!result)
throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(), throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(),
"' is not a valid choice for argument '", arg, "' is not a valid choice for argument '", arg,
@ -937,8 +896,7 @@ namespace blt::argparse
break; break;
} }
}, },
[this, &consumer, &positional, &dest, &parsed_args, arg](const i32 argc) [this, &consumer, &positional, &dest, &parsed_args, arg](const i32 argc) {
{
const auto args = consume_argc(argc, consumer, positional.m_choices ? &*positional.m_choices : nullptr, arg); const auto args = consume_argc(argc, consumer, positional.m_choices ? &*positional.m_choices : nullptr, arg);
switch (positional.m_action) switch (positional.m_action)
@ -1023,8 +981,7 @@ namespace blt::argparse
return args; return args;
} }
std::vector<std::string> argument_parser_t::consume_argc(const int argc, argument_consumer_t& consumer, std::vector<std::string> argument_parser_t::consume_argc(const int argc, argument_consumer_t& consumer, hashset_t<std::string>* allowed_choices,
hashset_t<std::string>* allowed_choices,
const std::string_view arg) const std::string_view arg)
{ {
std::vector<std::string> args; std::vector<std::string> args;
@ -1032,15 +989,13 @@ namespace blt::argparse
{ {
if (!consumer.can_consume()) if (!consumer.can_consume())
{ {
throw detail::missing_argument_error( throw detail::missing_argument_error(make_string("Expected ", argc, " arguments to be consumed by '", arg, "' but found ", i));
make_string("Expected ", argc, " arguments to be consumed by '", arg, "' but found ", i));
} }
if (consumer.peek().is_flag()) if (consumer.peek().is_flag())
{ {
std::cout << "Warning: arg '" << arg << "' expects " << argc << std::cout << "Warning: arg '" << arg << "' expects " << argc << " arguments to be consumed but we found a flag '" << consumer.peek().
" arguments to be consumed but we found a flag '" << consumer.peek(). get_argument()
get_argument() << << "'. We will comply as this may be desired if this argument is a file." << std::endl;
"'. We will comply as this may be desired if this argument is a file." << std::endl;
} }
if (allowed_choices != nullptr && !allowed_choices->contains(consumer.peek().get_argument())) if (allowed_choices != nullptr && !allowed_choices->contains(consumer.peek().get_argument()))
{ {
@ -1052,8 +1007,7 @@ namespace blt::argparse
valid_choices += ", "; valid_choices += ", ";
} }
valid_choices += "}"; valid_choices += "}";
throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(), throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(), "' is not a valid choice for argument '", arg,
"' is not a valid choice for argument '", arg,
"'! Expected one of ", valid_choices)); "'! Expected one of ", valid_choices));
} }
args.emplace_back(consumer.consume().get_argument()); args.emplace_back(consumer.consume().get_argument());
@ -1061,8 +1015,7 @@ namespace blt::argparse
if (args.size() != static_cast<size_t>(argc)) if (args.size() != static_cast<size_t>(argc))
{ {
throw std::runtime_error( throw std::runtime_error(
"This error condition should not be possible. " "This error condition should not be possible. " "Args consumed didn't equal the arguments requested and previous checks didn't fail. "
"Args consumed didn't equal the arguments requested and previous checks didn't fail. "
"Please report as an issue on the GitHub"); "Please report as an issue on the GitHub");
} }
return args; return args;
@ -1194,7 +1147,6 @@ namespace blt::argparse
BLT_ASSERT(arg.get_flag() == "++" && "Double plus value should match the input string."); BLT_ASSERT(arg.get_flag() == "++" && "Double plus value should match the input string.");
} }
void run_all_tests_argument_string_t() void run_all_tests_argument_string_t()
{ {
const hashset_t<char> prefixes = {'-', '+'}; const hashset_t<char> prefixes = {'-', '+'};
@ -1247,8 +1199,7 @@ namespace blt::argparse
{ {
parser.parse(args); parser.parse(args);
BLT_ASSERT(false && "Parsing should fail with invalid flag prefix '!'"); BLT_ASSERT(false && "Parsing should fail with invalid flag prefix '!'");
} } catch (...)
catch (...)
{ {
BLT_ASSERT(true && "Correctly threw on bad flag prefix"); BLT_ASSERT(true && "Correctly threw on bad flag prefix");
} }
@ -1278,8 +1229,7 @@ namespace blt::argparse
{ {
parser.parse(args); parser.parse(args);
BLT_ASSERT(false && "Parsing should fail due to invalid flag '!z'"); BLT_ASSERT(false && "Parsing should fail due to invalid flag '!z'");
} } catch (...)
catch (...)
{ {
BLT_ASSERT(true && "Correctly threw an exception for invalid flag"); BLT_ASSERT(true && "Correctly threw an exception for invalid flag");
} }
@ -1320,8 +1270,7 @@ namespace blt::argparse
{ {
auto parsed_args = parser.parse(consumer); auto parsed_args = parser.parse(consumer);
return consumer.remaining() == 0; return consumer.remaining() == 0;
} } catch (const std::exception&)
catch (const std::exception&)
{ {
return false; return false;
} }
@ -1393,18 +1342,15 @@ namespace blt::argparse
// Valid case: No arguments // Valid case: No arguments
const std::vector<std::string_view> valid_args_0 = {"./program"}; const std::vector<std::string_view> valid_args_0 = {"./program"};
BLT_ASSERT(!parse_arguments(valid_args_0, argparse::nargs_t::ALL) && BLT_ASSERT(!parse_arguments(valid_args_0, argparse::nargs_t::ALL) && "nargs=ALL: No arguments present. Should fail.)");
"nargs=ALL: No arguments present. Should fail.)");
// Valid case: Multiple arguments // Valid case: Multiple arguments
const std::vector<std::string_view> valid_args_2 = {"./program", "arg1", "arg2"}; const std::vector<std::string_view> valid_args_2 = {"./program", "arg1", "arg2"};
BLT_ASSERT(parse_arguments(valid_args_2, argparse::nargs_t::ALL) && BLT_ASSERT(parse_arguments(valid_args_2, argparse::nargs_t::ALL) && "nargs=ALL: Should accept all remaining arguments");
"nargs=ALL: Should accept all remaining arguments");
// Valid case: Many arguments // Valid case: Many arguments
const std::vector<std::string_view> valid_args_many = {"./program", "arg1", "arg2", "arg3", "arg4"}; const std::vector<std::string_view> valid_args_many = {"./program", "arg1", "arg2", "arg3", "arg4"};
BLT_ASSERT(parse_arguments(valid_args_many, argparse::nargs_t::ALL) && BLT_ASSERT(parse_arguments(valid_args_many, argparse::nargs_t::ALL) && "nargs=ALL: Should accept all remaining arguments");
"nargs=ALL: Should accept all remaining arguments");
std::cout << "Success: test_nargs_all\n"; std::cout << "Success: test_nargs_all\n";
} }
@ -1497,20 +1443,16 @@ namespace blt::argparse
{ {
parser.parse(a2); parser.parse(a2);
BLT_ASSERT(false && "Parsing should fail due to invalid flag '--hello'"); BLT_ASSERT(false && "Parsing should fail due to invalid flag '--hello'");
} } catch (...)
catch (...) {}
{
}
const auto a3 = make_arguments("--hello", "crazy", "not_a_choice"); const auto a3 = make_arguments("--hello", "crazy", "not_a_choice");
try try
{ {
parser.parse(a3); parser.parse(a3);
BLT_ASSERT(false && "Parsing should fail due to invalid positional 'iam'"); BLT_ASSERT(false && "Parsing should fail due to invalid positional 'iam'");
} } catch (...)
catch (...) {}
{
}
std::cout << "Success: run_choice_test\n"; std::cout << "Success: run_choice_test\n";
} }
@ -1541,20 +1483,16 @@ namespace blt::argparse
{ {
parser.parse(a1); parser.parse(a1);
BLT_ASSERT(false && "Subparser should throw an error when positional not supplied"); BLT_ASSERT(false && "Subparser should throw an error when positional not supplied");
} } catch (...)
catch (...) {}
{
}
const auto a2 = make_arguments("--open"); const auto a2 = make_arguments("--open");
try try
{ {
parser.parse(a2); parser.parse(a2);
BLT_ASSERT(false && "Subparser should throw an error when no subparser is supplied"); BLT_ASSERT(false && "Subparser should throw an error when no subparser is supplied");
} } catch (...)
catch (...) {}
{
}
const auto a3 = make_arguments("n1", "--silly", "path_n1"); const auto a3 = make_arguments("n1", "--silly", "path_n1");
const auto r3 = parser.parse(a3); const auto r3 = parser.parse(a3);
@ -1568,10 +1506,8 @@ namespace blt::argparse
{ {
parser.parse(a4); parser.parse(a4);
BLT_ASSERT(false && "Subparser should throw an error when second positional is not supplied"); BLT_ASSERT(false && "Subparser should throw an error when second positional is not supplied");
} } catch (...)
catch (...) {}
{
}
const auto a5 = make_arguments("--open", "n2", "path_n2", "output_n2"); const auto a5 = make_arguments("--open", "n2", "path_n2", "output_n2");
const auto r5 = parser.parse(a5); const auto r5 = parser.parse(a5);
@ -1586,10 +1522,8 @@ namespace blt::argparse
{ {
parser.parse(a6); parser.parse(a6);
BLT_ASSERT(false && "Subparser should throw an error when first positional is not a valid subparser"); BLT_ASSERT(false && "Subparser should throw an error when first positional is not a valid subparser");
} } catch (const std::exception&)
catch (const std::exception&) {}
{
}
const auto a7 = make_arguments("n3"); const auto a7 = make_arguments("n3");
const auto r7 = parser.parse(a7); const auto r7 = parser.parse(a7);