import os

import cauldron as cd
from cauldron import environ
from cauldron.session import projects
from cauldron.test.support import scaffolds
from cauldron.test import support


class TestProject(scaffolds.ResultsTest):
    """

    """

    def test_file_source_path(self):
        """A file source directory should be a directory"""

        support.create_project(self, 'lupin')
        project = cd.project.internal_project

        p = projects.Project(project.source_path)
        self.assertTrue(os.path.isdir(p.source_directory))
        self.assertEqual(p.source_directory, project.source_directory)

        support.run_command('close')

    def test_shared_dict(self):
        """A dict shared argument should be converted into a SharedCache"""

        support.create_project(self, 'tonks')
        project = cd.project.internal_project

        shared_data = {'a': 1, 'b': True}
        p = projects.Project(project.source_directory, shared=shared_data)

        self.assertIsInstance(p.shared, projects.SharedCache)

        for key, value in shared_data.items():
            self.assertEqual(p.shared.fetch(key), value)

        support.run_command('close')

    def test_title(self):
        """Project title should be readable and writable"""

        support.create_project(self, 'sirius')
        project = cd.project.internal_project

        title = 'My Title'
        project.title = title
        self.assertEqual(title, project.title)

        support.run_command('close')

    def test_results_path(self):
        """Results path should always be valid"""

        def assert_valid_path(test: str) -> bool:
            return self.assertTrue(
                test is not None and
                len(test) > 0
            )

        support.create_project(self, 'dudley')
        project = cd.project.internal_project

        project._results_path = None
        assert_valid_path(project.results_path)

        results_directory = environ.configs.fetch('results_directory')
        environ.configs.put(results_directory=None, persists=False)

        assert_valid_path(project.results_path)

        project.settings.put('path_results', os.path.realpath('.'))
        assert_valid_path(project.results_path)

        project.settings.put('path_results', None)
        assert_valid_path(project.results_path)

        environ.configs.put(results_directory=results_directory, persists=False)

        support.run_command('close')

    def test_has_no_error(self):
        """Should not have an error"""

        support.create_project(self, 'vernon')
        project = cd.project.internal_project

        self.assertFalse(project.has_error, 'error on project without steps')

        support.add_step(self)
        support.add_step(self)
        support.add_step(self)

        support.run_command('run')

        self.assertFalse(project.has_error, 'error after running steps')

        support.run_command('close')

    def test_has_error(self):
        """Should have error if step raises an error when run"""

        support.create_project(self, 'petunia')
        project = cd.project.internal_project

        support.add_step(self, contents='raise Exception("test")')
        support.run_command('run')

        self.assertTrue(project.has_error, 'step should have errored')

        support.run_command('close')

    def test_get_no_step(self):
        """Should not find a step that doesn't exist"""

        support.create_project(self, 'luna')
        project = cd.project.internal_project

        support.add_step(self)
        support.add_step(self)

        self.assertIsNone(project.get_step('NoSuchStep'))
        self.assertIsNone(project.get_step_by_reference_id('NoSuchStep'))
        self.assertIsNone(project.index_of_step('NoSuchStep'))

        support.run_command('close')

    def test_no_such_settings(self):
        """Error when no project settings file exists"""

        with self.assertRaises(FileNotFoundError):
            projects.load_project_settings(
                os.path.dirname(os.path.realpath(__file__))
            )
