diff --git a/testing/test_details.py b/testing/test_details.py index 237b7de1..f19b6334 100644 --- a/testing/test_details.py +++ b/testing/test_details.py @@ -230,6 +230,15 @@ def test_dist_facade_identity_equality_and_hash() -> None: assert {fc1: "ok"}[fc1] == "ok" +def test_dunder_version() -> None: + assert pluggy.__version__ == distribution("pluggy").version + + +def test_dunder_getattr_missing_raises() -> None: + with pytest.raises(AttributeError, match="module pluggy has no attribute 'nope'"): + pluggy.nope + + def test_hookimpl_disallow_invalid_combination() -> None: decorator = hookspec(historic=True, firstresult=True) with pytest.raises(ValueError, match="cannot have a historic firstresult hook"): diff --git a/testing/test_hookcaller.py b/testing/test_hookcaller.py index 0c9f91bd..cdf79ca0 100644 --- a/testing/test_hookcaller.py +++ b/testing/test_hookcaller.py @@ -511,3 +511,25 @@ def extra2() -> str: "2", "3", ] + + +def test_remove_plugin_not_found_raises(hc: HookCaller, pm: PluginManager) -> None: + """_remove_plugin() raises ValueError for a plugin that never registered + an implementation on this particular hook caller.""" + + class Plugin: + @hookimpl + def he_method1(self, arg): + pass # pragma: no cover + + plugin = Plugin() + pm.register(plugin) + assert len(hc.get_hookimpls()) == 1 + + other = Plugin() + with pytest.raises(ValueError, match=f"plugin {other!r} not found"): + hc._remove_plugin(other) + + # the failed removal must not have touched the existing registration + assert len(hc.get_hookimpls()) == 1 + pm.unregister(plugin)