def test_organ_repeated(self): """ Se prueba que no se pueda colocar un órgano repetido en el cuerpo. """ b = Body() b.piles[1].set_organ(Organ(color=Color.Red)) test_cases = [ { "organ": Organ(color=Color.Red), "body": Body.from_data(piles=[ OrganPile(), OrganPile.from_data(organ=Organ(color=Color.Red)), OrganPile(), OrganPile(), ]), "can_place": False, }, { "organ": Organ(color=Color.Green), "body": Body.from_data(piles=[ OrganPile(), OrganPile.from_data(organ=Organ(color=Color.Red)), OrganPile.from_data(organ=Organ(color=Color.Blue)), OrganPile(), ]), "can_place": True, }, { "organ": Organ(color=Color.All), "body": Body.from_data(piles=[ OrganPile(), OrganPile.from_data(organ=Organ(color=Color.Red)), OrganPile.from_data(organ=Organ(color=Color.Blue)), OrganPile(), ]), "can_place": True, }, ] for test in test_cases: self.check_can_place( target_body=test["body"], card=test["organ"], place_in_self=True, can_place=test["can_place"], )
def test_player_finished(self): """ Comprueba que si se reconoce cuando un jugador gana una partida. """ b = Body() b.piles[1].set_organ(Organ(color=Color.Red)) b.piles[2].set_organ(Organ(color=Color.Green)) b.piles[3].set_organ(Organ(color=Color.Blue)) callback_args, response, turn_player = self.place_card( target_body=b, card=Organ(color=Color.Yellow), place_in_self=True, ) self.assertNotIn("error", callback_args) _, args = self.get_msg_in_received(response, "game_update", json=True) self.assertIn("leaderboard", args) self.assertIn(turn_player.name, args["leaderboard"])
def infected_organ(color: Color, virus_color: Color = None) -> OrganPile: if virus_color is None: virus_color = color return OrganPile.from_data( organ=Organ(color=color), modifiers=[ Virus(color=virus_color), ], )
def test_organ_on_others(self): """ Se prueba que no se pueda colocar un órgano en el cuerpo de otro jugador. """ self.check_can_place( target_body=Body(), card=Organ(color=Color.Red), place_in_self=False, can_place=False, )
def test_interactions_immunize(self): """ Se prueba a inmunizar un órgano. """ card_order = [ Organ(color=Color.Red), Medicine(color=Color.Red), Medicine(color=Color.Red), ] expected_pile_states = [ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, # Se protege el órgano { "modifiers": [{ "card_type": "medicine", "color": "red" }], "organ": { "card_type": "organ", "color": "red" }, }, # Se inmuniza el órgano { "modifiers": [ { "card_type": "medicine", "color": "red" }, { "card_type": "medicine", "color": "red" }, ], "organ": { "card_type": "organ", "color": "red" }, }, ] self.check_card_interactions(card_order, expected_pile_states)
def test_virus_on_self(self): """ Se prueba que no se pueda colocar un virus a ti mismo, para evitar errores de los jugadores. """ b = Body() b.piles[0].set_organ(Organ(color=Color.Red)) self.check_can_place( target_body=b, card=Virus(color=Color.Red), place_in_self=True, can_place=False, )
def test_medicine_on_others(self): """ Se prueba que no se pueda colocar una vacuna a otro jugador, para evitar errores de los jugadores. """ b = Body() b.piles[0].set_organ(Organ(color=Color.Red)) self.check_can_place( target_body=b, card=Medicine(color=Color.Red), place_in_self=False, can_place=False, )
def test_interactions_medicine_destroy(self): """ Se prueba a destruir una vacuna. """ card_order = [ Organ(color=Color.Red), Medicine(color=Color.Red), Virus(color=Color.Red), ] expected_pile_states = [ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, # Se protege el órgano { "modifiers": [{ "card_type": "medicine", "color": "red" }], "organ": { "card_type": "organ", "color": "red" }, }, # Se destruye la medicina { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, ] self.check_card_interactions(card_order, expected_pile_states)
def test_interactions_cure(self): """ Se prueba a colocar un órgano, infectarlo y curarlo. """ card_order = [ Organ(color=Color.Red), Virus(color=Color.Red), Medicine(color=Color.Red), ] expected_pile_states = [ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, # Se infecta el órgano { "modifiers": [{ "card_type": "virus", "color": "red" }], "organ": { "card_type": "organ", "color": "red" }, }, # Se cura el órgano con la medicina { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, ] self.check_card_interactions(card_order, expected_pile_states)
def test_interactions_remove(self): """ Se prueba a extirpar un órgano. """ card_order = [ Organ(color=Color.Red), Virus(color=Color.Red), Virus(color=Color.Red), ] expected_pile_states = [ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, # Se infecta el órgano { "modifiers": [{ "card_type": "virus", "color": "red" }], "organ": { "card_type": "organ", "color": "red" }, }, # Se extirpa el órgano { "modifiers": [], "organ": None }, ] self.check_card_interactions(card_order, expected_pile_states)
def test_return_to_deck(self): """ Se comprueba que las cartas se devuelven a la baraja. En este test también se comprueba que las cartas usadas no dan problemas por tener parámetros incorrectos. """ TOTAL_CARDS = 30 # Generamos una baraja custom antes de que empiece la partida y se # repartan las cartas. custom_deck = [ Virus(color=Color.Red), Virus(color=Color.Red), Medicine(color=Color.Red), LatexGlove(), ] # Rellenamos las restantes con órganos. NOTE: no hacen falta 68 cartas # solo para 2 jugadores. for i in range(TOTAL_CARDS - 4): custom_deck.append(Organ(color=Color.Red)) self.set_custom_deck(custom_deck) def try_invalid(client, slot, pile_slot, target) -> None: payload = { "slot": slot, "organ_pile": pile_slot, "target": target, } items = payload.items() # Faltan de 1 a 3 campos for length in range(3): for payload in permutations(items, length): callback_args = client.emit("play_card", dict(payload), callback=True) self.assertIn("error", callback_args) # Tipos inválidos callback_args = client.emit("play_card", {"target": True}, callback=True) self.assertIn("error", callback_args) def try_use(slot, pile_cond, search_in, target) -> bool: pile_slot = None for (p_slot, pile) in enumerate(player.body.piles): if pile_cond(pile): pile_slot = p_slot break if pile_slot is not None: # Primero intenta las opciones inválidas try_invalid(client, slot, pile_slot, target) callback_args = client.emit( "play_card", { "slot": slot, "organ_pile": pile_slot, "target": target, }, callback=True, ) self.assertNotIn("error", callback_args) return pile_slot is not None clients, code = self.create_game(players=2) game = MM.get_match(code)._game game._turn = 0 def total_cards() -> int: count = len(game.deck) for player in game.players: count += len(player.hand) for pile in player.body.piles: if pile.is_empty(): continue count += 1 + len(pile.modifiers) return count # Ignoramos todos los mensajes anteriores for client in clients: _ = client.get_received() clients_order = list( map(lambda p: self.player_names.index(p.name), game.players)) for i in range(100): # Evitamos problemas con los saltos de turno p = game._turn self.assertEqual(total_cards(), TOTAL_CARDS) which_client = clients_order[p] client = clients[which_client] player = game.players[p] other_player = game.players[(p + 1) % 2] card_types = list(map(lambda c: c.card_type, player.hand)) if "treatment" in card_types: slot = card_types.index("treatment") callback_args = client.emit("play_card", {"slot": slot}, callback=True) self.assertNotIn("error", callback_args) continue if "organ" in card_types: slot = card_types.index("organ") if player.body.organ_unique(player.hand[slot]): if try_use( slot=slot, search_in=player.body.piles, pile_cond=lambda p: p.is_empty(), target=player.name, ): continue if "virus" in card_types: slot = card_types.index("virus") if try_use( slot=slot, search_in=other_player.body.piles, pile_cond=lambda p: not p.is_empty(), target=other_player.name, ): continue if "medicine" in card_types: slot = card_types.index("medicine") if try_use( slot=slot, search_in=player.body.piles, pile_cond=lambda p: not p.is_empty(), target=player.name, ): continue # Descartamos todas las cartas for i in reversed(range(3)): callback_args = client.emit("play_discard", i, callback=True) self.assertNotIn("error", callback_args) callback_args = client.emit("play_pass", callback=True) self.assertNotIn("error", callback_args)
def organ(color: Color) -> OrganPile: return OrganPile.from_data(organ=Organ(color=color))
def test_treatment_infection(self): """ Se prueba a usar el tratamiento Contagio. """ clients, code = self.create_game(players=3) # Primero se tendrá el game_update inicial received = clients[0].get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) self.assertNotIn("error", args) game = MM.get_match(code)._game # Forzamos el turno al client 0 game._turn = 0 def organ(color: Color) -> OrganPile: return OrganPile.from_data(organ=Organ(color=color)) def infected_organ(color: Color, virus_color: Color = None) -> OrganPile: if virus_color is None: virus_color = color return OrganPile.from_data( organ=Organ(color=color), modifiers=[ Virus(color=virus_color), ], ) bodies = [ { "have": [ infected_organ(Color.Yellow), infected_organ(Color.Red, virus_color=Color.All), infected_organ(Color.Blue), # El virus de este no se debería colocar en ningún sitio infected_organ(Color.Green), ], "expected": [ organ(Color.Yellow), organ(Color.Red), organ(Color.Blue), infected_organ(Color.Green), ], }, { "have": [ # No se debería colocar en esta infected_organ(Color.Green, virus_color=Color.All), OrganPile(), organ(Color.Blue), # Se debería colocar el multicolor organ(Color.Red), ], "expected": [ infected_organ(Color.Green, virus_color=Color.All), OrganPile(), infected_organ(Color.Blue), infected_organ(Color.Red, virus_color=Color.All), ], }, { "have": [ OrganPile(), # No se debería colocar en este OrganPile.from_data( organ=Organ(color=Color.Green), modifiers=[Medicine(color=Color.Green)], ), OrganPile(), organ(Color.Yellow), ], "expected": [ OrganPile(), OrganPile.from_data( organ=Organ(color=Color.Green), modifiers=[Medicine(color=Color.Green)], ), OrganPile(), infected_organ(Color.Yellow), ], }, ] clients_order = list( map(lambda p: self.player_names.index(p.name), game.players)) # Para todos los clientes, inicializamos su cuerpo al cuerpo de pruebas # y le damos la carta de contagio al cliente 0. for (i, which_client) in enumerate(clients_order): client = clients[which_client] player = game.players[i] if which_client == 0: player.hand[0] = Infection() player.body = Body.from_data(piles=bodies[i]["have"]) # Ignoramos los eventos anteriores con los clientes for client in clients: _ = client.get_received() # Usamos la carta desde el cliente 0 callback_args = clients[0].emit("play_card", {"slot": 0}, callback=True) self.assertNotIn("error", callback_args) # Comprobamos que todos los clientes reciben los cuerpos esperados. for (i, which_client) in enumerate(clients_order): client = clients[which_client] player = game.players[i] received = client.get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) self.assertNotIn("error", args) self.assertIn("bodies", args) self.assertIn(player.name, args["bodies"]) expected = list( map( lambda b: asdict(b, dict_factory=asdict_factory_enums), bodies[i]["expected"], )) self.assertEqual(args["bodies"][player.name], expected)
def test_treatment_organ_thief(self): """ Se prueba a usar el tratamiento Ladrón de órganos. """ clients, code = self.create_game() caller_name = GENERIC_USERS_NAME.format(0) target_name = GENERIC_USERS_NAME.format(1) game = MM.get_match(code)._game # Forzamos el turno al client 0 game._turn = 0 caller_player = game.players[game._turn] target_player = game.players[(game._turn + 1) % 2] caller_player.hand[0] = OrganThief() caller_player.body = Body.from_data(piles=[ OrganPile(), OrganPile.from_data(organ=Organ(color=Color.Red)), OrganPile.from_data( organ=Organ(color=Color.Blue), modifiers=[ Virus(color=Color.Blue), ], ), OrganPile(), ]) target_player.body = Body.from_data(piles=[ OrganPile.from_data(organ=Organ(color=Color.Green)), OrganPile(), OrganPile.from_data( organ=Organ(color=Color.Yellow), modifiers=[ Virus(color=Color.Yellow), ], ), OrganPile(), ]) # Guardamos en el cliente el cuerpo anterior clients[1].last_pile = asdict(target_player.body)["piles"][2] # Ignoramos los eventos anteriores con todos los clientes for client in clients: _ = client.get_received() # Usamos la carta desde el cliente 0 callback_args = clients[0].emit( "play_card", { "slot": 0, "target": target_name, "organ_pile": 2, }, callback=True, ) self.assertNotIn("error", callback_args) # Comprobamos que todos los clientes reciben los cuerpos intercambiados. for client in clients: received = client.get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) self.assertNotIn("error", args) self.assertIn("bodies", args) self.assertIn(caller_name, args["bodies"]) self.assertIn(target_name, args["bodies"]) self.assertEqual(args["bodies"][caller_name][0], clients[1].last_pile) self.assertEqual(args["bodies"][target_name][2], asdict(OrganPile()))
def test_treatment_medical_error(self): """ Se prueba a usar el tratamiento Error Médico. """ clients, code = self.create_game() caller_name = GENERIC_USERS_NAME.format(0) target_name = GENERIC_USERS_NAME.format(1) # Primero se tendrá el game_update inicial received = clients[0].get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) self.assertNotIn("error", args) game = MM.get_match(code)._game # Forzamos el turno al client 0 game._turn = 0 caller_player = game.players[game._turn] caller_player.hand[0] = MedicalError() caller_player.body = Body.from_data(piles=[ OrganPile(), OrganPile.from_data(organ=Organ(color=Color.Red)), OrganPile.from_data( organ=Organ(color=Color.Blue), modifiers=[ Virus(color=Color.Blue), ], ), OrganPile(), ]) clients[0].last_body = asdict(caller_player.body)["piles"] # Ignoramos los eventos anteriores con el target received = clients[1].get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) # Guardamos en el cliente el cuerpo anterior clients[1].last_body = asdict(Body())["piles"] # Ignoramos los eventos anteriores con el resto de los clientes for client in clients[2:]: _ = client.get_received() # Usamos la carta desde el cliente 0 callback_args = clients[0].emit( "play_card", { "slot": 0, "target": target_name, }, callback=True, ) self.assertNotIn("error", callback_args) # Comprobamos que todos los clientes reciben los cuerpos intercambiados. for client in clients: received = client.get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) self.assertNotIn("error", args) self.assertIn("bodies", args) self.assertIn(caller_name, args["bodies"]) self.assertIn(target_name, args["bodies"]) self.assertEqual(args["bodies"][caller_name], clients[1].last_body) self.assertEqual(args["bodies"][target_name], clients[0].last_body)
def test_player_leaderboard(self): """ Se comprueba la recepción del leaderboard cuando todos los jugadores han acabado. """ TOTAL_CARDS = 68 # Generamos una baraja custom antes de que empiece la partida y se # repartan las cartas. Todas las cartas serán órganos para solo permitir # ganar la partida. custom_deck = [] for i in range(int(TOTAL_CARDS / 4)): custom_deck.append(Organ(color=Color.Red)) custom_deck.append(Organ(color=Color.Green)) custom_deck.append(Organ(color=Color.Blue)) custom_deck.append(Organ(color=Color.Yellow)) self.set_custom_deck(custom_deck) def try_use(slot, pile_cond, search_in, target) -> bool: pile_slot = None for (p_slot, pile) in enumerate(player.body.piles): if pile_cond(pile): pile_slot = p_slot break if pile_slot is not None: callback_args = client.emit( "play_card", { "slot": slot, "organ_pile": pile_slot, "target": target, }, callback=True, ) self.assertNotIn("error", callback_args) return pile_slot is not None clients, code = self.create_game() game = MM.get_match(code)._game game._turn = 0 # Ignoramos todos los mensajes anteriores for client in clients: _ = client.get_received() clients_order = list( map(lambda p: self.player_names.index(p.name), game.players) ) players_finished = [] leaderboards_received = 0 for i in range(100): # Evitamos problemas con los saltos de turno p = game._turn which_client = clients_order[p] client = clients[which_client] player = game.players[p] # Tratamos de colocar alguno de los órganos could_place = False for (slot, organ) in enumerate(player.hand): if player.body.organ_unique(player.hand[slot]): if try_use( slot=slot, search_in=player.body.piles, pile_cond=lambda p: p.is_empty(), target=player.name, ): could_place = True break # Si no hemos podido colocar un órgano, descartamos toda la mano if not could_place: # Descartamos todas las cartas for i in reversed(range(3)): callback_args = client.emit("play_discard", i, callback=True) self.assertNotIn("error", callback_args) callback_args = client.emit("play_pass", callback=True) self.assertNotIn("error", callback_args) # Obtenemos el game_update received = clients[0].get_received() _, args = self.get_msg_in_received(received, "game_update", json=True) if args.get("leaderboard") is not None: # Si hemos recibido el leaderboard, es porque el jugador actual # ha acabado. players_finished.append(player.name) leaderboards_received += 1 # Debería estar su nombre en la clasificación. self.assertIn(player.name, args["leaderboard"]) # Si hemos contado 5 jugadores finalizados, deberíamos haber # recibido también el finished y el playtime_mins. if len(players_finished) == 5: self.assertIn("finished", args) self.assertIn("playtime_mins", args) self.assertEqual(args["finished"], True) expected_leaderboard = dict() for player in game.players: if player.name not in players_finished: players_finished.append(player.name) for (pos, player) in enumerate(players_finished): pos = pos + 1 expected_leaderboard[player] = { "position": pos, "coins": 10 * (6 - pos), } self.assertEqual(args["leaderboard"], expected_leaderboard) break # Comprobamos que realmente ha acabado la partida self.assertEqual(len(players_finished), 6) # Y que se han recibido todos los leaderboards esperados self.assertEqual(leaderboards_received, 5)
def test_interactions_cure_multicolored(self): """ Se prueba a colocar un órgano, infectarlo y curarlo alternando cartas multicolor. """ self.check_card_interactions( card_order=[ Organ(color=Color.All), Virus(color=Color.Red), Medicine(color=Color.Red), ], expected_pile_states=[ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "all" } }, # Se infecta el órgano { "modifiers": [{ "card_type": "virus", "color": "red" }], "organ": { "card_type": "organ", "color": "all" }, }, # Se cura el órgano con la medicina { "modifiers": [], "organ": { "card_type": "organ", "color": "all" } }, ], ) self.check_card_interactions( card_order=[ Organ(color=Color.Red), Virus(color=Color.All), Medicine(color=Color.Green), ], expected_pile_states=[ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, # Se infecta el órgano { "modifiers": [{ "card_type": "virus", "color": "all" }], "organ": { "card_type": "organ", "color": "red" }, }, # Se cura el órgano con la medicina { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, ], ) self.check_card_interactions( card_order=[ Organ(color=Color.Red), Virus(color=Color.Red), Medicine(color=Color.All), ], expected_pile_states=[ # Se coloca el órgano en la pila { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, # Se infecta el órgano { "modifiers": [{ "card_type": "virus", "color": "red" }], "organ": { "card_type": "organ", "color": "red" }, }, # Se cura el órgano con la medicina { "modifiers": [], "organ": { "card_type": "organ", "color": "red" } }, ], )