import django
from django.test import TestCase

from registration import forms
from registration.users import UserModel


class RegistrationFormTests(TestCase):
    """
    Test the default registration forms.

    """

    def test_registration_form(self):
        """
        Test that ``RegistrationForm`` enforces username constraints
        and matching passwords.

        """
        # Create a user so we can verify that duplicate usernames aren't
        # permitted.
        UserModel().objects.create_user('alice', 'alice@example.com', 'secret')
        bad_username_error = (
            'Enter a valid username. This value may contain only letters, '
            'numbers, and @/./+/-/_ characters.'
        )
        password_didnt_match_error = "The two password fields didn't match."
        if django.VERSION >= (3, 0):
            password_didnt_match_error = "The two password fields didn’t match."

        invalid_data_dicts = [
            # Non-alphanumeric username.
            {'data': {'username': 'foo/bar',
                      'email': 'foo@example.com',
                      'password1': 'foo',
                      'password2': 'foo'},
             'error': ('username', [bad_username_error])},
            # Already-existing username.
            {'data': {'username': 'alice',
                      'email': 'alice@example.com',
                      'password1': 'secret',
                      'password2': 'secret'},
             'error': ('username', ["A user with that username already exists."])},
            # Mismatched passwords.
            {'data': {'username': 'foo',
                      'email': 'foo@example.com',
                      'password1': 'foo',
                      'password2': 'bar'},
             'error': ('password2', [password_didnt_match_error])},
        ]

        for invalid_dict in invalid_data_dicts:
            form = forms.RegistrationForm(data=invalid_dict['data'])
            self.assertFalse(form.is_valid())
            self.assertEqual(form.errors[invalid_dict['error'][0]],
                             invalid_dict['error'][1])

        form = forms.RegistrationForm(data={'username': 'foo',
                                            'email': 'foo@example.com',
                                            'password1': 'foo',
                                            'password2': 'foo'})
        self.assertTrue(form.is_valid())

    def test_registration_form_username_lowercase(self):
        """
        Test that ``RegistrationFormUniqueEmail`` validates uniqueness
        of email addresses.

        """
        # Create a user so we can verify that duplicate addresses
        # aren't permitted.
        UserModel().objects.create_user('alice', 'alice@example.com', 'secret')

        form = forms.RegistrationFormUsernameLowercase(data={'username': 'Alice',
                                                             'email': 'alice@example.com',
                                                             'password1': 'foo',
                                                             'password2': 'foo'})
        self.assertFalse(form.is_valid())
        self.assertEqual(form.errors['username'],
                         ["A user with that username already exists."])

        form = forms.RegistrationFormUsernameLowercase(data={'username': 'foo',
                                                             'email': 'alice@example.com',
                                                             'password1': 'foo',
                                                             'password2': 'foo'})
        self.assertTrue(form.is_valid())

    def test_registration_form_tos(self):
        """
        Test that ``RegistrationFormTermsOfService`` requires
        agreement to the terms of service.

        """
        form = forms.RegistrationFormTermsOfService(data={'username': 'foo',
                                                          'email': 'foo@example.com',
                                                          'password1': 'foo',
                                                          'password2': 'foo'})
        self.assertFalse(form.is_valid())
        self.assertEqual(form.errors['tos'],
                         ["You must agree to the terms to register"])

        form = forms.RegistrationFormTermsOfService(data={'username': 'foo',
                                                          'email': 'foo@example.com',
                                                          'password1': 'foo',
                                                          'password2': 'foo',
                                                          'tos': 'on'})
        self.assertTrue(form.is_valid())

    def test_registration_form_unique_email(self):
        """
        Test that ``RegistrationFormUniqueEmail`` validates uniqueness
        of email addresses.

        """
        # Create a user so we can verify that duplicate addresses
        # aren't permitted.
        UserModel().objects.create_user('alice', 'alice@example.com', 'secret')

        form = forms.RegistrationFormUniqueEmail(data={'username': 'foo',
                                                       'email': 'alice@example.com',
                                                       'password1': 'foo',
                                                       'password2': 'foo'})
        self.assertFalse(form.is_valid())
        self.assertEqual(form.errors['email'],
                         ["This email address is already in use. Please supply a different email address."])

        form = forms.RegistrationFormUniqueEmail(data={'username': 'foo',
                                                       'email': 'foo@example.com',
                                                       'password1': 'foo',
                                                       'password2': 'foo'})
        self.assertTrue(form.is_valid())

    def test_registration_form_no_free_email(self):
        """
        Test that ``RegistrationFormNoFreeEmail`` disallows
        registration with free email addresses.

        """
        base_data = {'username': 'foo',
                     'password1': 'foo',
                     'password2': 'foo'}
        for domain in forms.RegistrationFormNoFreeEmail.bad_domains:
            invalid_data = base_data.copy()
            invalid_data['email'] = "foo@%s" % domain
            form = forms.RegistrationFormNoFreeEmail(data=invalid_data)
            self.assertFalse(form.is_valid())
            self.assertEqual(form.errors['email'],
                             ["Registration using free email addresses is prohibited. Please supply a different email address."])

        base_data['email'] = 'foo@example.com'
        form = forms.RegistrationFormNoFreeEmail(data=base_data)
        self.assertTrue(form.is_valid())
