flake8/tests/integration/test_checker.py
Ian Cordasco e14d0e6352
Serialize Checkers PluginTypeManager to a dict
It seems likely that the multiprocessing module on Windows is not
capable of serializing an object with the structure that we have and
preserving the attributes we dynamically set on plugins (like the
FlakesChecker). To avoid issues like this with all plugins (although
we have only found this on Windows with the FlakesChecker), let's try
serializing the Checkers PluginTypeManager to a dictionary so that the
only object that a Queue is really trying to serialize/deserialize is
the FlakesChecker itself.

Related to #179
2016-08-03 16:48:39 -05:00

150 lines
5.5 KiB
Python

"""Integration tests for the checker submodule."""
import mock
import pytest
from flake8 import checker
from flake8.plugins import manager
EXPECTED_REPORT = (1, 1, 'T000 Expected Message')
class PluginClass(object):
"""Simple file plugin class yielding the expected report."""
name = 'test'
version = '1.0.0'
def __init__(self, tree):
"""Dummy constructor to provide mandatory parameter."""
pass
def run(self):
"""Run class yielding one element containing the expected report."""
yield EXPECTED_REPORT + (type(self), )
def plugin_func(func):
"""Decorator for file plugins which are implemented as functions."""
func.name = 'test'
func.version = '1.0.0'
return func
@plugin_func
def plugin_func_gen(tree):
"""Simple file plugin function yielding the expected report."""
yield EXPECTED_REPORT + (type(plugin_func_gen), )
@plugin_func
def plugin_func_list(tree):
"""Simple file plugin function returning a list of reports."""
return [EXPECTED_REPORT + (type(plugin_func_list), )]
@pytest.mark.parametrize('plugin_target', [
PluginClass,
plugin_func_gen,
plugin_func_list,
])
def test_handle_file_plugins(plugin_target):
"""Test the FileChecker class handling different file plugin types."""
# Mock an entry point returning the plugin target
entry_point = mock.Mock(spec=['require', 'resolve', 'load'])
entry_point.name = plugin_target.name
entry_point.resolve.return_value = plugin_target
# Load the checker plugins using the entry point mock
with mock.patch('pkg_resources.iter_entry_points',
return_value=[entry_point]):
checks = manager.Checkers()
# Prevent it from reading lines from stdin or somewhere else
with mock.patch('flake8.processor.FileProcessor.read_lines',
return_value=['Line 1']):
file_checker = checker.FileChecker(
'-',
checks.to_dictionary(),
mock.MagicMock()
)
# Do not actually build an AST
file_checker.processor.build_ast = lambda: True
# Forward reports to this mock
report = mock.Mock()
file_checker.report = report
file_checker.run_ast_checks()
report.assert_called_once_with(error_code=None,
line_number=EXPECTED_REPORT[0],
column=EXPECTED_REPORT[1],
text=EXPECTED_REPORT[2])
PLACEHOLDER_CODE = 'some_line = "of" * code'
@pytest.mark.parametrize('results, expected_order', [
# No entries should be added
([], []),
# Results are correctly ordered
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 1]),
# Reversed order of lines
([('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE)], [1, 0]),
# Columns are not ordered correctly (when reports are ordered correctly)
([('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [1, 0, 2]),
([('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE)], [1, 2, 0]),
([('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 2, 1]),
([('A101', 1, 3, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 3, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 1, 2]),
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 3, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE)], [0, 1, 2]),
# Previously sort column and message (so reversed) (see bug 196)
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'charlie error', PLACEHOLDER_CODE)], [0, 1]),
])
def test_report_order(results, expected_order):
"""
Test in which order the results will be reported.
It gets a list of reports from the file checkers and verifies that the
result will be ordered independent from the original report.
"""
def count_side_effect(name, sorted_results):
"""Side effect for the result handler to tell all are reported."""
return len(sorted_results)
# To simplify the parameters (and prevent copy & pasting) reuse report
# tuples to create the expected result lists from the indexes
expected_results = [results[index] for index in expected_order]
file_checker = mock.Mock(spec=['results', 'display_name'])
file_checker.results = results
file_checker.display_name = 'placeholder'
style_guide = mock.Mock(spec=['options'])
# Create a placeholder manager without arguments or plugins
# Just add one custom file checker which just provides the results
manager = checker.Manager(style_guide, [], [])
manager.checkers = [file_checker]
# _handle_results is the first place which gets the sorted result
# Should something non-private be mocked instead?
handler = mock.Mock()
handler.side_effect = count_side_effect
manager._handle_results = handler
assert manager.report() == (len(results), len(results))
handler.assert_called_once_with('placeholder', expected_results)