aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.cli
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.cli')
-rw-r--r--nihil.cli/CMakeLists.txt3
-rw-r--r--nihil.cli/command_tree.ccm16
-rw-r--r--nihil.cli/command_tree.test.cc45
-rw-r--r--nihil.cli/dispatch_command.test.cc (renamed from nihil.cli/test.cc)0
4 files changed, 54 insertions, 10 deletions
diff --git a/nihil.cli/CMakeLists.txt b/nihil.cli/CMakeLists.txt
index 41fae52..091c34f 100644
--- a/nihil.cli/CMakeLists.txt
+++ b/nihil.cli/CMakeLists.txt
@@ -25,8 +25,9 @@ if(NIHIL_TESTS)
enable_testing()
add_executable(nihil.cli.test
- test.cc
command.test.cc
+ command_tree.test.cc
+ dispatch_command.test.cc
)
target_link_libraries(nihil.cli.test PRIVATE
nihil.cli
diff --git a/nihil.cli/command_tree.ccm b/nihil.cli/command_tree.ccm
index 6cfabe9..7399357 100644
--- a/nihil.cli/command_tree.ccm
+++ b/nihil.cli/command_tree.ccm
@@ -120,18 +120,15 @@ private:
};
// The command tree stores commands in a tree structure suitable for searching.
-struct command_tree
+export struct command_tree
{
// Add a node to the tree. Returns false if the node already exists.
- auto insert(this command_tree &self, std::ranges::range auto &&path,
- std::shared_ptr<command> command) -> void
- requires(std::constructible_from<std::string_view,
- std::ranges::range_value_t<decltype(path)>>)
+ auto insert(this command_tree &self, std::shared_ptr<command> command) -> void
{
auto *this_node = &self.m_root_node;
// Find the node for this key.
- for (auto &&this_word : path)
+ for (auto &&this_word : command->path() | std::views::split(' '))
this_node = this_node->get_or_create_child(std::string_view(this_word));
// Set the new value.
@@ -143,7 +140,7 @@ struct command_tree
requires(std::constructible_from<std::string_view,
std::ranges::range_value_t<decltype(args)>>)
{
- auto const *this_node = &self.m_root_node;
+ auto *this_node = &self.m_root_node;
auto rest =
args | std::views::take_while([&](auto &&str) {
@@ -169,9 +166,10 @@ private:
{
auto tree = command_tree();
- for (auto &&command : get_registered_commands())
+ for (auto &&command : get_registered_commands()) {
// Throws std::logic_error on duplicates.
- tree.insert(command->path() | std::views::split(' '), command);
+ tree.insert(command);
+ }
return tree;
}
diff --git a/nihil.cli/command_tree.test.cc b/nihil.cli/command_tree.test.cc
new file mode 100644
index 0000000..a1e7d32
--- /dev/null
+++ b/nihil.cli/command_tree.test.cc
@@ -0,0 +1,45 @@
+// This source code is released into the public domain.
+
+#include <catch2/catch_test_macros.hpp>
+
+import nihil.std;
+import nihil.cli;
+
+namespace {
+
+inline auto constexpr *test_tags = "[nihil][nihil.cli]";
+
+SCENARIO("Inserting and retrieving nodes in a command_tree", test_tags)
+{
+ GIVEN ("A command tree") {
+ auto tree = nihil::command_tree();
+
+ THEN ("We can insert nodes into the tree") {
+ tree.insert(std::make_shared<nihil::command>("cmd1 sub1"));
+ tree.insert(std::make_shared<nihil::command>("cmd1 sub2"));
+ tree.insert(std::make_shared<nihil::command>("cmd2 sub1"));
+
+ AND_THEN ("We can retrieve nodes from the tree") {
+ auto c1s1 = tree.find(std::vector{"cmd1", "sub1"});
+ REQUIRE(c1s1.first->command().path() == "cmd1 sub1");
+
+ auto c1s2 = tree.find(std::vector{"cmd1", "sub2"});
+ REQUIRE(c1s2.first->command().path() == "cmd1 sub2");
+
+ auto c2s1 = tree.find(std::vector{"cmd2", "sub1"});
+ REQUIRE(c2s1.first->command().path() == "cmd2 sub1");
+ }
+
+ AND_THEN ("Fetching an unknown command returns the root node") {
+ auto cmd = tree.find(std::vector{"cmd3", "sub1"});
+ REQUIRE(cmd.first->command().path() == "");
+ }
+
+ AND_THEN ("Fetching an unknown subcommand returns the cmd1 node") {
+ auto cmd = tree.find(std::vector{"cmd1", "sub3"});
+ REQUIRE(cmd.first->command().path() == "cmd1");
+ }
+ }
+ }
+}
+} // anonymous namespace
diff --git a/nihil.cli/test.cc b/nihil.cli/dispatch_command.test.cc
index 8253bdc..8253bdc 100644
--- a/nihil.cli/test.cc
+++ b/nihil.cli/dispatch_command.test.cc