diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2024-07-17 15:59:41 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2024-07-17 15:59:41 +0200 |
| commit | 79c06fc454b91bc14b4a85dd6ec0c870c8ab6da8 (patch) | |
| tree | be40741f637981b1e07b620c77cb2b34c67fc8c3 | |
| parent | 631a8065aa9753c27f84c08bee49334c1b473bdc (diff) | |
| download | turns-79c06fc454b91bc14b4a85dd6ec0c870c8ab6da8.tar.xz turns-79c06fc454b91bc14b4a85dd6ec0c870c8ab6da8.zip | |
domain/tests: improve turn_order tests
| -rw-r--r-- | domain/include/turns/domain/turn_order.hpp | 35 | ||||
| -rw-r--r-- | domain/src/turn_order.cpp | 25 | ||||
| -rw-r--r-- | domain/tests/turn_order.cpp | 477 |
3 files changed, 483 insertions, 54 deletions
diff --git a/domain/include/turns/domain/turn_order.hpp b/domain/include/turns/domain/turn_order.hpp index 59438d6..3b42562 100644 --- a/domain/include/turns/domain/turn_order.hpp +++ b/domain/include/turns/domain/turn_order.hpp @@ -4,6 +4,8 @@ #include "turns/domain/disposition.hpp" #include "turns/domain/participant.hpp" +#include <limits> + #include <giomm/liststore.h> #include <glibmm/property.h> #include <glibmm/refptr.h> @@ -21,6 +23,8 @@ namespace turns::domain using running_type = bool; using round_type = unsigned int; + auto static constexpr invalid_participant_index = std::numeric_limits<active_participant_type>::max(); + auto static create() -> Glib::RefPtr<turn_order>; turn_order(); @@ -38,12 +42,43 @@ namespace turns::domain /** Querries */ + /** + * Get the index of the currently active participant of this turn order, if any. + * + * @returns an unsigned integer in the range [0, size()) if there is an active participant, or turn_order::invalid_participant_index otherwise. + */ auto active_participant() const noexcept -> active_participant_type; + + /** + * Check if this turn order is empty. + */ auto empty() const noexcept -> empty_type; + + /** + * Get the actor at the specified position in this turn order. + * + * @return a valid pointer to a participant object if the index was valid, nullptr otherwise. + */ auto get(unsigned int index) const noexcept -> Glib::RefPtr<participant>; + + /** + * Get the underlying list model, to be used with list views. + */ auto list_model() -> Glib::RefPtr<Gio::ListModel>; + + /** + * Get the current round. + */ auto round() const noexcept -> round_type; + + /** + * Check if this turn order is currently running. + */ auto running() const noexcept -> running_type; + + /** + * Get the size of this turn order + */ auto size() const noexcept -> unsigned int; /** Properties */ diff --git a/domain/src/turn_order.cpp b/domain/src/turn_order.cpp index 595b55d..61ccdca 100644 --- a/domain/src/turn_order.cpp +++ b/domain/src/turn_order.cpp @@ -40,7 +40,7 @@ namespace turns::domain turn_order::turn_order() : Glib::ObjectBase{typeid(turn_order)} , m_model{Gio::ListStore<participant>::create()} - , m_active_participant(*this, "active_participant", std::numeric_limits<active_participant_type>::max()) + , m_active_participant(*this, "active_participant", invalid_participant_index) , m_empty{*this, "empty", true} , m_has_next{*this, "has-next", false} , m_has_previous{*this, "has-previous", false} @@ -62,7 +62,7 @@ namespace turns::domain auto position = m_model->insert_sorted(participant, comparator); participant->property_priority().signal_changed().connect([this] { m_model->sort(comparator); }); - if (m_active_participant != std::numeric_limits<active_participant_type>::max() && position <= m_active_participant) + if (m_active_participant != invalid_participant_index && position <= m_active_participant) { m_active_participant = m_active_participant + 1; } @@ -72,7 +72,7 @@ namespace turns::domain auto turn_order::clear() -> void { m_model->remove_all(); - m_active_participant = std::numeric_limits<active_participant_type>::max(); + m_active_participant = invalid_participant_index; m_has_next = false; m_has_previous = false; m_running = false; @@ -113,18 +113,21 @@ namespace turns::domain m_model->remove(index); if (empty()) { - m_active_participant = std::numeric_limits<active_participant_type>::max(); + m_active_participant = invalid_participant_index; m_has_next = false; m_has_previous = false; m_running = false; } - else if (m_active_participant >= size() - 1) + else if (m_active_participant != invalid_participant_index) { - m_active_participant = size() - 1; - } - else if (index <= m_active_participant) - { - m_active_participant = m_active_participant - 1; + if (m_active_participant > size() - 1) + { + m_active_participant = size() - 1; + } + else if (index <= m_active_participant) + { + m_active_participant = m_active_participant - 1; + } } } @@ -136,7 +139,7 @@ namespace turns::domain auto turn_order::start() -> void { - if (m_active_participant == std::numeric_limits<active_participant_type>::max()) + if (m_active_participant == invalid_participant_index) { m_active_participant = 0; } diff --git a/domain/tests/turn_order.cpp b/domain/tests/turn_order.cpp index 5bdc157..de1689c 100644 --- a/domain/tests/turn_order.cpp +++ b/domain/tests/turn_order.cpp @@ -1,71 +1,462 @@ #include "turns/domain/turn_order.hpp" -#include "turns/domain/participant.hpp" - #include <catch2/catch_test_macros.hpp> -#include <compare> - -#include <glibmm/init.h> +#include <glibmm/ustring.h> namespace turns::domain::tests { - TEST_CASE("A freshly constructed turn order") + SCENARIO("Queries on a fresh turn_order instance", "[turn_order]") { - auto instance = turn_order::create(); - - SECTION("can be created") + GIVEN("an empty turn_order") { - REQUIRE(instance); - } + auto instance = turn_order::create(); - SECTION("has 0 items") - { - REQUIRE(instance->size() == 0); - } + THEN("active_participant() is turn_order::invalid_participant_index") + { + REQUIRE(instance->active_participant() == turn_order::invalid_participant_index); + } - SECTION("accepts a new participant") - { - instance->add("River along the Field", 14, disposition::friendly); - REQUIRE(instance->size() == 1); - } + THEN("empty() is true") + { + REQUIRE(instance->empty()); + } - SECTION("does nothing when trying to remove an item if no items were added beforehand") - { - instance->remove(5); - REQUIRE(instance->size() == 0); - } + THEN("get() returns a nullptr") + { + REQUIRE(instance->get(0) == nullptr); + } - SECTION("automatically sorts elements added in descending order of priority") - { - SECTION("when adding the higher one last") + THEN("list_model() returns a non-null pointer") + { + REQUIRE(instance->list_model()); + } + + THEN("round() returns 0") + { + REQUIRE(instance->round() == 0); + } + + THEN("running() returns false") + { + REQUIRE_FALSE(instance->running()); + } + + THEN("size() returns 0") + { + REQUIRE(instance->size() == 0); + } + + THEN("size() returns the same value as list_model()->get_n_item()") + { + REQUIRE(instance->size() == instance->list_model()->get_n_items()); + } + + WHEN("accessing turn_order:active-participant") { - instance->add("Tree Blossom", 6, disposition::friendly); - instance->add("Fish in the River", 12, disposition::friendly); - REQUIRE(instance->get(0)->get_name() == "Fish in the River"); + THEN("get() returns turn_order::invalid_participant_index") + { + REQUIRE(instance->property_active_participant().get_value() == turn_order::invalid_participant_index); + } + + THEN("get_object() returns a pointer to the instance") + { + REQUIRE(instance->property_active_participant().get_object() == instance.get()); + } + + THEN("get_name() returns \"active-participant\"") + { + REQUIRE(instance->property_active_participant().get_name() == Glib::ustring{"active-participant"}); + } } - SECTION("when adding the higher one first") + WHEN("accessing turn_order:empty") { - instance->add("Fish in the River", 12, disposition::friendly); - instance->add("Tree Blossom", 6, disposition::friendly); - REQUIRE(instance->get(0)->get_name() == "Fish in the River"); + THEN("get() returns true") + { + REQUIRE(instance->property_empty().get_value()); + } + + THEN("get_object() returns a pointer to the instance") + { + REQUIRE(instance->property_empty().get_object() == instance.get()); + } + + THEN("get_name() returns \"empty\"") + { + REQUIRE(instance->property_empty().get_name() == Glib::ustring{"empty"}); + } } - SECTION("keeping the insertion order when adding items with equal priority") + WHEN("accessing turn_order:has-next") { - instance->add("Fish in the River", 6, disposition::friendly); - instance->add("Tree Blossom", 6, disposition::friendly); - REQUIRE(instance->get(0)->get_name() == "Fish in the River"); + THEN("get() returns false") + { + REQUIRE_FALSE(instance->property_has_next().get_value()); + } + + THEN("get_object() returns a pointer to the instance") + { + REQUIRE(instance->property_has_next().get_object() == instance.get()); + } + + THEN("get_name() returns \"has-next\"") + { + REQUIRE(instance->property_has_next().get_name() == Glib::ustring{"has-next"}); + } + } + + WHEN("accessing turn_order:has-previous") + { + THEN("get() returns false") + { + REQUIRE_FALSE(instance->property_has_previous().get_value()); + } + + THEN("get_object() returns a pointer to the instance") + { + REQUIRE(instance->property_has_previous().get_object() == instance.get()); + } + + THEN("get_name() returns \"has-previous\"") + { + REQUIRE(instance->property_has_previous().get_name() == Glib::ustring{"has-previous"}); + } + } + + WHEN("accessing turn_order:running") + { + THEN("get() returns false") + { + REQUIRE_FALSE(instance->property_running().get_value()); + } + + THEN("get_object() returns a pointer to the instance") + { + REQUIRE(instance->property_running().get_object() == instance.get()); + } + + THEN("get_name() returns \"running\"") + { + REQUIRE(instance->property_running().get_name() == Glib::ustring{"running"}); + } + } + + WHEN("accessing turn_order:running") + { + THEN("get() returns 0") + { + REQUIRE(instance->property_round().get_value() == 0); + } + + THEN("get_object() returns a pointer to the instance") + { + REQUIRE(instance->property_round().get_object() == instance.get()); + } + + THEN("get_name() returns \"round\"") + { + REQUIRE(instance->property_round().get_name() == Glib::ustring{"round"}); + } } } + } + + SCENARIO("Modification of an empty turn_order", "[turn_order]") + { + auto instance = turn_order::create(); - SECTION("does not accept the same item twice by components") + GIVEN("a single participant was added") { - instance->add("Frozen Apple Tree", 2.1, disposition::friendly); - instance->add("Frozen Apple Tree", 2.1, disposition::friendly); - REQUIRE(instance->size() == 1); + auto constexpr priority = 12.0f; + instance->add("Participant #0", priority, disposition::friendly); + + AND_GIVEN("the turn_order was never started") + { + WHEN("no other modification occurs") + { + THEN("active_participant() returns turn_order::invalid_participant_index") + { + REQUIRE(instance->active_participant() == turn_order::invalid_participant_index); + } + + THEN("empty() returns false") + { + REQUIRE_FALSE(instance->empty()); + } + + THEN("get() returns a valid pointer for index 0") + { + REQUIRE(instance->get(0)); + } + + THEN("get() returns a nullptr for an index greater than 0") + { + REQUIRE(instance->get(1) == nullptr); + } + + THEN("round() returns 0") + { + REQUIRE(instance->round() == 0); + } + + THEN("running() returns false") + { + REQUIRE_FALSE(instance->running()); + } + + THEN("size() returns 1") + { + REQUIRE(instance->size() == 1); + } + + THEN("turn_order:has-next is false") + { + REQUIRE(instance->property_has_next() == false); + } + + THEN("turn_order:has-previous is false") + { + REQUIRE(instance->property_has_previous() == false); + } + + THEN("turn_order:running is false") + { + REQUIRE(instance->property_running() == false); + } + } + + WHEN("the participant is removed again") + { + instance->remove(0); + + THEN("active_participant() returns turn_order::invalid_participant_index") + { + REQUIRE(instance->active_participant() == turn_order::invalid_participant_index); + } + + THEN("empty() returns true") + { + REQUIRE(instance->empty()); + } + + THEN("get() returns a nullptr for index 0") + { + REQUIRE(instance->get(0) == nullptr); + } + + THEN("round() returns 0") + { + REQUIRE(instance->round() == 0); + } + + THEN("running() returns false") + { + REQUIRE_FALSE(instance->running()); + } + + THEN("size() returns 0") + { + REQUIRE(instance->size() == 0); + } + + THEN("turn_order:has-next is false") + { + REQUIRE(instance->property_has_next() == false); + } + + THEN("turn_order:has-previous is false") + { + REQUIRE(instance->property_has_previous() == false); + } + + THEN("turn_order:running is false") + { + REQUIRE(instance->property_running() == false); + } + } + + WHEN("another participant with the same priority is added") + { + instance->add("Participant #1", priority, disposition::friendly); + + THEN("active_participant() returns turn_order::invalid_participant_index") + { + REQUIRE(instance->active_participant() == turn_order::invalid_participant_index); + } + + THEN("empty() returns false") + { + REQUIRE_FALSE(instance->empty()); + } + + THEN("get() returns a valid pointer for index 0") + { + REQUIRE(instance->get(0)); + } + + THEN("get() returns a valid pointer for index 1") + { + REQUIRE(instance->get(1)); + } + + THEN("get() returns a nullptr for an index greater than 1") + { + REQUIRE(instance->get(2) == nullptr); + } + + THEN("get(0) returns the participant that was added first") + { + REQUIRE(instance->get(0)->get_name() == "Participant #0"); + } + + THEN("get(1) returns the participant that was added second") + { + REQUIRE(instance->get(1)->get_name() == "Participant #1"); + } + + THEN("round() returns 0") + { + REQUIRE(instance->round() == 0); + } + + THEN("running() returns false") + { + REQUIRE_FALSE(instance->running()); + } + + THEN("size() returns 2") + { + REQUIRE(instance->size() == 2); + } + + THEN("turn_order:has-next is false") + { + REQUIRE(instance->property_has_next() == false); + } + + THEN("turn_order:has-previous is false") + { + REQUIRE(instance->property_has_previous() == false); + } + + THEN("turn_order:running is false") + { + REQUIRE(instance->property_running() == false); + } + + AND_WHEN("the participant at index 0 is removed") + { + instance->remove(0); + + THEN("active_participant() returns turn_order::invalid_participant_index") + { + REQUIRE(instance->active_participant() == turn_order::invalid_participant_index); + } + + THEN("empty() returns false") + { + REQUIRE_FALSE(instance->empty()); + } + + THEN("get() returns a valid pointer for index 0") + { + REQUIRE(instance->get(0)); + } + + THEN("get() returns a nullptr for an index greater than 0") + { + REQUIRE(instance->get(1) == nullptr); + } + + THEN("get(0) returns the participant that was added second") + { + REQUIRE(instance->get(0)->get_name() == "Participant #1"); + } + + THEN("round() returns 0") + { + REQUIRE(instance->round() == 0); + } + + THEN("running() returns false") + { + REQUIRE_FALSE(instance->running()); + } + + THEN("size() returns 1") + { + REQUIRE(instance->size() == 1); + } + + THEN("turn_order:has-next is false") + { + REQUIRE(instance->property_has_next() == false); + } + + THEN("turn_order:has-previous is false") + { + REQUIRE(instance->property_has_previous() == false); + } + + THEN("turn_order:running is false") + { + REQUIRE(instance->property_running() == false); + } + } + + AND_WHEN("the turn_order is cleared") + { + instance->clear(); + + THEN("active_participant() returns turn_order::invalid_participant_index") + { + REQUIRE(instance->active_participant() == turn_order::invalid_participant_index); + } + + THEN("empty() returns true") + { + REQUIRE(instance->empty()); + } + + THEN("get() returns a nullptr pointer for index 0") + { + REQUIRE(instance->get(0) == nullptr); + } + + THEN("round() returns 0") + { + REQUIRE(instance->round() == 0); + } + + THEN("running() returns false") + { + REQUIRE_FALSE(instance->running()); + } + + THEN("size() returns 0") + { + REQUIRE(instance->size() == 0); + } + + THEN("turn_order:has-next is false") + { + REQUIRE(instance->property_has_next() == false); + } + + THEN("turn_order:has-previous is false") + { + REQUIRE(instance->property_has_previous() == false); + } + + THEN("turn_order:running is false") + { + REQUIRE(instance->property_running() == false); + } + } + } + } } } |
