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 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_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"],
            )