# Copyright 2010-2017, The University of Melbourne
# Copyright 2010-2017, Brian May
#
# This file is part of Karaage.
#
# Karaage is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Karaage is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Karaage  If not, see <http://www.gnu.org/licenses/>.

import pytest
import six
from django.test import TestCase

import karaage.people.forms as forms
import karaage.tests.fixtures as fixtures
from karaage.tests.integration import skip_if_missing_requirements


@pytest.mark.django_db
class AddPersonFormTestCase(TestCase):
    def _valid_user(self):
        project = fixtures.ProjectFactory()
        valid_user = {
            "username": "testuser",
            "project": project.id,
            "institute": project.institute.id,
            "full_name": "Joe Blow",
            "short_name": "Joe",
            "needs_account": True,
            "email": "test@example.com",
            "telephone": "8888888888",
            "password1": "wai5bixa8Igohxa",
            "password2": "wai5bixa8Igohxa",
        }
        return valid_user

    def test_valid_data(self):
        form_data = self._valid_user()
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), True, form.errors.items())
        self.assertEqual(form.cleaned_data["password1"], "wai5bixa8Igohxa")
        self.assertEqual(form.cleaned_data["password2"], "wai5bixa8Igohxa")

    @skip_if_missing_requirements("cracklib")
    def test_password_short(self):
        form_data = self._valid_user()
        form_data["password1"] = "abc"
        form_data["password2"] = "abc"
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items(
                {
                    "password2": [
                        six.u("Your password was found to be insecure: Password must be at least 6 characters long.")
                    ]
                }
            ),
        )

    @skip_if_missing_requirements("cracklib")
    def test_password_simple(self):
        form_data = self._valid_user()
        form_data["password1"] = "qwerty"
        form_data["password2"] = "qwerty"
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items(
                {"password2": [six.u("Your password was found to be insecure: it is based on a dictionary word.")]}
            ),
        )

    def test_password_mismatch(self):
        form_data = self._valid_user()
        form_data["password2"] = "!invalid!"
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(), dict.items({"password2": [six.u("The two password fields didn't match.")]})
        )

    def test_invalid_username(self):
        form_data = self._valid_user()
        form_data["username"] = "!invalid!"
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items({"username": [six.u("Usernames can only contain letters, numbers and underscores")]}),
        )

    def test_upper_username(self):
        form_data = self._valid_user()
        form_data["username"] = "INVALID"
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(form.errors.items(), dict.items({"username": [six.u("Username must be all lowercase")]}))

    def test_long_username(self):
        form_data = self._valid_user()
        form_data["username"] = "long" * 100
        form = forms.AddPersonForm(data=form_data)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items({"username": [six.u("Ensure this value has at most 255 characters (it has 400).")]}),
        )


@pytest.mark.django_db
class AdminPasswordChangeFormTestCase(TestCase):
    def _valid_change(self):
        person = fixtures.PersonFactory()

        valid_change = {"username": person.username, "new1": "wai5bixa8Igohxa", "new2": "wai5bixa8Igohxa"}
        return person, valid_change

    def test_valid_data(self):
        person, form_data = self._valid_change()
        form = forms.AdminPasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), True, form.errors.items())
        self.assertEqual(form.cleaned_data["new1"], "wai5bixa8Igohxa")
        self.assertEqual(form.cleaned_data["new2"], "wai5bixa8Igohxa")

    @skip_if_missing_requirements("cracklib")
    def test_password_short(self):
        person, form_data = self._valid_change()
        form_data["new1"] = "abc"
        form_data["new2"] = "abc"
        form = forms.AdminPasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items(
                {
                    "new2": [
                        six.u("Your password was found to be insecure: Password must be at least 6 characters long.")
                    ]
                }
            ),
        )

    @skip_if_missing_requirements("cracklib")
    def test_password_simple(self):
        person, form_data = self._valid_change()
        form_data["new1"] = "qwerty"
        form_data["new2"] = "qwerty"
        form = forms.AdminPasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items({"new2": [six.u("Your password was found to be insecure: it is based on a dictionary word.")]}),
        )

    def test_password_mismatch(self):
        person, form_data = self._valid_change()
        form_data["new2"] = "!invalid!"
        form = forms.AdminPasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(form.errors.items(), dict.items({"new2": [six.u("The two password fields didn't match.")]}))


@pytest.mark.django_db
class PasswordChangeFormTestCase(TestCase):
    def _valid_change(self):
        person = fixtures.PersonFactory()

        valid_change = {
            "username": person.username,
            "old": "test",
            "new1": "wai5bixa8Igohxa",
            "new2": "wai5bixa8Igohxa",
        }
        return person, valid_change

    def test_valid_data(self):
        person, form_data = self._valid_change()
        form = forms.PasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), True, form.errors.items())
        self.assertEqual(form.cleaned_data["new1"], "wai5bixa8Igohxa")
        self.assertEqual(form.cleaned_data["new2"], "wai5bixa8Igohxa")

    def test_password_old_password_wrong(self):
        person, form_data = self._valid_change()
        form_data["old"] = "abc"
        form = forms.PasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(form.errors.items(), dict.items({"old": [six.u("Your old password was incorrect")]}))

    @skip_if_missing_requirements("cracklib")
    def test_password_short(self):
        person, form_data = self._valid_change()
        form_data["new1"] = "abc"
        form_data["new2"] = "abc"
        form = forms.PasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items(
                {
                    "new2": [
                        six.u("Your password was found to be insecure: Password must be at least 6 characters long.")
                    ]
                }
            ),
        )

    @skip_if_missing_requirements("cracklib")
    def test_password_simple(self):
        person, form_data = self._valid_change()
        form_data["new1"] = "qwerty"
        form_data["new2"] = "qwerty"
        form = forms.PasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(
            form.errors.items(),
            dict.items({"new2": [six.u("Your password was found to be insecure: it is based on a dictionary word.")]}),
        )

    def test_password_mismatch(self):
        person, form_data = self._valid_change()
        form_data["new2"] = "!invalid!"
        form = forms.PasswordChangeForm(data=form_data, person=person)
        self.assertEqual(form.is_valid(), False)
        self.assertEqual(form.errors.items(), dict.items({"new2": [six.u("The two password fields didn't match.")]}))
