# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals

import os
import os.path
import shutil
import sys
from copy import copy
from distutils.version import LooseVersion
from tempfile import mkdtemp

import django

from app_helper import runner
from app_helper.default_settings import get_boilerplates_settings
from app_helper.main import _make_settings, _map_argv, core
from app_helper.utils import DJANGO_1_9, captured_output, temp_dir, work_in

try:
    from unittest.mock import patch
except ImportError:
    from mock import patch

try:
    import unittest2 as unittest
except ImportError:
    import unittest

DEFAULT_ARGS = {
    "shell": False,
    "test": False,
    "cms_check": False,
    "compilemessages": False,
    "makemessages": False,
    "makemigrations": False,
    "pyflakes": False,
    "authors": False,
    "server": False,
    "--xvfb": "",
    "--runner": None,
    "--runner-options": None,
    "--cms": True,
    "--failfast": False,
    "--merge": False,
    "--locale": "",
    "--boilerplate": False,
    "--dry-run": False,
    "--empty": False,
    "--native": False,
    "--persistent": False,
    "--persistent-path": None,
    "--bind": "",
    "--port": "",
    "<test-label>": "",
    "<extra-applications>": "",
    "options": "",
    "<command>": "",
}


class CommandTests(unittest.TestCase):
    application = None
    basedir = None
    pofile = None
    mofile = None
    migration_dir = None

    @classmethod
    def setUpClass(cls):
        os.environ.setdefault("DATABASE_URL", "sqlite://localhost/:memory:")
        cls.basedir = os.path.abspath(os.path.join("app_helper", "test_utils"))
        cls.application = "example1"
        cls.application_2 = "example2"
        with work_in(cls.basedir):
            with captured_output():
                cls.migration_example = os.path.abspath(
                    os.path.join(cls.application, "data", "django_0001_initial.py")
                )
                cls.migration_partial = os.path.abspath(
                    os.path.join(cls.application, "data", "django_0001_partial.py")
                )
                cls.poexample = os.path.abspath(os.path.join(cls.application, "data", "django.po"))
                cls.pofile = os.path.abspath(os.path.join(cls.application, "locale", "en", "LC_MESSAGES", "django.po"))
                cls.mofile = os.path.abspath(os.path.join(cls.application, "locale", "en", "LC_MESSAGES", "django.mo"))
                cls.migration_dir = os.path.abspath(os.path.join(cls.application, "migrations"))
                cls.migration_dir_2 = os.path.abspath(os.path.join(cls.application_2, "migrations"))
                cls.migration_file = os.path.abspath(os.path.join(cls.application, "migrations", "0001_initial.py"))
                cls.migration_file_2 = os.path.abspath(
                    os.path.join(cls.application_2, "migrations", "0001_initial.py")
                )
        try:
            import cms
        except ImportError:
            DEFAULT_ARGS["--cms"] = False

    def setUp(self):
        try:
            os.unlink(self.pofile)
        except (OSError, TypeError):
            pass
        try:
            os.unlink(self.mofile)
        except (OSError, TypeError):
            pass
        try:
            if self.migration_dir:
                shutil.rmtree(self.migration_dir)
        except (OSError, TypeError):
            pass
        try:
            if self.migration_dir_2:
                shutil.rmtree(self.migration_dir_2)
        except (OSError, TypeError):
            pass
        try:
            del sys.modules["example1.migrations"]
        except KeyError as e:
            pass
        try:
            del sys.modules["example2.migrations"]
        except KeyError as e:
            pass

    def tearDown(self):
        os.environ["AUTH_USER_MODEL"] = "auth.User"
        self.setUp()

    def test_map_argv(self):
        from ..main import _map_argv

        argv_1 = [
            "helper.py",
            "example1",
            "test",
            "--cms",
            "--persistent-path=test",
            "--extra-settings==something.py",
            "--runner==something.py",
        ]
        target_1 = {
            "--bind": "127.0.0.1",
            "--boilerplate": False,
            "--cms": True,
            "--dry-run": False,
            "--empty": False,
            "--extra-settings": "",
            "--failfast": False,
            "--help": False,
            "--locale": None,
            "--merge": False,
            "--migrate": False,
            "--native": False,
            "--no-migrate": False,
            "--persistent": True,
            "--persistent-path": "test",
            "--port": "8000",
            "--runner": "",
            "--runner-options": None,
            "--verbose": None,
            "--version": False,
            "--xvfb": False,
            "<application>": "example1",
            "<command>": None,
            "<extra-applications>": [],
            "<test-label>": [],
            "authors": False,
            "cms_check": False,
            "compilemessages": False,
            "makemessages": False,
            "makemigrations": False,
            "options": [
                "helper.py",
                "test",
                "--cms",
                "--persistent-path=test",
                "--extra-settings==something.py",
                "--runner==something.py",
            ],
            "pyflakes": False,
            "server": False,
            "setup": False,
            "test": True,
        }
        argv_2 = [
            "helper.py",
            "example1",
            "server",
            "--cms",
            "--persistent-path=test",
            "--extra-settings==something.py",
            "--runner==something.py",
        ]
        target_2 = {
            "--bind": "127.0.0.1",
            "--boilerplate": False,
            "--cms": True,
            "--dry-run": False,
            "--empty": False,
            "--extra-settings": "",
            "--failfast": False,
            "--help": False,
            "--locale": None,
            "--merge": False,
            "--migrate": False,
            "--native": False,
            "--no-migrate": False,
            "--persistent": True,
            "--persistent-path": "test",
            "--port": "8000",
            "--runner": "",
            "--runner-options": None,
            "--verbose": None,
            "--version": False,
            "--xvfb": False,
            "<application>": "example1",
            "<command>": None,
            "<extra-applications>": [],
            "<test-label>": [],
            "authors": False,
            "cms_check": False,
            "compilemessages": False,
            "makemessages": False,
            "makemigrations": False,
            "options": [
                "helper.py",
                "server",
                "--cms",
                "--persistent-path=test",
                "--extra-settings==something.py",
                "--runner==something.py",
            ],
            "pyflakes": False,
            "server": True,
            "setup": False,
            "test": False,
        }

        argv_3 = [
            "helper.py",
            "example1",
            "some_command",
            "--cms",
            "--persistent-path=test",
            "--extra-settings==something.py",
            "--runner==something.py",
        ]
        target_3 = {
            "--bind": "127.0.0.1",
            "--boilerplate": False,
            "--cms": True,
            "--dry-run": False,
            "--empty": False,
            "--extra-settings": "",
            "--failfast": False,
            "--help": False,
            "--locale": None,
            "--merge": False,
            "--migrate": False,
            "--native": False,
            "--no-migrate": False,
            "--persistent": True,
            "--persistent-path": "test",
            "--port": "8000",
            "--runner": "",
            "--runner-options": None,
            "--verbose": None,
            "--version": False,
            "--xvfb": False,
            "<application>": "example1",
            "<command>": "some_command",
            "<extra-applications>": [],
            "<test-label>": [],
            "authors": False,
            "cms_check": False,
            "compilemessages": False,
            "makemessages": False,
            "makemigrations": False,
            "options": [
                "helper.py",
                "some_command",
                "--cms",
                "--persistent-path=test",
                "--extra-settings==something.py",
                "--runner==something.py",
            ],
            "pyflakes": False,
            "server": False,
            "setup": False,
            "test": False,
        }

        application_module = __import__(argv_1[1])
        args = _map_argv(argv_1, application_module)
        self.assertEqual(target_1, args)

        application_module = __import__(argv_2[1])
        args = _map_argv(argv_2, application_module)
        self.assertEqual(target_2, args)

        application_module = __import__(argv_3[1])
        args = _map_argv(argv_3, application_module)
        self.assertEqual(target_3, args)

    def test_extra_settings(self):
        from django.conf import settings

        with work_in(self.basedir):
            # with captured_output() as (out, err):
            args = copy(DEFAULT_ARGS)
            with temp_dir() as STATIC_ROOT:
                with temp_dir() as MEDIA_ROOT:
                    local_settings = _make_settings(args, self.application, settings, STATIC_ROOT, MEDIA_ROOT)
                    # Testing that helper.py in custom project is loaded
                    self.assertEqual(local_settings.TIME_ZONE, "Europe/Rome")

                    args["--boilerplate"] = True
                    args["--extra-settings"] = "cms_helper_extra.py"
                    local_settings = _make_settings(args, self.application, settings, STATIC_ROOT, MEDIA_ROOT)
                    # Testing that helper.py in the command option is loaded
                    self.assertEqual(local_settings.TIME_ZONE, "Europe/Paris")
                    # Existing application is kept
                    self.assertTrue("app_helper.test_data" in local_settings.INSTALLED_APPS)
                    # New ones are added both on top and in random positions
                    self.assertEqual("djangocms_admin_style", local_settings.INSTALLED_APPS[0])
                    self.assertTrue("some_app" in local_settings.INSTALLED_APPS)

                    # Ditto for middlewares
                    if DJANGO_1_9:
                        self.assertEqual("top_middleware", local_settings.MIDDLEWARE_CLASSES[0])
                        self.assertTrue("some_middleware" in local_settings.MIDDLEWARE_CLASSES)
                        self.assertTrue(
                            "django.contrib.sessions.middleware.SessionMiddleware" in local_settings.MIDDLEWARE_CLASSES
                        )
                    else:
                        self.assertTrue(
                            "django.contrib.sessions.middleware.SessionMiddleware" in local_settings.MIDDLEWARE
                        )
                        self.assertEqual("top_middleware", local_settings.MIDDLEWARE[0])
                        self.assertTrue("some_middleware" in local_settings.MIDDLEWARE)

                    boilerplate_settings = get_boilerplates_settings()

                    # Check the loaders
                    self.assertTrue(
                        "django.template.loaders.app_directories.Loader"
                        in local_settings.TEMPLATES[0]["OPTIONS"]["loaders"]
                    )
                    # Loaders declared in settings
                    self.assertTrue(
                        "admin_tools.template_loaders.Loader" in local_settings.TEMPLATES[0]["OPTIONS"]["loaders"]
                    )
                    # Existing application is kept
                    self.assertTrue(
                        "django.template.context_processors.request"
                        in local_settings.TEMPLATES[0]["OPTIONS"]["context_processors"]
                    )
                    # New one is added
                    self.assertTrue(
                        "django.template.context_processors.debug"
                        in local_settings.TEMPLATES[0]["OPTIONS"]["context_processors"]
                    )
                    # Check template dirs
                    self.assertTrue("some/dir" in local_settings.TEMPLATES[0]["DIRS"])
                    # Check for aldryn boilerplates
                    for name, value in boilerplate_settings.items():
                        if not name.startswith("TEMPLATE"):
                            if type(value) in (list, tuple):
                                self.assertTrue(set(getattr(local_settings, name)).intersection(set(value)))
                            elif name == "ALDRYN_BOILERPLATE_NAME":
                                self.assertEqual(getattr(local_settings, name), "legacy")
                            else:
                                self.assertTrue(value in getattr(local_settings, name))
                        elif name == "TEMPLATE_CONTEXT_PROCESSORS":
                            self.assertTrue(
                                set(local_settings.TEMPLATES[0]["OPTIONS"]["context_processors"]).intersection(
                                    set(value)
                                )
                            )
                        elif name == "TEMPLATE_LOADERS":
                            self.assertTrue(
                                set(local_settings.TEMPLATES[0]["OPTIONS"]["loaders"]).intersection(set(value))
                            )

    @patch("app_helper.main.autoreload")
    def test_server(self, mocked_command):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["server"] = True
                core(args, self.application)
            self.assertTrue("A admin user (username: admin, password: admin) has been created." in out.getvalue())

    def test_makemigrations(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["makemigrations"] = True
                args["<extra-applications>"] = ["example2"]
                core(args, self.application)
            self.assertTrue(os.path.exists(self.migration_file))
            self.assertTrue(os.path.exists(self.migration_file_2))
        self.assertTrue("Create model ExampleModel1" in out.getvalue())
        self.assertTrue("Create model ExampleModel2" in out.getvalue())

    def skip_test_makemigrations_update(self):
        os.makedirs(self.migration_dir)
        open(os.path.join(self.migration_dir, "__init__.py"), "w")
        shutil.copy(self.migration_partial, self.migration_file)
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["makemigrations"] = True
                core(args, self.application)
        self.assertTrue("Migrations for 'example1':" in out.getvalue())

    def test_makemigrations_empty(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                os.makedirs(self.migration_dir)
                open(os.path.join(self.migration_dir, "__init__.py"), "w")
                shutil.copy(self.migration_example, self.migration_file)
                args = copy(DEFAULT_ARGS)
                args["makemigrations"] = True
                args["--empty"] = True
                core(args, self.application)
        self.assertTrue("Migrations for 'example1':" in out.getvalue())

    def test_makemigrations_merge(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["makemigrations"] = True
                args["--merge"] = True
                core(args, self.application)
                self.assertTrue("No conflicts detected to merge" in out.getvalue())

    def test_makemessages(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["makemessages"] = True
                core(args, self.application)
                self.assertTrue(os.path.exists(self.pofile))

    def test_compilemessages(self):
        with work_in(self.basedir):
            shutil.copy(self.poexample, self.pofile)
            args = copy(DEFAULT_ARGS)
            args["compilemessages"] = True
            core(args, self.application)
            self.assertTrue(os.path.exists(self.mofile))

    def test_cms_check(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                shutil.copy(self.poexample, self.pofile)
                args = copy(DEFAULT_ARGS)
                args["cms_check"] = True
                args["--extra-settings"] = "helper.py"
                args["--migrate"] = False
                core(args, self.application)
            self.assertTrue("Installation okay" in out.getvalue())
            self.assertFalse("[WARNING]" in out.getvalue())
            self.assertFalse("[ERROR]" in out.getvalue())

    @unittest.skipIf(LooseVersion(django.get_version()) >= LooseVersion("1.9"), reason="Test for Django up until 1.8")
    def test_cms_check_nocms(self):
        try:
            import cms

            raise unittest.SkipTest("django CMS available, skipping test")
        except ImportError:
            pass
        with work_in(self.basedir):
            with captured_output() as (out, err):
                shutil.copy(self.poexample, self.pofile)
                args = copy(DEFAULT_ARGS)
                args["cms_check"] = True
                args["--extra-settings"] = "helper.py"
                args["--migrate"] = False
                core(args, self.application)
            self.assertTrue("cms_check available only if django CMS is installed" in out.getvalue())

    @unittest.skipIf(LooseVersion(django.get_version()) < LooseVersion("1.9"), reason="Test for Django 1.9+")
    def test_cms_check_nocms_19(self):
        try:
            import cms

            raise unittest.SkipTest("django CMS available, skipping test")
        except ImportError:
            pass
        with work_in(self.basedir):
            with self.assertRaises(ImportError):
                shutil.copy(self.poexample, self.pofile)
                args = copy(DEFAULT_ARGS)
                args["cms_check"] = True
                args["--extra-settings"] = "helper.py"
                args["--migrate"] = False
                core(args, self.application)

    @unittest.skipIf(
        LooseVersion(django.get_version()) < LooseVersion("1.7"), reason="check command available in Django 1.7+ only"
    )
    def test_any_command_check(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["<command>"] = "check"
                args["options"] = ["helper", "check", "--extra-settings=cms_helper_extra.py"]
                core(args, self.application)
        self.assertTrue("no issues" in out.getvalue())

    def test_any_command_compilemessages(self):
        with work_in(os.path.join(self.basedir, self.application)):
            with captured_output() as (out, err):
                shutil.copy(self.poexample, self.pofile)
                args = copy(DEFAULT_ARGS)
                args["<command>"] = "compilemessages"
                args["options"] = "helper compilemessages --cms -len --verbosity=2".split(" ")
                core(args, self.application)
                self.assertTrue(os.path.exists(self.mofile))

    def test_any_command_migrations(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["<command>"] = "makemigrations"
                args["options"] = "helper makemigrations example2 --verbosity=2".split(" ")
                core(args, self.application)
            self.assertFalse("Create model ExampleModel1" in out.getvalue())
            self.assertFalse(os.path.exists(self.migration_file))
            self.assertTrue("Create model ExampleModel2" in out.getvalue())
            self.assertTrue(os.path.exists(self.migration_file_2))

    @unittest.skipIf(sys.version_info[:2] in ((3, 8),),
                     reason='This test fails on Python 3.8+')
    def test_pyflakes(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["pyflakes"] = True
                core(args, self.application)
        self.assertFalse(os.path.exists(args["STATIC_ROOT"]))
        self.assertFalse(os.path.exists(args["MEDIA_ROOT"]))

    def test_pyflakes_nocms(self):
        try:
            import cms

            raise unittest.SkipTest("django CMS available, skipping test")
        except ImportError:
            pass
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["pyflakes"] = True
                core(args, self.application)
            self.assertTrue(
                "Static analysis available only if django CMS and pyflakes are installed" in out.getvalue()
            )
        self.assertFalse(os.path.exists(args["STATIC_ROOT"]))
        self.assertFalse(os.path.exists(args["MEDIA_ROOT"]))

    def test_testrun(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        path = os.path.join(self.basedir, "data")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                with self.assertRaises(SystemExit) as exit:
                    try:
                        from django.test.utils import _TestState

                        del _TestState.saved_data
                    except (ImportError, AttributeError):
                        pass
                    args = copy(DEFAULT_ARGS)
                    args["test"] = True
                    args["--persistent"] = True
                    args["--runner"] = "runners.CapturedOutputRunner"
                    core(args, self.application)
        self.assertTrue("Ran 14 tests in" in err.getvalue())
        self.assertEqual(exit.exception.code, 0)
        self.assertTrue(args["STATIC_ROOT"].startswith(path))
        self.assertTrue(args["MEDIA_ROOT"].startswith(path))
        self.assertTrue(os.path.exists(args["STATIC_ROOT"]))
        self.assertTrue(os.path.exists(args["MEDIA_ROOT"]))

    def test_testrun_persistent_path(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        path = mkdtemp()
        with work_in(self.basedir):
            with captured_output() as (out, err):
                with self.assertRaises(SystemExit) as exit:
                    try:
                        from django.test.utils import _TestState

                        del _TestState.saved_data
                    except (ImportError, AttributeError):
                        pass
                    args = copy(DEFAULT_ARGS)
                    args["test"] = True
                    args["--persistent"] = True
                    args["--persistent-path"] = path
                    args["--runner"] = "runners.CapturedOutputRunner"
                    core(args, self.application)
        self.assertTrue("Ran 14 tests in" in err.getvalue())
        self.assertEqual(exit.exception.code, 0)
        self.assertTrue(args["STATIC_ROOT"].startswith(path))
        self.assertTrue(args["MEDIA_ROOT"].startswith(path))
        self.assertTrue(os.path.exists(args["STATIC_ROOT"]))
        self.assertTrue(os.path.exists(args["MEDIA_ROOT"]))

    def test_runner_wrong(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            if sys.version_info < (3, 5):
                exception = ImportError
            else:
                exception = SystemExit
            with captured_output() as (out, err):
                with self.assertRaises(exception) as exit:
                    args = list()
                    args.append("helper")
                    args.append("test")
                    args.append("example1")
                    args.append("--runner=runners.CapturedOutputRunner")
                    args.append("whatever")
                    runner.cms("example1", args)
        if sys.version_info >= (3, 5):
            self.assertEqual(exit.exception.code, 1)

    def test_runner(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        from app_helper.test_utils.runners import CapturedOutputRunner

        with patch("django.test.runner.DiscoverRunner", CapturedOutputRunner):
            with work_in(self.basedir):
                with captured_output() as (out, err):
                    with self.assertRaises(SystemExit) as exit:
                        args = list()
                        args.append("helper")
                        args.append("test")
                        args.append("--extra-settings=helper.py")
                        args.append("example1")
                        runner.cms("example1", args)
        self.assertTrue("visible string" in out.getvalue())
        self.assertFalse("hidden string" in out.getvalue())
        self.assertFalse("hidden string" in err.getvalue())
        self.assertTrue("Ran 14 tests in" in err.getvalue())
        self.assertEqual(exit.exception.code, 0)

    def test_runner_compat(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        from app_helper.test_utils.runners import CapturedOutputRunner

        with patch("django.test.runner.DiscoverRunner", CapturedOutputRunner):
            with work_in(self.basedir):
                with captured_output() as (out, err):
                    with self.assertRaises(SystemExit) as exit:
                        args = list()
                        args.append("cms_helper")
                        args.append("test")
                        args.append("example1")
                        runner.cms("example1", args)
        self.assertTrue("visible string" in out.getvalue())
        self.assertFalse("hidden string" in out.getvalue())
        self.assertFalse("hidden string" in err.getvalue())
        self.assertTrue("Ran 14 tests in" in err.getvalue())
        self.assertEqual(exit.exception.code, 0)

    def test_runner_cms_exception(self):
        try:
            import cms

            raise unittest.SkipTest("django CMS available, skipping test")
        except ImportError:
            pass
        from app_helper.test_utils.runners import CapturedOutputRunner

        with patch("django.test.runner.DiscoverRunner", CapturedOutputRunner):
            with work_in(self.basedir):
                with captured_output() as (out, err):
                    with self.assertRaises(ImportError) as exit:
                        args = list()
                        args.append("helper")
                        runner.cms("example1", args)

    def test_runner_cms_argv(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")

        def fake_runner(argv):
            return argv

        from app_helper.test_utils.runners import CapturedOutputRunner

        with patch("django.test.runner.DiscoverRunner", CapturedOutputRunner):
            with work_in(self.basedir):
                with captured_output() as (out, err):
                    args = list()
                    args.append("helper")
                    with patch("app_helper.runner.runner", fake_runner):
                        data = runner.cms("example1", args)
                    self.assertEqual(data, ["helper", "example1", "test", "--cms"])

    def test_runner_argv(self):
        def fake_runner(argv):
            return argv

        from app_helper.test_utils.runners import CapturedOutputRunner

        with patch("django.test.runner.DiscoverRunner", CapturedOutputRunner):
            with work_in(self.basedir):
                with captured_output() as (out, err):
                    args = list()
                    args.append("helper")
                    with patch("app_helper.runner.runner", fake_runner):
                        data = runner.run("example1", args)
                    self.assertEqual(data, ["helper", "example1", "test"])

    def test_setup_cms(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                from app_helper.test_utils import helper

                settings = runner.setup("example1", helper, use_cms=True, extra_args=["--boilerplate"])
        self.assertTrue("example2" in settings.INSTALLED_APPS)
        self.assertTrue("aldryn_boilerplates" in settings.INSTALLED_APPS)
        self.assertTrue("cms" in settings.INSTALLED_APPS)

    def test_setup_custom_user(self):
        os.environ["AUTH_USER_MODEL"] = "custom_user.CustomUser"
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                from app_helper.test_utils import cms_helper_custom

                settings = runner.setup("example1", cms_helper_custom, use_cms=True, extra_args=["--boilerplate"])
        self.assertTrue("example2" in settings.INSTALLED_APPS)
        self.assertTrue("custom_user" in settings.INSTALLED_APPS)
        self.assertTrue("aldryn_boilerplates" in settings.INSTALLED_APPS)
        self.assertTrue("cms" in settings.INSTALLED_APPS)
        del os.environ["AUTH_USER_MODEL"]

    def test_setup_nocms(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                from app_helper.test_utils import helper

                settings = runner.setup("example1", helper, extra_args=[])
        self.assertTrue("example2" in settings.INSTALLED_APPS)
        self.assertFalse("aldryn_boilerplates" in settings.INSTALLED_APPS)
        self.assertFalse("cms" in settings.INSTALLED_APPS)

    def test_testrun_nocms(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                with self.assertRaises(SystemExit) as exit:
                    try:
                        from django.test.utils import _TestState

                        del _TestState.saved_data
                    except (ImportError, AttributeError):
                        pass
                    args = copy(DEFAULT_ARGS)
                    args["test"] = True
                    args["--cms"] = False
                    args["--runner"] = "runners.CapturedOutputRunner"
                    core(args, self.application)
        self.assertTrue("Ran 14 tests in" in err.getvalue())
        self.assertEqual(exit.exception.code, 0)

    def test_runner_nocms(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                with self.assertRaises(SystemExit) as exit:
                    args = list()
                    args.append("helper")
                    args.append("example1")
                    args.append("test")
                    args.append("--extra-settings=helper.py")
                    args.append("--runner=runners.CapturedOutputRunner")
                    runner.run("example1", args)
        self.assertTrue("Ran 14 tests in" in err.getvalue())
        self.assertEqual(exit.exception.code, 0)

    def test_testrun_native(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                try:
                    from django.test.utils import _TestState

                    del _TestState.saved_data
                except (ImportError, AttributeError):
                    pass
                args = copy(DEFAULT_ARGS)
                args["<command>"] = "test"
                args["--cms"] = False
                args["--native"] = True
                args["--extra-settings"] = "cms_helper_extra_runner.py"
                core(args, self.application)
        self.assertTrue("Ran 14 tests in" in err.getvalue())

    def test_testrun_pytest(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        with work_in(self.basedir):
            with captured_output() as (out, err):
                try:
                    from django.test.utils import _TestState

                    del _TestState.saved_data
                except (ImportError, AttributeError):
                    pass
                args = copy(DEFAULT_ARGS)
                args["<command>"] = "test"
                args["--cms"] = False
                args["--runner"] = "app_helper.pytest_runner.PytestTestRunner"
                args["--extra-settings"] = "helper_no_cms.py"
                core(args, self.application)
        self.assertTrue("collected 15 items" in out.getvalue())
        # warnings will depend on django version and adds too much noise
        self.assertTrue("10 passed, 5 skipped" in out.getvalue())

    def test_runner_pytest(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                with self.assertRaises(SystemExit) as exit:
                    args = list()
                    args.append("helper_no_cms")
                    args.append("example1")
                    args.append("test")
                    args.append("--extra-settings=helper_no_cms.py")
                    args.append("--runner=app_helper.pytest_runner.PytestTestRunner")
                    runner.run("example1", args)
        self.assertTrue("collected 15 items" in out.getvalue())
        # warnings will depend on django version and adds too much noise
        self.assertTrue("10 passed, 5 skipped" in out.getvalue())
        self.assertEqual(exit.exception.code, 0)

    def test_authors(self):
        with work_in(self.basedir):
            with captured_output() as (out, err):
                args = copy(DEFAULT_ARGS)
                args["authors"] = True
                core(args, self.application)
        self.assertTrue("Generating AUTHORS" in out.getvalue())
        self.assertTrue("* Iacopo Spalletti" in out.getvalue())
        self.assertTrue("Authors (" in out.getvalue())

    def test_urls(self):
        try:
            import cms
        except ImportError:
            raise unittest.SkipTest("django CMS not available, skipping test")
        try:
            from django.urls import reverse
        except ImportError:
            from django.core.urlresolvers import reverse
        with work_in(self.basedir):
            with captured_output() as (out, err):
                shutil.copy(self.poexample, self.pofile)
                args = copy(DEFAULT_ARGS)
                args["makemessages"] = True
                core(args, self.application)
                self.assertTrue(reverse("pages-root"))

    def test_urls_nocms(self):
        try:
            from django.urls import reverse, NoReverseMatch
        except ImportError:
            from django.core.urlresolvers import reverse, NoReverseMatch
        with work_in(self.basedir):
            with captured_output() as (out, err):
                shutil.copy(self.poexample, self.pofile)
                args = copy(DEFAULT_ARGS)
                args["makemessages"] = True
                args["--cms"] = False
                core(args, self.application)
                with self.assertRaises(NoReverseMatch):
                    reverse("pages-root")
