Add test coverage reporting

This commit is contained in:
RunasSudo 2021-01-12 03:15:47 +11:00
parent 7f30871296
commit fccb36ffbd
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
11 changed files with 46 additions and 30 deletions

12
.coveragerc Normal file
View 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
View File

@ -1,6 +1,8 @@
/.coverage
/.python-version /.python-version
/__target__ /__target__
/test
/html/bundle.js /html/bundle.js
/htmlcov
/test
__pycache__ __pycache__
.~* .~*

View File

@ -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):
""" """

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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