"""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.Violation(
        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_statistic_increment():
    """Verify we update the count."""
    stat = stats.Statistic.create_from(make_error())
    assert stat.count == 0
    stat.increment()
    assert stat.count == 1


def test_recording_statistics():
    """Verify that we appropriately create a new Statistic and store it."""
    aggregator = stats.Statistics()
    assert list(aggregator.statistics_for('E')) == []
    aggregator.record(make_error())
    storage = aggregator._store
    for key, value in storage.items():
        assert isinstance(key, stats.Key)
        assert isinstance(value, stats.Statistic)

    assert storage[stats.Key(DEFAULT_FILENAME, DEFAULT_ERROR_CODE)].count == 1


def test_statistics_for_single_record():
    """Show we can retrieve the only statistic recorded."""
    aggregator = stats.Statistics()
    assert list(aggregator.statistics_for('E')) == []
    aggregator.record(make_error())
    statistics = list(aggregator.statistics_for('E'))
    assert len(statistics) == 1
    assert isinstance(statistics[0], stats.Statistic)


def test_statistics_for_filters_by_filename():
    """Show we can retrieve the only statistic recorded."""
    aggregator = stats.Statistics()
    assert list(aggregator.statistics_for('E')) == []
    aggregator.record(make_error())
    aggregator.record(make_error(filename='example.py'))

    statistics = list(aggregator.statistics_for('E', DEFAULT_FILENAME))
    assert len(statistics) == 1
    assert isinstance(statistics[0], stats.Statistic)


def test_statistic_for_retrieves_more_than_one_value():
    """Show this works for more than a couple statistic values."""
    aggregator = stats.Statistics()
    for i in range(50):
        aggregator.record(make_error(code='E1{:02d}'.format(i)))
        aggregator.record(make_error(code='W2{:02d}'.format(i)))

    statistics = list(aggregator.statistics_for('E'))
    assert len(statistics) == 50

    statistics = list(aggregator.statistics_for('W22'))
    assert len(statistics) == 10
