import importlib
import inspect
import os
import re
import sys
import tempfile
from io import StringIO
from pathlib import Path

from django.conf.urls import url
from django.core import mail
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db import DatabaseError, connection
from django.shortcuts import render
from django.template import TemplateDoesNotExist
from django.test import RequestFactory, SimpleTestCase, override_settings
from django.test.utils import LoggingCaptureMixin, patch_logger
from django.urls import reverse
from django.utils.encoding import force_bytes
from django.utils.functional import SimpleLazyObject
from django.views.debug import (
    CLEANSED_SUBSTITUTE, CallableSettingWrapper, ExceptionReporter,
    cleanse_setting, technical_500_response,
)

from ..views import (
    custom_exception_reporter_filter_view, index_page,
    multivalue_dict_key_error, non_sensitive_view, paranoid_view,
    sensitive_args_function_caller, sensitive_kwargs_function_caller,
    sensitive_method_view, sensitive_view,
)

PY36 = sys.version_info >= (3, 6)


class User:
    def __str__(self):
        return 'jacob'


class WithoutEmptyPathUrls:
    urlpatterns = [url(r'url/$', index_page, name='url')]


class CallableSettingWrapperTests(SimpleTestCase):
    """ Unittests for CallableSettingWrapper
    """
    def test_repr(self):
        class WrappedCallable:
            def __repr__(self):
                return "repr from the wrapped callable"

            def __call__(self):
          
      pass

        actual = repr(CallableSettingWra
pper(WrappedCallable()))
        self.assertEqual(actual, "repr from the wrapped callable")


@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
class DebugViewTests(LoggingCaptureMixin, SimpleTestCase):

    def test_files(self):
        response = self.client.get('/raises/')
        self.assertEqual(response.status_code, 500)

        data = {
            'file_data.txt': SimpleUploadedFile('file_data.txt', b'haha'),
        }
        response = self.client.post('/raises/', data)
        self.assertContains(response, 'file_data.txt', status_code=500)
        self.assertNotContains(response, 'haha', status_code=500)

    def test_400(self):
        # When DEBUG=True, technical_500_template() is called.
        response = self.client.get('/raises400/')
        self.assertContains(response, '<div class="context" id="', status_code=400)

    # Ensure no 403.html template exists to test the default case.
    @override_settings(TEMPLATES=[{
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
    }])
    def test_403(self):
        response = self.client.get('/raises403/')
        self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403)

    # Set up a test 403.html template.
    @override_settings(TEMPLATES=[{
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'OPTIONS': {
            'loaders': [
                ('django.template.loaders.locmem.Loader', {
                    '403.html': 'This is a test template for a 403 error ({{ exception }}).',
                }),
            ],
        },
    }])
    def test_403_template(self):
        response = self.client.get('/raises403/')
        self.assertContains(response, 'test template', status_code=403)
        self.assertContains(response, '(Insufficient Permissions).', status_code=403)

    def test_404(self):
        response = self.client.get('/raises404/')
        self.assertEqual(response.status_code, 404)

    def test_raised_404(self):
        response = self.client.get('/views/raises404/')
        self.assertContains(response, "<code>not-in-urls</code>, didn't match", status_code=404)

    def test_404_not_in_urls(self):
        response = self.client.get('/not-in-urls')
        self.assertNotContains(response, "Raised by:", status_code=404)
        self.assertContains(response, "<code>not-in-urls</code>, didn't match", status_code=404)

    @override_settings(ROOT_URLCONF=WithoutEmptyPathUrls)
    def test_404_empty_path_not_in_urls(self):
        response = self.client.get('/')
        self.assertContains(response, "The empty path didn't match any of these.", status_code=404)

    def test_technical_404(self):
        response = self.client.get('/views/technical404/')
        self.assertContains(response, "Raised by:", status_code=404)
        self.assertContains(response, "view_tests.views.technical404", status_code=404)

    def test_classbased_technical_404(self):
        response = self.client.get('/views/classbased404/')
        self.assertContains(response, "Raised by:", status_code=404)
        self.assertContains(response, "view_tests.views.Http404View", status_code=404)

    def test_non_l10ned_numeric_ids(self):
        """
        Numeric IDs and fancy traceback context blocks line numbers shouldn't be localized.
        """
        with self.settings(DEBUG=True, USE_L10N=True):
            response = self.client.get('/raises500/')
            # We look for a HTML fragment of the form
            # '<div class="context" id="c38123208">', not '<div class="context" id="c38,123,208"'
            self.assertContains(response, '<div class="context" id="', status_code=500)
            match = re.search(b'<div class="context" id="(?P<id>[^"]+)">', response.content)
            self.assertIsNotNone(match)
            id_repr = match.group('id')
            self.assertFalse(
                re.search(b'[^c0-9]', id_repr),
                "Numeric IDs in debug response HTML page shouldn't be localized (value: %s)." % id_repr.decode()
            )

    def test_template_exceptions(self):
        try:
            self.client.get(reverse('template_exception'))
        except Exception:
            raising_loc = inspect.trace()[-1][-2][0].strip()
            self.assertNotEqual(
                raising_loc.find("raise Exception('boom')"), -1,
                "Failed to find 'raise Exception' in last frame of "
                "traceback, instead found: %s" % raising_loc
            )

    def test_template_loader_postmortem(self):
        """Tests for not existing file"""
        template_name = "notfound.html"
        with tempfile.NamedTemporaryFile(prefix=template_name) as tmpfile:
            tempdir = os.path.dirname(tmpfile.name)
            template_path = os.path.join(tempdir, template_name)
            with override_settings(TEMPLATES=[{
                'BACKEND': 'django.template.backends.django.DjangoTemplates',
                'DIRS': [tempdir],
            }]):
                response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
            self.assertContains(response, "%s (Source does not exist)" % template_path, status_code=500, count=2)
            # Assert as HTML.
            self.assertContains(
                response,
                '<li><code>django.template.loaders.filesystem.Loader</code>: '
                '%s (Source does not exist)</li>' % os.path.join(tempdir, 'notfound.html'),
                status_code=500,
                html=True,
            )

    def test_no_template_source_loaders(self):
        """
        Make sure if you don't specify a template, the debug view doesn't blow up.
        """
        with self.assertRaises(TemplateDoesNotExist):
            self.client.get('/render_no_template/')

    @override_settings(ROOT_URLCONF='view_tests.default_urls')
    def test_default_urlconf_template(self):
        """
        Make sure that the default URLconf template is shown shown instead
        of the technical 404 page, if the user has not altered their
        URLconf yet.
        """
        response = self.client.get('/')
        self.assertContains(
            response,
            "<h2>Congratulations on your first Django-powered page.</h2>"
        )

    @override_settings(ROOT_URLCONF='view_tests.regression_21530_urls')
    def test_regression_21530(self):
        """
        Regression test for bug #21530.

        If the admin app include is replaced with exactly one url
        pattern, then the technical 404 template should be displaye