from nose2 import events, loader, session
from nose2.tests._common import TestCase


class TestPluggableTestLoader(TestCase):
    def setUp(self):
        self.session = session.Session()
        self.loader = loader.PluggableTestLoader(self.session)

    def test_failed_load_tests_exception(self):
        suite = self.loader.failedLoadTests("test", RuntimeError("err"))
        tc = suite._tests[0]
        with self.assertRaises(RuntimeError) as cm:
            tc.test()
        self.assertEqual(cm.exception.args, ("err",))

    def test_failed_load_tests_exc_info(self):
        suite = self.loader.failedLoadTests(
            "test", (RuntimeError, RuntimeError("err"), None)
        )
        tc = suite._tests[0]
        with self.assertRaises(RuntimeError) as cm:
            tc.test()
        self.assertEqual(cm.exception.args, ("err",))

    def test_load_from_module_calls_hook(self):
        self.session.hooks.register("loadTestsFromModule", FakePlugin())
        evt = events.LoadFromModuleEvent(self.loader, "some_module")
        self.session.hooks.loadTestsFromModule(evt)
        self.assertTrue(
            evt.fakeLoadFromModule, "FakePlugin.loadTestsFromModule() was not called"
        )

    def test_load_from_name_calls_hook(self):
        self.session.hooks.register("loadTestsFromName", FakePlugin())
        evt = events.LoadFromNameEvent(self.loader, "some_name", "some_module")
        self.session.hooks.loadTestsFromName(evt)
        self.assertTrue(
            evt.fakeLoadFromName, "FakePlugin.fakeLoadFromName() was not called"
        )

    def test_load_from_names_calls_hook(self):
        self.session.hooks.register("loadTestsFromNames", FakePlugin())
        evt = events.LoadFromNamesEvent(self.loader, ["some_name"], "some_module")
        self.session.hooks.loadTestsFromNames(evt)
        self.assertTrue(
            evt.fakeLoadFromNames, "FakePlugin.fakeLoadFromNames() was not called"
        )

    def test_loader_from_names_calls_module_hook(self):
        fake_plugin = FakePlugin()
        self.session.hooks.register("loadTestsFromModule", fake_plugin)
        self.loader.loadTestsFromNames([], "some_module")
        self.assertTrue(
            fake_plugin.fakeLoadFromModule,
            "FakePlugin.loadTestsFromModule() was not called",
        )

    def test_loader_from_names_calls_name_hook(self):
        fake_plugin = FakePlugin()
        self.session.hooks.register("loadTestsFromName", fake_plugin)
        self.loader.loadTestsFromNames(["some_name"])
        self.assertTrue(
            fake_plugin.fakeLoadFromName,
            "FakePlugin.loadTestsFromName() was not called",
        )

    def test_loader_from_names_calls_names_hook(self):
        fake_plugin = FakePlugin()
        self.session.hooks.register("loadTestsFromNames", fake_plugin)
        self.loader.loadTestsFromNames(["some_name"])
        self.assertTrue(
            fake_plugin.fakeLoadFromNames,
            "FakePlugin.loadTestsFromNames() was not called",
        )


class FakePlugin:
    def __init__(self) -> None:
        self.fakeLoadFromModule = False
        self.fakeLoadFromName = False
        self.fakeLoadFromNames = False

    def loadTestsFromModule(self, event):
        event.fakeLoadFromModule = True
        self.fakeLoadFromModule = True

    def loadTestsFromName(self, event):
        event.fakeLoadFromName = True
        self.fakeLoadFromName = True

    def loadTestsFromNames(self, event):
        event.fakeLoadFromNames = True
        self.fakeLoadFromNames = True
