"""
This module provides tests for :py:mod:`userdbs.admin`.

"""
from unittest.mock import MagicMock, Mock, patch

from django.contrib.admin import AdminSite
from django.test import TestCase

from userdbs.admin import (
    DatabaseUserAdmin,
    DatabaseUserCreationForm,
    UserDatabaseAdmin,
    UserDatabaseCreationForm,
)
from userdbs.models import DB_TYPES, DatabaseUser, UserDatabase


class DatabaseUserCreationFormTest(TestCase):
    @patch("userdbs.admin.DatabaseUser.objects.create_database_user")
    def test_save(self, create_database_user):
        create_database_user.return_value = Mock()
        form = DatabaseUserCreationForm()
        mockuser = Mock(name="osuser")
        form.cleaned_data = {"osuser": mockuser, "db_type": DB_TYPES.pgsql}
        retval = form.save()
        create_database_user.assert_called_with(
            osuser=mockuser, db_type=DB_TYPES.pgsql, commit=True
        )
        self.assertEqual(retval, create_database_user.return_value)

    def test_save_m2m_returns_none(self):
        form = DatabaseUserCreationForm()
        self.assertIsNone(form.save_m2m())


class UserDatabaseCreationFormTest(TestCase):
    @patch("userdbs.admin.UserDatabase.objects.create_userdatabase")
    def test_save(self, create_userdatabase):
        create_userdatabase.return_value = Mock()
        form = UserDatabaseCreationForm()
        mockuser = Mock(name="mockuser")
        form.cleaned_data = {"db_user": mockuser}
        retval = form.save()
        create_userdatabase.assert_called_with(db_user=mockuser, commit=True)
        self.assertEqual(retval, create_userdatabase.return_value)

    def test_save_m2m_returns_none(self):
        form = UserDatabaseCreationForm()
        self.assertIsNone(form.save_m2m())


class DatabaseUserAdminTest(TestCase):
    def setUp(self):
        site = AdminSite()
        self.dbuadmin = DatabaseUserAdmin(DatabaseUser, site)
        super(DatabaseUserAdminTest, self).setUp()

    def test_get_form_with_instance(self):
        form = self.dbuadmin.get_form(Mock(name="request"), obj=Mock(name="dbuser"))
        self.assertEqual(form.Meta.fields, ["osuser", "name", "db_type"])

    def test_get_form_without_instance(self):
        form = self.dbuadmin.get_form(Mock(name="request"))
        self.assertEqual(form.Meta.fields, ["osuser", "db_type"])

    def test_get_readonly_fields_with_instance(self):
        fields = self.dbuadmin.get_readonly_fields(
            Mock(name="request"), obj=Mock(name="dbuser")
        )
        self.assertEqual(fields, ["osuser", "name", "db_type"])

    def test_get_readonly_fields_without_instance(self):
        fields = self.dbuadmin.get_readonly_fields(Mock(name="request"))
        self.assertEqual(fields, [])

    def test_save_model_change(self):
        objmock = Mock()
        self.dbuadmin.save_model(Mock(name="request"), objmock, Mock(), True)
        objmock.create_in_database.assert_not_called()

    def test_save_model_no_change(self):
        objmock = Mock()
        self.dbuadmin.save_model(Mock(name="request"), objmock, Mock(), False)
        objmock.create_in_database.assert_called_with()

    def test_perform_delete_selected(self):
        usermock = Mock()
        selected = Mock()
        selected.all.return_value = [usermock]
        self.dbuadmin.perform_delete_selected(Mock(name="request"), selected)
        selected.all.assert_called_with()
        usermock.delete.assert_called_with()

    def test_get_actions(self):
        requestmock = MagicMock(name="request")
        self.assertNotIn("delete_selected", self.dbuadmin.get_actions(requestmock))
        self.assertIn("perform_delete_selected", self.dbuadmin.get_actions(requestmock))


class UserDatabaseAdminTest(TestCase):
    def setUp(self):
        site = AdminSite()
        self.udbadmin = UserDatabaseAdmin(UserDatabase, site)
        super(UserDatabaseAdminTest, self).setUp()

    def test_get_form_with_instance(self):
        form = self.udbadmin.get_form(Mock(name="request"), obj=Mock(name="userdb"))
        self.assertEqual(form.Meta.fields, ["db_name", "db_user"])

    def test_get_form_without_instance(self):
        form = self.udbadmin.get_form(Mock(name="request"))
        self.assertEqual(form.Meta.fields, ["db_user"])

    def test_get_readonly_fields_with_instance(self):
        fields = self.udbadmin.get_readonly_fields(
            Mock(name="request"), obj=Mock(name="userdb")
        )
        self.assertEqual(fields, ["db_name", "db_user"])

    def test_get_readonly_fields_without_instance(self):
        fields = self.udbadmin.get_readonly_fields(Mock(name="request"))
        self.assertEqual(fields, [])

    def test_save_model_change(self):
        objmock = Mock()
        self.udbadmin.save_model(Mock(name="request"), objmock, Mock(), True)
        objmock.create_in_database.assert_not_called()

    def test_save_model_no_change(self):
        objmock = Mock()
        self.udbadmin.save_model(Mock(name="request"), objmock, Mock(), False)
        objmock.create_in_database.assert_called_with()

    def test_perform_delete_selected(self):
        userdbmock = Mock()
        selected = Mock()
        selected.all.return_value = [userdbmock]
        self.udbadmin.perform_delete_selected(Mock(name="request"), selected)
        selected.all.assert_called_with()
        userdbmock.delete.assert_called_with()

    def test_get_actions(self):
        requestmock = MagicMock(name="request")
        self.assertNotIn("delete_selected", self.udbadmin.get_actions(requestmock))
        self.assertIn("perform_delete_selected", self.udbadmin.get_actions(requestmock))
