#  Copyright 2022 The Debusine developers
#  See the AUTHORS file at the top-level directory of this distribution
#
#  This file is part of Debusine. It is subject to the license terms
#  in the LICENSE file found in the top-level directory of this
#  distribution. No part of Debusine, including this file, may be copied,
#  modified, propagated, or distributed except according to the terms
#  contained in the LICENSE file.

"""Unit tests for manage.py."""

import contextlib
import io
from unittest import mock

from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase

try:
    from manage import main
except ModuleNotFoundError:
    # When this test runs on the packaged debusine the source file "manage.py"
    # is installed in /usr/bin/debusine-admin . debusine_admin_main_importer()
    # return main.
    from debusine.project.tests.utils import debusine_admin_main_importer

    main = debusine_admin_main_importer()

from debusine.test import TestHelpersMixin


class DefaultSettingsTests(TestHelpersMixin, TestCase):
    """Tests for manage.py. Named debusine-admin when packaged."""

    def patch_execute_from_command_line(self, exception):
        """Patch execute_from_command_line: raise exception."""
        patcher = mock.patch(
            'django.core.management.execute_from_command_line', autospec=True
        )
        mocked_pathlib_owner = patcher.start()
        mocked_pathlib_owner.side_effect = exception
        self.addCleanup(patcher.stop)

    def assert_main_system_exit_with_stderr(self, stderr_expected):
        """Call main() assert system exit code is 3 and stderr as expected."""
        stderr = io.StringIO()

        with contextlib.redirect_stderr(stderr):
            with self.assertRaisesSystemExit(3):
                main()

        self.assertEqual(stderr.getvalue(), stderr_expected)

    def test_improperly_configured_output(self):
        """main() handle ImproperlyConfigured from execute_from_command_line."""
        self.patch_execute_from_command_line(ImproperlyConfigured("Error msg"))

        self.assert_main_system_exit_with_stderr(
            "Improperly configured error: Error msg\n"
        )

    def test_raise_error(self):
        """main() raise non-handled exception."""
        self.patch_execute_from_command_line(OSError("Some error"))

        with self.assertRaises(OSError):
            main()

    def assert_raise_error_permission_error(self, permission_error, msg):
        """Assert that permission_error is raised msg is in the stderr."""
        exception = ValueError("Some error")
        exception.__cause__ = permission_error

        self.patch_execute_from_command_line(exception)

        self.assert_main_system_exit_with_stderr(msg)

    def test_permission_error_raised_unknown_file(self):
        """main() handle ValueError caused by PermissionError."""
        permission_error = PermissionError("Internal error")

        self.assert_raise_error_permission_error(
            permission_error,
            "Permission error: Some error. Check that the user running "
            'debusine-admin has access to the file "Unknown".\n',
        )

    def test_permission_error_raised_file(self):
        """main() handle ValueError caused by PermissionError."""
        permission_error = PermissionError("Internal error")

        permission_error.filename = "/var/log/debusine/server/debug.log"

        self.assert_raise_error_permission_error(
            permission_error,
            "Permission error: Some error. Check that the user running "
            "debusine-admin has access to the file "
            f'"{permission_error.filename}".\n',
        )
