/* * SPDX-FileCopyrightText: 2025 Felix Morgner * SPDX-License-Identifier: LGPL-2.1-only */ #include "turnsmm/turn-order.hpp" #include "turnsmm/participant.hpp" #include #include #include #include #include namespace { auto list_model_notification = std::optional>{}; auto on_list_model_notification(guint position, guint removed, guint added) -> void { list_model_notification = std::tuple{position, removed, added}; } auto notify_sort_mode_received = false; auto on_notify_sort_mode() -> void { notify_sort_mode_received = true; } } // namespace SCENARIO("Creating a turn order", "[lib][object][lifetime]") { GIVEN("A turn order constructed using the default constructor") { auto instance = Turns::TurnOrder{}; THEN("its participant count is 0") { REQUIRE(instance.get_participant_count() == 0uz); REQUIRE(instance.property_participant_count() == 0uz); REQUIRE_FALSE(list_model_notification.has_value()); } THEN("its running state is false") { REQUIRE_FALSE(instance.get_running()); REQUIRE_FALSE(instance.property_running()); REQUIRE_FALSE(list_model_notification.has_value()); } THEN("its item count is 0") { REQUIRE(instance.get_n_items() == 0); REQUIRE_FALSE(list_model_notification.has_value()); } THEN("its item type is Turns.Participant") { REQUIRE(instance.get_item_type() == Turns::Participant::get_type()); REQUIRE_FALSE(list_model_notification.has_value()); } THEN("its first item is NULL") { REQUIRE(instance.get_object(0) == nullptr); REQUIRE(instance.get_typed_object(0) == nullptr); REQUIRE_FALSE(list_model_notification.has_value()); } THEN("its sort mode is descending") { REQUIRE(instance.get_sort_mode() == Turns::TurnOrder::SortMode::Descending); REQUIRE(instance.property_sort_mode() == Turns::TurnOrder::SortMode::Descending); REQUIRE_FALSE(list_model_notification.has_value()); } THEN("it's empty") { REQUIRE(instance.get_empty()); REQUIRE(instance.property_empty()); REQUIRE_FALSE(list_model_notification.has_value()); } } } SCENARIO("Modifying a turn order", "[lib][object][data]") { GIVEN("An empty turn order") { auto instance = Turns::TurnOrder{}; instance.signal_items_changed().connect(&on_list_model_notification); CHECK(instance.get_empty()); WHEN("a participant is added") { auto participant = Turns::Participant::create("Test Participant", 10.0f, Turns::Participant::Disposition::Friendly); list_model_notification.reset(); instance.add(participant); THEN("its participant count is 1") { REQUIRE(instance.get_participant_count() == 1); REQUIRE(instance.property_participant_count() == 1uz); } THEN("its running state is false") { REQUIRE_FALSE(instance.get_running()); } THEN("its item count is 1") { REQUIRE(instance.get_n_items() == 1); } THEN("its first item is the same participant") { auto obj = instance.get_object(0); auto cnt = obj->gobj()->ref_count; REQUIRE(cnt > 0); REQUIRE(obj == participant); } THEN("its sort mode is descending") { REQUIRE(instance.get_sort_mode() == Turns::TurnOrder::SortMode::Descending); REQUIRE(instance.property_sort_mode() == Turns::TurnOrder::SortMode::Descending); } THEN("the items-changed signal is emitted") { REQUIRE(list_model_notification.has_value()); } THEN("1 item was added at position 0 and 0 were removed") { auto [position, removed, added] = *list_model_notification; REQUIRE(position == 0); REQUIRE(removed == 0); REQUIRE(added == 1); } THEN("it's not empty") { REQUIRE_FALSE(instance.get_empty()); REQUIRE_FALSE(instance.property_empty()); } AND_WHEN("calling clear") { list_model_notification.reset(); instance.clear(); THEN("its participant count is 0") { REQUIRE(instance.get_participant_count() == 0uz); REQUIRE(instance.property_participant_count() == 0uz); } THEN("its running state is false") { REQUIRE_FALSE(instance.get_running()); REQUIRE_FALSE(instance.property_running()); } THEN("its item count is 0") { REQUIRE(instance.get_n_items() == 0); } THEN("its first item is NULL") { REQUIRE(instance.get_object(0) == nullptr); REQUIRE(instance.get_typed_object(0) == nullptr); } THEN("its sort mode is descending") { REQUIRE(instance.get_sort_mode() == Turns::TurnOrder::SortMode::Descending); REQUIRE(instance.property_sort_mode() == Turns::TurnOrder::SortMode::Descending); } THEN("the items-changed signal is emitted") { REQUIRE(list_model_notification.has_value()); } THEN("1 item was removed at position 0 and 0 were added") { auto [position, removed, added] = *list_model_notification; REQUIRE(position == 0); REQUIRE(removed == 1); REQUIRE(added == 0); } THEN("it's empty") { REQUIRE(instance.get_empty()); REQUIRE(instance.property_empty()); } } AND_WHEN("removing the first element") { list_model_notification.reset(); instance.remove_at(0); THEN("its participant count is 0") { REQUIRE(instance.get_participant_count() == 0); REQUIRE(instance.property_participant_count() == 0uz); } THEN("the items-changed notification is emitted") { REQUIRE(list_model_notification.has_value()); } THEN("1 item got deleted at position 0 and none were added") { auto [position, removed, added] = *list_model_notification; REQUIRE(position == 0); REQUIRE(removed == 1); REQUIRE(added == 0); } THEN("it's empty") { REQUIRE(instance.get_empty()); REQUIRE(instance.property_empty()); } AND_WHEN("removing the first element again") { list_model_notification.reset(); instance.remove_at(0); THEN("its participant count is 0") { REQUIRE(instance.get_participant_count() == 0); REQUIRE(instance.property_participant_count() == 0uz); } THEN("the items-changed notification is not emitted") { REQUIRE(!list_model_notification.has_value()); } THEN("it's empty") { REQUIRE(instance.get_empty()); REQUIRE(instance.property_empty()); } } } } } } SCENARIO("Sorting a turn order") { GIVEN("A turn order with two participants - A/10/H and B/20/N") { auto instance = Turns::TurnOrder{}; auto participant_a = Turns::Participant::create("A", 10, Turns::Participant::Disposition::Hostile); auto participant_b = Turns::Participant::create("B", 20, Turns::Participant::Disposition::Neutral); instance.add(participant_a); instance.add(participant_b); instance.signal_items_changed().connect(&on_list_model_notification); instance.property_sort_mode().signal_changed().connect(&on_notify_sort_mode); THEN("B is the first and A the second element") { auto first = instance.get_typed_object(0); auto second = instance.get_typed_object(1); REQUIRE(first == participant_b); REQUIRE(second == participant_a); } WHEN("the priority of A is changed to 30") { participant_a->set_priority(30); THEN("A is the first and B the second element") { auto first = instance.get_typed_object(0); auto second = instance.get_typed_object(1); REQUIRE(first == participant_a); REQUIRE(second == participant_b); } } WHEN("the priority of A is changed to 0") { participant_a->set_priority(0); THEN("B is the first and A the second element") { auto first = instance.get_typed_object(0); auto second = instance.get_typed_object(1); REQUIRE(first == participant_b); REQUIRE(second == participant_a); } } WHEN("the priority of B is changed to 0") { participant_b->set_priority(0); THEN("A is the first and B the second element") { auto first = instance.get_typed_object(0); auto second = instance.get_typed_object(1); REQUIRE(first == participant_a); REQUIRE(second == participant_b); } } WHEN("the sort mode is changed to ascending") { list_model_notification.reset(); notify_sort_mode_received = false; instance.set_sort_mode(Turns::TurnOrder::SortMode::Ascending); CHECK(instance.property_sort_mode() == Turns::TurnOrder::SortMode::Ascending); THEN("notify::sort-mode was emitted") { REQUIRE(notify_sort_mode_received); } THEN("A is the first and B the second element") { auto first = instance.get_typed_object(0); auto second = instance.get_typed_object(1); REQUIRE(first == participant_a); REQUIRE(second == participant_b); } THEN("the items-changed signal is emitted") { REQUIRE(list_model_notification.has_value()); } THEN("2 items were removed at position 2 and 2 were added") { auto [position, removed, added] = *list_model_notification; REQUIRE(position == 0); REQUIRE(removed == 2); REQUIRE(added == 2); } } WHEN("the sort mode is set to the current value") { auto current_sort_mode = instance.get_sort_mode(); list_model_notification.reset(); instance.set_sort_mode(current_sort_mode); CHECK(instance.property_sort_mode() == current_sort_mode); THEN("the items-changed signal is not emitted") { REQUIRE_FALSE(list_model_notification.has_value()); } } WHEN("a signal handler is registered for the 'items-changed' signal") { } } }