Add test coverage reporting
This commit is contained in:
parent
7f30871296
commit
fccb36ffbd
12
.coveragerc
Normal file
12
.coveragerc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[run]
|
||||||
|
command_line=-m pytest
|
||||||
|
omit=
|
||||||
|
*_js.py
|
||||||
|
pyRCV2/transcrypt.py
|
||||||
|
source=pyRCV2
|
||||||
|
|
||||||
|
[report]
|
||||||
|
exclude_lines=
|
||||||
|
__pragma__
|
||||||
|
def __repr__
|
||||||
|
pragma: no cover
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,6 +1,8 @@
|
|||||||
|
/.coverage
|
||||||
/.python-version
|
/.python-version
|
||||||
/__target__
|
/__target__
|
||||||
/test
|
|
||||||
/html/bundle.js
|
/html/bundle.js
|
||||||
|
/htmlcov
|
||||||
|
/test
|
||||||
__pycache__
|
__pycache__
|
||||||
.~*
|
.~*
|
||||||
|
@ -142,7 +142,7 @@ class BaseSTVCounter:
|
|||||||
if result:
|
if result:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
raise STVException('Unable to complete step')
|
raise STVException('Unable to complete step') # pragma: no cover
|
||||||
|
|
||||||
def step_count_cards(self):
|
def step_count_cards(self):
|
||||||
"""
|
"""
|
||||||
@ -249,7 +249,7 @@ class BaseSTVCounter:
|
|||||||
has_surplus.sort(key=lambda x: x[1].votes, reverse=True)
|
has_surplus.sort(key=lambda x: x[1].votes, reverse=True)
|
||||||
elif self.options['surplus_order'] == 'order':
|
elif self.options['surplus_order'] == 'order':
|
||||||
has_surplus.sort(key=lambda x: x[1].order_elected)
|
has_surplus.sort(key=lambda x: x[1].order_elected)
|
||||||
else:
|
else: # pragma: no cover
|
||||||
raise STVException('Invalid surplus order option')
|
raise STVException('Invalid surplus order option')
|
||||||
|
|
||||||
# Attempt to defer all remaining surpluses if possible
|
# Attempt to defer all remaining surpluses if possible
|
||||||
@ -286,7 +286,7 @@ class BaseSTVCounter:
|
|||||||
Transfer the surplus of the given candidate
|
Transfer the surplus of the given candidate
|
||||||
Subclasses must override this function
|
Subclasses must override this function
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
def before_exclusion(self):
|
def before_exclusion(self):
|
||||||
"""
|
"""
|
||||||
@ -440,7 +440,7 @@ class BaseSTVCounter:
|
|||||||
Exclude the given candidate and transfer the votes
|
Exclude the given candidate and transfer the votes
|
||||||
Subclasses must override this function
|
Subclasses must override this function
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
def compute_quota(self):
|
def compute_quota(self):
|
||||||
"""
|
"""
|
||||||
@ -457,7 +457,7 @@ class BaseSTVCounter:
|
|||||||
elif self.options['quota'] == 'hare' or self.options['quota'] == 'hare_exact':
|
elif self.options['quota'] == 'hare' or self.options['quota'] == 'hare_exact':
|
||||||
self.quota = self.total / Num(self.election.seats)
|
self.quota = self.total / Num(self.election.seats)
|
||||||
else:
|
else:
|
||||||
raise STVException('Invalid quota option')
|
raise STVException('Invalid quota option') # pragma: no cover
|
||||||
|
|
||||||
if self.options['round_quota'] is not None:
|
if self.options['round_quota'] is not None:
|
||||||
if self.options['quota'] == 'droop' or self.options['quota'] == 'hare':
|
if self.options['quota'] == 'droop' or self.options['quota'] == 'hare':
|
||||||
@ -501,7 +501,7 @@ class BaseSTVCounter:
|
|||||||
return count_card.votes > self.quota or (self.options['quota_mode'] == 'ers97' and count_card.votes > self.vote_required_election)
|
return count_card.votes > self.quota or (self.options['quota_mode'] == 'ers97' and count_card.votes > self.vote_required_election)
|
||||||
__pragma__('noopov')
|
__pragma__('noopov')
|
||||||
else:
|
else:
|
||||||
raise STVException('Invalid quota criterion')
|
raise STVException('Invalid quota criterion') # pragma: no cover
|
||||||
|
|
||||||
def elect_meeting_quota(self):
|
def elect_meeting_quota(self):
|
||||||
"""
|
"""
|
||||||
|
@ -31,7 +31,7 @@ def groupby(iterable, keyfunc):
|
|||||||
import itertools
|
import itertools
|
||||||
return [list(g) for k, g in itertools.groupby(iterable, keyfunc)]
|
return [list(g) for k, g in itertools.groupby(iterable, keyfunc)]
|
||||||
__pragma__('noskip')
|
__pragma__('noskip')
|
||||||
else:
|
else: # pragma: no cover
|
||||||
groups = []
|
groups = []
|
||||||
group = []
|
group = []
|
||||||
last_result = None
|
last_result = None
|
||||||
@ -173,7 +173,7 @@ class WIGSTVCounter(BaseSTVCounter):
|
|||||||
# TODO: Can we combine ballots for each candidate within each stage?
|
# TODO: Can we combine ballots for each candidate within each stage?
|
||||||
self._exclusion = (candidates_excluded, [[(c, [(b, bv)]) for c, b, bv in x] for x in ballots_by_value])
|
self._exclusion = (candidates_excluded, [[(c, [(b, bv)]) for c, b, bv in x] for x in ballots_by_value])
|
||||||
else:
|
else:
|
||||||
raise STVException('Invalid exclusion mode')
|
raise STVException('Invalid exclusion mode') # pragma: no cover
|
||||||
|
|
||||||
this_exclusion = self._exclusion[1][0]
|
this_exclusion = self._exclusion[1][0]
|
||||||
self._exclusion[1].remove(this_exclusion)
|
self._exclusion[1].remove(this_exclusion)
|
||||||
|
@ -25,7 +25,7 @@ class Candidate:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Candidate ' + self.name + '>'
|
return '<Candidate ' + self.name + '>'
|
||||||
|
|
||||||
def toString(self):
|
def toString(self): # pragma: no cover
|
||||||
return repr(self)
|
return repr(self)
|
||||||
|
|
||||||
class CandidateState:
|
class CandidateState:
|
||||||
|
@ -26,7 +26,7 @@ if is_py:
|
|||||||
from pyRCV2.numbers.native_py import Native
|
from pyRCV2.numbers.native_py import Native
|
||||||
from pyRCV2.numbers.rational_py import Rational
|
from pyRCV2.numbers.rational_py import Rational
|
||||||
__pragma__('noskip')
|
__pragma__('noskip')
|
||||||
else:
|
else: # pragma: no cover
|
||||||
from pyRCV2.numbers.fixed_js import Fixed, set_dps, get_dps
|
from pyRCV2.numbers.fixed_js import Fixed, set_dps, get_dps
|
||||||
from pyRCV2.numbers.native_js import Native
|
from pyRCV2.numbers.native_js import Native
|
||||||
from pyRCV2.numbers.rational_js import Rational
|
from pyRCV2.numbers.rational_js import Rational
|
||||||
|
@ -36,7 +36,7 @@ def compatible_types(f):
|
|||||||
else:
|
else:
|
||||||
return f
|
return f
|
||||||
__pragma__('noskip')
|
__pragma__('noskip')
|
||||||
else:
|
else: # pragma: no cover
|
||||||
# FIXME: Do we need to perform type checking in JS?
|
# FIXME: Do we need to perform type checking in JS?
|
||||||
return f
|
return f
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class BaseNum:
|
|||||||
Internal use: Convert the given value to an impl
|
Internal use: Convert the given value to an impl
|
||||||
Subclasses must override this method
|
Subclasses must override this method
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_impl(cls, impl):
|
def _from_impl(cls, impl):
|
||||||
@ -79,52 +79,52 @@ class BaseNum:
|
|||||||
Pretty print to specified number of decimal places
|
Pretty print to specified number of decimal places
|
||||||
Subclasses must override this method
|
Subclasses must override this method
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
# Implementation of arithmetic on impls
|
# Implementation of arithmetic on impls
|
||||||
# Subclasses must override these functions:
|
# Subclasses must override these functions:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _add_impl(cls, i1, i2):
|
def _add_impl(cls, i1, i2):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sub_impl(cls, i1, i2):
|
def _sub_impl(cls, i1, i2):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@classmethod
|
@classmethod
|
||||||
def _mul_impl(cls, i1, i2):
|
def _mul_impl(cls, i1, i2):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@classmethod
|
@classmethod
|
||||||
def _truediv_impl(cls, i1, i2):
|
def _truediv_impl(cls, i1, i2):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
@compatible_types
|
@compatible_types
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@compatible_types
|
@compatible_types
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not (self.__eq__(other))
|
return not (self.__eq__(other))
|
||||||
@compatible_types
|
@compatible_types
|
||||||
def __gt__(self, other):
|
def __gt__(self, other):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@compatible_types
|
@compatible_types
|
||||||
def __ge__(self, other):
|
def __ge__(self, other):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@compatible_types
|
@compatible_types
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
@compatible_types
|
@compatible_types
|
||||||
def __le__(self, other):
|
def __le__(self, other):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
def __pow__(self, power):
|
def __pow__(self, power):
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
def round(self, dps, mode):
|
def round(self, dps, mode):
|
||||||
"""
|
"""
|
||||||
Round to the specified number of decimal places, using the ROUND_* mode specified
|
Round to the specified number of decimal places, using the ROUND_* mode specified
|
||||||
Subclasses must override this method
|
Subclasses must override this method
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Method not implemented')
|
raise NotImplementedError('Method not implemented') # pragma: no cover
|
||||||
|
|
||||||
# Implement various data model functions based on _*_impl
|
# Implement various data model functions based on _*_impl
|
||||||
|
|
||||||
|
@ -24,5 +24,5 @@ if is_py:
|
|||||||
__pragma__('skip')
|
__pragma__('skip')
|
||||||
from pyRCV2.random.sharandom_py import SHARandom
|
from pyRCV2.random.sharandom_py import SHARandom
|
||||||
__pragma__('noskip')
|
__pragma__('noskip')
|
||||||
else:
|
else: # pragma: no cover
|
||||||
from pyRCV2.random.sharandom_js import SHARandom
|
from pyRCV2.random.sharandom_js import SHARandom
|
||||||
|
@ -24,5 +24,5 @@ if is_py:
|
|||||||
__pragma__('skip')
|
__pragma__('skip')
|
||||||
from pyRCV2.safedict.safedict_py import SafeDict
|
from pyRCV2.safedict.safedict_py import SafeDict
|
||||||
__pragma__('noskip')
|
__pragma__('noskip')
|
||||||
else:
|
else: # pragma: no cover
|
||||||
from pyRCV2.safedict.safedict_js import SafeDict
|
from pyRCV2.safedict.safedict_js import SafeDict
|
||||||
|
@ -22,7 +22,8 @@ __pragma__('noskip')
|
|||||||
|
|
||||||
from pyRCV2.random import SHARandom
|
from pyRCV2.random import SHARandom
|
||||||
|
|
||||||
class RequireInput(Exception):
|
class RequireInput(Exception): # pragma: no cover
|
||||||
|
# For JS only
|
||||||
# Exceptions for control flow? In my code? It's more likely thank you think!
|
# Exceptions for control flow? In my code? It's more likely thank you think!
|
||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
self.message = message
|
self.message = message
|
||||||
@ -51,7 +52,7 @@ class TiesPrompt:
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
return l[i - 1]
|
return l[i - 1]
|
||||||
else:
|
else: # pragma: no cover
|
||||||
if self.buffer is not None:
|
if self.buffer is not None:
|
||||||
try:
|
try:
|
||||||
choice = int(self.buffer)
|
choice = int(self.buffer)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
# Dependencies
|
# Dependencies
|
||||||
Transcrypt==3.7.16
|
coverage==5.3.1
|
||||||
py-mini-racer==0.4.0
|
py-mini-racer==0.4.0
|
||||||
pytest==6.2.1
|
pytest==6.2.1
|
||||||
pytest-steps==1.7.3
|
pytest-steps==1.7.3
|
||||||
|
Transcrypt==3.7.16
|
||||||
|
|
||||||
# Dependency tree
|
# Dependency tree
|
||||||
attrs==20.3.0
|
attrs==20.3.0
|
||||||
|
Reference in New Issue
Block a user