424 lines
14 KiB
PHP
424 lines
14 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Game;
|
|
|
|
use App\Game\Entity\Game;
|
|
use App\Game\Entity\Player;
|
|
use App\Game\Entity\Session;
|
|
use App\Game\Entity\SessionSetting;
|
|
use App\Game\Enum\GameStatus;
|
|
use App\Game\Enum\SessionStatus;
|
|
use App\Game\Enum\SessionSettingType;
|
|
use App\Game\Service\GameDashboardService;
|
|
use App\Tech\Entity\User;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use App\Game\Repository\GameRepository;
|
|
use App\Game\Repository\SessionRepository;
|
|
use Symfony\Component\Mercure\HubInterface;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class GameDashboardServiceTest extends TestCase
|
|
{
|
|
private $entityManager;
|
|
private $gameRepository;
|
|
private $sessionRepository;
|
|
private $hub;
|
|
private $service;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->entityManager = $this->createMock(EntityManagerInterface::class);
|
|
$this->gameRepository = $this->createMock(GameRepository::class);
|
|
$this->sessionRepository = $this->createMock(SessionRepository::class);
|
|
$this->hub = $this->createMock(HubInterface::class);
|
|
|
|
$this->service = new GameDashboardService(
|
|
$this->gameRepository,
|
|
$this->sessionRepository,
|
|
$this->entityManager,
|
|
$this->hub,
|
|
'http://localhost/topic'
|
|
);
|
|
}
|
|
|
|
public function testCreateSessionDoesNotInitializeSettings(): void
|
|
{
|
|
$game = new Game();
|
|
$game->setStatus(GameStatus::OPEN);
|
|
|
|
$user = new User();
|
|
$user->setUsername('testuser');
|
|
|
|
$this->entityManager->expects($this->exactly(2))
|
|
->method('persist');
|
|
// 1. Session, 2. Player
|
|
|
|
$session = $this->service->createSession($game, $user, false);
|
|
|
|
$this->assertInstanceOf(Session::class, $session);
|
|
}
|
|
|
|
public function testJoinSessionDoesNotInitializeSettings(): void
|
|
{
|
|
$user = new User();
|
|
$user->setUsername('testuser');
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(3);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
|
|
$setting = new SessionSetting();
|
|
$setting->setSession($session);
|
|
$setting->setName(SessionSettingType::INVITE_CODE);
|
|
$setting->setValue('abc-123');
|
|
|
|
$repo = $this->createMock(\Doctrine\ORM\EntityRepository::class);
|
|
$this->entityManager->method('getRepository')
|
|
->willReturn($repo);
|
|
|
|
$repo->method('findOneBy')
|
|
->willReturn($setting);
|
|
|
|
$this->entityManager->expects($this->exactly(1))
|
|
->method('persist');
|
|
// 1. Player
|
|
|
|
$result = $this->service->joinSession('abc-123', $user);
|
|
|
|
$this->assertTrue($result);
|
|
}
|
|
|
|
public function testStartSessionAssignsScreensAndInitializesSettings(): void
|
|
{
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(2);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
$session->setStatus(\App\Game\Enum\SessionStatus::CREATED);
|
|
|
|
$user1 = new User();
|
|
$user1->setUsername('user1');
|
|
$player1 = new Player();
|
|
$player1->setUser($user1);
|
|
$session->addPlayer($player1);
|
|
|
|
$user2 = new User();
|
|
$user2->setUsername('user2');
|
|
$player2 = new Player();
|
|
$player2->setUser($user2);
|
|
$session->addPlayer($player2);
|
|
|
|
// For each player (2):
|
|
// Player (persist)
|
|
// SessionSetting (rights)
|
|
// SessionSetting (pwd)
|
|
// SessionSetting (chat tracking)
|
|
// SessionSetting (verify codes)
|
|
// SessionSetting (verification progress)
|
|
// Total = 2 * 6 = 12
|
|
// PLUS Session (persist)
|
|
// Total = 13
|
|
|
|
$this->entityManager->expects($this->exactly(13))
|
|
->method('persist');
|
|
|
|
$result = $this->service->startSession($session);
|
|
|
|
$this->assertTrue($result);
|
|
$this->assertEquals(\App\Game\Enum\SessionStatus::READY, $session->getStatus());
|
|
$this->assertNotNull($player1->getScreen());
|
|
$this->assertNotNull($player2->getScreen());
|
|
$this->assertNotEquals($player1->getScreen(), $player2->getScreen());
|
|
}
|
|
|
|
public function testStartSessionWithFourPlayers(): void
|
|
{
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(4);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
$session->setStatus(\App\Game\Enum\SessionStatus::CREATED);
|
|
|
|
for ($i = 1; $i <= 4; $i++) {
|
|
$user = new User();
|
|
$user->setUsername('user' . $i);
|
|
$player = new Player();
|
|
$player->setUser($user);
|
|
$session->addPlayer($player);
|
|
}
|
|
|
|
// For each player (4):
|
|
// Player (persist) + 5 Settings = 6 persists
|
|
// Total = 4 * 6 = 24
|
|
// PLUS Session (persist)
|
|
// Total = 25
|
|
|
|
$this->entityManager->expects($this->exactly(25))
|
|
->method('persist');
|
|
|
|
$result = $this->service->startSession($session);
|
|
|
|
$this->assertTrue($result);
|
|
foreach ($session->getPlayers() as $player) {
|
|
$this->assertNotNull($player->getScreen());
|
|
$this->assertGreaterThanOrEqual(1, $player->getScreen());
|
|
$this->assertLessThanOrEqual(4, $player->getScreen());
|
|
}
|
|
}
|
|
|
|
public function testLeaveSession(): void
|
|
{
|
|
$user = new User();
|
|
$session = new Session();
|
|
$session->setStatus(\App\Game\Enum\SessionStatus::CREATED);
|
|
$session->setTimer(0);
|
|
|
|
$player1 = new Player();
|
|
$player1->setUser($user);
|
|
$player1->setSession($session);
|
|
$session->addPlayer($player1);
|
|
|
|
$player2 = new Player();
|
|
$player2->setUser(new User());
|
|
$player2->setSession($session);
|
|
$session->addPlayer($player2);
|
|
|
|
$setting = new SessionSetting();
|
|
$setting->setPlayer($player1);
|
|
$setting->setSession($session);
|
|
$session->addSetting($setting);
|
|
|
|
$this->entityManager->expects($this->exactly(2))
|
|
->method('remove');
|
|
// 1. SessionSetting, 2. Player
|
|
|
|
$result = $this->service->leaveSession($session, $user);
|
|
|
|
$this->assertTrue($result);
|
|
$this->assertCount(1, $session->getPlayers());
|
|
}
|
|
|
|
public function testToggleReady(): void
|
|
{
|
|
$user = new User();
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(1);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
$session->setStatus(SessionStatus::READY);
|
|
|
|
$player = new Player();
|
|
$player->setUser($user);
|
|
$player->setScreen(1);
|
|
$session->addPlayer($player);
|
|
|
|
$repo = $this->createMock(\App\Game\Repository\SessionSettingRepository::class);
|
|
$this->entityManager->method('getRepository')
|
|
->willReturn($repo);
|
|
|
|
// First call: toggle ON
|
|
$repo->expects($this->atLeastOnce())
|
|
->method('getSetting')
|
|
->willReturn(null); // No setting initially
|
|
|
|
$this->entityManager->expects($this->atLeastOnce())
|
|
->method('persist')
|
|
->with($this->callback(function($entity) {
|
|
return $entity instanceof SessionSetting && $entity->getName() === SessionSettingType::READY_AT_FOR_PLAYER1;
|
|
}));
|
|
|
|
$result = $this->service->toggleReady($session, $user);
|
|
$this->assertTrue($result);
|
|
}
|
|
|
|
public function testCheckAllPlayersReadyTransitionsStatus(): void
|
|
{
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(2);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
$session->setStatus(SessionStatus::READY);
|
|
|
|
$player1 = new Player();
|
|
$player1->setScreen(1);
|
|
$session->addPlayer($player1);
|
|
|
|
$player2 = new Player();
|
|
$player2->setScreen(2);
|
|
$session->addPlayer($player2);
|
|
|
|
$repo = $this->createMock(\App\Game\Repository\SessionSettingRepository::class);
|
|
$this->entityManager->method('getRepository')
|
|
->willReturn($repo);
|
|
|
|
$setting1 = new SessionSetting();
|
|
$setting1->setName(SessionSettingType::READY_AT_FOR_PLAYER1);
|
|
$setting1->setValue((string)time());
|
|
$setting1->setPlayer($player1);
|
|
|
|
$setting2 = new SessionSetting();
|
|
$setting2->setName(SessionSettingType::READY_AT_FOR_PLAYER2);
|
|
$setting2->setValue((string)time());
|
|
$setting2->setPlayer($player2);
|
|
|
|
$repo->method('getSetting')
|
|
->willReturnCallback(function($s, $name, $p) use ($setting1, $setting2) {
|
|
if ($name === SessionSettingType::READY_AT_FOR_PLAYER1) return $setting1;
|
|
if ($name === SessionSettingType::READY_AT_FOR_PLAYER2) return $setting2;
|
|
return null;
|
|
});
|
|
|
|
$this->service->checkAllPlayersReady($session);
|
|
|
|
$this->assertEquals(SessionStatus::PLAYING, $session->getStatus());
|
|
}
|
|
|
|
public function testCheckAllPlayersReadyTimeouts(): void
|
|
{
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(2);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
$session->setStatus(SessionStatus::READY);
|
|
|
|
$player1 = new Player();
|
|
$player1->setScreen(1);
|
|
$session->addPlayer($player1);
|
|
|
|
$player2 = new Player();
|
|
$player2->setScreen(2);
|
|
$session->addPlayer($player2);
|
|
|
|
$repo = $this->createMock(\App\Game\Repository\SessionSettingRepository::class);
|
|
$this->entityManager->method('getRepository')
|
|
->willReturn($repo);
|
|
|
|
$setting1 = new SessionSetting();
|
|
$setting1->setName(SessionSettingType::READY_AT_FOR_PLAYER1);
|
|
$setting1->setValue((string)(time() - 70)); // Timed out
|
|
$setting1->setPlayer($player1);
|
|
$session->addSetting($setting1);
|
|
|
|
$repo->method('getSetting')
|
|
->willReturnCallback(function($s, $name, $p) use ($setting1) {
|
|
if ($name === SessionSettingType::READY_AT_FOR_PLAYER1) return $setting1;
|
|
return null;
|
|
});
|
|
|
|
$this->entityManager->expects($this->once())
|
|
->method('remove')
|
|
->with($setting1);
|
|
|
|
$this->entityManager->expects($this->atLeastOnce())
|
|
->method('flush');
|
|
|
|
$this->hub->expects($this->once())
|
|
->method('publish');
|
|
|
|
$this->service->checkAllPlayersReady($session);
|
|
|
|
$this->assertEquals(SessionStatus::READY, $session->getStatus());
|
|
}
|
|
|
|
public function testJoinSessionTriggersStartSessionWhenFull(): void
|
|
{
|
|
$user = new User();
|
|
$user->setUsername('testuser');
|
|
$game = new Game();
|
|
$game->setNumberOfPlayers(2);
|
|
$session = new Session();
|
|
$session->setGame($game);
|
|
$session->setStatus(\App\Game\Enum\SessionStatus::CREATED);
|
|
|
|
$existingUser = new User();
|
|
$existingUser->setUsername('existing');
|
|
$existingPlayer = new Player();
|
|
$existingPlayer->setUser($existingUser);
|
|
$session->addPlayer($existingPlayer);
|
|
|
|
$setting = new SessionSetting();
|
|
$setting->setSession($session);
|
|
$setting->setName(SessionSettingType::INVITE_CODE);
|
|
$setting->setValue('abc-123');
|
|
|
|
$repo = $this->createMock(\Doctrine\ORM\EntityRepository::class);
|
|
$this->entityManager->method('getRepository')
|
|
->willReturn($repo);
|
|
|
|
$repo->method('findOneBy')
|
|
->willReturn($setting);
|
|
|
|
// Expectation:
|
|
// 1. Persist new Player
|
|
// 2. Persist Player 1 (existing) screen update
|
|
// 3. Persist Player 2 (new) screen update
|
|
// 4. Persist Session status update
|
|
// 5. 5 Settings for Player 1
|
|
// 6. 5 Settings for Player 2
|
|
// Total = 1 + 1 + 1 + 1 + 5 + 5 = 14 persists
|
|
$this->entityManager->expects($this->exactly(14))
|
|
->method('persist');
|
|
|
|
$result = $this->service->joinSession('abc-123', $user);
|
|
|
|
$this->assertTrue($result);
|
|
$this->assertEquals(\App\Game\Enum\SessionStatus::READY, $session->getStatus());
|
|
}
|
|
|
|
public function testLeaveSessionRevertsFromReady(): void
|
|
{
|
|
$user = new User();
|
|
$user->setUsername('testuser');
|
|
$session = new Session();
|
|
$session->setStatus(\App\Game\Enum\SessionStatus::READY);
|
|
$session->setTimer(0);
|
|
|
|
$player1 = new Player();
|
|
$player1->setUser($user);
|
|
$player1->setScreen(1);
|
|
$player1->setSession($session);
|
|
$session->addPlayer($player1);
|
|
|
|
$player2 = new Player();
|
|
$player2->setUser(new User());
|
|
$player2->setScreen(2);
|
|
$player2->setSession($session);
|
|
$session->addPlayer($player2);
|
|
|
|
$this->entityManager->expects($this->exactly(1))
|
|
->method('remove');
|
|
// 1. Player1, any settings (none in this test setup)
|
|
|
|
$result = $this->service->leaveSession($session, $user);
|
|
|
|
$this->assertTrue($result);
|
|
$this->assertEquals(\App\Game\Enum\SessionStatus::CREATED, $session->getStatus());
|
|
$this->assertNull($player2->getScreen());
|
|
}
|
|
|
|
public function testCreateSessionForOnePlayerGame(): void
|
|
{
|
|
$game = new Game();
|
|
$game->setStatus(GameStatus::OPEN);
|
|
$game->setNumberOfPlayers(1);
|
|
|
|
$user = new User();
|
|
$user->setUsername('testuser');
|
|
|
|
// 1. Session persist
|
|
// 2. Player persist
|
|
// 3. Player screen persist (during startSession)
|
|
// 4. Session status persist (during startSession)
|
|
// 5. 5 Settings for Player (during startSession)
|
|
// Total = 1 + 1 + 1 + 1 + 5 = 9 persists
|
|
$this->entityManager->expects($this->exactly(9))
|
|
->method('persist');
|
|
|
|
$session = $this->service->createSession($game, $user, false);
|
|
|
|
$this->assertInstanceOf(Session::class, $session);
|
|
$this->assertEquals(\App\Game\Enum\SessionStatus::READY, $session->getStatus());
|
|
}
|
|
}
|