def test_randomly_pairs_empty_teams(self):
        teams = [get_team(x, 0, 0, 0, 0, 0) for x in range(100)]

        pairings_1 = generate_round(1, teams, "Heads")
        pairings_2 = generate_round(1, teams, "Heads")

        serialized_1 = self.serialize_pairings(pairings_1)
        serialized_2 = self.serialize_pairings(pairings_2)

        # Chance these aren't equal < 1/10^156
        self.assertNotEqual(serialized_1, serialized_2)
    def test_coin_flip_determines_sides(self):
        teams = [
            get_team(8 - team_num, wins=team_num // 2, ties=team_num % 2)
            for team_num in range(0, 8)
        ]

        self.pairings = generate_round(3, teams, "Tails", "Tails")

        self.assertPairingExists(2, 1, True)
        self.assertPairingExists(3, 4, True)

        self.pairings = generate_round(3, teams, "Heads", "Heads")

        self.assertPairingExists(1, 2, True)
        self.assertPairingExists(4, 3, True)
    def test_uses_pd_tie_breaker(self):
        teams = [get_team(0, wins=4)]
        teams.extend(
            get_team(team_num, wins=2, pd=8) for team_num in range(2, 50))
        teams.append(get_team(1, wins=2, pd=16))

        self.pairings = generate_round(1, teams, "Heads")
        self.assertPairingExists(0, 1)
    def test_real_rounds(self):
        for true_round in true_rounds:
            with self.subTest(true_round['name']):
                self.pairings = generate_round(true_round['round'],
                                               true_round['teams'],
                                               true_round['coin_flip'],
                                               true_round['r3_coin_flip'])

                for [p, d] in true_round["true_pairs"]:
                    self.assertPairingExists(p, d, enforce_sides=True)
    def test_coin_flip_determines_rank(self):
        teams = [
            get_team(1, wins=4),
            get_team(2, wins=2),
            get_team(3, wins=2),
            get_team(4, wins=0),
        ]

        with self.subTest("Heads"):
            for i in range(10):  # Ensure it is deterministic
                self.pairings = generate_round(3, teams, "Heads")
                self.assertPairingExists(1, 3)
                self.assertPairingExists(2, 4)

        with self.subTest("Tails"):
            for i in range(10):
                self.pairings = generate_round(3, teams, "Tails")
                self.assertPairingExists(1, 2)
                self.assertPairingExists(3, 4)
    def test_accounts_for_ties(self):
        teams = [
            get_team(0, wins=4),
            get_team(1, wins=1, ties=3),
            get_team(2, wins=2, losses=2),
            get_team(3, losses=4),
        ]

        self.pairings = generate_round(1, teams, "Heads")

        self.assertPairingExists(0, 1)
    def test_always_pairs_bye_bust_last(self):
        teams = [
            get_team(1, wins=1, losses=1),
            get_team(2, wins=1, losses=1),
            get_team(3, losses=2),
            get_team(4, wins=2, bye_bust=True)
        ]

        self.pairings = generate_round(1, teams, "Heads")

        self.assertPairingExists(1, 2)
        self.assertPairingExists(3, 4)
    def test_pairs_high_high(self):
        # Teams from 1 - 8, where team 01 has 4 losses, team 2 has 3 losses and a tie, team 3 with 3 losses and a win, etc. (#/2 ballots)
        teams = [
            get_team(x, wins=x // 2, ties=x % 2, losses=(4 - x // 2 - x % 2))
            for x in range(8)
        ]

        self.pairings = generate_round(1, teams, "Heads")

        for (team_1, team_2) in zip(range(0, 8, 2), range(1, 8, 2)):
            with self.subTest(teams=(team_1, team_2)):
                self.assertPairingExists(team_1, team_2)
    def test_calls_resolve_impermissibles(self):
        teams = [
            get_team(1, wins=2, past_pairings=[2]),
            get_team(2, wins=1, ties=1, past_pairings=[1]),
            get_team(3, losses=1, ties=1, past_pairings=[4]),
            get_team(4, losses=2, past_pairings=[3])
        ]

        self.pairings = generate_round(3, teams, "Heads")

        self.assertPairingExists(1, 3)
        self.assertPairingExists(4, 2)
    def test_snakes_teams_in_round_3(self):
        teams = [
            get_team(0, wins=4),
            get_team(1, wins=2, ties=1, losses=1),
            get_team(2, wins=1, ties=1, losses=2),
            get_team(3, losses=4)
        ]

        self.pairings = generate_round(3, teams, "Heads")

        self.assertPairingExists(0, 1, True)
        self.assertPairingExists(3, 2, True)
    def test_handles_fractions(self):
        teams = [
            get_team(0, wins=2),
            get_team(1, wins=Fraction(4, 3), losses=Fraction(2, 3)),
            get_team(2, wins=Fraction(2, 3), losses=Fraction(4, 2)),
            get_team(3, losses=2)
        ]

        self.pairings = generate_round(1, teams, "Heads")

        self.assertPairingExists(0, 1)
        self.assertPairingExists(2, 3)
    def test_pairs_pl_and_def(self):
        teams = [
            get_team(0, wins=1, side=Side.PI),
            get_team(1, wins=1, side=Side.PI),
            get_team(2, losses=1, side=Side.DEF),
            get_team(3, losses=1, side=Side.DEF)
        ]

        for i in range(10):
            self.pairings = generate_round(2, teams, "Heads")

            self.assertPairingExists(0, 2, True)
            self.assertPairingExists(1, 3, True)
    def test_snakes_r1_as_pl_in_r3(self):
        teams = [
            get_team(0, wins=4),
            get_team(1, wins=3),
            get_team(2, wins=2, ties=1),
            get_team(3, wins=1, ties=1),
            get_team(4, wins=1),
            get_team(5)
        ]

        self.pairings = generate_round(3, teams, "Heads")

        self.assertPairingExists(0, 1, True)
        self.assertPairingExists(3, 2, True)
        self.assertPairingExists(4, 5, True)
    def test_pairs_teams(self):
        teams = [get_team(1), get_team(2)]

        self.pairings = generate_round(1, teams, "Heads")

        self.assertPairingExists(1, 2)