|
13 | 13 | # included in all copies or substantial portions of the Software.
|
14 | 14 |
|
15 | 15 |
|
| 16 | +import importlib |
16 | 17 | import itertools
|
| 18 | +import logging |
17 | 19 | import os
|
| 20 | +import pkgutil |
| 21 | +import sys |
18 | 22 | from unittest.mock import ANY, Mock, patch
|
19 | 23 |
|
20 | 24 | import pytest
|
|
30 | 34 | )
|
31 | 35 | from beets.library import Item
|
32 | 36 | from beets.test import helper
|
33 |
| -from beets.test.helper import AutotagStub, ImportHelper, TerminalImportMixin |
| 37 | +from beets.test.helper import ( |
| 38 | + AutotagStub, |
| 39 | + ImportHelper, |
| 40 | + PluginMixin, |
| 41 | + TerminalImportMixin, |
| 42 | +) |
34 | 43 | from beets.test.helper import PluginTestCase as BasePluginTestCase
|
35 | 44 | from beets.util import displayable_path, syspath
|
36 | 45 |
|
@@ -531,3 +540,56 @@ def foo(self, session, task):
|
531 | 540 | self.mock_input_options.assert_called_once_with(
|
532 | 541 | opts, default="a", require=ANY
|
533 | 542 | )
|
| 543 | + |
| 544 | + |
| 545 | +def get_available_plugins(): |
| 546 | + """Get all available plugins in the beetsplug namespace.""" |
| 547 | + namespace_pkg = importlib.import_module("beetsplug") |
| 548 | + |
| 549 | + return [ |
| 550 | + m.name |
| 551 | + for m in pkgutil.iter_modules(namespace_pkg.__path__) |
| 552 | + if not m.name.startswith("_") |
| 553 | + ] |
| 554 | + |
| 555 | + |
| 556 | +class TestImportAllPlugins(PluginMixin): |
| 557 | + def unimport_plugins(self): |
| 558 | + """Unimport plugins before each test to avoid conflicts.""" |
| 559 | + self.unload_plugins() |
| 560 | + for mod in list(sys.modules): |
| 561 | + if mod.startswith("beetsplug."): |
| 562 | + del sys.modules[mod] |
| 563 | + |
| 564 | + @pytest.fixture(autouse=True) |
| 565 | + def cleanup(self): |
| 566 | + """Ensure plugins are unimported before and after each test.""" |
| 567 | + self.unimport_plugins() |
| 568 | + yield |
| 569 | + self.unimport_plugins() |
| 570 | + |
| 571 | + @pytest.mark.skipif( |
| 572 | + os.environ.get("GITHUB_ACTIONS") != "true", |
| 573 | + reason="Requires all dependencies to be installed, " |
| 574 | + + "which we can't guarantee in the local environment.", |
| 575 | + ) |
| 576 | + @pytest.mark.parametrize("plugin_name", get_available_plugins()) |
| 577 | + def test_import_plugin(self, caplog, plugin_name): # |
| 578 | + """Test that a plugin is importable without an error using the |
| 579 | + load_plugins function.""" |
| 580 | + |
| 581 | + # skip gstreamer plugins on windows |
| 582 | + gstreamer_plugins = ["bpd", "replaygain"] |
| 583 | + if sys.platform == "win32" and plugin_name in gstreamer_plugins: |
| 584 | + pytest.xfail("GStreamer is not available on Windows: {plugin_name}") |
| 585 | + |
| 586 | + caplog.set_level(logging.WARNING) |
| 587 | + caplog.clear() |
| 588 | + plugins.load_plugins([plugin_name]) |
| 589 | + |
| 590 | + # Check for warnings, is a bit hacky but we can make full use of the beets |
| 591 | + # load_plugins code that way |
| 592 | + assert len(caplog.records) == 0, ( |
| 593 | + f"Plugin '{plugin_name}' has issues during import. ", |
| 594 | + caplog.records, |
| 595 | + ) |
0 commit comments