diff --git a/tests/test_entities_smoke.cpp b/tests/test_entities_smoke.cpp index abaeac3..ff6e938 100644 --- a/tests/test_entities_smoke.cpp +++ b/tests/test_entities_smoke.cpp @@ -22,6 +22,10 @@ // sprite sencer (pixel_rect). // T13 mummy step — camina en línia recta pel playfield i gira en topar // un mur (insidePlayfield=false) o sarc (Map::collides). +// T14 exited aggregator — EntityManager compta `player_exited` i emet +// `level_complete` quan iguala `expected_players`. Verifica +// idempotència (3r event no re-emet) i reset del comptador +// via `setExpectedPlayerCount` (cicle següent torna a emetre). // // Execució (des de la ruta del repo): // make build && cd build && ctest --output-on-failure @@ -449,6 +453,46 @@ namespace { REQUIRE(torch.getAnimation()->currentFrame() == 2); } + void testExitedAggregator() { + std::cout << "[T14] EntityManager: player_exited → level_complete\n"; + EntityManager manager; + + // Comptador inicialitzat per a 2 jugadors. Sense aquesta crida, + // l'agregador no faria res (expected_players_ = 0). + manager.setExpectedPlayerCount(2); + + int level_complete_count = 0; + manager.getBus().subscribe("level_complete", [&](const Event& ev) { + ++level_complete_count; + // Event d'agregat: no atribuïble a un jugador concret. + REQUIRE(ev.player_id == -1); + }); + + // Primer player_exited: comptador a 1 < 2, no emet encara. + manager.getBus().publish(Event{.name = "player_exited", .payload = std::monostate{}, .player_id = 0}); + REQUIRE(manager.exitedPlayerCount() == 1); + REQUIRE(level_complete_count == 0); + + // Segon player_exited: comptador a 2 == expected, emet una vegada. + manager.getBus().publish(Event{.name = "player_exited", .payload = std::monostate{}, .player_id = 1}); + REQUIRE(manager.exitedPlayerCount() == 2); + REQUIRE(level_complete_count == 1); + + // Un tercer player_exited (no hauria de passar amb 2 jugadors, + // però defensa contra publicacions extra): no torna a emetre. + manager.getBus().publish(Event{.name = "player_exited", .payload = std::monostate{}, .player_id = 0}); + REQUIRE(level_complete_count == 1); + + // setExpectedPlayerCount torna a obrir el cicle (això simularia + // el que fa GameScene després d'un reload de sala). El comptador + // d'EXITED es reinicia a 0 i el flag d'emissió també. + manager.setExpectedPlayerCount(2); + REQUIRE(manager.exitedPlayerCount() == 0); + manager.getBus().publish(Event{.name = "player_exited", .payload = std::monostate{}, .player_id = 0}); + manager.getBus().publish(Event{.name = "player_exited", .payload = std::monostate{}, .player_id = 1}); + REQUIRE(level_complete_count == 2); // segon cicle ha emès una vegada més + } + } // namespace auto main() -> int { @@ -467,6 +511,7 @@ auto main() -> int { testCollisionBox(); testMummyStep(); testTorchAnimation(); + testExitedAggregator(); if (g_failures == 0) { std::cout << "ALL OK\n";