/* * SPDX-FileCopyrightText: 2025 Felix Morgner * SPDX-License-Identifier: LGPL-2.1-only */ #include "turns-participant.h" #include #include #include #include #include #include namespace { auto record_notification(TurnsParticipant const *, GParamSpec *, bool * out) -> void { *out = true; } } // namespace SCENARIO("Creating a participant", "[lib][object][lifetime]") { GIVEN("A participant constructed using turns_participant_new()") { g_autoptr(TurnsParticipant) instance = turns_participant_new(); THEN("its name is empty") { auto name = turns_participant_get_name(instance); REQUIRE(name); REQUIRE(std::string{name}.empty()); } THEN("its priority is 0.0f") { REQUIRE(turns_participant_get_priority(instance) == Catch::Approx{0.0}); } THEN("its disposition is neutral") { REQUIRE(turns_participant_get_disposition(instance) == TURNS_PARTICIPANT_DISPOSITION_NEUTRAL); } THEN("its active state is false") { REQUIRE_FALSE(turns_participant_get_active(instance)); } THEN("its defeated state is false") { REQUIRE_FALSE(turns_participant_get_defeated(instance)); } THEN("its id is not null") { REQUIRE(turns_participant_get_id(instance) != nullptr); } THEN("its id is a valid UUID") { REQUIRE(g_uuid_string_is_valid(turns_participant_get_id(instance))); } } GIVEN("A participant constructed using turns_participant_new_with(...)") { auto name = "Test Participant"; auto priority = 12.4f; auto disposition = TURNS_PARTICIPANT_DISPOSITION_FRIENDLY; g_autoptr(TurnsParticipant) instance = turns_participant_new_with(name, priority, disposition); THEN("it's name is set") { REQUIRE(turns_participant_get_name(instance) == std::string{name}); } THEN("it's priority is set") { REQUIRE(turns_participant_get_priority(instance) == Catch::Approx{priority}); } THEN("it's disposition is") { REQUIRE(turns_participant_get_disposition(instance) == disposition); } THEN("it's active state is false") { REQUIRE_FALSE(turns_participant_get_active(instance)); } THEN("it's defeated state is false") { REQUIRE_FALSE(turns_participant_get_defeated(instance)); } } GIVEN("A participant is constructed using turns_participant_new_with(nullptr, ...)") { auto instance = turns_participant_new_with(nullptr, 10.0f, TURNS_PARTICIPANT_DISPOSITION_HOSTILE); THEN("the instance is NULL") { REQUIRE(instance == nullptr); } } } SCENARIO("Modifying a participant", "[lib][object][data]") { GIVEN("A default participant instance") { g_autoptr(TurnsParticipant) instance = turns_participant_new(); WHEN("a new name is set") { auto new_value = "Test Participant"; CHECK(std::string{turns_participant_get_name(instance)}.empty()); CHECK_FALSE(std::string{turns_participant_get_name(instance)} == new_value); turns_participant_set_name(instance, new_value); THEN("it's name is not empty") { REQUIRE_FALSE(std::string{turns_participant_get_name(instance)}.empty()); } THEN("it's name has the new value") { REQUIRE(std::string{turns_participant_get_name(instance)} == new_value); } } WHEN("a new priority is set") { auto new_value = GENERATE(-8.0f, 12.0f, 4.0f); CHECK_FALSE(turns_participant_get_priority(instance) == new_value); turns_participant_set_priority(instance, new_value); THEN("it's priority has the new value") { REQUIRE(turns_participant_get_priority(instance) == Catch::Approx{new_value}); } } WHEN("a new disposition is set") { auto new_value = GENERATE(TURNS_PARTICIPANT_DISPOSITION_FRIENDLY, TURNS_PARTICIPANT_DISPOSITION_HOSTILE, TURNS_PARTICIPANT_DISPOSITION_SECRET); CHECK_FALSE(turns_participant_get_disposition(instance) == new_value); turns_participant_set_disposition(instance, new_value); THEN("it's disposition has the new value") { REQUIRE(turns_participant_get_disposition(instance) == new_value); } } WHEN("a new active state is set") { auto new_value = true; CHECK_FALSE(turns_participant_get_active(instance) == new_value); turns_participant_set_active(instance, new_value); THEN("it's active state has the new value") { REQUIRE(turns_participant_get_active(instance) == new_value); } } WHEN("a new defeated state is set") { auto new_value = true; CHECK_FALSE(turns_participant_get_defeated(instance) == new_value); turns_participant_set_defeated(instance, new_value); THEN("it's defeated state has the new value") { REQUIRE(turns_participant_get_defeated(instance) == new_value); } } AND_GIVEN("a signal handler has been subscribed to the name property") { auto was_notified = false; g_signal_connect(instance, "notify::name", G_CALLBACK(&record_notification), &was_notified); WHEN("a new name is set using set_name") { auto new_value = "Test Participant"; CHECK_FALSE(std::string{turns_participant_get_name(instance)} == new_value); turns_participant_set_name(instance, new_value); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same name is set using set_name") { auto new_value = turns_participant_get_name(instance); CHECK(std::string{turns_participant_get_name(instance)} == new_value); turns_participant_set_name(instance, new_value); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } WHEN("a new name is set using g_object_set") { auto new_value = "Test Participant"; CHECK_FALSE(std::string{turns_participant_get_name(instance)} == new_value); g_object_set(G_OBJECT(instance), "name", new_value, nullptr); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same name is set using g_object_set") { auto new_value = turns_participant_get_name(instance); CHECK(std::string{turns_participant_get_name(instance)} == new_value); g_object_set(G_OBJECT(instance), "name", new_value, nullptr); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } } AND_GIVEN("a signal handler has been subscribed to the priority property") { auto was_notified = false; g_signal_connect(instance, "notify::priority", G_CALLBACK(&record_notification), &was_notified); WHEN("a new priority is set using set_priority") { auto new_value = 17.15; CHECK_FALSE(turns_participant_get_priority(instance) == new_value); turns_participant_set_priority(instance, new_value); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same priority is set using set_priority") { auto new_value = turns_participant_get_priority(instance); CHECK(turns_participant_get_priority(instance) == new_value); turns_participant_set_priority(instance, new_value); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } WHEN("a new priority is set using g_object_set") { auto new_value = 17.15; CHECK_FALSE(turns_participant_get_priority(instance) == new_value); g_object_set(G_OBJECT(instance), "priority", new_value, nullptr); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same priority is set using g_object_set") { auto new_value = turns_participant_get_priority(instance); CHECK(turns_participant_get_priority(instance) == new_value); g_object_set(G_OBJECT(instance), "priority", new_value, nullptr); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } } AND_GIVEN("a signal handler has been subscribed to the disposition property") { auto was_notified = false; g_signal_connect(instance, "notify::disposition", G_CALLBACK(&record_notification), &was_notified); WHEN("a new disposition is set using set_disposition") { auto new_value = TURNS_PARTICIPANT_DISPOSITION_HOSTILE; CHECK_FALSE(turns_participant_get_disposition(instance) == new_value); turns_participant_set_disposition(instance, new_value); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same disposition is set using set_disposition") { auto new_value = turns_participant_get_disposition(instance); CHECK(turns_participant_get_disposition(instance) == new_value); turns_participant_set_disposition(instance, new_value); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } WHEN("a new disposition is set using g_object_set") { auto new_value = TURNS_PARTICIPANT_DISPOSITION_HOSTILE; CHECK_FALSE(turns_participant_get_disposition(instance) == new_value); g_object_set(G_OBJECT(instance), "disposition", new_value, nullptr); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same disposition is set using g_object_set") { auto new_value = turns_participant_get_disposition(instance); CHECK(turns_participant_get_disposition(instance) == new_value); g_object_set(G_OBJECT(instance), "disposition", new_value, nullptr); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } } AND_GIVEN("a signal handler has been subscribed to the active property") { auto was_notified = false; g_signal_connect(instance, "notify::active", G_CALLBACK(&record_notification), &was_notified); WHEN("a new active is set using set_active") { auto new_value = true; CHECK_FALSE(turns_participant_get_active(instance) == new_value); turns_participant_set_active(instance, new_value); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same active is set using set_active") { auto new_value = turns_participant_get_active(instance); CHECK(turns_participant_get_active(instance) == new_value); turns_participant_set_active(instance, new_value); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } WHEN("a new active is set using g_object_set") { auto new_value = true; CHECK_FALSE(turns_participant_get_active(instance) == new_value); g_object_set(G_OBJECT(instance), "active", new_value, nullptr); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same active is set using g_object_set") { auto new_value = turns_participant_get_active(instance); CHECK(turns_participant_get_active(instance) == new_value); g_object_set(G_OBJECT(instance), "active", new_value, nullptr); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } } AND_GIVEN("a signal handler has been subscribed to the defeated property") { auto was_notified = false; g_signal_connect(instance, "notify::defeated", G_CALLBACK(&record_notification), &was_notified); WHEN("a new defeated is set using set_defeated") { auto new_value = true; CHECK_FALSE(turns_participant_get_defeated(instance) == new_value); turns_participant_set_defeated(instance, new_value); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same defeated is set using set_defeated") { auto new_value = turns_participant_get_defeated(instance); CHECK(turns_participant_get_defeated(instance) == new_value); turns_participant_set_defeated(instance, new_value); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } WHEN("a new defeated is set using g_object_set") { auto new_value = true; CHECK_FALSE(turns_participant_get_defeated(instance) == new_value); g_object_set(G_OBJECT(instance), "defeated", new_value, nullptr); THEN("a notification is issued") { REQUIRE(was_notified); } } WHEN("the same defeated is set using g_object_set") { auto new_value = turns_participant_get_defeated(instance); CHECK(turns_participant_get_defeated(instance) == new_value); g_object_set(G_OBJECT(instance), "defeated", new_value, nullptr); THEN("no notification is issued") { REQUIRE_FALSE(was_notified); } } } } } SCENARIO("Reading a participant", "[lib][object][data]") { GIVEN("A participant with a set name, priority, and disposition") { auto name = "Test Participant"; auto priority = 75.f; auto disposition = TURNS_PARTICIPANT_DISPOSITION_FRIENDLY; g_autoptr(TurnsParticipant) instance = turns_participant_new_with(name, priority, disposition); WHEN("reading the name via get_name and g_object_get") { auto getter_value = turns_participant_get_name(instance); g_autofree auto property_value = decltype(turns_participant_get_name(instance)){}; g_object_get(instance, "name", &property_value, nullptr); THEN("they both compare equal") { REQUIRE(std::string{getter_value} == property_value); } } WHEN("reading the priority via get_priority and g_object_get") { auto getter_value = turns_participant_get_priority(instance); auto property_value = decltype(turns_participant_get_priority(instance)){}; g_object_get(instance, "priority", &property_value, nullptr); THEN("they both compare equal") { REQUIRE(getter_value == property_value); } } WHEN("reading the disposition via get_disposition and g_object_get") { auto getter_value = turns_participant_get_disposition(instance); auto property_value = decltype(turns_participant_get_disposition(instance)){}; g_object_get(instance, "disposition", &property_value, nullptr); THEN("they both compare equal") { REQUIRE(getter_value == property_value); } } WHEN("reading the active state via get_active and g_object_get") { auto getter_value = turns_participant_get_active(instance); auto property_value = decltype(turns_participant_get_active(instance)){}; g_object_get(instance, "active", &property_value, nullptr); THEN("they both compare equal") { REQUIRE(getter_value == property_value); } } WHEN("reading the defeated state via get_defeated and g_object_get") { auto getter_value = turns_participant_get_defeated(instance); auto property_value = decltype(turns_participant_get_defeated(instance)){}; g_object_get(instance, "defeated", &property_value, nullptr); THEN("they both compare equal") { REQUIRE(getter_value == property_value); } } } } SCENARIO("Comparing two participants", "[lib][object][logic]") { auto name_lhs = "LHS"; auto name_rhs = "RHS"; auto disposition = TurnsParticipantDisposition::TURNS_PARTICIPANT_DISPOSITION_NEUTRAL; GIVEN("A participant with priority 0") { g_autoptr(TurnsParticipant) lhs = turns_participant_new_with(name_lhs, 0.0f, disposition); THEN("the it compares equal to itself") { REQUIRE(turns_participant_compare(lhs, lhs) == 0); } AND_GIVEN("A participant with priority 10") { g_autoptr(TurnsParticipant) rhs = turns_participant_new_with(name_rhs, 10.0f, disposition); THEN("the first compares less than the second") { REQUIRE(turns_participant_compare(lhs, rhs) < 0); } THEN("the second compares greater than the first") { REQUIRE(turns_participant_compare(rhs, lhs) > 0); } } AND_GIVEN("A participant with priority -10") { g_autoptr(TurnsParticipant) rhs = turns_participant_new_with(name_rhs, -10.0f, disposition); THEN("the first compares greater than the second") { REQUIRE(turns_participant_compare(lhs, rhs) > 0); } THEN("the second compares less than the first") { REQUIRE(turns_participant_compare(rhs, lhs) < 0); } } } }