summaryrefslogtreecommitdiff
path: root/core/tests
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2024-07-24 10:44:13 +0200
committerFelix Morgner <felix.morgner@gmail.com>2024-07-24 10:44:13 +0200
commit3f5499cebc06356ed99159be3fb9676292cf7b8b (patch)
tree63d36c3cd33de5746b8e3a29922e6ab7a6578def /core/tests
parent0d61f98434b95c754f46c918af5152eda82077cb (diff)
downloadturns-3f5499cebc06356ed99159be3fb9676292cf7b8b.tar.xz
turns-3f5499cebc06356ed99159be3fb9676292cf7b8b.zip
turns: rename domain to core
Diffstat (limited to 'core/tests')
-rw-r--r--core/tests/disposition.cpp32
-rw-r--r--core/tests/participant.cpp113
-rw-r--r--core/tests/register_types.cpp13
-rw-r--r--core/tests/turn_order.cpp225
-rw-r--r--core/tests/turn_order_bugs.cpp42
5 files changed, 425 insertions, 0 deletions
diff --git a/core/tests/disposition.cpp b/core/tests/disposition.cpp
new file mode 100644
index 0000000..3a35741
--- /dev/null
+++ b/core/tests/disposition.cpp
@@ -0,0 +1,32 @@
+#include "turns/core/disposition.hpp"
+
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/generators/catch_generators.hpp>
+
+#include <compare>
+#include <format>
+#include <limits>
+#include <utility>
+
+#include <glibmm/i18n.h>
+#include <glibmm/ustring.h>
+
+namespace turns::core::tests
+{
+
+ TEST_CASE("to_presentation_name returns the correct string for the current language", "[disposition]")
+ {
+ auto [value, name] = GENERATE(std::pair{disposition::neutral, Glib::ustring{_("Neutral")}},
+ std::pair{disposition::friendly, Glib::ustring{_("Friendly")}},
+ std::pair{disposition::hostile, Glib::ustring{_("Hostile")}},
+ std::pair{disposition::secret, Glib::ustring{_("Secret")}},
+ std::pair{static_cast<disposition>(std::numeric_limits<std::underlying_type_t<disposition>>::max()),
+ Glib::ustring{_("Unknown disposition value")}});
+
+ SECTION(std::format("the presentation name for '{}' is '{}'", static_cast<std::underlying_type_t<disposition>>(value), name.c_str()))
+ {
+ REQUIRE(presentation_name_for(value) == name);
+ }
+ }
+
+} // namespace turns::core::tests \ No newline at end of file
diff --git a/core/tests/participant.cpp b/core/tests/participant.cpp
new file mode 100644
index 0000000..14fb1ae
--- /dev/null
+++ b/core/tests/participant.cpp
@@ -0,0 +1,113 @@
+#include "turns/core/participant.hpp"
+#include "turns/core/disposition.hpp"
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <compare>
+
+#include <glibmm/init.h>
+
+namespace turns::core::tests
+{
+
+ TEST_CASE("A freshly constructed participant")
+ {
+ auto constexpr constructed_name = "Vana Thistletop";
+ auto constexpr constructed_priority = 17;
+ auto constexpr constructed_disposition = disposition::friendly;
+ auto instance = participant{constructed_name, constructed_priority, constructed_disposition};
+
+ SECTION("can be created")
+ {
+ REQUIRE(participant::create(constructed_name, constructed_priority, constructed_disposition));
+ }
+
+ SECTION("allows access to its disposition")
+ {
+ SECTION("allowing to get it")
+ {
+ REQUIRE(instance.disposition() == constructed_disposition);
+ }
+
+ SECTION("allowing to get it via a constant object")
+ {
+ auto const & cref = instance;
+ REQUIRE(cref.disposition() == constructed_disposition);
+ }
+
+ SECTION("allowing to set it")
+ {
+ instance.disposition() = disposition::hostile;
+ REQUIRE(instance.disposition() == disposition::hostile);
+ }
+ }
+
+ SECTION("allows access to its name")
+ {
+ SECTION("allowing to get it")
+ {
+ REQUIRE(instance.name() == constructed_name);
+ }
+
+ SECTION("allowing to get it via a constant object")
+ {
+ auto const & cref = instance;
+ REQUIRE(cref.name() == constructed_name);
+ }
+
+ SECTION("allowing to set it")
+ {
+ instance.name() = "replaced";
+ REQUIRE(instance.name() == "replaced");
+ }
+ }
+
+ SECTION("allows access to its priority")
+ {
+ SECTION("allowing to get it")
+ {
+ REQUIRE(instance.priority() == constructed_priority);
+ }
+
+ SECTION("allowing to get it via a constant object")
+ {
+ auto const & cref = instance;
+ REQUIRE(cref.priority() == constructed_priority);
+ }
+
+ SECTION("allowing to set it")
+ {
+ instance.priority() = 4;
+ REQUIRE(instance.priority() == 4);
+ }
+ }
+
+ SECTION("can be compared with another participant")
+ {
+ auto equivalent_instance = participant{"Equivalent", constructed_priority, constructed_disposition};
+ auto lesser_instance = participant{"Lesser", constructed_priority - 1, constructed_disposition};
+ auto greater_instance = participant{"Greater", constructed_priority + 1, constructed_disposition};
+
+ SECTION("yielding std::partial_ordering::equivalent for itself")
+ {
+ REQUIRE((instance <=> equivalent_instance) == std::partial_ordering::equivalent);
+ }
+
+ SECTION("yielding std::partial_ordering::equivalent for an equivalent participant")
+ {
+ REQUIRE((instance <=> equivalent_instance) == std::partial_ordering::equivalent);
+ }
+
+ SECTION("yielding std::partial_ordering::greater for a lesser participant")
+ {
+ REQUIRE((instance <=> lesser_instance) == std::partial_ordering::greater);
+ }
+
+ SECTION("yielding std::partial_ordering::less for a greater participant")
+ {
+ REQUIRE((instance <=> greater_instance) == std::partial_ordering::less);
+ }
+ }
+ }
+
+} // namespace turns::core::tests \ No newline at end of file
diff --git a/core/tests/register_types.cpp b/core/tests/register_types.cpp
new file mode 100644
index 0000000..2ad0628
--- /dev/null
+++ b/core/tests/register_types.cpp
@@ -0,0 +1,13 @@
+#include "turns/core/participant.hpp"
+#include "turns/core/turn_order.hpp"
+
+namespace turns::tests
+{
+
+ auto register_types() -> void
+ {
+ static_cast<void>(core::participant{});
+ static_cast<void>(core::turn_order{});
+ }
+
+} // namespace turns::tests \ No newline at end of file
diff --git a/core/tests/turn_order.cpp b/core/tests/turn_order.cpp
new file mode 100644
index 0000000..fc779d7
--- /dev/null
+++ b/core/tests/turn_order.cpp
@@ -0,0 +1,225 @@
+#include "turns/core/turn_order.hpp"
+
+#include "turns/core/participant.hpp"
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <giomm/liststore.h>
+
+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")
+ {
+ auto str = Gio::ListStore<Glib::Object>::create();
+ REQUIRE(instance->get_n_items() == str->get_n_items());
+ }
+
+ 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<participant>(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<participant>(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<participant>(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<participant>(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<participant>(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);
+ }
+ }
+ }
+ }
+ }
+
+} // 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
new file mode 100644
index 0000000..0fa0720
--- /dev/null
+++ b/core/tests/turn_order_bugs.cpp
@@ -0,0 +1,42 @@
+#include "turns/core/participant.hpp"
+#include "turns/core/turn_order.hpp"
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <giomm/liststore.h>
+
+namespace turns::core::tests
+{
+ /**
+ * Bug description:
+ *
+ * After having stepped according to the step pattern below, tt was possible to step backward often enough to underflow the round number:
+ * - forward
+ * - backward
+ * - forward
+ */
+ SCENARIO("Can step back infinitely", "[turn_order][bug]")
+ {
+ GIVEN("a non-empty turn_order")
+ {
+ auto instance = turn_order::create();
+
+ instance->add("A", 0, disposition::neutral);
+
+ WHEN("it is started and then stepped forward, backward, forward")
+ {
+ instance->start();
+ instance->next();
+ instance->previous();
+ instance->next();
+
+ THEN("it is not possible to step backwards more than once")
+ {
+ instance->previous();
+ instance->previous();
+ REQUIRE(instance->round_number() == 0);
+ }
+ }
+ }
+ }
+} // namespace turns::core::tests \ No newline at end of file