# -*- coding: utf-8 -*-
"""
Regression tests for the Test Client, especially the customized assertions.
"""
from __future__ import unicode_literals

import os
import itertools

from django.conf import settings
from django.core.urlresolvers import reverse
from django.template import (TemplateSyntaxError,
    Context, Template, loader)
import django.template.context
from django.test import Client, TestCase, override_settings
from django.test.client import encode_file, RequestFactory
from django.test.utils import ContextList, str_prefix
from django.template.response import SimpleTemplateResponse
from django.utils._os import upath
from django.utils.translation import ugettext_lazy
from django.http import HttpResponse
from django.contrib.auth.signals import user_logged_out, user_logged_in
from django.contrib.auth.models import User

from .models import CustomUser
from .views import CustomTestException


@override_settings(
    TEMPLATE_DIRS=(os.path.join(os.path.dirname(upath(__file__)), 'templates'),)
)
class AssertContainsTests(TestCase):
    def test_contains(self):
        "Responses can be inspected for content, including counting repeated substrings"
        response = self.client.get('/test_client_regress/no_template_view/')

        self.assertNotContains(response, 'never')
        self.assertContains(response, 'never', 0)
        self.assertContains(response, 'once')
        self.assertContains(response, 'once', 1)
        self.assertContains(response, 'twice')
        self.assertContains(response, 'twice', 2)

        try:
            self.assertContains(response, 'text', status_code=999)
        except AssertionError as e:
            self.assertIn("Couldn't retrieve content: Response code was 200 (expected 999)", str(e))
        try:
            self.assertContains(response, 'text', status_code=999, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Couldn't retrieve content: Response code was 200 (expected 999)", str(e))

        try:
            self.assertNotContains(response, 'text', status_code=999)
        except AssertionError as e:
            self.assertIn("Couldn't retrieve content: Response code was 200 (expected 999)", str(e))
        try:
            self.assertNotContains(response, 'text', status_code=999, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Couldn't retrieve content: Response code was 200 (expected 999)", str(e))

        try:
            self.assertNotContains(response, 'once')
        except AssertionError as e:
            self.assertIn("Response should not contain 'once'", str(e))
        try:
            self.assertNotContains(response, 'once', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Response should not contain 'once'", str(e))

        try:
            self.assertContains(response, 'never', 1)
        except AssertionError as e:
            self.assertIn("Found 0 instances of 'never' in response (expected 1)", str(e))
        try:
            self.assertContains(response, 'never', 1, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Found 0 instances of 'never' in response (expected 1)", str(e))

        try:
            self.assertContains(response, 'once', 0)
        except AssertionError as e:
            self.assertIn("Found 1 instances of 'once' in response (expected 0)", str(e))
        try:
            self.assertContains(response, 'once', 0, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Found 1 instances of 'once' in response (expected 0)", str(e))

        try:
            self.assertContains(response, 'once', 2)
        except AssertionError as e:
            self.assertIn("Found 1 instances of 'once' in response (expected 2)", str(e))
        try:
            self.assertContains(response, 'once', 2, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Found 1 instances of 'once' in response (expected 2)", str(e))

        try:
            self.assertContains(response, 'twice', 1)
        except AssertionError as e:
            self.assertIn("Found 2 instances of 'twice' in response (expected 1)", str(e))
        try:
            self.assertContains(response, 'twice', 1, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Found 2 instances of 'twice' in response (expected 1)", str(e))

        try:
            self.assertContains(response, 'thrice')
        except AssertionError as e:
            self.assertIn("Couldn't find 'thrice' in response", str(e))
        try:
            self.assertContains(response, 'thrice', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Couldn't find 'thrice' in response", str(e))

        try:
            self.assertContains(response, 'thrice', 3)
        except AssertionError as e:
            self.assertIn("Found 0 instances of 'thrice' in response (expected 3)", str(e))
        try:
            self.assertContains(response, 'thrice', 3, msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Found 0 instances of 'thrice' in response (expected 3)", str(e))

    def test_unicode_contains(self):
        "Unicode characters can be found in template context"
        # Regression test for #10183
        r = self.client.get('/test_client_regress/check_unicode/')
        self.assertContains(r, 'さかき')
        self.assertContains(r, b'\xe5\xb3\xa0'.decode('utf-8'))

    def test_unicode_not_contains(self):
        "Unicode characters can be searched for, and not found in template context"
        # Regression test for #10183
        r = self.client.get('/test_client_regress/check_unicode/')
        self.assertNotContains(r, 'はたけ')
        self.assertNotContains(r, b'\xe3\x81\xaf\xe3\x81\x9f\xe3\x81\x91'.decode('utf-8'))

    def test_binary_contains(self):
        r = self.client.get('/test_client_regress/check_binary/')
        self.assertContains(r, b'%PDF-1.4\r\n%\x93\x8c\x8b\x9e')
        with self.assertRaises(AssertionError):
            self.assertContains(r, b'%PDF-1.4\r\n%\x93\x8c\x8b\x9e', count=2)

    def test_binary_not_contains(self):
        r = self.client.get('/test_client_regress/check_binary/')
        self.assertNotContains(r, b'%ODF-1.4\r\n%\x93\x8c\x8b\x9e')
        with self.assertRaises(AssertionError):
            self.assertNotContains(r, b'%PDF-1.4\r\n%\x93\x8c\x8b\x9e')

    def test_nontext_contains(self):
        r = self.client.get('/test_client_regress/no_template_view/')
        self.assertContains(r, ugettext_lazy('once'))

    def test_nontext_not_contains(self):
        r = self.client.get('/test_client_regress/no_template_view/')
        self.assertNotContains(r, ugettext_lazy('never'))

    def test_assert_contains_renders_template_response(self):
        """ Test that we can pass in an unrendered SimpleTemplateReponse
            without throwing an error.
            Refs #15826.
        """
        response = SimpleTemplateResponse(Template('Hello'), status=200)
        self.assertContains(response, 'Hello')

    def test_assert_contains_using_non_template_response(self):
        """ Test that auto-rendering does not affect responses that aren't
            instances (or subclasses) of SimpleTemplateResponse.
            Refs #15826.
        """
        response = HttpResponse('Hello')
        self.assertContains(response, 'Hello')

    def test_assert_not_contains_renders_template_response(self):
        """ Test that we can pass in an unrendered SimpleTemplateReponse
            without throwing an error.
            Refs #15826.
        """
        response = SimpleTemplateResponse(Template('Hello'), status=200)
        self.assertNotContains(response, 'Bye')

    def test_assert_not_contains_using_non_template_response(self):
        """ Test that auto-rendering does not affect responses that aren't
            instances (or subclasses) of SimpleTemplateResponse.
            Refs #15826.
        """
        response = HttpResponse('Hello')
        self.assertNotContains(response, 'Bye')


@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class AssertTemplateUsedTests(TestCase):
    fixtures = ['testdata.json']

    def test_no_context(self):
        "Template usage assertions work then templates aren't in use"
        response = self.client.get('/test_client_regress/no_template_view/')

        # Check that the no template case doesn't mess with the template assertions
        self.assertTemplateNotUsed(response, 'GET Template')

        try:
            self.assertTemplateUsed(response, 'GET Template')
        except AssertionError as e:
            self.assertIn("No templates used to render the response", str(e))

        try:
            self.assertTemplateUsed(response, 'GET Template', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: No templates used to render the response", str(e))

    def test_single_context(self):
        "Template assertions work when there is a single context"
        response = self.client.get('/test_client/post_view/', {})

        try:
            self.assertTemplateNotUsed(response, 'Empty GET Template')
        except AssertionError as e:
            self.assertIn("Template 'Empty GET Template' was used unexpectedly in rendering the response", str(e))

        try:
            self.assertTemplateNotUsed(response, 'Empty GET Template', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Template 'Empty GET Template' was used unexpectedly in rendering the response", str(e))

        try:
            self.assertTemplateUsed(response, 'Empty POST Template')
        except AssertionError as e:
            self.assertIn("Template 'Empty POST Template' was not a template used to render the response. Actual template(s) used: Empty GET Template", str(e))

        try:
            self.assertTemplateUsed(response, 'Empty POST Template', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Template 'Empty POST Template' was not a template used to render the response. Actual template(s) used: Empty GET Template", str(e))

    def test_multiple_context(self):
        "Template assertions work when there are multiple contexts"
        post_data = {
            'text': 'Hello World',
            'email': 'foo@example.com',
            'value': 37,
            'single': 'b',
            'multi': ('b', 'c', 'e')
        }
        response = self.client.post('/test_client/form_view_with_template/', post_data)
        self.assertContains(response, 'POST data OK')
        try:
            self.assertTemplateNotUsed(response, "form_view.html")
        except AssertionError as e:
            self.assertIn("Template 'form_view.html' was used unexpectedly in rendering the response", str(e))

        try:
            self.assertTemplateNotUsed(response, 'base.html')
        except AssertionError as e:
            self.assertIn("Template 'base.html' was used unexpectedly in rendering the response", str(e))

        try:
            self.assertTemplateUsed(response, "Valid POST Template")
        except AssertionError as e:
            self.assertIn("Template 'Valid POST Template' was not a template used to render the response. Actual template(s) used: form_view.html, base.html", str(e))


class AssertRedirectsTests(TestCase):
    def test_redirect_page(self):
        "An assertion is raised if the original page couldn't be retrieved as expected"
        # This page will redirect with code 301, not 302
        response = self.client.get('/test_client/permanent_redirect_view/')
        try:
            self.assertRedirects(response, '/test_client/get_view/')
        except AssertionError as e:
            self.assertIn("Response didn't redirect as expected: Response code was 301 (expected 302)", str(e))

        try:
            self.assertRedirects(response, '/test_client/get_view/', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Response didn't redirect as expected: Response code was 301 (expected 302)", str(e))

    def test_lost_query(self):
        "An assertion is raised if the redirect location doesn't preserve GET parameters"
        response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
        try:
            self.assertRedirects(response, '/test_client/get_view/')
        except AssertionError as e:
            self.assertIn("Response redirected to 'http://testserver/test_client/get_view/?var=value', expected 'http://testserver/test_client/get_view/'", str(e))

        try:
            self.assertRedirects(response, '/test_client/get_view/', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Response redirected to 'http://testserver/test_client/get_view/?var=value', expected 'http://testserver/test_client/get_view/'", str(e))

    def test_incorrect_target(self):
        "An assertion is raised if the response redirects to another target"
        response = self.client.get('/test_client/permanent_redirect_view/')
        try:
            # Should redirect to get_view
            self.assertRedirects(response, '/test_client/some_view/')
        except AssertionError as e:
            self.assertIn("Response didn't redirect as expected: Response code was 301 (expected 302)", str(e))

    def test_target_page(self):
        "An assertion is raised if the response redirect target cannot be retrieved as expected"
        response = self.client.get('/test_client/double_redirect_view/')
        try:
            # The redirect target responds with a 301 code, not 200
            self.assertRedirects(response, 'http://testserver/test_client/permanent_redirect_view/')
        except AssertionError as e:
            self.assertIn("Couldn't retrieve redirection page '/test_client/permanent_redirect_view/': response code was 301 (expected 200)", str(e))

        try:
            # The redirect target responds with a 301 code, not 200
            self.assertRedirects(response, 'http://testserver/test_client/permanent_redirect_view/', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Couldn't retrieve redirection page '/test_client/permanent_redirect_view/': response code was 301 (expected 200)", str(e))

    def test_redirect_chain(self):
        "You can follow a redirect chain of multiple redirects"
        response = self.client.get('/test_client_regress/redirects/further/more/', {}, follow=True)
        self.assertRedirects(response, '/test_client_regress/no_template_view/',
            status_code=301, target_status_code=200)

        self.assertEqual(len(response.redirect_chain), 1)
        self.assertEqual(response.redirect_chain[0], ('http://testserver/test_client_regress/no_template_view/', 301))

    def test_multiple_redirect_chain(self):
        "You can follow a redirect chain of multiple redirects"
        response = self.client.get('/test_client_regress/redirects/', {}, follow=True)
        self.assertRedirects(response, '/test_client_regress/no_template_view/',
            status_code=301, target_status_code=200)

        self.assertEqual(len(response.redirect_chain), 3)
        self.assertEqual(response.redirect_chain[0], ('http://testserver/test_client_regress/redirects/further/', 301))
        self.assertEqual(response.redirect_chain[1], ('http://testserver/test_client_regress/redirects/further/more/', 301))
        self.assertEqual(response.redirect_chain[2], ('http://testserver/test_client_regress/no_template_view/', 301))

    def test_redirect_chain_to_non_existent(self):
        "You can follow a chain to a non-existent view"
        response = self.client.get('/test_client_regress/redirect_to_non_existent_view2/', {}, follow=True)
        self.assertRedirects(response, '/test_client_regress/non_existent_view/',
            status_code=301, target_status_code=404)

    def test_redirect_chain_to_self(self):
        "Redirections to self are caught and escaped"
        response = self.client.get('/test_client_regress/redirect_to_self/', {}, follow=True)
        # The chain of redirects stops once the cycle is detected.
        self.assertRedirects(response, '/test_client_regress/redirect_to_self/',
            status_code=301, target_status_code=301)
        self.assertEqual(len(response.redirect_chain), 2)

    def test_circular_redirect(self):
        "Circular redirect chains are caught and escaped"
        response = self.client.get('/test_client_regress/circular_redirect_1/', {}, follow=True)
        # The chain of redirects will get back to the starting point, but stop there.
        self.assertRedirects(response, '/test_client_regress/circular_redirect_2/',
            status_code=301, target_status_code=301)
        self.assertEqual(len(response.redirect_chain), 4)

    def test_redirect_chain_post(self):
        "A redirect chain will be followed from an initial POST post"
        response = self.client.post('/test_client_regress/redirects/',
            {'nothing': 'to_send'}, follow=True)
        self.assertRedirects(response,
            '/test_client_regress/no_template_view/', 301, 200)
        self.assertEqual(len(response.redirect_chain), 3)

    def test_redirect_chain_head(self):
        "A redirect chain will be followed from an initial HEAD request"
        response = self.client.head('/test_client_regress/redirects/',
            {'nothing': 'to_send'}, follow=True)
        self.assertRedirects(response,
            '/test_client_regress/no_template_view/', 301, 200)
        self.assertEqual(len(response.redirect_chain), 3)

    def test_redirect_chain_options(self):
        "A redirect chain will be followed from an initial OPTIONS request"
        response = self.client.options('/test_client_regress/redirects/',
            follow=True)
        self.assertRedirects(response,
            '/test_client_regress/no_template_view/', 301, 200)
        self.assertEqual(len(response.redirect_chain), 3)

    def test_redirect_chain_put(self):
        "A redirect chain will be followed from an initial PUT request"
        response = self.client.put('/test_client_regress/redirects/',
            follow=True)
        self.assertRedirects(response,
            '/test_client_regress/no_template_view/', 301, 200)
        self.assertEqual(len(response.redirect_chain), 3)

    def test_redirect_chain_delete(self):
        "A redirect chain will be followed from an initial DELETE request"
        response = self.client.delete('/test_client_regress/redirects/',
            follow=True)
        self.assertRedirects(response,
            '/test_client_regress/no_template_view/', 301, 200)
        self.assertEqual(len(response.redirect_chain), 3)

    def test_redirect_to_different_host(self):
        "The test client will preserve scheme, host and port changes"
        response = self.client.get('/test_client_regress/redirect_other_host/', follow=True)
        self.assertRedirects(response,
            'https://otherserver:8443/test_client_regress/no_template_view/',
            status_code=301, target_status_code=200)
        # We can't use is_secure() or get_host()
        # because response.request is a dictionary, not an HttpRequest
        self.assertEqual(response.request.get('wsgi.url_scheme'), 'https')
        self.assertEqual(response.request.get('SERVER_NAME'), 'otherserver')
        self.assertEqual(response.request.get('SERVER_PORT'), '8443')

    def test_redirect_chain_on_non_redirect_page(self):
        "An assertion is raised if the original page couldn't be retrieved as expected"
        # This page will redirect with code 301, not 302
        response = self.client.get('/test_client/get_view/', follow=True)
        try:
            self.assertRedirects(response, '/test_client/get_view/')
        except AssertionError as e:
            self.assertIn("Response didn't redirect as expected: Response code was 200 (expected 302)", str(e))

        try:
            self.assertRedirects(response, '/test_client/get_view/', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Response didn't redirect as expected: Response code was 200 (expected 302)", str(e))

    def test_redirect_on_non_redirect_page(self):
        "An assertion is raised if the original page couldn't be retrieved as expected"
        # This page will redirect with code 301, not 302
        response = self.client.get('/test_client/get_view/')
        try:
            self.assertRedirects(response, '/test_client/get_view/')
        except AssertionError as e:
            self.assertIn("Response didn't redirect as expected: Response code was 200 (expected 302)", str(e))

        try:
            self.assertRedirects(response, '/test_client/get_view/', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: Response didn't redirect as expected: Response code was 200 (expected 302)", str(e))

    def test_redirect_scheme(self):
        "An assertion is raised if the response doesn't have the scheme specified in expected_url"

        # Assure that original request scheme is preserved if no scheme specified in the redirect location
        response = self.client.get('/test_client/redirect_view/', secure=True)
        self.assertRedirects(response, 'https://testserver/test_client/get_view/')

        # For all possible True/False combinations of follow and secure
        for follow, secure in itertools.product([True, False], repeat=2):
            # always redirects to https
            response = self.client.get('/test_client/https_redirect_view/', follow=follow, secure=secure)
            # no scheme to compare too, always succeeds
            self.assertRedirects(response, '/test_client/secure_view/', status_code=301)
            # the goal scheme is https
            self.assertRedirects(response, 'https://testserver/test_client/secure_view/', status_code=301)
            with self.assertRaises(AssertionError):
                self.assertRedirects(response, 'http://testserver/test_client/secure_view/', status_code=301)


class AssertFormErrorTests(TestCase):
    def test_unknown_form(self):
        "An assertion is raised if the form name is unknown"
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b', 'c', 'e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'wrong_form', 'some_field', 'Some error.')
        except AssertionError as e:
            self.assertIn("The form 'wrong_form' was not used to render the response", str(e))
        try:
            self.assertFormError(response, 'wrong_form', 'some_field', 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: The form 'wrong_form' was not used to render the response", str(e))

    def test_unknown_field(self):
        "An assertion is raised if the field name is unknown"
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b', 'c', 'e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'form', 'some_field', 'Some error.')
        except AssertionError as e:
            self.assertIn("The form 'form' in context 0 does not contain the field 'some_field'", str(e))
        try:
            self.assertFormError(response, 'form', 'some_field', 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: The form 'form' in context 0 does not contain the field 'some_field'", str(e))

    def test_noerror_field(self):
        "An assertion is raised if the field doesn't have any errors"
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b', 'c', 'e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'form', 'value', 'Some error.')
        except AssertionError as e:
            self.assertIn("The field 'value' on form 'form' in context 0 contains no errors", str(e))
        try:
            self.assertFormError(response, 'form', 'value', 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: The field 'value' on form 'form' in context 0 contains no errors", str(e))

    def test_unknown_error(self):
        "An assertion is raised if the field doesn't contain the provided error"
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b', 'c', 'e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'form', 'email', 'Some error.')
        except AssertionError as e:
            self.assertIn(str_prefix("The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid email address.'])"), str(e))
        try:
            self.assertFormError(response, 'form', 'email', 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn(str_prefix("abc: The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid email address.'])"), str(e))

    def test_unknown_nonfield_error(self):
        """
        Checks that an assertion is raised if the form's non field errors
        doesn't contain the provided error.
        """
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b', 'c', 'e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'form', None, 'Some error.')
        except AssertionError as e:
            self.assertIn("The form 'form' in context 0 does not contain the non-field error 'Some error.' (actual errors: )", str(e))
        try:
            self.assertFormError(response, 'form', None, 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn("abc: The form 'form' in context 0 does not contain the non-field error 'Some error.' (actual errors: )", str(e))


class AssertFormsetErrorTests(TestCase):
    msg_prefixes = [("", {}), ("abc: ", {"msg_prefix": "abc"})]

    def setUp(self):
        """Makes response object for testing field and non-field errors"""
        # For testing field and non-field errors
        self.response_form_errors = self.getResponse({
            'form-TOTAL_FORMS': '2',
            'form-INITIAL_FORMS': '2',
            'form-0-text': 'Raise non-field error',
            'form-0-email': 'not an email address',
            'form-0-value': 37,
            'form-0-single': 'b',
            'form-0-multi': ('b', 'c', 'e'),
            'form-1-text': 'Hello World',
            'form-1-email': 'email@domain.com',
            'form-1-value': 37,
            'form-1-single': 'b',
            'form-1-multi': ('b', 'c', 'e'),
        })
        # For testing non-form errors
        self.response_nonform_errors = self.getResponse({
            'form-TOTAL_FORMS': '2',
            'form-INITIAL_FORMS': '2',
            'form-0-text': 'Hello World',
            'form-0-email': 'email@domain.com',
            'form-0-value': 37,
            'form-0-single': 'b',
            'form-0-multi': ('b', 'c', 'e'),
            'form-1-text': 'Hello World',
            'form-1-email': 'email@domain.com',
            'form-1-value': 37,
            'form-1-single': 'b',
            'form-1-multi': ('b', 'c', 'e'),
        })

    def getResponse(self, post_data):
        response = self.client.post('/test_client/formset_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")
        return response

    def test_unknown_formset(self):
        "An assertion is raised if the formset name is unknown"
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'wrong_formset',
                                        0,
                                        'Some_field',
                                        'Some error.',
                                        **kwargs)
            self.assertIn(prefix + "The formset 'wrong_formset' was not "
                                   "used to render the response",
                          str(cm.exception))

    def test_unknown_field(self):
        "An assertion is raised if the field name is unknown"
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'my_formset',
                                        0,
                                        'Some_field',
                                        'Some error.',
                                        **kwargs)
            self.assertIn(prefix + "The formset 'my_formset', "
                                   "form 0 in context 0 "
                                   "does not contain the field 'Some_field'",
                          str(cm.exception))

    def test_no_error_field(self):
        "An assertion is raised if the field doesn't have any errors"
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'my_formset',
                                        1,
                                        'value',
                                        'Some error.',
                                        **kwargs)
            self.assertIn(prefix + "The field 'value' "
                                   "on formset 'my_formset', form 1 "
                                   "in context 0 contains no errors",
                          str(cm.exception))

    def test_unknown_error(self):
        "An assertion is raised if the field doesn't contain the specified error"
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'my_formset',
                                        0,
                                        'email',
                                        'Some error.',
                                        **kwargs)
            self.assertIn(str_prefix(prefix + "The field 'email' "
                "on formset 'my_formset', form 0 in context 0 does not "
                "contain the error 'Some error.' (actual errors: "
                "[%(_)s'Enter a valid email address.'])"),
                str(cm.exception))

    def test_field_error(self):
        "No assertion is raised if the field contains the provided error"
        for prefix, kwargs in self.msg_prefixes:
            self.assertFormsetError(self.response_form_errors,
                                    'my_formset',
                                    0,
                                    'email',
                                    ['Enter a valid email address.'],
                                    **kwargs)

    def test_no_nonfield_error(self):
        "An assertion is raised if the formsets non-field errors doesn't contain any errors."
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'my_formset',
                                        1,
                                        None,
                                        'Some error.',
                                        **kwargs)
            self.assertIn(prefix + "The formset 'my_formset', form 1 in "
                                   "context 0 does not contain any "
                                   "non-field errors.",
                          str(cm.exception))

    def test_unknown_nonfield_error(self):
        "An assertion is raised if the formsets non-field errors doesn't contain the provided error."
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'my_formset',
                                        0,
                                        None,
                                        'Some error.',
                                        **kwargs)
            self.assertIn(str_prefix(prefix +
                "The formset 'my_formset', form 0 in context 0 does not "
                "contain the non-field error 'Some error.' (actual errors: "
                "[%(_)s'Non-field error.'])"), str(cm.exception))

    def test_nonfield_error(self):
        "No assertion is raised if the formsets non-field errors contains the provided error."
        for prefix, kwargs in self.msg_prefixes:
            self.assertFormsetError(self.response_form_errors,
                                    'my_formset',
                                    0,
                                    None,
                                    'Non-field error.',
                                    **kwargs)

    def test_no_nonform_error(self):
        "An assertion is raised if the formsets non-form errors doesn't contain any errors."
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_form_errors,
                                        'my_formset',
                                        None,
                                        None,
                                        'Some error.',
                                        **kwargs)
            self.assertIn(prefix + "The formset 'my_formset' in context 0 "
                                   "does not contain any non-form errors.",
                          str(cm.exception))

    def test_unknown_nonform_error(self):
        "An assertion is raised if the formsets non-form errors doesn't contain the provided error."
        for prefix, kwargs in self.msg_prefixes:
            with self.assertRaises(AssertionError) as cm:
                self.assertFormsetError(self.response_nonform_errors,
                                        'my_formset',
                                        None,
                                        None,
                                        'Some error.',
                                        **kwargs)
            self.assertIn(str_prefix(prefix +
                "The formset 'my_formset' in context 0 does not contain the "
                "non-form error 'Some error.' (actual errors: [%(_)s'Forms "
                "in a set must have distinct email addresses.'])"), str(cm.exception))

    def test_nonform_error(self):
        "No assertion is raised if the formsets non-form errors contains the provided error."
        for prefix, kwargs in self.msg_prefixes:
            self.assertFormsetError(self.response_nonform_errors,
                                    'my_formset',
                                    None,
                                    None,
                                    'Forms in a set must have distinct email '
                                    'addresses.',
                                    **kwargs)


class ProcessedMiddleware(object):
    def process_request(self, request):
        request.has_been_processed = True


@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class LoginTests(TestCase):
    fixtures = ['testdata']

    def test_login_different_client(self):
        "Check that using a different test client doesn't violate authentication"

        # Create a second client, and log in.
        c = Client()
        login = c.login(username='testclient', password='password')
        self.assertTrue(login, 'Could not log in')

        # Get a redirection page with the second client.
        response = c.get("/test_client_regress/login_protected_redirect_view/")

        # At this points, the self.client isn't logged in.
        # Check that assertRedirects uses the original client, not the
        # default client.
        self.assertRedirects(response, "http://testserver/test_client_regress/get_view/")

    @override_settings(
        MIDDLEWARE_CLASSES=list(settings.MIDDLEWARE_CLASSES) +
        ['test_client_regress.tests.ProcessedMiddleware'])
    def test_request_middleware(self):
        "Check that the request middleware is executed on login request"

        def listener(sender, signal, **kwargs):
            request = kwargs['request']
            self.assertTrue(hasattr(request, 'has_been_processed'))

        # Unlike other Client request performing methods, login and logout don't
        # return the response, therefore we must use signals to get it
        user_logged_in.connect(listener)
        try:
            self.client.login(username='testclient', password='password')
        finally:
            user_logged_in.disconnect(listener)


@override_settings(
    PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
    SESSION_ENGINE='test_client_regress.session'
)
class SessionEngineTests(TestCase):
    fixtures = ['testdata']

    def test_login(self):
        "A session engine that modifies the session key can be used to log in"
        login = self.client.login(username='testclient', password='password')
        self.assertTrue(login, 'Could not log in')

        # Try to access a login protected page.
        response = self.client.get("/test_client/login_protected_view/")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context['user'].username, 'testclient')


class URLEscapingTests(TestCase):
    def test_simple_argument_get(self):
        "Get a view that has a simple string argument"
        response = self.client.get(reverse('arg_view', args=['Slartibartfast']))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'Howdy, Slartibartfast')

    def test_argument_with_space_get(self):
        "Get a view that has a string argument that requires escaping"
        response = self.client.get(reverse('arg_view', args=['Arthur Dent']))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'Hi, Arthur')

    def test_simple_argument_post(self):
        "Post for a view that has a simple string argument"
        response = self.client.post(reverse('arg_view', args=['Slartibartfast']))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'Howdy, Slartibartfast')

    def test_argument_with_space_post(self):
        "Post for a view that has a string argument that requires escaping"
        response = self.client.post(reverse('arg_view', args=['Arthur Dent']))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'Hi, Arthur')


@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class ExceptionTests(TestCase):
    fixtures = ['testdata.json']

    def test_exception_cleared(self):
        "#5836 - A stale user exception isn't re-raised by the test client."

        login = self.client.login(username='testclient', password='password')
        self.assertTrue(login, 'Could not log in')
        try:
            self.client.get("/test_client_regress/staff_only/")
            self.fail("General users should not be able to visit this page")
        except CustomTestException:
            pass

        # At this point, an exception has been raised, and should be cleared.

        # This next operation should be successful; if it isn't we have a problem.
        login = self.client.login(username='staff', password='password')
        self.assertTrue(login, 'Could not log in')
        try:
            self.client.get("/test_client_regress/staff_only/")
        except CustomTestException:
            self.fail("Staff should be able to visit this page")


class TemplateExceptionTests(TestCase):
    def setUp(self):
        # Reset the loaders so they don't try to render cached templates.
        if loader.template_source_loaders is not None:
            for template_loader in loader.template_source_loaders:
                if hasattr(template_loader, 'reset'):
                    template_loader.reset()

    @override_settings(
        TEMPLATE_DIRS=(os.path.join(os.path.dirname(upath(__file__)), 'bad_templates'),)
    )
    def test_bad_404_template(self):
        "Errors found when rendering 404 error templates are re-raised"
        try:
            self.client.get("/no_such_view/")
            self.fail("Should get error about syntax error in template")
        except TemplateSyntaxError:
            pass


# We need two different tests to check URLconf substitution -  one to check
# it was changed, and another one (without self.urls) to check it was reverted on
# teardown. This pair of tests relies upon the alphabetical ordering of test execution.
class UrlconfSubstitutionTests(TestCase):
    urls = 'test_client_regress.urls'

    def test_urlconf_was_changed(self):
        "TestCase can enforce a custom URLconf on a per-test basis"
        url = reverse('arg_view', args=['somename'])
        self.assertEqual(url, '/arg_view/somename/')


# This test needs to run *after* UrlconfSubstitutionTests; the zz prefix in the
# name is to ensure alphabetical ordering.
class zzUrlconfSubstitutionTests(TestCase):
    def test_urlconf_was_reverted(self):
        "URLconf is reverted to original value after modification in a TestCase"
        url = reverse('arg_view', args=['somename'])
        self.assertEqual(url, '/test_client_regress/arg_view/somename/')


@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class ContextTests(TestCase):
    fixtures = ['testdata']

    def test_single_context(self):
        "Context variables can be retrieved from a single context"
        response = self.client.get("/test_client_regress/request_data/", data={'foo': 'whiz'})
        self.assertEqual(response.context.__class__, Context)
        self.assertTrue('get-foo' in response.context)
        self.assertEqual(response.context['get-foo'], 'whiz')
        self.assertEqual(response.context['request-foo'], 'whiz')
        self.assertEqual(response.context['data'], 'sausage')

        try:
            response.context['does-not-exist']
            self.fail('Should not be able to retrieve non-existent key')
        except KeyError as e:
            self.assertEqual(e.args[0], 'does-not-exist')

    def test_inherited_context(self):
        "Context variables can be retrieved from a list of contexts"
        response = self.client.get("/test_client_regress/request_data_extended/", data={'foo': 'whiz'})
        self.assertEqual(response.context.__class__, ContextList)
        self.assertEqual(len(response.context), 2)
        self.assertTrue('get-foo' in response.context)
        self.assertEqual(response.context['get-foo'], 'whiz')
        self.assertEqual(response.context['request-foo'], 'whiz')
        self.assertEqual(response.context['data'], 'bacon')

        try:
            response.context['does-not-exist']
            self.fail('Should not be able to retrieve non-existent key')
        except KeyError as e:
            self.assertEqual(e.args[0], 'does-not-exist')

    def test_contextlist_keys(self):
        c1 = Context()
        c1.update({'hello': 'world', 'goodbye': 'john'})
        c1.update({'hello': 'dolly', 'dolly': 'parton'})
        c2 = Context()
        c2.update({'goodbye': 'world', 'python': 'rocks'})
        c2.update({'goodbye': 'dolly'})

        l = ContextList([c1, c2])
        # None, True and False are builtins of BaseContext, and present
        # in every Context without needing to be added.
        self.assertEqual(set(['None', 'True', 'False', 'hello', 'goodbye',
                              'python', 'dolly']),
                         l.keys())

    def test_15368(self):
        # Need to insert a context processor that assumes certain things about
        # the request instance. This triggers a bug caused by some ways of
        # copying RequestContext.
        try:
            django.template.context._standard_context_processors = (lambda request: {'path': request.special_path},)
            response = self.client.get("/test_client_regress/request_context_view/")
            self.assertContains(response, 'Path: /test_client_regress/request_context_view/')
        finally:
            django.template.context._standard_context_processors = None

    def test_nested_requests(self):
        """
        response.context is not lost when view call another view.
        """
        response = self.client.get("/test_client_regress/nested_view/")
        self.assertEqual(response.context.__class__, Context)
        self.assertEqual(response.context['nested'], 'yes')


@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class SessionTests(TestCase):
    fixtures = ['testdata.json']

    def test_session(self):
        "The session isn't lost if a user logs in"
        # The session doesn't exist to start.
        response = self.client.get('/test_client_regress/check_session/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'NO')

        # This request sets a session variable.
        response = self.client.get('/test_client_regress/set_session/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'set_session')

        # Check that the session has been modified
        response = self.client.get('/test_client_regress/check_session/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'YES')

        # Log in
        login = self.client.login(username='testclient', password='password')
        self.assertTrue(login, 'Could not log in')

        # Session should still contain the modified value
        response = self.client.get('/test_client_regress/check_session/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'YES')

    def test_logout(self):
        """Logout should work whether the user is logged in or not (#9978)."""
        self.client.logout()
        login = self.client.login(username='testclient', password='password')
        self.assertTrue(login, 'Could not log in')
        self.client.logout()
        self.client.logout()

    def test_logout_with_user(self):
        """Logout should send user_logged_out signal if user was logged in."""
        def listener(*args, **kwargs):
            listener.executed = True
            self.assertEqual(kwargs['sender'], User)
        listener.executed = False

        user_logged_out.connect(listener)
        self.client.login(username='testclient', password='password')
        self.client.logout()
        user_logged_out.disconnect(listener)
        self.assertTrue(listener.executed)

    @override_settings(AUTH_USER_MODEL='test_client_regress.CustomUser')
    def test_logout_with_custom_user(self):
        """Logout should send user_logged_out signal if custom user was logged in."""
        def listener(*args, **kwargs):
            self.assertEqual(kwargs['sender'], CustomUser)
            listener.executed = True
        listener.executed = False
        u = CustomUser.custom_objects.create(email='test@test.com')
        u.set_password('password')
        u.save()

        user_logged_out.connect(listener)
        self.client.login(username='test@test.com', password='password')
        self.client.logout()
        user_logged_out.disconnect(listener)
        self.assertTrue(listener.executed)

    def test_logout_without_user(self):
        """Logout should send signal even if user not authenticated."""
        def listener(user, *args, **kwargs):
            listener.user = user
            listener.executed = True
        listener.executed = False

        user_logged_out.connect(listener)
        self.client.login(username='incorrect', password='password')
        self.client.logout()
        user_logged_out.disconnect(listener)

        self.assertTrue(listener.executed)
        self.assertIsNone(listener.user)

    def test_login_with_user(self):
        """Login should send user_logged_in signal on successful login."""
        def listener(*args, **kwargs):
            listener.executed = True
        listener.executed = False

        user_logged_in.connect(listener)
        self.client.login(username='testclient', password='password')
        user_logged_out.disconnect(listener)

        self.assertTrue(listener.executed)

    def test_login_without_signal(self):
        """Login shouldn't send signal if user wasn't logged in"""
        def listener(*args, **kwargs):
            listener.executed = True
        listener.executed = False

        user_logged_in.connect(listener)
        self.client.login(username='incorrect', password='password')
        user_logged_in.disconnect(listener)

        self.assertFalse(listener.executed)


class RequestMethodTests(TestCase):
    def test_get(self):
        "Request a view via request method GET"
        response = self.client.get('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: GET')

    def test_post(self):
        "Request a view via request method POST"
        response = self.client.post('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: POST')

    def test_head(self):
        "Request a view via request method HEAD"
        response = self.client.head('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        # A HEAD request doesn't return any content.
        self.assertNotEqual(response.content, b'request method: HEAD')
        self.assertEqual(response.content, b'')

    def test_options(self):
        "Request a view via request method OPTIONS"
        response = self.client.options('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: OPTIONS')

    def test_put(self):
        "Request a view via request method PUT"
        response = self.client.put('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: PUT')

    def test_delete(self):
        "Request a view via request method DELETE"
        response = self.client.delete('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: DELETE')

    def test_patch(self):
        "Request a view via request method PATCH"
        response = self.client.patch('/test_client_regress/request_methods/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: PATCH')


class RequestMethodStringDataTests(TestCase):
    def test_post(self):
        "Request a view with string data via request method POST"
        # Regression test for #11371
        data = '{"test": "json"}'
        response = self.client.post('/test_client_regress/request_methods/', data=data, content_type='application/json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: POST')

    def test_put(self):
        "Request a view with string data via request method PUT"
        # Regression test for #11371
        data = '{"test": "json"}'
        response = self.client.put('/test_client_regress/request_methods/', data=data, content_type='application/json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: PUT')

    def test_patch(self):
        "Request a view with string data via request method PATCH"
        # Regression test for #17797
        data = '{"test": "json"}'
        response = self.client.patch('/test_client_regress/request_methods/', data=data, content_type='application/json')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'request method: PATCH')


class QueryStringTests(TestCase):
    def test_get_like_requests(self):
        # See: https://code.djangoproject.com/ticket/10571.
        for method_name in ('get', 'head'):
            # A GET-like request can pass a query string as data
            method = getattr(self.client, method_name)
            response = method("/test_client_regress/request_data/", data={'foo': 'whiz'})
            self.assertEqual(response.context['get-foo'], 'whiz')
            self.assertEqual(response.context['request-foo'], 'whiz')

            # A GET-like request can pass a query string as part of the URL
            response = method("/test_client_regress/request_data/?foo=whiz")
            self.assertEqual(response.context['get-foo'], 'whiz')
            self.assertEqual(response.context['request-foo'], 'whiz')

            # Data provided in the URL to a GET-like request is overridden by actual form data
            response = method("/test_client_regress/request_data/?foo=whiz", data={'foo': 'bang'})
            self.assertEqual(response.context['get-foo'], 'bang')
            self.assertEqual(response.context['request-foo'], 'bang')

            response = method("/test_client_regress/request_data/?foo=whiz", data={'bar': 'bang'})
            self.assertEqual(response.context['get-foo'], None)
            self.assertEqual(response.context['get-bar'], 'bang')
            self.assertEqual(response.context['request-foo'], None)
            self.assertEqual(response.context['request-bar'], 'bang')

    def test_post_like_requests(self):
        # A POST-like request can pass a query string as data
        response = self.client.post("/test_client_regress/request_data/", data={'foo': 'whiz'})
        self.assertEqual(response.context['get-foo'], None)
        self.assertEqual(response.context['post-foo'], 'whiz')

        # A POST-like request can pass a query string as part of the URL
        response = self.client.post("/test_client_regress/request_data/?foo=whiz")
        self.assertEqual(response.context['get-foo'], 'whiz')
        self.assertEqual(response.context['post-foo'], None)
        self.assertEqual(response.context['request-foo'], 'whiz')

        # POST data provided in the URL augments actual form data
        response = self.client.post("/test_client_regress/request_data/?foo=whiz", data={'foo': 'bang'})
        self.assertEqual(response.context['get-foo'], 'whiz')
        self.assertEqual(response.context['post-foo'], 'bang')
        self.assertEqual(response.context['request-foo'], 'bang')

        response = self.client.post("/test_client_regress/request_data/?foo=whiz", data={'bar': 'bang'})
        self.assertEqual(response.context['get-foo'], 'whiz')
        self.assertEqual(response.context['get-bar'], None)
        self.assertEqual(response.context['post-foo'], None)
        self.assertEqual(response.context['post-bar'], 'bang')
        self.assertEqual(response.context['request-foo'], 'whiz')
        self.assertEqual(response.context['request-bar'], 'bang')


class UnicodePayloadTests(TestCase):
    def test_simple_unicode_payload(self):
        "A simple ASCII-only unicode JSON document can be POSTed"
        # Regression test for #10571
        json = '{"english": "mountain pass"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json")
        self.assertEqual(response.content, json.encode())

    def test_unicode_payload_utf8(self):
        "A non-ASCII unicode data encoded as UTF-8 can be POSTed"
        # Regression test for #10571
        json = '{"dog": "собака"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json; charset=utf-8")
        self.assertEqual(response.content, json.encode('utf-8'))

    def test_unicode_payload_utf16(self):
        "A non-ASCII unicode data encoded as UTF-16 can be POSTed"
        # Regression test for #10571
        json = '{"dog": "собака"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json; charset=utf-16")
        self.assertEqual(response.content, json.encode('utf-16'))

    def test_unicode_payload_non_utf(self):
        "A non-ASCII unicode data as a non-UTF based encoding can be POSTed"
        # Regression test for #10571
        json = '{"dog": "собака"}'
        response = self.client.post("/test_client_regress/parse_unicode_json/", json,
                                    content_type="application/json; charset=koi8-r")
        self.assertEqual(response.content, json.encode('koi8-r'))


class DummyFile(object):
    def __init__(self, filename):
        self.name = filename

    def read(self):
        return b'TEST_FILE_CONTENT'


class UploadedFileEncodingTest(TestCase):
    def test_file_encoding(self):
        encoded_file = encode_file('TEST_BOUNDARY', 'TEST_KEY', DummyFile('test_name.bin'))
        self.assertEqual(b'--TEST_BOUNDARY', encoded_file[0])
        self.assertEqual(b'Content-Disposition: form-data; name="TEST_KEY"; filename="test_name.bin"', encoded_file[1])
        self.assertEqual(b'TEST_FILE_CONTENT', encoded_file[-1])

    def test_guesses_content_type_on_file_encoding(self):
        self.assertEqual(b'Content-Type: application/octet-stream',
                         encode_file('IGNORE', 'IGNORE', DummyFile("file.bin"))[2])
        self.assertEqual(b'Content-Type: text/plain',
                         encode_file('IGNORE', 'IGNORE', DummyFile("file.txt"))[2])
        self.assertIn(encode_file('IGNORE', 'IGNORE', DummyFile("file.zip"))[2], (
            b'Content-Type: application/x-compress',
            b'Content-Type: application/x-zip',
            b'Content-Type: application/x-zip-compressed',
            b'Content-Type: application/zip',))
        self.assertEqual(b'Content-Type: application/octet-stream',
                         encode_file('IGNORE', 'IGNORE', DummyFile("file.unknown"))[2])


class RequestHeadersTest(TestCase):
    fixtures = ['testdata']

    def test_client_headers(self):
        "A test client can receive custom headers"
        response = self.client.get("/test_client_regress/check_headers/", HTTP_X_ARG_CHECK='Testing 123')
        self.assertEqual(response.content, b"HTTP_X_ARG_CHECK: Testing 123")
        self.assertEqual(response.status_code, 200)

    @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
    def test_client_login_headers(self):
        "Test client headers are used in login"

        client = Client(HTTP_HOST='different')

        def listener(sender, signal, **kwargs):
            request = kwargs['request']
            self.assertEqual(request.get_host(), 'different')

        # Unlike other Client request performing methods, login and logout don't
        # return the response, therefore we must use signals to get it
        user_logged_in.connect(listener)
        try:
            client.login(username='testclient', password='password')
        finally:
            user_logged_in.disconnect(listener)

    def test_client_headers_redirect(self):
        "Test client headers are preserved through redirects"
        response = self.client.get("/test_client_regress/check_headers_redirect/", follow=True, HTTP_X_ARG_CHECK='Testing 123')
        self.assertEqual(response.content, b"HTTP_X_ARG_CHECK: Testing 123")
        self.assertRedirects(response, '/test_client_regress/check_headers/',
            status_code=301, target_status_code=200)


class ReadLimitedStreamTest(TestCase):
    """
    Tests that ensure that HttpRequest.body, HttpRequest.read() and
    HttpRequest.read(BUFFER) have proper LimitedStream behavior.

    Refs #14753, #15785
    """

    def test_body_from_empty_request(self):
        """HttpRequest.body on a test client GET request should return
        the empty string."""
        self.assertEqual(self.client.get("/test_client_regress/body/").content, b'')

    def test_read_from_empty_request(self):
        """HttpRequest.read() on a test client GET request should return the
        empty string."""
        self.assertEqual(self.client.get("/test_client_regress/read_all/").content, b'')

    def test_read_numbytes_from_empty_request(self):
        """HttpRequest.read(LARGE_BUFFER) on a test client GET request should
        return the empty string."""
        self.assertEqual(self.client.get("/test_client_regress/read_buffer/").content, b'')

    def test_read_from_nonempty_request(self):
        """HttpRequest.read() on a test client PUT request with some payload
        should return that payload."""
        payload = b'foobar'
        self.assertEqual(self.client.put(
            "/test_client_regress/read_all/",
            data=payload,
            content_type='text/plain').content, payload)

    def test_read_numbytes_from_nonempty_request(self):
        """HttpRequest.read(LARGE_BUFFER) on a test client PUT request with
        some payload should return that payload."""
        payload = b'foobar'
        self.assertEqual(
            self.client.put("/test_client_regress/read_buffer/",
            data=payload,
            content_type='text/plain').content, payload)


class RequestFactoryStateTest(TestCase):
    """Regression tests for #15929."""
    # These tests are checking that certain middleware don't change certain
    # global state. Alternatively, from the point of view of a test, they are
    # ensuring test isolation behavior. So, unusually, it doesn't make sense to
    # run the tests individually, and if any are failing it is confusing to run
    # them with any other set of tests.

    def common_test_that_should_always_pass(self):
        request = RequestFactory().get('/')
        request.session = {}
        self.assertFalse(hasattr(request, 'user'))

    def test_request(self):
        self.common_test_that_should_always_pass()

    def test_request_after_client(self):
        # apart from the next line the three tests are identical
        self.client.get('/')
        self.common_test_that_should_always_pass()

    def test_request_after_client_2(self):
        # This test is executed after the previous one
        self.common_test_that_should_always_pass()


class RequestFactoryEnvironmentTests(TestCase):
    """
    Regression tests for #8551 and #17067: ensure that environment variables
    are set correctly in RequestFactory.
    """

    def test_should_set_correct_env_variables(self):
        request = RequestFactory().get('/path/')

        self.assertEqual(request.META.get('REMOTE_ADDR'), '127.0.0.1')
        self.assertEqual(request.META.get('SERVER_NAME'), 'testserver')
        self.assertEqual(request.META.get('SERVER_PORT'), '80')
        self.assertEqual(request.META.get('SERVER_PROTOCOL'), 'HTTP/1.1')
        self.assertEqual(request.META.get('SCRIPT_NAME') +
                         request.META.get('PATH_INFO'), '/path/')
