positionals are broken because im silly
parent
188e9dba88
commit
389762e2ae
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
include(cmake/color.cmake)
|
||||
set(BLT_VERSION 4.0.18)
|
||||
set(BLT_VERSION 4.0.19)
|
||||
|
||||
set(BLT_TARGET BLT)
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <blt/iterator/enumerate.h>
|
||||
#include <blt/std/assert.h>
|
||||
#include <blt/std/expected.h>
|
||||
#include <blt/std/ranges.h>
|
||||
#include <blt/std/utility.h>
|
||||
|
@ -308,8 +308,16 @@ namespace blt::argparse
|
|||
class argument_consumer_t
|
||||
{
|
||||
public:
|
||||
explicit argument_consumer_t(const span<argument_string_t>& args): m_begin(args.data()), m_end(args.data() + args.size())
|
||||
explicit argument_consumer_t(const span<argument_string_t>& args): m_absolute_begin(args.data()), m_begin(args.data() + 1),
|
||||
m_end(args.data() + args.size())
|
||||
{
|
||||
BLT_ASSERT(!args.empty() &&
|
||||
"Argument consumer must have at least one argument allocated to it. First argument is always assumed to be program");
|
||||
}
|
||||
|
||||
[[nodiscard]] const argument_string_t& absolute_first() const
|
||||
{
|
||||
return *m_absolute_begin;
|
||||
}
|
||||
|
||||
[[nodiscard]] argument_string_t peek(const i32 offset = 0) const
|
||||
|
@ -348,6 +356,7 @@ namespace blt::argparse
|
|||
return m_end - m_begin;
|
||||
}
|
||||
|
||||
argument_string_t* m_absolute_begin;
|
||||
argument_string_t* m_begin;
|
||||
argument_string_t* m_end;
|
||||
};
|
||||
|
@ -580,9 +589,20 @@ namespace blt::argparse
|
|||
|
||||
argument_storage_t parse(argument_consumer_t& consumer); // NOLINT
|
||||
|
||||
argument_storage_t parse(const std::vector<std::string_view>& args)
|
||||
{
|
||||
std::vector<argument_string_t> arg_strings;
|
||||
arg_strings.reserve(args.size());
|
||||
for (const auto& arg : args)
|
||||
arg_strings.emplace_back(arg, allowed_flag_prefixes);
|
||||
argument_consumer_t consumer{arg_strings};
|
||||
return parse(consumer);
|
||||
}
|
||||
|
||||
argument_storage_t parse(const std::vector<std::string>& args)
|
||||
{
|
||||
std::vector<argument_string_t> arg_strings;
|
||||
arg_strings.reserve(args.size());
|
||||
for (const auto& arg : args)
|
||||
arg_strings.emplace_back(arg, allowed_flag_prefixes);
|
||||
argument_consumer_t consumer{arg_strings};
|
||||
|
@ -592,6 +612,7 @@ namespace blt::argparse
|
|||
argument_storage_t parse(const int argc, const char** argv)
|
||||
{
|
||||
std::vector<argument_string_t> arg_strings;
|
||||
arg_strings.reserve(argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
arg_strings.emplace_back(argv[i], allowed_flag_prefixes);
|
||||
argument_consumer_t consumer{arg_strings};
|
||||
|
@ -643,6 +664,11 @@ namespace blt::argparse
|
|||
return m_epilogue;
|
||||
}
|
||||
|
||||
[[nodiscard]] const hashset_t<char>& get_allowed_flag_prefixes() const
|
||||
{
|
||||
return allowed_flag_prefixes;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_compound_flags(hashset_t<std::string>& found_flags, argument_storage_t& parsed_args, argument_consumer_t& consumer,
|
||||
const argument_string_t& arg);
|
||||
|
@ -653,7 +679,7 @@ namespace blt::argparse
|
|||
static expected<std::vector<std::string_view>, std::string> consume_until_flag_or_end(argument_consumer_t& consumer,
|
||||
hashset_t<std::string>* allowed_choices);
|
||||
static std::vector<std::string_view> consume_argc(i32 argc, argument_consumer_t& consumer, hashset_t<std::string>* allowed_choices,
|
||||
std::string_view arg);
|
||||
std::string_view arg);
|
||||
|
||||
std::optional<std::string> m_name;
|
||||
std::optional<std::string> m_usage;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <blt/std/assert.h>
|
||||
#include <blt/meta/type_traits.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/iterator/enumerate.h>
|
||||
|
||||
namespace blt::argparse
|
||||
{
|
||||
|
@ -195,7 +196,7 @@ namespace blt::argparse
|
|||
|
||||
void test_argparse_empty()
|
||||
{
|
||||
std::vector<std::string> const argv;
|
||||
const std::vector<std::string> argv{"./program"};
|
||||
argument_parser_t parser;
|
||||
const auto args = parser.parse(argv);
|
||||
BLT_ASSERT(args.size() == 0 && "Empty argparse should have no args on output");
|
||||
|
@ -208,7 +209,7 @@ namespace blt::argparse
|
|||
parser.add_flag("+b").set_action(action_t::STORE_FALSE);
|
||||
parser.add_flag("/c").as_type<int>().set_action(action_t::STORE);
|
||||
|
||||
const std::vector<std::string> args = {"-a", "+b", "/c", "42"};
|
||||
const std::vector<std::string> args = {"./program", "-a", "+b", "/c", "42"};
|
||||
const auto parsed_args = parser.parse(args);
|
||||
|
||||
BLT_ASSERT(parsed_args.get<bool>("-a") == true && "Flag '-a' should store `true`");
|
||||
|
@ -224,7 +225,7 @@ namespace blt::argparse
|
|||
parser.add_flag("+b");
|
||||
parser.add_flag("/c");
|
||||
|
||||
const std::vector<std::string> args = {"!d", "-a"};
|
||||
const std::vector<std::string> args = {"./program", "!d", "-a"};
|
||||
try
|
||||
{
|
||||
parser.parse(args);
|
||||
|
@ -241,7 +242,7 @@ namespace blt::argparse
|
|||
argument_parser_t parser;
|
||||
parser.add_flag("-v").as_type<int>().set_action(action_t::COUNT);
|
||||
|
||||
const std::vector<std::string> args = {"-vvv"};
|
||||
const std::vector<std::string> args = {"./program", "-vvv"};
|
||||
const auto parsed_args = parser.parse(args);
|
||||
|
||||
BLT_ASSERT(parsed_args.get<size_t>("-v") == 3 && "Flag '-v' should count occurrences in compound form");
|
||||
|
@ -255,7 +256,7 @@ namespace blt::argparse
|
|||
parser.add_flag("-x").as_type<int>();
|
||||
parser.add_flag("/y").as_type<std::string_view>();
|
||||
|
||||
const std::vector<std::string> args = {"-x", "10", "!z", "/y", "value"};
|
||||
const std::vector<std::string> args = {"./program", "-x", "10", "!z", "/y", "value"};
|
||||
try
|
||||
{
|
||||
parser.parse(args);
|
||||
|
@ -277,7 +278,7 @@ namespace blt::argparse
|
|||
parser.add_flag("-f").set_action(action_t::STORE_FALSE); // STORE_FALSE action
|
||||
parser.add_flag("-c").set_action(action_t::STORE_TRUE); // STORE_TRUE action
|
||||
|
||||
const std::vector<std::string> args = {"-k", "100", "-t", "-f", "-c"};
|
||||
const std::vector<std::string> args = {"./program", "-k", "100", "-t", "-f", "-c"};
|
||||
const auto parsed_args = parser.parse(args);
|
||||
|
||||
BLT_ASSERT(parsed_args.get<int>("-k") == 100 && "Flag '-k' should store 100");
|
||||
|
@ -286,6 +287,90 @@ namespace blt::argparse
|
|||
BLT_ASSERT(parsed_args.get<bool>("-c") == true && "Flag '-c' should store `true`");
|
||||
}
|
||||
|
||||
// Helper function to simulate argument parsing for nargs tests
|
||||
bool parse_arguments(const std::vector<std::string_view>& args, int expected_nargs)
|
||||
{
|
||||
argument_parser_t parser;
|
||||
|
||||
std::vector<argument_string_t> arg_strings;
|
||||
arg_strings.reserve(args.size());
|
||||
for (const auto& arg : args)
|
||||
arg_strings.emplace_back(arg, parser.get_allowed_flag_prefixes());
|
||||
argument_consumer_t consumer{arg_strings};
|
||||
|
||||
parser.add_positional("positional").set_nargs(expected_nargs);
|
||||
try
|
||||
{
|
||||
auto parsed_args = parser.parse(consumer);
|
||||
return consumer.remaining() == 0;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Test case for nargs = 0
|
||||
void test_nargs_0()
|
||||
{
|
||||
std::cout << "[Running Test: test_nargs_0]\n";
|
||||
|
||||
// Valid case: No arguments
|
||||
const std::vector<std::string_view> valid_args = {"./program"};
|
||||
BLT_ASSERT(parse_arguments(valid_args, 0) && "nargs=0: Should accept no arguments");
|
||||
|
||||
// Invalid case: 1 argument
|
||||
const std::vector<std::string_view> invalid_args = {"./program", "arg1"};
|
||||
BLT_ASSERT(!parse_arguments(invalid_args, 0) && "nargs=0: Should not accept any arguments");
|
||||
|
||||
std::cout << "Success: test_nargs_0\n";
|
||||
}
|
||||
|
||||
// Test case for nargs = 1
|
||||
void test_nargs_1()
|
||||
{
|
||||
std::cout << "[Running Test: test_nargs_1]\n";
|
||||
|
||||
// Valid case: 1 argument
|
||||
const std::vector<std::string_view> valid_args = {"./program", "arg1"};
|
||||
BLT_ASSERT(parse_arguments(valid_args, 1) && "nargs=1: Should accept exactly 1 argument");
|
||||
|
||||
// Invalid case: 0 arguments
|
||||
const std::vector<std::string_view> invalid_args_0 = {"./program"};
|
||||
BLT_ASSERT(!parse_arguments(invalid_args_0, 1) && "nargs=1: Should not accept 0 arguments");
|
||||
|
||||
// Invalid case: 2 arguments
|
||||
const std::vector<std::string_view> invalid_args_2 = {"./program", "arg1", "arg2"};
|
||||
BLT_ASSERT(!parse_arguments(invalid_args_2, 1) && "nargs=1: Should not accept more than 1 argument");
|
||||
|
||||
std::cout << "Success: test_nargs_1\n";
|
||||
}
|
||||
|
||||
// Test case for nargs = 2
|
||||
void test_nargs_2()
|
||||
{
|
||||
std::cout << "[Running Test: test_nargs_2]\n";
|
||||
|
||||
// Valid case: 2 arguments
|
||||
const std::vector<std::string_view> valid_args = {"./program", "arg1", "arg2"};
|
||||
BLT_ASSERT(parse_arguments(valid_args, 2) && "nargs=2: Should accept exactly 2 arguments");
|
||||
|
||||
// Invalid case: 0 arguments
|
||||
const std::vector<std::string_view> invalid_args_0 = {"./program"};
|
||||
BLT_ASSERT(!parse_arguments(invalid_args_0, 2) && "nargs=2: Should not accept 0 arguments");
|
||||
|
||||
// Invalid case: 1 argument
|
||||
const std::vector<std::string_view> invalid_args_1 = {"./program", "arg1"};
|
||||
BLT_ASSERT(!parse_arguments(invalid_args_1, 2) && "nargs=2: Should not accept less than 2 arguments");
|
||||
|
||||
// Invalid case: 3 arguments
|
||||
const std::vector<std::string_view> invalid_args_3 = {"./program", "arg1", "arg2", "arg3"};
|
||||
BLT_ASSERT(!parse_arguments(invalid_args_3, 2) && "nargs=2: Should not accept more than 2 arguments");
|
||||
|
||||
std::cout << "Success: test_nargs_2\n";
|
||||
}
|
||||
|
||||
void run_argparse_flag_tests()
|
||||
{
|
||||
test_single_flag_prefixes();
|
||||
|
@ -295,11 +380,20 @@ namespace blt::argparse
|
|||
test_flags_with_different_actions();
|
||||
}
|
||||
|
||||
void run_all_nargs_tests()
|
||||
{
|
||||
test_nargs_0();
|
||||
test_nargs_1();
|
||||
test_nargs_2();
|
||||
std::cout << "All nargs tests passed successfully.\n";
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
run_all_tests_argument_string_t();
|
||||
test_argparse_empty();
|
||||
run_argparse_flag_tests();
|
||||
run_all_nargs_tests();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string subparse_error::error_string() const
|
||||
|
@ -337,6 +431,8 @@ namespace blt::argparse
|
|||
|
||||
argument_storage_t argument_parser_t::parse(argument_consumer_t& consumer)
|
||||
{
|
||||
if (!m_name)
|
||||
m_name = consumer.absolute_first().get_argument();
|
||||
hashset_t<std::string> found_flags;
|
||||
hashset_t<std::string> found_positional;
|
||||
argument_storage_t parsed_args;
|
||||
|
|
Loading…
Reference in New Issue