def test_exclude_candidate_with_fewest_votes(self):
        """
        Check that the method moves the candidate with the fewest vote total
        to excluded
        """
        votes = (('Chocolate', ), ('Chocolate', ), ('Chocolate', ),
                 ('Chocolate', ), ('Fruit', ), ('Fruit', ), ('Vegetables', ))

        candidates = ('Vegetables', 'Chocolate', 'Fruit')
        vacancies = 2

        expected_results = {
            'provisionally_elected': {},
            'continuing': {
                'Chocolate': 4,
                'Fruit': 2
            },
            'excluded': {
                'Vegetables': 1
            }
        }

        stv_round = Round(vacancies, candidates, votes)
        stv_round._exclude_candidates_with_fewest_votes()

        self.assertEqual(expected_results, stv_round.results())
    def test_tied_really_low_fewest_candidates_excludes_both(self):
        """
        In this case, two candidates are tied for last place but they
        have so few votes they couldn't win.
        The calculation here is - if their votes added together are not enough
        to reach the next candidate or the quota, we don't have to worry about
        who to eliminate first and can eliminate both at the same time.
        """
        votes = (('Beatles', ), ('Beatles', ), ('Beatles', ), ('Beatles', ),
                 ('Beatles', ), ('Beatles', ), ('Beatles', ), ('Beatles', ),
                 ('Beatles', ), ('Beatles', ), ('Beatles', ), ('Beatles', ),
                 ('Rolling Stones', ), ('Rolling Stones', ),
                 ('Rolling Stones', ), ('Rolling Stones', ),
                 ('Rolling Stones', ), ('Rolling Stones', ),
                 ('Rolling Stones', ), ('Rolling Stones', ),
                 ('Rolling Stones', ), ('Killers', ), ('Killers', ),
                 ('Killers', ), ('Killers', ), ('Killers', ), ('Blur', ),
                 ('Blur', ), ('Pulp', ), ('Pulp', ))

        candidates = ('Beatles', 'Rolling Stones', 'Killers', 'Blur', 'Pulp')
        vacancies = 3

        # Note that we expect them to be in continuing
        # rather than provisionally elected as we are
        # just calling the method, not the whole round
        expected_results = {
            'provisionally_elected': {},
            'continuing': {
                'Beatles': 12,
                'Rolling Stones': 9,
                'Killers': 5,
            },
            'excluded': {
                'Blur': 2,
                'Pulp': 2
            }
        }

        stv_round = Round(vacancies, candidates, votes)
        stv_round._exclude_candidates_with_fewest_votes()

        self.assertEqual(expected_results, stv_round.results())
    def test_tied_fewest_candidates_throws_Failed_Election(self):
        """
        If candidates are tied for last place, it throws a Failed
        Election error. This is the case where they are not so
        low that they can both be excluded.
        """
        votes = (('Chocolate', ), ('Chocolate', ), ('Chocolate', ),
                 ('Chocolate', ), ('Chocolate', ), ('Crisps', ), ('Crisps', ),
                 ('Crisps', ), ('Crisps', ), ('Crisps', ), ('Popcorn', ),
                 ('Popcorn', ), ('Popcorn', ), ('Popcorn', ), ('Fruit', ),
                 ('Fruit', ), ('Fruit', ), ('Vegetables', ), ('Vegetables', ),
                 ('Vegetables', ))

        candidates = ('Vegetables', 'Chocolate', 'Fruit', 'Crisps', 'Popcorn')
        vacancies = 3

        stv_round = Round(vacancies, candidates, votes)

        with self.assertRaises(FailedElectionError):
            stv_round._exclude_candidates_with_fewest_votes()