import pytest

from porcupine import pluginloader


def test_all_plugins_loaded_successfully():
    # If loading failed, errors were logged and printed to stderr
    assert pluginloader.plugin_infos, "if this fails, it means no plugins got loaded"
    for info in pluginloader.plugin_infos:
        # it's ok if you don't have tkdnd installed, doesn't get installed with pip
        if info.name != "drop_to_open":
            assert info.status == pluginloader.Status.ACTIVE


# filetypes plugin adds custom command line arguments
def test_filetypes_plugin_cant_be_loaded_while_running():
    [info] = [info for info in pluginloader.plugin_infos if info.name == "filetypes"]
    assert not pluginloader.can_setup_while_running(info)


# Tests cases ("deps" parameter) were generated by AI.
@pytest.mark.parametrize(
    "deps, result",
    [
        ({0: set(), 1: {0}, 2: {0}, 3: {1, 2}}, [{0}, {1, 2}, {3}]),
        ({0: set(), 1: {0}, 2: {0, 1}, 3: {2, 1}}, [{0}, {1}, {2}, {3}]),
        ({0: set(), 1: set(), 2: set(), 3: set(), 4: {0, 1}, 5: {2, 3}}, [{0, 1, 2, 3}, {4, 5}]),
        ({0: set()}, [{0}]),
    ],
)
def test_determining_setup_order_from_dependencies(mocker, deps, result):
    m = mocker.Mock()
    assert list(pluginloader._decide_loading_order(deps, m)) == result
    assert m.call_count == 0


def test_simple_dependency_cycle(mocker):
    m = mocker.Mock()
    assert list(pluginloader._decide_loading_order({0: {0}}, m)) == []
    m.assert_called_once_with([0, 0])  # cycle: 0 -> 0


def test_complex_dependency_cycle(mocker):
    m = mocker.Mock()
    order = list(
        pluginloader._decide_loading_order({0: {1}, 1: {2}, 2: {3}, 3: {1}, 4: {3}, 5: set()}, m)
    )
    assert order == [{5}, {0, 4}]
    m.assert_called_once_with([1, 2, 3, 1])  # cycle: 1 -> 2 -> 3 -> 1


def test_setup_order_bugs(monkeypatch):
    [autoindent] = [i for i in pluginloader.plugin_infos if i.name == "autoindent"]
    [rstrip] = [i for i in pluginloader.plugin_infos if i.name == "rstrip"]

    assert autoindent.status == pluginloader.Status.ACTIVE
    assert rstrip.status == pluginloader.Status.ACTIVE

    with monkeypatch.context() as monkey:
        # can setup rstrip when autoindent is already active
        monkey.setattr(rstrip, "status", pluginloader.Status.DISABLED_BY_SETTINGS)
        assert pluginloader.can_setup_while_running(rstrip)

    with monkeypatch.context() as monkey:
        # but not the other way, autoindent must go first
        monkey.setattr(autoindent, "status", pluginloader.Status.DISABLED_BY_SETTINGS)
        assert not pluginloader.can_setup_while_running(autoindent)
