Cockatrice/tests/command_zone_tests/new_counter_id_test.cpp
DawnFire42 bc09a19b50
Wire command zone menu, harden counter command handling, and expand tests
- Connect aMoveToCommandZone to cmMoveToCommandZone; the menu item was
    added, shown, and shortcut-bound but never wired, so it did nothing
  - Extract evaluateModifyCounter() and route cmdIncCounter/cmdSetCounter
    through it, replacing isCommandZoneCounterBlocked; reject inc/set on
    an inactive tax counter so a hidden counter cannot accumulate value
  - Reject reserved tax counter names in cmdCreateCounter to prevent a
    client from spoofing a system tax counter via a user-created counter
  - Route AbstractCounter::valueChanged through the virtual setValue() so
    CommanderTaxCounter clamps and refreshes its tooltip on value changes
  - Deduplicate actPlayAndIncreaseTax/actPlayAndIncreasePartnerTax into a
    single playAndIncreaseTax(counterId) helper
  - Move MINIMUM_STACKING_HEIGHT from CommandZone to the PlayerGraphicsItem
    layout code, its only consumer
  - Remove unused AbstractCounter forward declaration from player_logic.h
  - Add EvaluateModifyCounter tests and PartnerTax cases for
    evaluateSetCounterActive
  - Pin the FirstUserId floor in new_counter_id_test using ids 3 and 5 so
    a naive "highest id + 1" regression fails the test
2026-06-30 09:30:29 -04:00

78 lines
2.9 KiB
C++

#include "../movecard_tests/server_test_helpers.h"
#include "game/server_counter.h"
#include "game/server_game.h"
#include "game/server_player.h"
#include "server_room.h"
#include <gtest/gtest.h>
#include <libcockatrice/protocol/pb/color.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <libcockatrice/rng/rng_abstract.h>
#include <libcockatrice/utility/counter_ids.h>
RNG_Abstract *rng = nullptr; // required by linked server code
namespace
{
// Wires up a Server_Player backed by a minimal fake game so that counters can be
// added directly via addCounter() to exercise newCounterId() in isolation.
// newCounterId() depends only on the player's counter map, not on game state,
// so the game never needs to be started.
struct PlayerFixture
{
ServerInfo_User user;
FakeServer server;
Server_Room room{0, 0, "", "", "", "", false, "", {}, &server};
Server_Game game{user, 1, "", "", 2, QList<int>(), false, false,
false, false, false, false, 20, false, false, &room};
Server_Player player{&game, 1, user, false, nullptr};
~PlayerFixture()
{
player.clearZones(); // owns and deletes any counters added during the test
}
};
} // namespace
// With no counters at all, the first allocated id must be FirstUserId, never 0.
TEST(NewCounterId, ReturnsFirstUserIdWhenNoCounters)
{
PlayerFixture f;
EXPECT_EQ(f.player.newCounterId(), CounterIds::FirstUserId);
}
// Reserved ids must not drag a new user counter down into the reserved range. The
// ids here (3 and 5) are chosen so a naive "highest id + 1" implementation would
// return 6 (inside the reserved range) and fail this test; only the FirstUserId
// floor yields the correct 10, so this pins the floor against regression.
TEST(NewCounterId, SkipsReservedRangeWhenOnlyReservedCountersExist)
{
PlayerFixture f;
f.player.addCounter(new Server_Counter(3, "g", color(), 20, 0));
f.player.addCounter(new Server_Counter(5, "h", color(), 20, 0));
EXPECT_EQ(f.player.newCounterId(), CounterIds::FirstUserId);
}
// Once user counters exist, the next id is one above the highest of them.
TEST(NewCounterId, ReturnsNextIdAboveHighestUserCounter)
{
PlayerFixture f;
f.player.addCounter(new Server_Counter(CounterIds::FirstUserId, "a", color(), 20, 0)); // 10
f.player.addCounter(new Server_Counter(15, "b", color(), 20, 0));
EXPECT_EQ(f.player.newCounterId(), 16);
}
// A reserved counter present alongside user counters must not affect the result.
TEST(NewCounterId, IgnoresReservedCountersWhenUserCountersPresent)
{
PlayerFixture f;
f.player.addCounter(new Server_Counter(5, "r", color(), 20, 0)); // reserved range
f.player.addCounter(new Server_Counter(11, "user", color(), 20, 0)); // user range
EXPECT_EQ(f.player.newCounterId(), 12);
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}