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()); } }