[Refactor] Move game logic into libcockatrice_game

This commit is contained in:
Lukas Brübach 2026-10-07 11:11:39 +02:00 • committed by GitHub
parent 710dfabea2
commit 7556f6465a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
91 changed files with 388 additions and 179 deletions

View file

@ -400,6 +400,11 @@ add_subdirectory(movecard_tests)
add_subdirectory(oracle)
add_subdirectory(settings)
# libcockatrice_game only exists when the client is built.
if(WITH_CLIENT)
add_subdirectory(game)
endif()
# theme_migration_test compiles client sources, whose headers are only reachable from a client build.
if(WITH_CLIENT)
add_subdirectory(theme_migration)

View file

@ -1,4 +1,4 @@
cockatrice_add_test(
NAME card_zone_algorithms_test SOURCES card_zone_algorithms_test.cpp INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/cockatrice/src/game/zones
${CMAKE_SOURCE_DIR}/libcockatrice_game/libcockatrice/game/zones
)

28
tests/game/CMakeLists.txt Normal file
View file

@ -0,0 +1,28 @@
add_executable(
game_smoke_test
${CMAKE_SOURCE_DIR}/cockatrice/src/client/settings/cache_settings.cpp
${CMAKE_SOURCE_DIR}/cockatrice/src/client/settings/card_counter_settings.cpp
${CMAKE_SOURCE_DIR}/cockatrice/src/client/settings/shortcuts_settings.cpp
${CMAKE_SOURCE_DIR}/cockatrice/src/client/network/update/client/release_channel.cpp
${VERSION_STRING_CPP}
game_smoke_test.cpp
)
# SettingsCache is still reached from the game logic, but it lives in the application sources
# rather than in libcockatrice_settings, so the client settings sources are compiled in here
# exactly like loader_local_matching_test and theme_migration_test do.
target_include_directories(game_smoke_test PRIVATE ${CMAKE_SOURCE_DIR}/cockatrice/src)
target_link_libraries(
game_smoke_test
PRIVATE libcockatrice_game
PRIVATE Threads::Threads
PRIVATE ${GTEST_BOTH_LIBRARIES}
PRIVATE ${TEST_QT_MODULES}
)
add_test(NAME game_smoke_test COMMAND game_smoke_test)
if(NOT GTEST_FOUND)
add_dependencies(game_smoke_test gtest)
endif()

View file

@ -0,0 +1,106 @@
/**
* @file game_smoke_test.cpp
*
* Links the game logic library into a target that contains no graphics code at all, and drives
* the two seams the graphics layer used to own: the attachment graph on CardState and the
* card-creation request a zone makes so the graphics side can build the matching card item.
*/
#include "gtest/gtest.h"
#include <QCoreApplication>
#include <QLoggingCategory>
#include <QSignalSpy>
#include <QStandardPaths>
#include <QTemporaryDir>
#include <libcockatrice/game/board/card_state.h>
#include <libcockatrice/game/zones/hand_zone_logic.h>
namespace
{
CardRef cardRefFor(const QString &name)
{
CardRef cardRef;
cardRef.name = name;
return cardRef;
}
} // namespace
TEST(CardStateTest, AttachmentGraphKeepsBothEndsConsistent)
{
CardState host(nullptr, nullptr, cardRefFor(QStringLiteral("Host")), 1);
CardState guest(nullptr, nullptr, cardRefFor(QStringLiteral("Guest")), 2);
guest.setAttachedTo(&host);
host.addAttachedCard(&guest);
EXPECT_EQ(guest.getAttachedTo(), &host);
ASSERT_EQ(host.getAttachedCards().size(), 1);
EXPECT_EQ(host.getAttachedCards().first(), &guest);
host.removeAttachedCard(&guest);
guest.setAttachedTo(nullptr);
EXPECT_TRUE(host.getAttachedCards().isEmpty());
EXPECT_EQ(guest.getAttachedTo(), nullptr);
}
TEST(CardZoneLogicTest, AddsAndTakesCardsWithoutAGraphicsSide)
{
HandZoneLogic zone(nullptr, QStringLiteral("hand"), false, false, true);
CardState card(nullptr, nullptr, cardRefFor(QStringLiteral("Lightning Bolt")), 7);
QSignalSpy cardAddedSpy(&zone, &CardZoneLogic::cardAdded);
QSignalSpy cardCountSpy(&zone, &CardZoneLogic::cardCountChanged);
zone.addCard(&card, false, 0);
ASSERT_EQ(zone.getCards().size(), 1);
EXPECT_EQ(zone.getCards().first(), &card);
EXPECT_EQ(card.getZone(), &zone);
EXPECT_EQ(cardAddedSpy.count(), 1);
EXPECT_GE(cardCountSpy.count(), 1);
EXPECT_EQ(zone.takeCard(0, 7), &card);
EXPECT_TRUE(zone.getCards().isEmpty());
EXPECT_EQ(card.getId(), 7);
}
TEST(CardZoneLogicTest, AsksTheGraphicsSideToCreateCards)
{
HandZoneLogic zone(nullptr, QStringLiteral("library"), false, true, true);
QSignalSpy requestSpy(&zone, &CardZoneLogic::requestCreateCard);
ServerInfo_Card cardInfo;
cardInfo.set_name("Lightning Bolt");
cardInfo.set_id(7);
cardInfo.set_x(0);
cardInfo.set_y(1);
zone.requestCreateCard(cardInfo, true);
ASSERT_EQ(requestSpy.count(), 1);
const QList<QVariant> arguments = requestSpy.takeFirst();
EXPECT_EQ(arguments.at(0).value<ServerInfo_Card>().id(), 7);
EXPECT_TRUE(arguments.at(1).toBool());
}
int main(int argc, char **argv)
{
// Keep SettingsCache reads and writes away from the real user profile: the game logic still
// reaches for a handful of settings, and the client settings sources linked into this test
// would otherwise touch the developer's own configuration.
QStandardPaths::setTestModeEnabled(true);
QTemporaryDir home;
if (home.isValid()) {
qputenv("HOME", home.path().toLocal8Bit());
}
QCoreApplication app(argc, argv);
QLoggingCategory::setFilterRules("settings_cache.*=false");
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}