1"""Tests for flake8.plugins.manager.PluginTypeManager."""
2from unittest import mock
3
4import pytest
5
6from flake8 import exceptions
7from flake8.plugins import manager
8
9TEST_NAMESPACE = "testing.plugin-type-manager"
10
11
12def create_plugin_mock(raise_exception=False):
13    """Create an auto-spec'd mock of a flake8 Plugin."""
14    plugin = mock.create_autospec(manager.Plugin, instance=True)
15    if raise_exception:
16        plugin.load_plugin.side_effect = exceptions.FailedToLoadPlugin(
17            plugin_name="T101",
18            exception=ValueError("Test failure"),
19        )
20    return plugin
21
22
23def create_mapping_manager_mock(plugins):
24    """Create a mock for the PluginManager."""
25    # Have a function that will actually call the method underneath
26    def fake_map(func):
27        for plugin in plugins:
28            yield func(plugin)
29
30    # Mock out the PluginManager instance
31    manager_mock = mock.Mock(spec=["map"])
32    # Replace the map method
33    manager_mock.map = fake_map
34    return manager_mock
35
36
37class FakeTestType(manager.PluginTypeManager):
38    """Fake PluginTypeManager."""
39
40    namespace = TEST_NAMESPACE
41
42
43@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
44def test_instantiates_a_manager(PluginManager):  # noqa: N803
45    """Verify we create a PluginManager on instantiation."""
46    FakeTestType()
47
48    PluginManager.assert_called_once_with(TEST_NAMESPACE, local_plugins=None)
49
50
51@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
52def test_proxies_names_to_manager(PluginManager):  # noqa: N803
53    """Verify we proxy the names attribute."""
54    PluginManager.return_value = mock.Mock(names=["T100", "T200", "T300"])
55    type_mgr = FakeTestType()
56
57    assert type_mgr.names == ["T100", "T200", "T300"]
58
59
60@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
61def test_proxies_plugins_to_manager(PluginManager):  # noqa: N803
62    """Verify we proxy the plugins attribute."""
63    PluginManager.return_value = mock.Mock(plugins=["T100", "T200", "T300"])
64    type_mgr = FakeTestType()
65
66    assert type_mgr.plugins == ["T100", "T200", "T300"]
67
68
69def test_generate_call_function():
70    """Verify the function we generate."""
71    optmanager = object()
72    plugin = mock.Mock(method_name=lambda x: x)
73    func = manager.PluginTypeManager._generate_call_function(
74        "method_name",
75        optmanager,
76    )
77
78    assert callable(func)
79    assert func(plugin) is optmanager
80
81
82@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
83def test_load_plugins(PluginManager):  # noqa: N803
84    """Verify load plugins loads *every* plugin."""
85    # Create a bunch of fake plugins
86    plugins = [
87        create_plugin_mock(),
88        create_plugin_mock(),
89        create_plugin_mock(),
90        create_plugin_mock(),
91        create_plugin_mock(),
92        create_plugin_mock(),
93        create_plugin_mock(),
94        create_plugin_mock(),
95    ]
96    # Return our PluginManager mock
97    PluginManager.return_value = create_mapping_manager_mock(plugins)
98
99    type_mgr = FakeTestType()
100    # Load the tests (do what we're actually testing)
101    assert len(type_mgr.load_plugins()) == 8
102    # Assert that our closure does what we think it does
103    for plugin in plugins:
104        plugin.load_plugin.assert_called_once_with()
105    assert type_mgr.plugins_loaded is True
106
107
108@mock.patch("flake8.plugins.manager.PluginManager")
109def test_load_plugins_fails(PluginManager):  # noqa: N803
110    """Verify load plugins bubbles up exceptions."""
111    plugins = [
112        create_plugin_mock(),
113        create_plugin_mock(True),
114        create_plugin_mock(),
115        create_plugin_mock(),
116        create_plugin_mock(),
117        create_plugin_mock(),
118        create_plugin_mock(),
119        create_plugin_mock(),
120    ]
121    # Return our PluginManager mock
122    PluginManager.return_value = create_mapping_manager_mock(plugins)
123
124    type_mgr = FakeTestType()
125    with pytest.raises(exceptions.FailedToLoadPlugin):
126        type_mgr.load_plugins()
127
128    # Assert we didn't finish loading plugins
129    assert type_mgr.plugins_loaded is False
130    # Assert the first two plugins had their load_plugin method called
131    plugins[0].load_plugin.assert_called_once_with()
132    plugins[1].load_plugin.assert_called_once_with()
133    # Assert the rest of the plugins were not loaded
134    for plugin in plugins[2:]:
135        assert plugin.load_plugin.called is False
136
137
138@mock.patch("flake8.plugins.manager.PluginManager")
139def test_register_options(PluginManager):  # noqa: N803
140    """Test that we map over every plugin to register options."""
141    plugins = [
142        create_plugin_mock(),
143        create_plugin_mock(),
144        create_plugin_mock(),
145        create_plugin_mock(),
146        create_plugin_mock(),
147        create_plugin_mock(),
148        create_plugin_mock(),
149        create_plugin_mock(),
150    ]
151    # Return our PluginManager mock
152    PluginManager.return_value = create_mapping_manager_mock(plugins)
153    optmanager = object()
154
155    type_mgr = FakeTestType()
156    type_mgr.register_options(optmanager)
157
158    for plugin in plugins:
159        plugin.register_options.assert_called_with(optmanager)
160
161
162@mock.patch("flake8.plugins.manager.PluginManager")
163def test_provide_options(PluginManager):  # noqa: N803
164    """Test that we map over every plugin to provide parsed options."""
165    plugins = [
166        create_plugin_mock(),
167        create_plugin_mock(),
168        create_plugin_mock(),
169        create_plugin_mock(),
170        create_plugin_mock(),
171        create_plugin_mock(),
172        create_plugin_mock(),
173        create_plugin_mock(),
174    ]
175    # Return our PluginManager mock
176    PluginManager.return_value = create_mapping_manager_mock(plugins)
177    optmanager = object()
178    options = object()
179
180    type_mgr = FakeTestType()
181    type_mgr.provide_options(optmanager, options, [])
182
183    for plugin in plugins:
184        plugin.provide_options.assert_called_with(optmanager, options, [])
185
186
187@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
188def test_proxy_contains_to_managers_plugins_dict(PluginManager):  # noqa: N803
189    """Verify that we proxy __contains__ to the manager's dictionary."""
190    plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
191    # Return our PluginManager mock
192    PluginManager.return_value.plugins = plugins
193
194    type_mgr = FakeTestType()
195    for i in range(8):
196        key = "T10%i" % i
197        assert key in type_mgr
198
199
200@mock.patch("flake8.plugins.manager.PluginManager")
201def test_proxies_getitem_to_managers_plugins_dict(PluginManager):  # noqa: N803
202    """Verify that we can use the PluginTypeManager like a dictionary."""
203    plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
204    # Return our PluginManager mock
205    PluginManager.return_value.plugins = plugins
206
207    type_mgr = FakeTestType()
208    for i in range(8):
209        key = "T10%i" % i
210        assert type_mgr[key] is plugins[key]
211