From 71fe1d395a3c1d94dac68469826118e357f7086d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 9 May 2025 10:48:30 +0200 Subject: core: rename turn_order to TurnOderModel --- core/CMakeLists.txt | 4 +- core/include/turns/core/fwd.hpp | 2 +- core/include/turns/core/turn_order.hpp | 102 --------- core/include/turns/core/turn_order_model.hpp | 102 +++++++++ core/src/init.cpp | 4 +- core/src/turn_order.cpp | 312 -------------------------- core/src/turn_order_model.cpp | 312 ++++++++++++++++++++++++++ core/tests/turn_order.cpp | 314 --------------------------- core/tests/turn_order_bugs.cpp | 4 +- core/tests/turn_order_model.cpp | 314 +++++++++++++++++++++++++++ 10 files changed, 735 insertions(+), 735 deletions(-) delete mode 100644 core/include/turns/core/turn_order.hpp create mode 100644 core/include/turns/core/turn_order_model.hpp delete mode 100644 core/src/turn_order.cpp create mode 100644 core/src/turn_order_model.cpp delete mode 100644 core/tests/turn_order.cpp create mode 100644 core/tests/turn_order_model.cpp (limited to 'core') diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index b52519f..7b223d5 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -5,7 +5,7 @@ add_library("core" "src/init.cpp" "src/participant.cpp" "src/settings.cpp" - "src/turn_order.cpp" + "src/turn_order_model.cpp" ) add_library("turns::core" ALIAS "core") @@ -52,7 +52,7 @@ add_executable("core-tests" "tests/disposition.cpp" "tests/participant.cpp" "tests/turn_order_bugs.cpp" - "tests/turn_order.cpp" + "tests/turn_order_model.cpp" ) target_link_libraries("core-tests" PRIVATE diff --git a/core/include/turns/core/fwd.hpp b/core/include/turns/core/fwd.hpp index 48380e3..c006084 100644 --- a/core/include/turns/core/fwd.hpp +++ b/core/include/turns/core/fwd.hpp @@ -8,7 +8,7 @@ namespace turns::core enum struct Disposition : std::uint8_t; struct Participant; - struct turn_order; + struct TurnOderModel; } // namespace turns::core #endif \ No newline at end of file diff --git a/core/include/turns/core/turn_order.hpp b/core/include/turns/core/turn_order.hpp deleted file mode 100644 index 030f4c9..0000000 --- a/core/include/turns/core/turn_order.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef TURNS_CORE_TURN_ORDER_HPP -#define TURNS_CORE_TURN_ORDER_HPP - -#include "turns/core/fwd.hpp" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include - -namespace turns::core -{ - - struct turn_order : Gio::ListModel, - Glib::Object - { - using value_type = Glib::RefPtr; - using container_type = std::vector; - using iterator = container_type::iterator; - using const_iterator = container_type::const_iterator; - - using active_participant_type = unsigned int; - using is_empty_type = bool; - using has_next_type = bool; - using has_previous_type = bool; - using is_running_type = bool; - using progress_type = double; - using round_number_type = unsigned int; - using skip_defeated_type = bool; - - auto static constexpr invalid_participant_index = std::numeric_limits::max(); - auto static constexpr invalid_round_number = std::numeric_limits::max(); - - /** Life-time */ - turn_order(); - - auto static create() -> Glib::RefPtr; - auto static create(nlohmann::json const & from) -> Glib::RefPtr; - - /** Properties */ - auto is_empty() const -> Glib::PropertyProxy_ReadOnly; - auto has_next() const -> Glib::PropertyProxy_ReadOnly; - auto has_previous() const -> Glib::PropertyProxy_ReadOnly; - auto is_running() const -> Glib::PropertyProxy_ReadOnly; - auto progress() const -> Glib::PropertyProxy_ReadOnly; - auto round_number() const -> Glib::PropertyProxy_ReadOnly; - auto skip_defeated() -> Glib::PropertyProxy; - - /** Element Modifications */ - auto add(Glib::ustring const & name, float priority, Disposition disposition) -> void; - auto clear() -> void; - auto remove(unsigned index) -> void; - - /** Turn Modification */ - auto next() -> void; - auto previous() -> void; - auto start() -> void; - auto stop() -> void; - - /** Serialization */ - auto load(nlohmann::json const & from) -> void; - auto serialize() -> nlohmann::json; - - private: - explicit turn_order(nlohmann::json const & from); - - auto get_item_type_vfunc() -> GType override; - auto get_n_items_vfunc() -> unsigned override; - auto get_item_vfunc(unsigned position) -> void * override; - - /** Signal handlers */ - auto handle_priority_changed(value_type entry) -> void; - - /** Data management */ - auto find(value_type entry) const -> const_iterator; - auto insert(value_type entry) -> const_iterator; - - container_type m_data{}; - std::optional m_active{}; - - Glib::Property m_has_next{*this, "has-next", false}; - Glib::Property m_has_previous{*this, "has-previous", false}; - Glib::Property m_is_empty{*this, "is-empty", true}; - Glib::Property m_is_running{*this, "is-running", false}; - Glib::Property m_progress{*this, "progress", 0.0}; - Glib::Property m_round_number{*this, "round-number", invalid_round_number}; - Glib::Property m_skip_defeated{*this, "skip-defeated", false}; - }; - -} // namespace turns::core - -#endif \ No newline at end of file diff --git a/core/include/turns/core/turn_order_model.hpp b/core/include/turns/core/turn_order_model.hpp new file mode 100644 index 0000000..7d9947d --- /dev/null +++ b/core/include/turns/core/turn_order_model.hpp @@ -0,0 +1,102 @@ +#ifndef TURNS_CORE_TURN_ORDER_MODEL_HPP +#define TURNS_CORE_TURN_ORDER_MODEL_HPP + +#include "turns/core/fwd.hpp" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +namespace turns::core +{ + + struct TurnOderModel : Gio::ListModel, + Glib::Object + { + using value_type = Glib::RefPtr; + using container_type = std::vector; + using iterator = container_type::iterator; + using const_iterator = container_type::const_iterator; + + using active_participant_type = unsigned int; + using is_empty_type = bool; + using has_next_type = bool; + using has_previous_type = bool; + using is_running_type = bool; + using progress_type = double; + using round_number_type = unsigned int; + using skip_defeated_type = bool; + + auto static constexpr invalid_participant_index = std::numeric_limits::max(); + auto static constexpr invalid_round_number = std::numeric_limits::max(); + + /** Life-time */ + TurnOderModel(); + + auto static create() -> Glib::RefPtr; + auto static create(nlohmann::json const & from) -> Glib::RefPtr; + + /** Properties */ + auto is_empty() const -> Glib::PropertyProxy_ReadOnly; + auto has_next() const -> Glib::PropertyProxy_ReadOnly; + auto has_previous() const -> Glib::PropertyProxy_ReadOnly; + auto is_running() const -> Glib::PropertyProxy_ReadOnly; + auto progress() const -> Glib::PropertyProxy_ReadOnly; + auto round_number() const -> Glib::PropertyProxy_ReadOnly; + auto skip_defeated() -> Glib::PropertyProxy; + + /** Element Modifications */ + auto add(Glib::ustring const & name, float priority, Disposition disposition) -> void; + auto clear() -> void; + auto remove(unsigned index) -> void; + + /** Turn Modification */ + auto next() -> void; + auto previous() -> void; + auto start() -> void; + auto stop() -> void; + + /** Serialization */ + auto load(nlohmann::json const & from) -> void; + auto serialize() -> nlohmann::json; + + private: + explicit TurnOderModel(nlohmann::json const & from); + + auto get_item_type_vfunc() -> GType override; + auto get_n_items_vfunc() -> unsigned override; + auto get_item_vfunc(unsigned position) -> void * override; + + /** Signal handlers */ + auto handle_priority_changed(value_type entry) -> void; + + /** Data management */ + auto find(value_type entry) const -> const_iterator; + auto insert(value_type entry) -> const_iterator; + + container_type m_data{}; + std::optional m_active{}; + + Glib::Property m_has_next{*this, "has-next", false}; + Glib::Property m_has_previous{*this, "has-previous", false}; + Glib::Property m_is_empty{*this, "is-empty", true}; + Glib::Property m_is_running{*this, "is-running", false}; + Glib::Property m_progress{*this, "progress", 0.0}; + Glib::Property m_round_number{*this, "round-number", invalid_round_number}; + Glib::Property m_skip_defeated{*this, "skip-defeated", false}; + }; + +} // namespace turns::core + +#endif \ No newline at end of file diff --git a/core/src/init.cpp b/core/src/init.cpp index 3434f91..4f67817 100644 --- a/core/src/init.cpp +++ b/core/src/init.cpp @@ -2,7 +2,7 @@ #include "turns/core/disposition.hpp" #include "turns/core/participant.hpp" -#include "turns/core/turn_order.hpp" +#include "turns/core/turn_order_model.hpp" #include @@ -12,7 +12,7 @@ namespace turns::core auto register_types() -> void { static_cast(Participant{}); - static_cast(turn_order{}); + static_cast(TurnOderModel{}); g_type_ensure(Glib::Value::value_type()); } diff --git a/core/src/turn_order.cpp b/core/src/turn_order.cpp deleted file mode 100644 index 669f746..0000000 --- a/core/src/turn_order.cpp +++ /dev/null @@ -1,312 +0,0 @@ -#include "turns/core/turn_order.hpp" - -#include "turns/core/disposition.hpp" -#include "turns/core/json_ext.hpp" -#include "turns/core/participant.hpp" - -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace std::placeholders; - -namespace turns::core -{ - - namespace - { - auto constexpr comparator = [](auto lhs, auto rhs) { - return *lhs > *rhs; - }; - } // namespace - - /** Construction */ - - turn_order::turn_order() - : Glib::ObjectBase{typeid(turn_order)} - , Gio::ListModel{} - { - } - - turn_order::turn_order(nlohmann::json const & from) - : turn_order{} - { - load(from); - } - - auto turn_order::create() -> Glib::RefPtr - { - return Glib::make_refptr_for_instance(new turn_order{}); - } - - auto turn_order::create(nlohmann::json const & from) -> Glib::RefPtr - { - return Glib::make_refptr_for_instance(new turn_order{from}); - } - - /** Queries */ - - auto turn_order::is_empty() const -> Glib::PropertyProxy_ReadOnly - { - return m_is_empty.get_proxy(); - } - - auto turn_order::has_next() const -> Glib::PropertyProxy_ReadOnly - { - return m_has_next.get_proxy(); - } - - auto turn_order::has_previous() const -> Glib::PropertyProxy_ReadOnly - { - return m_has_previous.get_proxy(); - } - - auto turn_order::is_running() const -> Glib::PropertyProxy_ReadOnly - { - return m_is_running.get_proxy(); - } - - auto turn_order::progress() const -> Glib::PropertyProxy_ReadOnly - { - return m_progress.get_proxy(); - } - - auto turn_order::round_number() const -> Glib::PropertyProxy_ReadOnly - { - return m_round_number.get_proxy(); - } - - auto turn_order::skip_defeated() -> Glib::PropertyProxy - { - return m_skip_defeated.get_proxy(); - } - - /** Modifiers */ - - auto turn_order::add(Glib::ustring const & name, float priority, Disposition disposition) -> void - { - auto entry = Participant::create(name, priority, disposition); - entry->property_priority().signal_changed().connect(sigc::bind(sigc::mem_fun(*this, &turn_order::handle_priority_changed), entry)); - auto position = std::distance(m_data.cbegin(), insert(entry)); - items_changed(position, 0, 1); - - if (get_n_items() == 1) - { - m_is_empty = false; - m_has_next = true; - } - } - - auto turn_order::clear() -> void - { - m_is_running = false; - m_is_empty = true; - m_has_next = false; - m_has_previous = false; - m_active.reset(); - m_round_number = invalid_round_number; - m_progress = 0; - - auto old_size = get_n_items(); - m_data.clear(); - items_changed(0, old_size, 0); - } - - auto turn_order::next() -> void - { - auto old_active = *m_active; - m_active = m_active.transform([this](auto index) { return (index + 1) % get_n_items(); }); - - m_has_previous = true; - m_data[old_active]->property_is_active() = false; - m_data[*m_active]->property_is_active() = true; - - m_progress = (static_cast(*m_active) + 1) / get_n_items(); - - if (m_active == 0) - { - m_round_number = m_round_number + 1; - } - } - - auto turn_order::previous() -> void - { - if (!(m_has_previous && m_is_running)) - { - return; - } - - auto old_active = *m_active; - m_active = m_active.transform([this](auto index) { return index ? index - 1 : get_n_items() - 1; }); - - m_has_previous = m_round_number > 0 || m_active > 0; - m_data[old_active]->property_is_active() = false; - m_data[*m_active]->property_is_active() = true; - - m_progress = (static_cast(*m_active) + 1) / get_n_items(); - - if (m_active == 0 && m_round_number > 0) - { - m_round_number = m_round_number - 1; - } - } - - auto turn_order::remove(unsigned index) -> void - { - if (index >= get_n_items()) - { - return; - } - - auto position = m_data.begin() + index; - m_data.erase(position); - items_changed(index, 1, 0); - if (get_n_items() == 0) - { - m_is_empty = true; - m_is_running = false; - m_has_next = false; - } - } - - auto turn_order::start() -> void - { - if (!m_active) - { - m_active = 0; - m_data[*m_active]->property_is_active() = true; - } - if (m_round_number == invalid_round_number) - { - m_round_number = 0; - } - m_is_running = true; - - m_progress = (static_cast(*m_active) + 1) / get_n_items(); - } - - auto turn_order::stop() -> void - { - m_is_running = false; - m_progress = 0; - } - - /** Serialization */ - auto turn_order::load(nlohmann::json const & from) -> void - { - auto old_size = get_n_items(); - - this->freeze_notify(); - - m_round_number = from.value("round", invalid_round_number); - - m_data.clear(); - auto participants = from.value("participants", std::vector{}); - auto factory = [](auto s) { - return Participant::create(s); - }; - auto inserter = std::bind(&turn_order::insert, this, _1); - std::ranges::for_each(participants | std::views::transform(factory), inserter); - - auto active = std::ranges::find_if(m_data, [](auto participant) { return participant->property_is_active(); }); - if (active != std::ranges::end(m_data)) - { - m_active = std::ranges::distance(std::ranges::begin(m_data), active); - } - - m_is_empty = m_data.empty(); - m_has_next = !m_is_empty; - m_has_previous = m_round_number > 0 || m_active > 0; - - this->thaw_notify(); - - items_changed(0, old_size, get_n_items()); - } - - auto turn_order::serialize() -> nlohmann::json - { - auto serialized = nlohmann::json{}; - if (m_round_number != invalid_round_number) - { - serialized["round"] = m_round_number; - } - serialized["participants"] = m_data | std::views::transform([](auto const & p) { return p->serialize(); }) | std::ranges::to(); - ; - return serialized; - } - - /** ListModel implementation */ - - auto turn_order::get_item_type_vfunc() -> GType - { - return Participant::get_type(); - } - - auto turn_order::get_n_items_vfunc() -> unsigned - { - return m_data.size(); - } - - auto turn_order::get_item_vfunc(unsigned position) -> void * - { - if (position >= get_n_items()) - { - return nullptr; - } - auto item = m_data[position]; - item->reference(); - return Glib::unwrap(item); - } - - /** Signal handlers */ - - auto turn_order::handle_priority_changed(value_type entry) -> void - { - auto original_position = find(entry); - auto original_index = distance(m_data.cbegin(), original_position); - auto target_position = std::ranges::upper_bound(m_data, entry, comparator); - if (original_position == target_position) - { - return; - } - - m_data.erase(original_position); - auto inserted_position = insert(entry); - items_changed(0, get_n_items(), get_n_items()); - if (m_active == original_index) - { - m_active = distance(m_data.cbegin(), inserted_position); - m_has_previous = m_round_number > 0 || m_active > 0; - } - } - - /** Data management */ - - auto turn_order::find(value_type entry) const -> const_iterator - { - return std::ranges::find(m_data, entry); - } - - auto turn_order::insert(value_type entry) -> const_iterator - { - return m_data.insert(std::ranges::upper_bound(m_data, entry, comparator), entry); - } - -} // namespace turns::core \ No newline at end of file diff --git a/core/src/turn_order_model.cpp b/core/src/turn_order_model.cpp new file mode 100644 index 0000000..e430fed --- /dev/null +++ b/core/src/turn_order_model.cpp @@ -0,0 +1,312 @@ +#include "turns/core/turn_order_model.hpp" + +#include "turns/core/disposition.hpp" +#include "turns/core/json_ext.hpp" +#include "turns/core/participant.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std::placeholders; + +namespace turns::core +{ + + namespace + { + auto constexpr comparator = [](auto lhs, auto rhs) { + return *lhs > *rhs; + }; + } // namespace + + /** Construction */ + + TurnOderModel::TurnOderModel() + : Glib::ObjectBase{typeid(TurnOderModel)} + , Gio::ListModel{} + { + } + + TurnOderModel::TurnOderModel(nlohmann::json const & from) + : TurnOderModel{} + { + load(from); + } + + auto TurnOderModel::create() -> Glib::RefPtr + { + return Glib::make_refptr_for_instance(new TurnOderModel{}); + } + + auto TurnOderModel::create(nlohmann::json const & from) -> Glib::RefPtr + { + return Glib::make_refptr_for_instance(new TurnOderModel{from}); + } + + /** Queries */ + + auto TurnOderModel::is_empty() const -> Glib::PropertyProxy_ReadOnly + { + return m_is_empty.get_proxy(); + } + + auto TurnOderModel::has_next() const -> Glib::PropertyProxy_ReadOnly + { + return m_has_next.get_proxy(); + } + + auto TurnOderModel::has_previous() const -> Glib::PropertyProxy_ReadOnly + { + return m_has_previous.get_proxy(); + } + + auto TurnOderModel::is_running() const -> Glib::PropertyProxy_ReadOnly + { + return m_is_running.get_proxy(); + } + + auto TurnOderModel::progress() const -> Glib::PropertyProxy_ReadOnly + { + return m_progress.get_proxy(); + } + + auto TurnOderModel::round_number() const -> Glib::PropertyProxy_ReadOnly + { + return m_round_number.get_proxy(); + } + + auto TurnOderModel::skip_defeated() -> Glib::PropertyProxy + { + return m_skip_defeated.get_proxy(); + } + + /** Modifiers */ + + auto TurnOderModel::add(Glib::ustring const & name, float priority, Disposition disposition) -> void + { + auto entry = Participant::create(name, priority, disposition); + entry->property_priority().signal_changed().connect(sigc::bind(sigc::mem_fun(*this, &TurnOderModel::handle_priority_changed), entry)); + auto position = std::distance(m_data.cbegin(), insert(entry)); + items_changed(position, 0, 1); + + if (get_n_items() == 1) + { + m_is_empty = false; + m_has_next = true; + } + } + + auto TurnOderModel::clear() -> void + { + m_is_running = false; + m_is_empty = true; + m_has_next = false; + m_has_previous = false; + m_active.reset(); + m_round_number = invalid_round_number; + m_progress = 0; + + auto old_size = get_n_items(); + m_data.clear(); + items_changed(0, old_size, 0); + } + + auto TurnOderModel::next() -> void + { + auto old_active = *m_active; + m_active = m_active.transform([this](auto index) { return (index + 1) % get_n_items(); }); + + m_has_previous = true; + m_data[old_active]->property_is_active() = false; + m_data[*m_active]->property_is_active() = true; + + m_progress = (static_cast(*m_active) + 1) / get_n_items(); + + if (m_active == 0) + { + m_round_number = m_round_number + 1; + } + } + + auto TurnOderModel::previous() -> void + { + if (!(m_has_previous && m_is_running)) + { + return; + } + + auto old_active = *m_active; + m_active = m_active.transform([this](auto index) { return index ? index - 1 : get_n_items() - 1; }); + + m_has_previous = m_round_number > 0 || m_active > 0; + m_data[old_active]->property_is_active() = false; + m_data[*m_active]->property_is_active() = true; + + m_progress = (static_cast(*m_active) + 1) / get_n_items(); + + if (m_active == 0 && m_round_number > 0) + { + m_round_number = m_round_number - 1; + } + } + + auto TurnOderModel::remove(unsigned index) -> void + { + if (index >= get_n_items()) + { + return; + } + + auto position = m_data.begin() + index; + m_data.erase(position); + items_changed(index, 1, 0); + if (get_n_items() == 0) + { + m_is_empty = true; + m_is_running = false; + m_has_next = false; + } + } + + auto TurnOderModel::start() -> void + { + if (!m_active) + { + m_active = 0; + m_data[*m_active]->property_is_active() = true; + } + if (m_round_number == invalid_round_number) + { + m_round_number = 0; + } + m_is_running = true; + + m_progress = (static_cast(*m_active) + 1) / get_n_items(); + } + + auto TurnOderModel::stop() -> void + { + m_is_running = false; + m_progress = 0; + } + + /** Serialization */ + auto TurnOderModel::load(nlohmann::json const & from) -> void + { + auto old_size = get_n_items(); + + this->freeze_notify(); + + m_round_number = from.value("round", invalid_round_number); + + m_data.clear(); + auto participants = from.value("participants", std::vector{}); + auto factory = [](auto s) { + return Participant::create(s); + }; + auto inserter = std::bind(&TurnOderModel::insert, this, _1); + std::ranges::for_each(participants | std::views::transform(factory), inserter); + + auto active = std::ranges::find_if(m_data, [](auto participant) { return participant->property_is_active(); }); + if (active != std::ranges::end(m_data)) + { + m_active = std::ranges::distance(std::ranges::begin(m_data), active); + } + + m_is_empty = m_data.empty(); + m_has_next = !m_is_empty; + m_has_previous = m_round_number > 0 || m_active > 0; + + this->thaw_notify(); + + items_changed(0, old_size, get_n_items()); + } + + auto TurnOderModel::serialize() -> nlohmann::json + { + auto serialized = nlohmann::json{}; + if (m_round_number != invalid_round_number) + { + serialized["round"] = m_round_number; + } + serialized["participants"] = m_data | std::views::transform([](auto const & p) { return p->serialize(); }) | std::ranges::to(); + ; + return serialized; + } + + /** ListModel implementation */ + + auto TurnOderModel::get_item_type_vfunc() -> GType + { + return Participant::get_type(); + } + + auto TurnOderModel::get_n_items_vfunc() -> unsigned + { + return m_data.size(); + } + + auto TurnOderModel::get_item_vfunc(unsigned position) -> void * + { + if (position >= get_n_items()) + { + return nullptr; + } + auto item = m_data[position]; + item->reference(); + return Glib::unwrap(item); + } + + /** Signal handlers */ + + auto TurnOderModel::handle_priority_changed(value_type entry) -> void + { + auto original_position = find(entry); + auto original_index = distance(m_data.cbegin(), original_position); + auto target_position = std::ranges::upper_bound(m_data, entry, comparator); + if (original_position == target_position) + { + return; + } + + m_data.erase(original_position); + auto inserted_position = insert(entry); + items_changed(0, get_n_items(), get_n_items()); + if (m_active == original_index) + { + m_active = distance(m_data.cbegin(), inserted_position); + m_has_previous = m_round_number > 0 || m_active > 0; + } + } + + /** Data management */ + + auto TurnOderModel::find(value_type entry) const -> const_iterator + { + return std::ranges::find(m_data, entry); + } + + auto TurnOderModel::insert(value_type entry) -> const_iterator + { + return m_data.insert(std::ranges::upper_bound(m_data, entry, comparator), entry); + } + +} // namespace turns::core \ No newline at end of file diff --git a/core/tests/turn_order.cpp b/core/tests/turn_order.cpp deleted file mode 100644 index a7633cd..0000000 --- a/core/tests/turn_order.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include "turns/core/turn_order.hpp" - -#include "turns/core/disposition.hpp" -#include "turns/core/participant.hpp" - -#include - -#include - -#include - -#include - -namespace turns::core::tests -{ - SCENARIO("Queries on a fresh turn_order instance", "[turn_order]") - { - GIVEN("an empty turn_order") - { - auto instance = turn_order::create(); - - THEN("get_n_items() returns 0") - { - REQUIRE(instance->get_n_items() == 0); - } - - THEN("get_type() returns participant::get_type()") - { - REQUIRE(instance->get_item_type() == Participant::get_type()); - } - - THEN("get_typed_object(0) returns nullptr") - { - REQUIRE(instance->get_typed_object(0) == nullptr); - } - - THEN("has_next() returns false") - { - REQUIRE_FALSE(instance->has_next()); - } - - THEN("has_previous() returns false") - { - REQUIRE_FALSE(instance->has_previous()); - } - - THEN("is_empty() returns true") - { - REQUIRE(instance->is_empty()); - } - - THEN("is_running() returns false") - { - REQUIRE_FALSE(instance->is_running()); - } - - THEN("round_number() returns invalid_round_number") - { - REQUIRE(instance->round_number() == turn_order::invalid_round_number); - } - } - } - - SCENARIO("Adding participants") - { - auto instance = turn_order::create(); - - GIVEN("a participant has been added to a turn_order") - { - instance->add("Participant #0", 0, Disposition::Neutral); - - THEN("get_n_items() returns 1") - { - REQUIRE(instance->get_n_items() == 1); - } - - THEN("get_typed_object(0) returns a non-null pointer") - { - REQUIRE(instance->get_typed_object(0) != nullptr); - } - - THEN("has_next() returns true") - { - REQUIRE(instance->has_next()); - } - - THEN("has_previous() returns false") - { - REQUIRE_FALSE(instance->has_previous()); - } - - THEN("is_empty() returns false") - { - REQUIRE_FALSE(instance->is_empty()); - } - - THEN("is_running() returns false") - { - REQUIRE_FALSE(instance->is_running()); - } - - THEN("round_number() returns invalid_round_number") - { - REQUIRE(instance->round_number() == turn_order::invalid_round_number); - } - - WHEN("the turn_order is start()ed") - { - instance->start(); - - THEN("get_n_items() still returns 1") - { - REQUIRE(instance->get_n_items() == 1); - } - - THEN("get_typed_object(0) still returns a non-null pointer") - { - REQUIRE(instance->get_typed_object(0) != nullptr); - } - - THEN("has_next() still returns true") - { - REQUIRE(instance->has_next()); - } - - THEN("has_previous() still returns false") - { - REQUIRE_FALSE(instance->has_previous()); - } - - THEN("is_empty() still returns false") - { - REQUIRE_FALSE(instance->is_empty()); - } - - THEN("is_running() returns true") - { - REQUIRE(instance->is_running()); - } - - THEN("round_number() returns 0") - { - REQUIRE(instance->round_number() == 0); - } - - AND_WHEN("invoking previous()") - { - instance->previous(); - - THEN("get_n_items() still returns 1") - { - REQUIRE(instance->get_n_items() == 1); - } - - THEN("get_typed_object(0) still returns a non-null pointer") - { - REQUIRE(instance->get_typed_object(0) != nullptr); - } - - THEN("has_next() still returns true") - { - REQUIRE(instance->has_next()); - } - - THEN("has_previous() still returns false") - { - REQUIRE_FALSE(instance->has_previous()); - } - - THEN("is_empty() still returns false") - { - REQUIRE_FALSE(instance->is_empty()); - } - - THEN("is_running() returns true") - { - REQUIRE(instance->is_running()); - } - - THEN("round_number() returns 0") - { - REQUIRE(instance->round_number() == 0); - } - } - - AND_WHEN("invoking next()") - { - instance->next(); - - THEN("get_n_items() still returns 1") - { - REQUIRE(instance->get_n_items() == 1); - } - - THEN("get_typed_object(0) still returns a non-null pointer") - { - REQUIRE(instance->get_typed_object(0) != nullptr); - } - - THEN("has_next() still returns true") - { - REQUIRE(instance->has_next()); - } - - THEN("has_previous() returns true") - { - REQUIRE(instance->has_previous()); - } - - THEN("is_empty() still returns false") - { - REQUIRE_FALSE(instance->is_empty()); - } - - THEN("is_running() returns true") - { - REQUIRE(instance->is_running()); - } - - THEN("round_number() returns 1") - { - REQUIRE(instance->round_number() == 1); - } - } - } - } - } - - SCENARIO("Loading from json data") - { - GIVEN("an empty turn order") - { - auto instance = turn_order{}; - CHECK(instance.is_empty()); - - WHEN("loading a serialized turn order with one named participant") - { - auto data = Gio::Resource::lookup_data_global("/ch/arknet/Turns/core-tests/single_participant.trns"); - auto size = 0uz; - instance.load(nlohmann::json::parse(std::string_view{static_cast(data->get_data(size)), data->get_size()})); - - THEN("it is no longer empty") - { - REQUIRE_FALSE(instance.is_empty()); - } - - THEN("it has 1 element") - { - REQUIRE(instance.get_n_items() == 1); - } - - THEN("the single participant's name is set") - { - auto participant = instance.get_typed_object(0); - REQUIRE_FALSE(participant->get_name().empty()); - } - - AND_THEN("adding another participant with a higher priority") - { - auto participant = instance.get_typed_object(0); - instance.add("Higher Priority", 100.0f, Disposition::Neutral); - - THEN("the index of the test participant is 1") - { - CHECK(instance.get_typed_object(0) != participant); - REQUIRE(instance.get_typed_object(1) == participant); - } - } - - AND_WHEN("calling clear") - { - instance.clear(); - - THEN("it is empty") - { - REQUIRE(instance.is_empty()); - } - } - } - } - } - - SCENARIO("Sorting of participants") - { - GIVEN("A turn order with 3 participants (A,B,C) of priorities 100, 0, and -100 respectively") - { - auto instance = turn_order{}; - - instance.add("A", 100, Disposition::Friendly); - instance.add("B", 0, Disposition::Friendly); - instance.add("C", -100, Disposition::Friendly); - - THEN("A comes before B comes before C") - { - REQUIRE(instance.get_typed_object(0)->get_name() == "A"); - REQUIRE(instance.get_typed_object(1)->get_name() == "B"); - REQUIRE(instance.get_typed_object(2)->get_name() == "C"); - } - - WHEN("changing the priority of the B to 50") - { - instance.get_typed_object(1)->set_priority(50); - - THEN("the order stays the same") - { - REQUIRE(instance.get_typed_object(0)->get_name() == "A"); - REQUIRE(instance.get_typed_object(1)->get_name() == "B"); - REQUIRE(instance.get_typed_object(2)->get_name() == "C"); - } - } - } - } - -} // namespace turns::core::tests \ No newline at end of file diff --git a/core/tests/turn_order_bugs.cpp b/core/tests/turn_order_bugs.cpp index a79e9b4..7bfde78 100644 --- a/core/tests/turn_order_bugs.cpp +++ b/core/tests/turn_order_bugs.cpp @@ -1,5 +1,5 @@ #include "turns/core/disposition.hpp" -#include "turns/core/turn_order.hpp" +#include "turns/core/turn_order_model.hpp" #include @@ -17,7 +17,7 @@ namespace turns::core::tests { GIVEN("a non-empty turn_order") { - auto instance = turn_order::create(); + auto instance = TurnOderModel::create(); instance->add("A", 0, Disposition::Neutral); diff --git a/core/tests/turn_order_model.cpp b/core/tests/turn_order_model.cpp new file mode 100644 index 0000000..1cd3633 --- /dev/null +++ b/core/tests/turn_order_model.cpp @@ -0,0 +1,314 @@ +#include "turns/core/turn_order_model.hpp" + +#include "turns/core/disposition.hpp" +#include "turns/core/participant.hpp" + +#include + +#include + +#include + +#include + +namespace turns::core::tests +{ + SCENARIO("Queries on a fresh turn_order instance", "[turn_order]") + { + GIVEN("an empty turn_order") + { + auto instance = TurnOderModel::create(); + + THEN("get_n_items() returns 0") + { + REQUIRE(instance->get_n_items() == 0); + } + + THEN("get_type() returns participant::get_type()") + { + REQUIRE(instance->get_item_type() == Participant::get_type()); + } + + THEN("get_typed_object(0) returns nullptr") + { + REQUIRE(instance->get_typed_object(0) == nullptr); + } + + THEN("has_next() returns false") + { + REQUIRE_FALSE(instance->has_next()); + } + + THEN("has_previous() returns false") + { + REQUIRE_FALSE(instance->has_previous()); + } + + THEN("is_empty() returns true") + { + REQUIRE(instance->is_empty()); + } + + THEN("is_running() returns false") + { + REQUIRE_FALSE(instance->is_running()); + } + + THEN("round_number() returns invalid_round_number") + { + REQUIRE(instance->round_number() == TurnOderModel::invalid_round_number); + } + } + } + + SCENARIO("Adding participants") + { + auto instance = TurnOderModel::create(); + + GIVEN("a participant has been added to a turn_order") + { + instance->add("Participant #0", 0, Disposition::Neutral); + + THEN("get_n_items() returns 1") + { + REQUIRE(instance->get_n_items() == 1); + } + + THEN("get_typed_object(0) returns a non-null pointer") + { + REQUIRE(instance->get_typed_object(0) != nullptr); + } + + THEN("has_next() returns true") + { + REQUIRE(instance->has_next()); + } + + THEN("has_previous() returns false") + { + REQUIRE_FALSE(instance->has_previous()); + } + + THEN("is_empty() returns false") + { + REQUIRE_FALSE(instance->is_empty()); + } + + THEN("is_running() returns false") + { + REQUIRE_FALSE(instance->is_running()); + } + + THEN("round_number() returns invalid_round_number") + { + REQUIRE(instance->round_number() == TurnOderModel::invalid_round_number); + } + + WHEN("the turn_order is start()ed") + { + instance->start(); + + THEN("get_n_items() still returns 1") + { + REQUIRE(instance->get_n_items() == 1); + } + + THEN("get_typed_object(0) still returns a non-null pointer") + { + REQUIRE(instance->get_typed_object(0) != nullptr); + } + + THEN("has_next() still returns true") + { + REQUIRE(instance->has_next()); + } + + THEN("has_previous() still returns false") + { + REQUIRE_FALSE(instance->has_previous()); + } + + THEN("is_empty() still returns false") + { + REQUIRE_FALSE(instance->is_empty()); + } + + THEN("is_running() returns true") + { + REQUIRE(instance->is_running()); + } + + THEN("round_number() returns 0") + { + REQUIRE(instance->round_number() == 0); + } + + AND_WHEN("invoking previous()") + { + instance->previous(); + + THEN("get_n_items() still returns 1") + { + REQUIRE(instance->get_n_items() == 1); + } + + THEN("get_typed_object(0) still returns a non-null pointer") + { + REQUIRE(instance->get_typed_object(0) != nullptr); + } + + THEN("has_next() still returns true") + { + REQUIRE(instance->has_next()); + } + + THEN("has_previous() still returns false") + { + REQUIRE_FALSE(instance->has_previous()); + } + + THEN("is_empty() still returns false") + { + REQUIRE_FALSE(instance->is_empty()); + } + + THEN("is_running() returns true") + { + REQUIRE(instance->is_running()); + } + + THEN("round_number() returns 0") + { + REQUIRE(instance->round_number() == 0); + } + } + + AND_WHEN("invoking next()") + { + instance->next(); + + THEN("get_n_items() still returns 1") + { + REQUIRE(instance->get_n_items() == 1); + } + + THEN("get_typed_object(0) still returns a non-null pointer") + { + REQUIRE(instance->get_typed_object(0) != nullptr); + } + + THEN("has_next() still returns true") + { + REQUIRE(instance->has_next()); + } + + THEN("has_previous() returns true") + { + REQUIRE(instance->has_previous()); + } + + THEN("is_empty() still returns false") + { + REQUIRE_FALSE(instance->is_empty()); + } + + THEN("is_running() returns true") + { + REQUIRE(instance->is_running()); + } + + THEN("round_number() returns 1") + { + REQUIRE(instance->round_number() == 1); + } + } + } + } + } + + SCENARIO("Loading from json data") + { + GIVEN("an empty turn order") + { + auto instance = TurnOderModel{}; + CHECK(instance.is_empty()); + + WHEN("loading a serialized turn order with one named participant") + { + auto data = Gio::Resource::lookup_data_global("/ch/arknet/Turns/core-tests/single_participant.trns"); + auto size = 0uz; + instance.load(nlohmann::json::parse(std::string_view{static_cast(data->get_data(size)), data->get_size()})); + + THEN("it is no longer empty") + { + REQUIRE_FALSE(instance.is_empty()); + } + + THEN("it has 1 element") + { + REQUIRE(instance.get_n_items() == 1); + } + + THEN("the single participant's name is set") + { + auto participant = instance.get_typed_object(0); + REQUIRE_FALSE(participant->get_name().empty()); + } + + AND_THEN("adding another participant with a higher priority") + { + auto participant = instance.get_typed_object(0); + instance.add("Higher Priority", 100.0f, Disposition::Neutral); + + THEN("the index of the test participant is 1") + { + CHECK(instance.get_typed_object(0) != participant); + REQUIRE(instance.get_typed_object(1) == participant); + } + } + + AND_WHEN("calling clear") + { + instance.clear(); + + THEN("it is empty") + { + REQUIRE(instance.is_empty()); + } + } + } + } + } + + SCENARIO("Sorting of participants") + { + GIVEN("A turn order with 3 participants (A,B,C) of priorities 100, 0, and -100 respectively") + { + auto instance = TurnOderModel{}; + + instance.add("A", 100, Disposition::Friendly); + instance.add("B", 0, Disposition::Friendly); + instance.add("C", -100, Disposition::Friendly); + + THEN("A comes before B comes before C") + { + REQUIRE(instance.get_typed_object(0)->get_name() == "A"); + REQUIRE(instance.get_typed_object(1)->get_name() == "B"); + REQUIRE(instance.get_typed_object(2)->get_name() == "C"); + } + + WHEN("changing the priority of the B to 50") + { + instance.get_typed_object(1)->set_priority(50); + + THEN("the order stays the same") + { + REQUIRE(instance.get_typed_object(0)->get_name() == "A"); + REQUIRE(instance.get_typed_object(1)->get_name() == "B"); + REQUIRE(instance.get_typed_object(2)->get_name() == "C"); + } + } + } + } + +} // namespace turns::core::tests \ No newline at end of file -- cgit v1.2.3