diff --git a/cockatrice/src/game_graphics/player/menu/hand_menu.cpp b/cockatrice/src/game_graphics/player/menu/hand_menu.cpp index 1592a948b..8ef47d4cb 100644 --- a/cockatrice/src/game_graphics/player/menu/hand_menu.cpp +++ b/cockatrice/src/game_graphics/player/menu/hand_menu.cpp @@ -13,9 +13,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -25,7 +23,6 @@ #include #include #include -#include #include class QWidget; @@ -33,7 +30,6 @@ class QWidget; HandMenu::HandMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player) { auto *actions = player->getLogic()->getPlayerActions(); - connect(actions, &PlayerActions::randomHandRevealFailed, this, &HandMenu::onRandomHandRevealFailed); if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) { aViewHand = new QAction(this); @@ -279,12 +275,7 @@ void HandMenu::onRevealRandomHandCardsTriggered() return; } const int targetId = action->data().toInt(); - QPointer actions = player->getLogic()->getPlayerActions(); - QPointer client = - player->getLogic()->getGame()->getClientForPlayer(player->getLogic()->getPlayerInfo()->getId()); - if (!client) { - return; - } + auto *actions = player->getLogic()->getPlayerActions(); auto *dialog = new QInputDialog(dialogParent()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setWindowTitle(tr("Reveal Random Hand Cards")); @@ -292,15 +283,8 @@ void HandMenu::onRevealRandomHandCardsTriggered() dialog->setInputMode(QInputDialog::IntInput); dialog->setIntRange(1, handSize); dialog->setIntValue(qMin(2, handSize)); - connect(this, &QObject::destroyed, dialog, &QDialog::reject); - connect(client, &QObject::destroyed, dialog, &QDialog::reject); - connect(actions, &QObject::destroyed, dialog, &QDialog::reject); - connect(dialog, &QDialog::accepted, this, [dialog, actions, client, targetId] { - if (!actions || !client) { - return; - } - actions->actRevealRandomHandCards(targetId, dialog->intValue()); - }); + connect(dialog, &QDialog::accepted, actions, + [dialog, actions, targetId] { actions->actRevealRandomHandCards(targetId, dialog->intValue()); }); dialog->open(); } @@ -311,20 +295,3 @@ QWidget *HandMenu::dialogParent() const } return nullptr; } - -void HandMenu::onRandomHandRevealFailed(bool unsupported) -{ - const QString text = - unsupported ? tr("This server does not support revealing multiple random cards. No cards were revealed.") - : tr("The random reveal could not be completed. The hand or recipient may have changed."); - auto *message = - new QMessageBox(QMessageBox::Warning, tr("Reveal Random Hand Cards"), text, QMessageBox::Ok, dialogParent()); - message->setAttribute(Qt::WA_DeleteOnClose); - connect(this, &QObject::destroyed, message, &QDialog::reject); - connect(player->getLogic()->getPlayerActions(), &QObject::destroyed, message, &QDialog::reject); - if (auto *client = - player->getLogic()->getGame()->getClientForPlayer(player->getLogic()->getPlayerInfo()->getId())) { - connect(client, &QObject::destroyed, message, &QDialog::reject); - } - message->open(); -} diff --git a/cockatrice/src/game_graphics/player/menu/hand_menu.h b/cockatrice/src/game_graphics/player/menu/hand_menu.h index c2ca110de..03ecd7544 100644 --- a/cockatrice/src/game_graphics/player/menu/hand_menu.h +++ b/cockatrice/src/game_graphics/player/menu/hand_menu.h @@ -44,7 +44,6 @@ private slots: void onRevealRandomHandCardTriggered(); void populateRevealRandomHandCardsMenuWithActivePlayers(); void onRevealRandomHandCardsTriggered(); - void onRandomHandRevealFailed(bool unsupported); private: QWidget *dialogParent() const; diff --git a/doc/doxygen/pages/user_documentation/gameplay/revealing_cards.md b/doc/doxygen/pages/user_documentation/gameplay/revealing_cards.md index bac74cff7..3e6252511 100644 --- a/doc/doxygen/pages/user_documentation/gameplay/revealing_cards.md +++ b/doc/doxygen/pages/user_documentation/gameplay/revealing_cards.md @@ -8,4 +8,4 @@ When you choose a specific player, that player receives the selected card identi If the hand becomes too small or the recipient leaves before the server processes the request, the request fails without a partial reveal. Cancelling the count dialog sends nothing. -This operation requires a server that supports multiple random reveals. An older server rejects it without revealing any cards, and the client explains that it is unsupported. The existing **Reveal random card to...** action and its shortcut remain available for single-card reveals. +This operation requires a server that supports multiple random reveals. An older server rejects it without revealing any cards. The existing **Reveal random card to...** action and its shortcut remain available for single-card reveals. diff --git a/libcockatrice_game/libcockatrice/game/player/player_actions.cpp b/libcockatrice_game/libcockatrice/game/player/player_actions.cpp index fe152ec88..1e854cbd4 100644 --- a/libcockatrice_game/libcockatrice/game/player/player_actions.cpp +++ b/libcockatrice_game/libcockatrice/game/player/player_actions.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -48,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -68,8 +66,6 @@ #include #include #include -#include -#include #include #include #include @@ -1762,23 +1758,13 @@ void PlayerActions::actRevealRandomHandCard(int revealToPlayerId) void PlayerActions::actRevealRandomHandCards(int revealToPlayerId, int amount) { - QPointer client = player->getGame()->getClientForPlayer(player->getPlayerInfo()->getId()); - if (!client) { - return; - } Command_RevealRandomCards cmd; if (revealToPlayerId != -1) { cmd.set_player_id(revealToPlayerId); } cmd.set_zone_name(ZoneNames::HAND); cmd.set_number_of_cards(amount); - auto *pending = prepareGameCommand(cmd); - connect(pending, &PendingCommand::finished, this, [this, client](const Response &response) { - if (client && response.response_code() != Response::RespOk) { - emit randomHandRevealFailed(response.response_code() == Response::RespInvalidCommand); - } - }); - sendGameCommand(pending); + sendGameCommand(cmd); } void PlayerActions::actRevealLibrary(int revealToPlayerId) diff --git a/libcockatrice_game/libcockatrice/game/player/player_actions.h b/libcockatrice_game/libcockatrice/game/player/player_actions.h index 8baac760e..81d18315c 100644 --- a/libcockatrice_game/libcockatrice/game/player/player_actions.h +++ b/libcockatrice_game/libcockatrice/game/player/player_actions.h @@ -120,7 +120,6 @@ public: } signals: - void randomHandRevealFailed(bool unsupported); void requestViewTopCardsDialog(int defaultNumberTopCards, int deckSize); void requestViewBottomCardsDialog(int defaultNumberBottomCards, int deckSize); void requestShuffleTopDialog(int defaultNumberTopCards, int maxCards); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.cpp index a37b9f101..f23917e6f 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.cpp @@ -406,6 +406,13 @@ Response::ResponseCode Server_AbstractParticipant::cmdRevealCards(const Command_ return Response::RespFunctionNotAllowed; } +Response::ResponseCode Server_AbstractParticipant::cmdRevealRandomCards(const Command_RevealRandomCards & /*cmd*/, + ResponseContainer & /*rc*/, + GameEventStorage & /*ges*/) +{ + return Response::RespFunctionNotAllowed; +} + Response::ResponseCode Server_AbstractParticipant::cmdChangeZoneProperties(const Command_ChangeZoneProperties & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) @@ -545,20 +552,9 @@ Server_AbstractParticipant::processGameCommand(const GameCommand &command, Respo case GameCommand::REVEAL_CARDS: return cmdRevealCards(command.GetExtension(Command_RevealCards::ext), rc, ges); break; - case GameCommand::REVEAL_RANDOM_CARDS: { - const auto &random = command.GetExtension(Command_RevealRandomCards::ext); - if (random.number_of_cards() <= 0) { - return Response::RespInvalidData; - } - // Reuse the existing player/judge authorization and private reveal delivery. - Command_RevealCards reveal; - reveal.set_zone_name(random.zone_name()); - reveal.add_card_id(-2); - if (random.has_player_id()) { - reveal.set_player_id(random.player_id()); - } - return cmdRevealCards(reveal, rc, ges, random.number_of_cards()); - } + case GameCommand::REVEAL_RANDOM_CARDS: + return cmdRevealRandomCards(command.GetExtension(Command_RevealRandomCards::ext), rc, ges); + break; case GameCommand::MOVE_CARD: return cmdMoveCard(command.GetExtension(Command_MoveCard::ext), rc, ges); break; diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.h b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.h index e7fd64df3..efba983b5 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_participant.h @@ -46,6 +46,7 @@ class Command_NextTurn; class Command_SetActivePhase; class Command_DumpZone; class Command_RevealCards; +class Command_RevealRandomCards; class Command_ReverseTurn; class Command_MoveCard; class Command_SetSideboardPlan; @@ -176,6 +177,8 @@ public: virtual Response::ResponseCode cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer &rc, GameEventStorage &ges, int randomCount = 1); virtual Response::ResponseCode + cmdRevealRandomCards(const Command_RevealRandomCards &cmd, ResponseContainer &rc, GameEventStorage &ges); + virtual Response::ResponseCode cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges); virtual Response::ResponseCode cmdSetPlayerOrder(const Command_SetPlayerOrder &cmd, ResponseContainer &rc, GameEventStorage &ges); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp index e8bfa8cad..f6288960f 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp @@ -1494,6 +1494,22 @@ Server_AbstractPlayer::cmdDumpZone(const Command_DumpZone &cmd, ResponseContaine return Response::RespOk; } +Response::ResponseCode Server_AbstractPlayer::cmdRevealRandomCards(const Command_RevealRandomCards &cmd, + ResponseContainer &rc, + GameEventStorage &ges) +{ + if (cmd.number_of_cards() <= 0) { + return Response::RespInvalidData; + } + Command_RevealCards reveal; + reveal.set_zone_name(cmd.zone_name()); + reveal.add_card_id(-2); + if (cmd.has_player_id()) { + reveal.set_player_id(cmd.player_id()); + } + return cmdRevealCards(reveal, rc, ges, cmd.number_of_cards()); +} + Response::ResponseCode Server_AbstractPlayer::cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges, diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h index c11780c37..17b4016ad 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.h @@ -165,6 +165,8 @@ public: ResponseContainer &rc, GameEventStorage &ges, int randomCount = 1) override; + Response::ResponseCode + cmdRevealRandomCards(const Command_RevealRandomCards &cmd, ResponseContainer &rc, GameEventStorage &ges) override; virtual Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd, ResponseContainer &rc, GameEventStorage &ges) override; diff --git a/tests/random_reveal_test.cpp b/tests/random_reveal_test.cpp index 579fc46b5..b42584361 100644 --- a/tests/random_reveal_test.cpp +++ b/tests/random_reveal_test.cpp @@ -9,46 +9,34 @@ #include "server_room.h" #include -#include -#include -#include #include #include -#include #include #include #include #include -#include #include #include #include -RNG_Abstract *rng = nullptr; - namespace { -class AlternatingRng : public RNG_Abstract +class FirstRng : public RNG_Abstract { - int calls = 0; - -public: - unsigned int rand(int min, int max) override + unsigned int rand(int min, int) override { - EXPECT_LE(min, max); - return calls++ % 2 == 0 && min < max ? min + 1 : min; + return min; } -}; +} firstRng; -class Recipient : public Server_AbstractUserInterface +class User : public Server_AbstractUserInterface { public: - QList reveals; - Recipient(Server *server, const char *name) : Server_AbstractUserInterface(server) + User(Server *server, const char *name) : Server_AbstractUserInterface(server) { - ServerInfo_User user; - user.set_name(name); - setUserInfo(user); + ServerInfo_User info; + info.set_name(name); + setUserInfo(info); } int getLastCommandTime() const override { @@ -67,180 +55,96 @@ public: void sendProtocolItem(const RoomEvent &) override { } - void sendProtocolItem(const GameEventContainer &container) override + void sendProtocolItem(const GameEventContainer &) override { - for (const auto &event : container.event_list()) { - if (event.HasExtension(Event_RevealCards::ext)) { - reveals.append(event.GetExtension(Event_RevealCards::ext)); - } - } } }; -GameCommand randomReveal(int count, int recipient = -1) +class RandomReveal : public ::testing::Test { - GameCommand command; - auto *request = command.MutableExtension(Command_RevealRandomCards::ext); - request->set_zone_name(ZoneNames::HAND); - request->set_number_of_cards(count); - if (recipient != -1) { - request->set_player_id(recipient); +protected: + FakeServer server; + User owner{&server, "Owner"}, target{&server, "Target"}; + Server_Room room{0, 0, "", "", "", "", false, "", {}, &server}; + std::unique_ptr game; + Server_AbstractPlayer *player; + Server_CardZone *hand; + ResponseContainer response{1}; + + void SetUp() override + { + GameConfig config; + config.creatorInfo = *owner.getUserInfo(); + config.gameId = 1; + config.maxPlayers = 2; + config.shareDecklistsOnLoad = false; + game = std::make_unique(config, &room); + game->addPlayer(&owner, response, {}); + game->addPlayer(&target, response, {}); + for (auto *participant : game->getPlayers()) { + GameCommand command; + command.MutableExtension(Command_DeckSelect::ext) + ->set_deck(DeckList().writeToString_Native().toStdString()); + GameEventStorage events; + ASSERT_EQ(participant->processGameCommand(command, response, events), Response::RespOk); + participant->setReadyStart(true); + } + game->startGameIfReady(false); + QCoreApplication::processEvents(); + ASSERT_TRUE(game->getGameStarted()); + player = game->getPlayer(0); + hand = player->getZones().value(ZoneNames::HAND); + for (int i = 0; i < 4; ++i) { + hand->insertCard(new Server_Card({"Twin", QString::number(i)}, player->newCardId(), i, 0), -1, 0); + } + } + + Response::ResponseCode reveal(int count, GameEventStorage &events) + { + GameCommand command; + auto *request = command.MutableExtension(Command_RevealRandomCards::ext); + request->set_zone_name(ZoneNames::HAND); + request->set_player_id(1); + request->set_number_of_cards(count); + return player->processGameCommand(command, response, events); + } +}; + +TEST_F(RandomReveal, DistinctPhysicalCardsArePrivateAndLeaveTheHandUnchanged) +{ + const auto original = hand->getCards(); + GameEventStorage events; + ASSERT_EQ(reveal(2, events), Response::RespOk); + ASSERT_EQ(events.getGameEventList().size(), 2); + EXPECT_EQ(events.getPrivatePlayerId(), 1); + const auto *privateEvent = events.getGameEventList().at(0); + EXPECT_EQ(privateEvent->getRecipients(), GameEventStorageItem::SendToPrivate); + const auto &cards = privateEvent->getGameEvent().GetExtension(Event_RevealCards::ext); + ASSERT_EQ(cards.cards_size(), 2); + EXPECT_NE(cards.cards(0).id(), cards.cards(1).id()); + const auto *publicEvent = events.getGameEventList().at(1); + EXPECT_EQ(publicEvent->getRecipients(), GameEventStorageItem::SendToOthers); + const auto ¬ice = publicEvent->getGameEvent().GetExtension(Event_RevealCards::ext); + EXPECT_EQ(notice.cards_size(), 0); + EXPECT_EQ(notice.number_of_cards(), 2); + EXPECT_EQ(hand->getCards(), original); +} + +TEST_F(RandomReveal, InvalidCountsDoNotQueueAnyReveal) +{ + for (int count : {0, -1, 5}) { + GameEventStorage events; + EXPECT_NE(reveal(count, events), Response::RespOk); + EXPECT_TRUE(events.getGameEventList().isEmpty()); } - return command; } } // namespace -TEST(RandomReveal, DistinctSamplesPrivacyAndCompatibility) -{ - int argc = 1; - char name[] = "random-reveal-test"; - char *argv[] = {name, nullptr}; - std::unique_ptr application; - if (!QCoreApplication::instance()) { - application = std::make_unique(argc, argv); - } - AlternatingRng random; - rng = &random; - FakeServer server; - Recipient owner(&server, "Owner"), target(&server, "Target"), bystander(&server, "Bystander"), - judge(&server, "Judge"), spectator(&server, "Spectator"); - Server_Room room(0, 0, "", "", "", "", false, "", {}, &server); - GameConfig config; - config.creatorInfo = *owner.getUserInfo(); - config.gameId = 1; - config.maxPlayers = 3; - config.spectatorsAllowed = true; - config.spectatorsSeeEverything = false; - config.shareDecklistsOnLoad = false; - Server_Game game(config, &room); - for (auto *recipient : {&owner, &target, &bystander}) { - ResponseContainer response(1); - game.addPlayer(recipient, response, false, false, false); - } - ResponseContainer judgeResponse(1); - game.addPlayer(&judge, judgeResponse, true, true, false); - ResponseContainer spectatorResponse(1); - game.addPlayer(&spectator, spectatorResponse, true, false, false); - auto *player = game.getPlayer(0); - ASSERT_NE(player, nullptr); - ASSERT_NE(game.getPlayer(1), nullptr); - ResponseContainer response(2); - GameEventStorage notStarted; - EXPECT_EQ(player->processGameCommand(randomReveal(2, 1), response, notStarted), Response::RespGameNotStarted); - EXPECT_TRUE(notStarted.getGameEventList().isEmpty()); - for (auto *participant : game.getPlayers()) { - Command_DeckSelect select; - select.set_deck(DeckList().writeToString_Native().toStdString()); - GameCommand command; - command.MutableExtension(Command_DeckSelect::ext)->CopyFrom(select); - GameEventStorage events; - EXPECT_EQ(participant->processGameCommand(command, response, events), Response::RespOk); - participant->setReadyStart(true); - } - game.startGameIfReady(false); - QCoreApplication::processEvents(); - ASSERT_TRUE(game.getGameStarted()); - auto *hand = player->getZones().value(ZoneNames::HAND); - ASSERT_NE(hand, nullptr); - for (int i = 0; i < 4; ++i) { - auto *card = new Server_Card({i < 2 ? "Twin" : "Other", QString::number(i)}, player->newCardId(), i, 0); - hand->insertCard(card, -1, 0); - } - const auto original = hand->getCards(); - GameEventStorage privateReveal; - EXPECT_EQ(player->processGameCommand(randomReveal(2, 1), response, privateReveal), Response::RespOk); - ASSERT_EQ(privateReveal.getGameEventList().size(), 2); - EXPECT_EQ(privateReveal.getPrivatePlayerId(), 1); - privateReveal.sendToGame(&game); - ASSERT_EQ(owner.reveals.size(), 1); - ASSERT_EQ(target.reveals.size(), 1); - ASSERT_EQ(bystander.reveals.size(), 1); - ASSERT_EQ(judge.reveals.size(), 1); - ASSERT_EQ(spectator.reveals.size(), 1); - EXPECT_EQ(target.reveals.last().cards_size(), 2); - EXPECT_EQ(judge.reveals.last().cards_size(), 2); // existing judge visibility is retained - EXPECT_NE(target.reveals.last().cards(0).id(), target.reveals.last().cards(1).id()); - EXPECT_EQ(target.reveals.last().cards(0).id(), original.at(1)->getId()); - EXPECT_EQ(target.reveals.last().cards(1).id(), original.at(0)->getId()); - EXPECT_EQ(target.reveals.last().cards(0).name(), - target.reveals.last().cards(1).name()); // physical copies are distinct - for (auto *recipient : {&owner, &bystander, &spectator}) { - EXPECT_EQ(recipient->reveals.last().cards_size(), 0); - EXPECT_EQ(recipient->reveals.last().number_of_cards(), 2); - ASSERT_EQ(recipient->reveals.last().card_id_size(), 1); - EXPECT_EQ(recipient->reveals.last().card_id(0), -2); // no actual card ids leak - EXPECT_EQ(recipient->reveals.last().other_player_id(), 1); - } - EXPECT_EQ(hand->getCards(), original); - GameEventStorage publicReveal; - EXPECT_EQ(player->processGameCommand(randomReveal(4), response, publicReveal), Response::RespOk); - publicReveal.sendToGame(&game); - for (auto *recipient : {&owner, &target, &bystander, &judge, &spectator}) { - ASSERT_EQ(recipient->reveals.last().cards_size(), 4); - QSet ids; - for (const auto &card : recipient->reveals.last().cards()) { - ids.insert(card.id()); - } - EXPECT_EQ(ids.size(), 4); - } - EXPECT_EQ(hand->getCards(), original); - for (int amount : {0, -1, 5, 2147483647}) { - GameEventStorage invalid; - EXPECT_NE(player->processGameCommand(randomReveal(amount, 1), response, invalid), Response::RespOk); - EXPECT_TRUE(invalid.getGameEventList().isEmpty()); - } - GameEventStorage missingRecipient; - EXPECT_EQ(player->processGameCommand(randomReveal(2, 999), response, missingRecipient), Response::RespNameNotFound); - EXPECT_TRUE(missingRecipient.getGameEventList().isEmpty()); - player->setConceded(true); - GameEventStorage conceded; - EXPECT_EQ(player->processGameCommand(randomReveal(2, 1), response, conceded), Response::RespContextError); - EXPECT_TRUE(conceded.getGameEventList().isEmpty()); - player->setConceded(false); - GameCommand legacy; - auto *single = legacy.MutableExtension(Command_RevealCards::ext); - single->set_zone_name(ZoneNames::HAND); - single->add_card_id(-2); - single->set_player_id(1); - GameEventStorage legacyReveal; - EXPECT_EQ(player->processGameCommand(legacy, response, legacyReveal), Response::RespOk); - legacyReveal.sendToGame(&game); - EXPECT_EQ(target.reveals.last().cards_size(), 1); - EXPECT_EQ(owner.reveals.last().cards_size(), 0); +RNG_Abstract *rng = &firstRng; - // A reader with only the old GameCommand schema keeps the new extension unknown. - // Existing dispatch returns RespInvalidCommand; it cannot fall back to reveal-all. - google::protobuf::FileDescriptorProto file; - GameCommand::descriptor()->file()->CopyTo(&file); - auto *values = file.mutable_message_type(0)->mutable_enum_type(0)->mutable_value(); - for (int i = values->size() - 1; i >= 0; --i) { - if (values->Get(i).number() == 1036) { - values->DeleteSubrange(i, 1); - } - } - google::protobuf::DescriptorPool pool; - ASSERT_NE(pool.BuildFile(file), nullptr); - google::protobuf::FileDescriptorProto legacyRevealFile; - Command_RevealCards::descriptor()->file()->CopyTo(&legacyRevealFile); - auto *messages = legacyRevealFile.mutable_message_type(); - for (int i = messages->size() - 1; i >= 0; --i) { - if (messages->Get(i).name() == "Command_RevealRandomCards") { - messages->DeleteSubrange(i, 1); - } - } - ASSERT_NE(pool.BuildFile(legacyRevealFile), nullptr); - google::protobuf::DynamicMessageFactory factory(&pool); - std::unique_ptr old( - factory.GetPrototype(pool.FindMessageTypeByName("GameCommand"))->New()); - ASSERT_TRUE(old->ParseFromString(legacy.SerializeAsString())); - EXPECT_EQ(getPbExtension(*old), GameCommand::REVEAL_CARDS); - old->Clear(); - ASSERT_TRUE(old->ParseFromString(randomReveal(2, 1).SerializeAsString())); - EXPECT_EQ(getPbExtension(*old), -1); - GameCommand unknown; - unknown.GetReflection()->MutableUnknownFields(&unknown)->MergeFrom(old->GetReflection()->GetUnknownFields(*old)); - GameEventStorage unsupported; - EXPECT_EQ(player->processGameCommand(unknown, response, unsupported), Response::RespInvalidCommand); - EXPECT_TRUE(unsupported.getGameEventList().isEmpty()); - rng = nullptr; +int main(int argc, char **argv) +{ + QCoreApplication application(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); }