import pytest

from leapp.repository.actor_definition import ActorDefinition, ActorInspectionFailedError, MultipleActorsError
from leapp.exceptions import UnsupportedDefinitionKindError
from leapp.repository import DefinitionKind
from helpers import repository_dir
import logging
import mock

_FAKE_META_DATA = {
    'description': 'Fake Description',
    'class_name': 'FakeActor',
    'name': 'fake-actor',
    'path': 'actors/test',
    'tags': (),
    'consumes': (),
    'produces': (),
    'dialogs': (),
}


def test_actor_definition(repository_dir):
    with repository_dir.as_cwd():
        logger = logging.getLogger('leapp.actor.test')
        with mock.patch.object(logger, 'log') as log_mock:
            definition = ActorDefinition('actors/test', '.', log=log_mock)
            for kind in set(DefinitionKind.REPO_WHITELIST + DefinitionKind.ACTOR_WHITELIST):
                if kind in DefinitionKind.ACTOR_WHITELIST:
                    definition.add(kind, '.')
                else:
                    with pytest.raises(UnsupportedDefinitionKindError):
                        definition.add(kind, '.')
                    log_mock.error.assert_called_with(
                        "Attempt to add item type %s to actor that is not supported", kind.name)
                    log_mock.reset_mock()
            with mock.patch('leapp.repository.actor_definition.get_actor_metadata', return_value=_FAKE_META_DATA):
                with mock.patch('leapp.repository.actor_definition.get_actors', return_value=[True]):
                    definition._module = True
                    assert definition.consumes == _FAKE_META_DATA['consumes']
                    assert definition.produces == _FAKE_META_DATA['produces']
                    assert definition.tags == _FAKE_META_DATA['tags']
                    assert definition.class_name == _FAKE_META_DATA['class_name']
                    assert definition.dialogs == _FAKE_META_DATA['dialogs']
                    assert definition.name == _FAKE_META_DATA['name']
                    assert definition.description == _FAKE_META_DATA['description']
                    dumped = definition.dump()
                    assert dumped.pop('path') == _FAKE_META_DATA['path']
                    assert dumped.pop('name') == definition.name
                    assert dumped.pop('files') == ('.',)
                    assert dumped.pop('libraries') == ('.',)
                    assert dumped.pop('tests') == ('.',)
                    assert dumped.pop('tools') == ('.',)
                    # Assert to ensure we covered all keys
                    assert not dumped

            with pytest.raises(ActorInspectionFailedError):
                with mock.patch('leapp.repository.actor_definition.get_actors', return_value=[]):
                    definition._discovery = None
                    definition.discover()

            with pytest.raises(ActorInspectionFailedError):
                with mock.patch('leapp.repository.actor_definition.get_actors') as mocked_actors:
                    mocked_actors.side_effect = RuntimeError('Test error')
                    definition._discovery = None
                    definition.discover()

            with pytest.raises(MultipleActorsError):
                with mock.patch('leapp.repository.actor_definition.get_actor_metadata', return_value=_FAKE_META_DATA):
                    with mock.patch('leapp.repository.actor_definition.get_actors', return_value=[True, True]):
                        definition._discovery = None
                        definition.discover()

[((23, 9, 23, 32), 'helpers.repository_dir.as_cwd', 'repository_dir.as_cwd', ({}, {}), '()', False, 'from helpers import repository_dir\n'), ((24, 17, 24, 54), 'logging.getLogger', 'logging.getLogger', ({(24, 35, 24, 53): '"""leapp.actor.test"""'}, {}), "('leapp.actor.test')", False, 'import logging\n'), ((25, 13, 25, 45), 'mock.patch.object', 'mock.patch.object', ({(25, 31, 25, 37): 'logger', (25, 39, 25, 44): '"""log"""'}, {}), "(logger, 'log')", False, 'import mock\n'), ((26, 25, 26, 74), 'leapp.repository.actor_definition.ActorDefinition', 'ActorDefinition', (), '', False, 'from leapp.repository.actor_definition import ActorDefinition, ActorInspectionFailedError, MultipleActorsError\n'), ((36, 17, 36, 113), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((56, 17, 56, 58), 'pytest.raises', 'pytest.raises', ({(56, 31, 56, 57): 'ActorInspectionFailedError'}, {}), '(ActorInspectionFailedError)', False, 'import pytest\n'), ((61, 17, 61, 58), 'pytest.raises', 'pytest.raises', ({(61, 31, 61, 57): 'ActorInspectionFailedError'}, {}), '(ActorInspectionFailedError)', False, 'import pytest\n'), ((67, 17, 67, 51), 'pytest.raises', 'pytest.raises', ({(67, 31, 67, 50): 'MultipleActorsError'}, {}), '(MultipleActorsError)', False, 'import pytest\n'), ((37, 21, 37, 100), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((57, 21, 57, 96), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((62, 21, 62, 79), 'mock.patch', 'mock.patch', ({(62, 32, 62, 78): '"""leapp.repository.actor_definition.get_actors"""'}, {}), "('leapp.repository.actor_definition.get_actors')", False, 'import mock\n'), ((68, 21, 68, 117), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((31, 25, 31, 70), 'pytest.raises', 'pytest.raises', ({(31, 39, 31, 69): 'UnsupportedDefinitionKindError'}, {}), '(UnsupportedDefinitionKindError)', False, 'import pytest\n'), ((69, 25, 69, 110), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n')]