summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Cordasco <graffatcolmingov@gmail.com>2016-07-12 08:21:57 -0500
committerIan Cordasco <graffatcolmingov@gmail.com>2016-07-12 08:21:57 -0500
commit2d3f06219199a4a7307a3c9a5c14b69be8608dca (patch)
tree5c30f94e45a9efd7f7c0a938327702c436344643
parent1a722bbe7bb1918d26a073108ae362e731296a3e (diff)
downloadflake8-add-statistics.tar.gz
Add actual tests around statistics moduleadd-statistics
Also refactor our statistics module to be a bit smarter and less namedtuple happy. The Statistic class had no reason to be a tuple, I have no clue why I wrote it that way last night.
-rw-r--r--src/flake8/statistics.py63
-rw-r--r--tests/unit/test_statistics.py71
2 files changed, 109 insertions, 25 deletions
diff --git a/src/flake8/statistics.py b/src/flake8/statistics.py
index 2ae6c64..2512089 100644
--- a/src/flake8/statistics.py
+++ b/src/flake8/statistics.py
@@ -18,11 +18,9 @@ class Statistics(object):
flake8.style_guide.Error
"""
key = Key.create_from(error)
- if key in self._store:
- statistic = self._store[key]
- else:
- statistic = Statistic.create_from(error)
- self._store[key] = statistic.increment()
+ if key not in self._store:
+ self._store[key] = Statistic.create_from(error)
+ self._store[key].increment()
def statistics_for(self, prefix, filename=None):
"""Generate statistics for the prefix and filename.
@@ -54,48 +52,67 @@ class Statistics(object):
class Key(collections.namedtuple('Key', ['filename', 'code'])):
+ """Simple key structure for the Statistics dictionary.
+
+ To make things clearer, easier to read, and more understandable, we use a
+ namedtuple here for all Keys in the underlying dictionary for the
+ Statistics object.
+ """
+
__slots__ = ()
@classmethod
def create_from(cls, error):
+ """Create a Key from :class:`flake8.style_guide.Error`."""
return cls(
filename=error.filename,
code=error.code,
)
def matches(self, prefix, filename):
+ """Determine if this key matches some constraints.
+
+ :param str prefix:
+ The error code prefix that this key's error code should start with.
+ :param str filename:
+ The filename that we potentially want to match on. This can be
+ None to only match on error prefix.
+ :returns:
+ True if the Key's code starts with the prefix and either filename
+ is None, or the Key's filename matches the value passed in.
+ :rtype:
+ bool
+ """
return (self.code.startswith(prefix) and
(filename is None or
self.filename == filename))
-_Statistic = collections.namedtuple('Statistic', [
- 'error_code',
- 'filename',
- 'message',
- 'count',
-])
+class Statistic(object):
+ """Simple wrapper around the logic of each statistic.
+ Instead of maintaining a simple but potentially hard to reason about
+ tuple, we create a namedtuple which has attributes and a couple
+ convenience methods on it.
+ """
-class Statistic(_Statistic):
- __slots__ = ()
+ def __init__(self, error_code, filename, message, count):
+ """Initialize our Statistic."""
+ self.error_code = error_code
+ self.filename = filename
+ self.message = message
+ self.count = count
@classmethod
def create_from(cls, error):
+ """Create a Statistic from a :class:`flake8.style_guide.Error`."""
return cls(
error_code=error.code,
filename=error.filename,
- message=error.message,
+ message=error.text,
count=0,
)
def increment(self):
- return Statistic(
- error_code=self.error_code,
- filename=self.filename,
- message=self.message,
- count=self.count + 1,
- )
-
-
-del _Statistic
+ """Increment the number of times we've seen this error in this file."""
+ self.count += 1
diff --git a/tests/unit/test_statistics.py b/tests/unit/test_statistics.py
index 015e94b..c60af33 100644
--- a/tests/unit/test_statistics.py
+++ b/tests/unit/test_statistics.py
@@ -1,5 +1,72 @@
+"""Tests for the statistics module in Flake8."""
+import pytest
+
from flake8 import statistics as stats
+from flake8 import style_guide
+
+DEFAULT_ERROR_CODE = 'E100'
+DEFAULT_FILENAME = 'file.py'
+DEFAULT_TEXT = 'Default text'
+
+
+def make_error(**kwargs):
+ """Create errors with a bunch of default values."""
+ return style_guide.Error(
+ code=kwargs.pop('code', DEFAULT_ERROR_CODE),
+ filename=kwargs.pop('filename', DEFAULT_FILENAME),
+ line_number=kwargs.pop('line_number', 1),
+ column_number=kwargs.pop('column_number', 1),
+ text=kwargs.pop('text', DEFAULT_TEXT),
+ physical_line=None,
+ )
+
+
+def test_key_creation():
+ """Verify how we create Keys from Errors."""
+ key = stats.Key.create_from(make_error())
+ assert key == (DEFAULT_FILENAME, DEFAULT_ERROR_CODE)
+ assert key.filename == DEFAULT_FILENAME
+ assert key.code == DEFAULT_ERROR_CODE
+
+
+@pytest.mark.parametrize('code, filename, args, expected_result', [
+ # Error prefix matches
+ ('E123', 'file000.py', ('E', None), True),
+ ('E123', 'file000.py', ('E1', None), True),
+ ('E123', 'file000.py', ('E12', None), True),
+ ('E123', 'file000.py', ('E123', None), True),
+ # Error prefix and filename match
+ ('E123', 'file000.py', ('E', 'file000.py'), True),
+ ('E123', 'file000.py', ('E1', 'file000.py'), True),
+ ('E123', 'file000.py', ('E12', 'file000.py'), True),
+ ('E123', 'file000.py', ('E123', 'file000.py'), True),
+ # Error prefix does not match
+ ('E123', 'file000.py', ('W', None), False),
+ # Error prefix matches but filename does not
+ ('E123', 'file000.py', ('E', 'file001.py'), False),
+ # Error prefix does not match but filename does
+ ('E123', 'file000.py', ('W', 'file000.py'), False),
+ # Neither error prefix match nor filename
+ ('E123', 'file000.py', ('W', 'file001.py'), False),
+])
+def test_key_matching(code, filename, args, expected_result):
+ """Verify Key#matches behaves as we expect with fthe above input."""
+ key = stats.Key.create_from(make_error(code=code, filename=filename))
+ assert key.matches(*args) is expected_result
+
+
+def test_statistic_creation():
+ """Verify how we create Statistic objects from Errors."""
+ stat = stats.Statistic.create_from(make_error())
+ assert stat.error_code == DEFAULT_ERROR_CODE
+ assert stat.message == DEFAULT_TEXT
+ assert stat.filename == DEFAULT_FILENAME
+ assert stat.count == 0
-def test_nothing():
- pass
+def test_statistic_increment():
+ """Verify we update the count."""
+ stat = stats.Statistic.create_from(make_error())
+ assert stat.count == 0
+ stat.increment()
+ assert stat.count == 1