def testCompareFile(self): "normal init from file: 2 seats" path = testdir + '/blt/42.blt' pd = ElectionProfile(data=p_42) pp = ElectionProfile(path) self.assertFalse(pp.compare(pd), 'compare election 42 from file vs data blob')
def testDefeatBatch(self): "tag is name of rule" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), dict(rule='wigm-prf')) self.assertEqual(E.rule.tag(), 'wigm-prf') E = Election(ElectionProfile(data=b), dict(rule='wigm-prf-batch')) self.assertEqual(E.rule.tag(), 'wigm-prf-batch')
def testInitTitle(self): "normal init: title set" t1 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' t2 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie" junk''' self.assertEqual( ElectionProfile(data=t1).title, 'Pollux and Helen should tie') self.assertEqual( ElectionProfile(data=t2).title, 'Pollux and Helen should tie')
def testDroopOptions(self): "test [droop ...]" if 'meek' in droop.electionRuleNames(): b = '''3 2 [droop arithmetic=fixed precision=4] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), dict(rule='meek')) self.assertEqual(E.V.precision, 4) E = Election(ElectionProfile(data=b), dict(rule='meek', precision=6)) self.assertEqual(E.V.precision, 6) b = '''3 2 [droop rational precision=4] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), dict(rule='meek')) self.assertEqual(E.V.name, 'rational') b = '''3 2 [droop meek] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), dict()) self.assertEqual(E.rule.method, 'meek') E = Election(ElectionProfile(data=b), None) self.assertEqual(E.rule.method, 'meek') b = '''3 2 [droop dump meek] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), None) self.assertTrue(E.options.getopt('dump')) b = '''3 2 [droop dump=true meek] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), None) self.assertTrue(E.options.getopt('dump')) b = '''3 2 [droop dump=false meek] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), None) self.assertFalse(E.options.getopt('dump')) # fake a path to test double-path logic b = '''3 2 [droop 42.blt 513.blt meek] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' self.assertRaises(UsageError, Election, ElectionProfile(data=b), dict())
def testDroopOptionCount(self): "set arithmetic options" b0 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' self.assertEqual(len(ElectionProfile(data=b0).options), 0) b1 = '''3 2 [droop arithmetic=fixed] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' self.assertEqual(len(ElectionProfile(data=b1).options), 1) b2 = '''3 2 [droop arithmetic=fixed precision=6] 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' p = ElectionProfile(data=b2) self.assertEqual(len(p.options), 2) self.assertEqual(p.options[0], 'arithmetic=fixed') self.assertEqual(p.options[1], 'precision=6')
def testBallotEQ8(self): "test profile compare with equal rankings" b1 = '''3 2 4 1 2=3 0 2 2=3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' b2 = '''3 2 4 1 2=3 0 2 2=3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' b3 = '''3 2 3 1 2=3 0 3 2=3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' b4 = '''3 2 4 1 2=3 0 2 2=1 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' p1 = ElectionProfile(data=b1) p2 = ElectionProfile(data=b2) self.assertFalse(p1.compare(p2)) p3 = ElectionProfile(data=b3) p4 = ElectionProfile(data=b4) self.assertTrue(p1.compare(p3)) self.assertTrue(p1.compare(p4))
def testNickReport(self): "using nicknames shouldn't alter dump or report" b1 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' b2 = '''3 2 [nick a b c] 4 a b 0 2 c 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b1), dict(rule='meek-prf')) E.count() r1 = E.report() d1 = E.dump() E = Election(ElectionProfile(data=b2), dict(rule='meek-prf')) E.count() r2 = E.report() d2 = E.dump() self.assertEqual(r1, r2) self.assertEqual(d1, d2)
def testNick1(self): "test basic nicknames" b0 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' b1 = '''3 2 [nick a b c ] 4 a b 0 2 c 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' b2 = '''3 2 [nick a b c] 4 a b 0 2 c 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' p0 = ElectionProfile(data=b0) self.assertEqual(len(p0.nickName), 3) p1 = ElectionProfile(data=b1) self.assertEqual(len(p1.nickName), 3) p2 = ElectionProfile(data=b2) self.assertEqual(len(p2.nickName), 3) self.assertEqual(len(p2._nickCid), 3) for i in xrange(len(p1.ballotLines)): self.assertEqual(p1.ballotLines[i].multiplier, p2.ballotLines[i].multiplier) self.assertEqual(p1.ballotLines[i].ranking, p2.ballotLines[i].ranking) self.assertEqual(p1.ballotLines[i].multiplier, p0.ballotLines[i].multiplier) self.assertEqual(p1.ballotLines[i].ranking, p0.ballotLines[i].ranking)
def testBadOptions(self): "try wigm with bad options" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' profile = ElectionProfile(data=b) self.assertRaises(UsageError, Election, profile, dict(rule='wigm', integer_quota=2)) self.assertRaises(UsageError, Election, profile, dict(rule='wigm', defeat_batch="bad"))
def testMeekWarren1(self): "meek responds to warren" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' profile = ElectionProfile(data=b) E = Election(profile, dict(rule='warren')) self.assertEqual(E.rule.tag(), 'warren-o9') self.assertRaises(UsageError, Election, profile, dict(rule='warren', defeat_batch='whatever'))
def testArithmetic(self): "wigm-prf uses fixed" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' E = Election(ElectionProfile(data=b), dict(rule='wigm-prf', arithmetic='guarded', abc=4)) self.assertEqual(E.options.getopt('arithmetic'), 'fixed') self.assertEqual(E.options.getopt('precision'), 4) self.assertEqual(E.options.overrides(), ['arithmetic']) self.assertEqual(E.options.unused(), ['abc'])
def testElectAll(self): "count a profile with nSeats candidates" b = '''2 2 4 1 0 4 2 0 2 1 0 0 "Castor" "Pollux" "test nseats candidates"''' E = Election(ElectionProfile(data=b), dict(rule='cfer')) E.count() elected = [c.name for c in E.elected] self.assertEqual(elected, ['Castor', 'Pollux']) defeated = [c.name for c in E.defeated] self.assertEqual(defeated, []) report = E.report() self.assertTrue(report.find('Elect all'))
def testDefeatRemaining(self): "count a profile that has hopeful candidates left over to defeat" b = '''3 2 4 1 0 4 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "test defeat-remaining"''' E = Election(ElectionProfile(data=b), dict(rule='wigm-prf')) E.count() elected = [c.name for c in E.elected] self.assertEqual(elected, ['Castor', 'Pollux']) defeated = [c.name for c in E.defeated] self.assertEqual(defeated, ['Helen']) report = E.report() self.assertTrue(report.find('Defeat remaining'))
def testDefeatBatch(self): "count a profile that has with defeat_batch option" b = '''4 2 4 1 0 3 2 0 2 3 2 0 0 "Castor" "Pollux" "Helen" "George" "test defeat-batch"''' E = Election(ElectionProfile(data=b), dict(rule='wigm', defeat_batch='zero')) E.count() elected = [c.name for c in E.elected] self.assertEqual(elected, ['Castor', 'Pollux']) defeated = [c.name for c in E.defeated] self.assertEqual(defeated, ['Helen', 'George']) report = E.report() self.assertTrue(report.find('Defeat batch'))
def testInitSourceComment(self): "normal init: source & comment set" b1 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "title" "source less" "comment more"''' b2 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "title" "source less''' b3 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "title" "source less" "comment more''' b4 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "title" "source less" junk''' b5 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "title" "source less" "comment more" junk''' b6 = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "title" "source less"''' self.assertEqual(ElectionProfile(data=b1).title, 'title') self.assertEqual(ElectionProfile(data=b1).source, 'source less') self.assertEqual(ElectionProfile(data=b6).source, 'source less') self.assertEqual(ElectionProfile(data=b4).source, 'source less') self.assertEqual(ElectionProfile(data=b1).comment, 'comment more') self.assertEqual(ElectionProfile(data=b5).comment, 'comment more') self.assertRaises(ElectionProfileError, ElectionProfile, data=b2) self.assertRaises(ElectionProfileError, ElectionProfile, data=b3)
def testReports(self): "look at election outputs" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' profile = ElectionProfile(data=b) rulename = droop.electionRuleNames()[ 0] # pick the first rule arbitrarily E = Election(profile, dict(rule=rulename)) E.count() self.assertEqual(E.report().find('interrupted'), -1) self.assertTrue(E.report(intr=True).find('interrupted') > 0) E = Election(profile, dict(rule=rulename)) E.count() self.assertEqual(E.dump().find('interrupted'), -1) self.assertTrue(E.dump(intr=True).find('interrupted') > 0) E = Election(profile, dict(rule=rulename)) E.count() self.assertEqual(E.json().find('interrupted'), -1) self.assertTrue(E.json(intr=True).find('interrupted') > 0) r = E.record() self.assertTrue(r, dict) self.assertEqual(r['actions'][-1]['tag'], 'log')
def testRules(self): "basic test of each rule" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' profile = ElectionProfile(data=b) for rulename in droop.electionRuleNames(): options = dict(rule=rulename) E = Election(profile, options) self.assertTrue(E.rule.__class__.__name__ == 'Rule', 'bad rule class') self.assertTrue( len(options) >= 1, 'rule should set/leave at least one option') self.assertTrue( E.options.getopt('arithmetic') in ('fixed', 'integer', 'guarded', 'rational'), 'legal arithmetic') candidates = E.C self.assertTrue("Castor" in [c.name for c in candidates]) self.assertTrue("Castor" in [str(c) for c in candidates]) self.assertTrue(1 in [c for c in candidates]) for c in candidates: self.assertEqual(c.order, c.tieOrder) E.count() self.assertEqual(len(E.elected), E.nSeats)
def doQpqCount(filename): "each of five elections from the Woodall paper" blt = os.path.join(testdir, 'blt', 'qpq', filename) E = Election(ElectionProfile(blt), dict(rule='qpq')) E.count() return E
def main(options=None): "run an election" if not options: raise droop.common.UsageError("no ballot file specified") # process options # # we know about (path, profile) # all the others are passed to the various consumers # path = None # ballot path must be specified doProfile = False # performance profiling reps = 1 # repetitions (for profiling) for opt, arg in options.items(): if opt == 'path': # path=<path to ballot file> path = arg elif opt == 'profile': # profile=<number of repetitions> import cProfile import pstats reps = int(arg) doProfile = True profilefile = "profile.out" if not path: raise droop.common.UsageError("no ballot file specfied") # run the election # # fetch the election profile # create the Election object # count # report # def countElection(E, repeat=1): "encapsulate for optional profiling" for i in xrange(repeat): # pylint: disable=W0612 E.count() electionProfile = ElectionProfile( path=path) # don't repeat the profile loading E = Election(electionProfile, options) try: intr = False if doProfile: cProfile.runctx('countElection(E, reps)', globals(), locals(), profilefile) else: countElection(E, reps) except KeyboardInterrupt: intr = True E.options.setopt('dump', default=False) E.options.setopt('json', default=False) ereport = '' if E.options.setopt('report', default=True): ereport += E.report(intr) if E.options.getopt('dump'): ereport += E.dump(intr) if E.options.getopt('json'): ereport += E.json(intr) if doProfile: p = pstats.Stats(profilefile) p.strip_dirs().sort_stats('time').print_stats(50) return ereport
def getDump(options, base): "run a count and return the dump" blt = '%s/blt/%s.blt' % (testdir, base) E = Election(ElectionProfile(blt), options) E.count() return E.dump()
def doCount(options, blt): "run the count and return the Election" p = ElectionProfile(testdir + '/blt/' + blt) E = Election(p, options) E.count() return E
def testInitSeats(self): "normal init: 2 seats" self.assertEqual(ElectionProfile(data=p_42).nSeats, 2)
def testElectionNoRule(self): "trying an election without a rule should fail" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' p = ElectionProfile(data=b) self.assertRaises(ElectionError, Election, p, dict())
def testElectionBadRule(self): "trying an election with an undefined rule should fail" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' p = ElectionProfile(data=b) self.assertRaises(ElectionError, Election, p, dict(rule='nothing'))
def testInitOneLine(self): "normal init: 2 seats (no newlines)" self.assertEqual(ElectionProfile(data=p_42a).nSeats, 2)
def testInitOneTokenComment(self): "normal init: 2 seats (single-token comment)" b = '''3 2 4 1 2 0 2 3 0 0 /* nested /*comment*/ */ "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' self.assertEqual(ElectionProfile(data=b).nSeats, 2)
def testInitHashComment(self): "normal init: 2 seats (hash comment)" b = '''3 2 4 1 2 0 2 3 0 0 # comment\n "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' self.assertEqual(ElectionProfile(data=b).nSeats, 2)
def testElectionMpls1(self): "mpls: everyone elected at first" p_mpls1 = '''3 2 4 1 2 0 4 2 1 0 1 3 0 0 "a" "b" "c" "2 elected at first"''' E = Election(ElectionProfile(data=p_mpls1), dict(rule='mpls')) E.count() self.assertEqual(len(E.elected), 2)
def testElectionQpq1(self): "qpq: everyone elected at first" b = '''3 2 4 1 2 0 4 2 1 0 1 3 0 0 "a" "b" "c" "2 elected at first"''' E = Election(ElectionProfile(data=b), dict(rule='qpq')) E.count() self.assertEqual(len(E.elected), 2)
def setUp(self): "initialize profile and rule" b = '''3 2 4 1 2 0 2 3 0 0 "Castor" "Pollux" "Helen" "Pollux and Helen should tie"''' self.Profile = ElectionProfile(data=b) self.E = Election(self.Profile, dict(rule='qpq'))