import json
import base64

from django.test import Client, RequestFactory
from nacl.encoding import HexEncoder
from nacl.signing import SigningKey

from authentication.models import ToolshedUser, KnownIdentity
from authentication.tests import UserTestMixin, SignatureAuthClient, DummyExternalUser, ToolshedTestCase
from files.models import File


class AuthorizationTestCase(ToolshedTestCase):

    def setUp(self):
        self.client = Client()
        self.factory = RequestFactory()
        from nacl.signing import SigningKey
        self.key = SigningKey.generate()
        self.signature = self.key.sign("test".encode('utf-8'), encoder=HexEncoder).signature.decode('utf-8')
        self.data = json.dumps({'a': 'b'})
        self.signature_with_data = self.key.sign(
            ("test" + self.data).encode('utf-8'), encoder=HexEncoder).signature.decode('utf-8')

    def test_parse_auth_header(self):
        request = self.factory.get('/test')
        from authentication.signature_auth import verify_request
        with self.assertRaises(ValueError):
            verify_request(request, "")

    def test_parse_auth_header2(self):
        request = self.factory.get('/test', HTTP_AUTHORIZATION="Signature ")
        from authentication.signature_auth import verify_request
        with self.assertRaises(ValueError):
            verify_request(request, "")

    def test_parse_auth_header3(self):
        request = self.factory.get('/test', HTTP_AUTHORIZATION="Signature author@domain")
        from authentication.signature_auth import verify_request
        with self.assertRaises(ValueError):
            verify_request(request, "")

    def test_parse_auth_header4(self):
        from authentication.signature_auth import verify_request
        request = self.factory.get('/test', HTTP_AUTHORIZATION="Signature author@domain:" + self.signature)
        username, domain, signed_data, signature_bytes_hex = verify_request(request, "")
        self.assertEqual(username, "author")
        self.assertEqual(domain, "domain")
        self.assertEqual(signed_data, "http://testserver/test")
        self.assertEqual(signature_bytes_hex, self.signature)

    def test_parse_auth_header5(self):
        from authentication.signature_auth import verify_request
        request = self.factory.post('/test', self.data, content_type="application/json",
                                    HTTP_AUTHORIZATION="Signature author@domain:" + self.signature_with_data)
        username, domain, signed_data, signature_bytes_hex = verify_request(request, request.body.decode('utf-8'))
        self.assertEqual(username, "author")
        self.assertEqual(domain, "domain")
        self.assertEqual(signed_data, "http://testserver/test" + self.data)
        self.assertEqual(signature_bytes_hex, self.signature_with_data)

    def test_parse_auth_header6(self):
        from authentication.signature_auth import verify_request
        request = self.factory.put('/test', self.data, content_type="application/json",
                                   HTTP_AUTHORIZATION="Signature author@domain:" + self.signature_with_data)
        username, domain, signed_data, signature_bytes_hex = verify_request(request, request.body.decode('utf-8'))
        self.assertEqual(username, "author")
        self.assertEqual(domain, "domain")
        self.assertEqual(signed_data, "http://testserver/test" + self.data)
        self.assertEqual(signature_bytes_hex, self.signature_with_data)

    def test_parse_auth_header7(self):
        from authentication.signature_auth import verify_request
        request = self.factory.delete('/test', HTTP_AUTHORIZATION="Signature author@domain:" + self.signature)
        username, domain, signed_data, signature_bytes_hex = verify_request(request, request.body.decode('utf-8'))
        self.assertEqual(username, "author")
        self.assertEqual(domain, "domain")
        self.assertEqual(signed_data, "http://testserver/test")
        self.assertEqual(signature_bytes_hex, self.signature)

    def test_parse_auth_header8(self):
        from authentication.signature_auth import verify_request
        request = self.factory.patch('/test', self.data, content_type="application/json",
                                     HTTP_AUTHORIZATION="Signature author@domain:" + self.signature_with_data)
        username, domain, signed_data, signature_bytes_hex = verify_request(request, request.body.decode('utf-8'))
        self.assertEqual(username, "author")
        self.assertEqual(domain, "domain")
        self.assertEqual(signed_data, "http://testserver/test" + self.data)
        self.assertEqual(signature_bytes_hex, self.signature_with_data)


class KnownIdentityTestCase(ToolshedTestCase):
    key = None

    def setUp(self):
        self.key = SigningKey.generate()
        KnownIdentity.objects.create(username="testuser", domain='external.com',
                                     public_key=self.key.verify_key.encode(encoder=HexEncoder).decode('utf-8'))

    def test_known_identity(self):
        identity = KnownIdentity.objects.get(username="testuser", domain='external.com')
        self.assertEqual(identity.username, "testuser")
        self.assertEqual(identity.domain, "external.com")
        self.assertEqual(identity.public_key, self.key.verify_key.encode(encoder=HexEncoder).decode('utf-8'))
        self.assertEqual(str(identity), "testuser@external.com")
        self.assertTrue(identity.is_authenticated())

    def test_known_identity_verify(self):
        identity = KnownIdentity.objects.get(username="testuser", domain='external.com')
        message = "Hello world, this is a test message."
        signed = self.key.sign(message.encode('utf-8'), encoder=HexEncoder).signature
        self.assertTrue(identity.verify(message, signed.decode('utf-8')))

    def test_known_identity_verify_fail(self):
        identity = KnownIdentity.objects.get(username="testuser", domain='external.com')
        message = "Hello world, this is a test message."
        signed = self.key.sign(message.encode('utf-8'), encoder=HexEncoder).signature
        self.assertFalse(identity.verify(message + "x", signed.decode('utf-8')))

    def test_known_identity_verify_fail2(self):
        identity = KnownIdentity.objects.get(username="testuser", domain='external.com')
        message = "Hello world, this is a test message."
        signed = self.key.sign(message.encode('utf-8'), encoder=HexEncoder).signature
        with self.assertRaises(TypeError):
            identity.verify(message.encode('utf-8'), signed.decode('utf-8'))

    def test_known_identity_verify_fail3(self):
        identity = KnownIdentity.objects.get(username="testuser", domain='external.com')
        message = "Hello world, this is a test message."
        signed = self.key.sign(message.encode('utf-8'), encoder=HexEncoder).signature
        with self.assertRaises(TypeError):
            identity.verify(message, signed)

    def test_known_identity_verify_fail4(self):
        identity = KnownIdentity.objects.get(username="testuser", domain='external.com')
        message = "Hello world, this is a test message."
        signed = self.key.sign(message.encode('utf-8'), encoder=HexEncoder).signature
        with self.assertRaises(TypeError):
            identity.verify(message, bytes.fromhex(signed.decode('utf-8')))


class UserModelTestCase(UserTestMixin, ToolshedTestCase):
    def setUp(self):
        super().setUp()
        self.prepare_users()

    def test_admin(self):
        user = self.f['admin']
        self.assertTrue(user.is_superuser)
        self.assertTrue(user.is_staff)
        self.assertTrue(user.is_active)
        self.assertEqual(user.domain, 'localhost')
        self.assertEqual(user.email, 'testadmin@localhost')
        self.assertEqual(user.username, 'testadmin')

    def test_user(self):
        user = self.f['local_user1']
        self.assertFalse(user.is_superuser)
        self.assertFalse(user.is_staff)
        self.assertTrue(user.is_active)
        self.assertEqual(user.domain, 'example.com')
        self.assertEqual(user.email, 'test1@abc.de')
        self.assertEqual(user.username, 'testuser1')
        self.assertEqual(len(user.private_key), 64)
        self.assertEqual(type(user.public_identity), KnownIdentity)
        self.assertEqual(user.public_identity.domain, 'example.com')
        self.assertEqual(user.public_identity.username, 'testuser1')
        self.assertEqual(len(user.public_identity.public_key), 64)

    def test_create_existing_user(self):
        with self.assertRaises(ValueError):
            ToolshedUser.objects.create_user('testuser1', 'test3@abc.de', 'testpassword', domain='example.com')

    def test_create_existing_user2(self):
        key = SigningKey.generate()
        KnownIdentity.objects.create(username="testuser3", domain='localhost',
                                     public_key=key.verify_key.encode(encoder=HexEncoder).decode('utf-8'))
        with self.assertRaises(ValueError):
            ToolshedUser.objects.create_user('testuser3', 'test3@abc.de', 'testpassword', domain='localhost')

    def test_create_reuse_email(self):
        with self.assertRaises(ValueError):
            ToolshedUser.objects.create_user('testuser3', 'test1@abc.de', 'testpassword', domain='example.com')

    def test_create_user_invalid_private_key(self):
        with self.assertRaises(TypeError):
            ToolshedUser.objects.create_user('testuser3', 'test3@abc.de', '', domain='example.com',
                                             private_key=b'0123456789abcdef0123456789abcdef')
        with self.assertRaises(ValueError):
            ToolshedUser.objects.create_user('testuser3', 'test3@abc.de', '', domain='example.com',
                                             private_key='7005c4097')
        with self.assertRaises(ValueError):
            ToolshedUser.objects.create_user('testuser3', 'test3@abc.de', '', domain='example.com',
                                             private_key='0123456789abcdef0123456789abcdef'
                                                         'Z123456789abcdef0123456789abcdef')

    def test_signature(self):
        user = self.f['local_user1']
        message = 'some message'
        signature = user.sign(message)
        self.assertEqual(len(signature), 128)
        self.assertTrue(user.public_identity.verify(message, signature))

    def test_signature_fail(self):
        user = self.f['local_user1']
        message = 'some message'
        signature = user.sign(message)
        self.assertFalse(user.public_identity.verify(message + 'x', signature))

    def test_signature_fail2(self):
        user = self.f['local_user1']
        message = 'some message'
        signature = user.sign(message)
        signature = signature[:-2] + 'ee'
        self.assertFalse(user.public_identity.verify(message, signature))

    def test_signature_fail3(self):
        user1 = self.f['local_user1']
        user2 = self.f['local_user2']
        message = 'some message'
        signature = user1.sign(message)
        self.assertFalse(user2.public_identity.verify(message, signature))

    def test_signature_fail4(self):
        user = self.f['local_user1']
        message = 'some message'
        with self.assertRaises(TypeError):
            user.sign(message.encode('utf-8'))


class UserApiTestCase(UserTestMixin, ToolshedTestCase):

    def setUp(self):
        super().setUp()
        self.prepare_users()
        self.anonymous_client = Client(SERVER_NAME='testserver')
        self.client = SignatureAuthClient()

    def test_user_info(self):
        reply = self.client.get('/auth/user/', self.f['local_user1'])
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(reply.json()['username'], 'testuser1')
        self.assertEqual(reply.json()['domain'], 'example.com')
        self.assertEqual(reply.json()['email'], 'test1@abc.de')
        self.assertIsNone(reply.json()['profile_picture'])

    def test_user_info2(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + str(self.f['local_user1']) + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(reply.json()['username'], 'testuser1')
        self.assertEqual(reply.json()['domain'], 'example.com')
        self.assertIsNone(reply.json()['profile_picture'])

    def test_user_info_patch_profile_picture(self):
        content = base64.b64encode(b'user-profile-image').decode('utf-8')
        reply = self.client.patch('/auth/user/', self.f['local_user1'], {
            'profile_picture': {
                'data': content,
                'mime_type': 'image/png'
            }
        })
        self.assertEqual(reply.status_code, 200)
        self.assertTrue(reply.json()['profile_picture'])
        self.assertEqual(reply.json()['profile_picture']['mime_type'], 'image/png')
        self.assertEqual(File.objects.count(), 1)
        self.f['local_user1'].refresh_from_db()
        self.assertIsNotNone(self.f['local_user1'].profile_picture)

    def test_user_info_patch_profile_picture_clear(self):
        encoded_content = base64.b64encode(b'user-profile-image').decode('utf-8')
        test_file = File.objects.create(mime_type='image/png', data=encoded_content)
        self.f['local_user1'].profile_picture = test_file
        self.f['local_user1'].save()

        reply = self.client.patch('/auth/user/', self.f['local_user1'], {'profile_picture': None})
        self.assertEqual(reply.status_code, 200)
        self.assertIsNone(reply.json()['profile_picture'])
        self.f['local_user1'].refresh_from_db()
        self.assertIsNone(self.f['local_user1'].profile_picture)
        self.assertFalse(File.objects.filter(id=test_file.id).exists())

    def test_user_info_patch_profile_picture_invalid(self):
        reply = self.client.patch('/auth/user/', self.f['local_user1'], {'profile_picture': 'invalid'})
        self.assertEqual(reply.status_code, 400)

    def test_user_info_patch_profile_picture_id(self):
        encoded_content = base64.b64encode(b'user-profile-image-by-id').decode('utf-8')
        test_file = File.objects.create(mime_type='image/jpeg', data=encoded_content)
        reply = self.client.patch('/auth/user/', self.f['local_user1'], {'profile_picture_id': test_file.id})
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(reply.json()['profile_picture']['id'], test_file.id)

    def test_user_info_patch_profile_picture_id_not_found(self):
        reply = self.client.patch('/auth/user/', self.f['local_user1'], {'profile_picture_id': 999999})
        self.assertEqual(reply.status_code, 400)

    def test_user_info_fail(self):
        reply = self.anonymous_client.get('/auth/user/')
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail2(self):
        reply = self.client.get('/auth/user/', self.f['ext_user1'])
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail3(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver2" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + str(self.f['local_user1']) + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail4(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Auth ' + str(self.f['local_user1']) + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail5(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + str(self.f['local_user1'])}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail6(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + str(self.f['local_user1']) + ':' + signature + 'f'}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail7(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + self.f['local_user1'].username + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail8(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + self.f['local_user1'].username + '@:' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_user_info_fail9(self):
        target = "/auth/user/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature @' + self.f['local_user1'].domain + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)


class UserProfileByHandleApiTestCase(UserTestMixin, ToolshedTestCase):
    """Tests for GET /auth/user/<handle>/ - viewing another (friend) user's public profile."""

    def setUp(self):
        super().setUp()
        self.prepare_users()
        self.f['local_user1'].friends.add(self.f['ext_user1'].public_identity)
        self.anonymous_client = Client(SERVER_NAME='testserver')
        self.client = SignatureAuthClient()

    def test_view_friend_profile(self):
        target = '/auth/user/' + str(self.f['local_user1']) + '/'
        reply = self.client.get(target, self.f['ext_user1'])
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(reply.json()['username'], 'testuser1')
        self.assertEqual(reply.json()['domain'], 'example.com')
        self.assertIsNone(reply.json()['profile_picture'])
        self.assertNotIn('email', reply.json())

    def test_view_own_profile_via_handle(self):
        target = '/auth/user/' + str(self.f['local_user1']) + '/'
        reply = self.client.get(target, self.f['local_user1'])
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(reply.json()['username'], 'testuser1')

    def test_view_profile_not_friend(self):
        target = '/auth/user/' + str(self.f['local_user1']) + '/'
        reply = self.client.get(target, self.f['ext_user2'])
        self.assertEqual(reply.status_code, 403)

    def test_view_profile_unknown_user(self):
        target = '/auth/user/nosuchuser@example.com/'
        reply = self.client.get(target, self.f['ext_user1'])
        self.assertEqual(reply.status_code, 404)

    def test_view_profile_bad_handle(self):
        target = '/auth/user/notahandle/'
        reply = self.client.get(target, self.f['ext_user1'])
        self.assertEqual(reply.status_code, 400)

    def test_view_profile_unauthenticated(self):
        target = '/auth/user/' + str(self.f['local_user1']) + '/'
        reply = self.anonymous_client.get(target)
        self.assertEqual(reply.status_code, 403)


class FriendApiTestCase(UserTestMixin, ToolshedTestCase):
    def setUp(self):
        super().setUp()
        self.prepare_users()
        self.f['local_user1'].friends.add(self.f['local_user2'].public_identity)
        self.f['local_user1'].friends.add(self.f['ext_user1'].public_identity)
        self.f['ext_user1'].friends.add(self.f['local_user1'].public_identity)
        self.anonymous_client = Client(SERVER_NAME='testserver')
        self.client = SignatureAuthClient()

    def test_friend_local(self):
        reply = self.client.get('/api/friends/', self.f['local_user1'])
        self.assertEqual(reply.status_code, 200)

    def test_friend_external(self):
        reply = self.client.get('/api/friends/', self.f['ext_user1'])
        self.assertEqual(reply.status_code, 200)

    def test_friend_fail(self):
        reply = self.anonymous_client.get('/api/friends/')
        self.assertEqual(reply.status_code, 403)

    def test_friend_fail2(self):
        target = "/api/friends/"
        signature = self.f['local_user1'].sign("http://testserver2" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + str(self.f['local_user1']) + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_friend_fail3(self):
        target = "/api/friends/"
        unknown_user = DummyExternalUser('extuser3', 'external.org', False)
        signature = unknown_user.sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Signature ' + str(unknown_user) + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)

    def test_friend_fail4(self):
        target = "/api/friends/"
        signature = self.f['local_user1'].sign("http://testserver" + target)
        header = {'HTTP_AUTHORIZATION': 'Auth ' + str(self.f['local_user1']) + ':' + signature}
        reply = self.anonymous_client.get(target, **header)
        self.assertEqual(reply.status_code, 403)


class LoginApiTestCase(UserTestMixin, ToolshedTestCase):
    user = None
    client = Client(SERVER_NAME='testserver')

    def setUp(self):
        super().setUp()
        self.prepare_users()
        self.user = self.f['local_user1']

    def test_login(self):
        reply = self.client.post('/auth/token/',
                                 {'username': self.user.username + '@' + self.user.domain, 'password': 'testpassword2'})
        self.assertEqual(reply.status_code, 200)
        self.assertTrue('token' in reply.json())
        self.assertTrue(len(reply.json()['token']) == 40)
        self.assertTrue('key' in reply.json())
        self.assertEqual(len(reply.json()['key']), 64)

    def test_login_fail(self):
        reply = self.client.post('/auth/token/',
                                 {'username': self.user.username + '@' + self.user.domain, 'password': 'testpassword3'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('token' not in reply.json())
        self.assertTrue('error' in reply.json())

    def test_login_fail2(self):
        reply = self.client.post('/auth/token/',
                                 {'username': self.user.username, 'password': 'testpassword2'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('token' not in reply.json())
        self.assertTrue('error' in reply.json())


class RegistrationApiTestCase(UserTestMixin, ToolshedTestCase):
    client = Client(SERVER_NAME='testserver')

    def setUp(self):
        super().setUp()
        self.prepare_users()

    def test_registration(self):
        self.assertEqual(ToolshedUser.objects.all().count(), 3)
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'domain': 'example.com',
                                  'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 200)
        self.assertTrue('username' in reply.json())
        self.assertTrue('domain' in reply.json())
        user = ToolshedUser.objects.get(username='testuser')
        self.assertEqual(user.email, 'test@abc.de')
        self.assertEqual(user.domain, 'example.com')
        self.assertTrue(user.check_password('testpassword2'))
        self.assertEqual(ToolshedUser.objects.all().count(), 4)

    def test_registration_fail(self):
        reply = self.client.post('/auth/register/',
                                 {'username': '', 'password': 'testpassword2', 'domain': 'example.com',
                                  'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('username' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail2(self):
        reply = self.client.post('/auth/register/',
                                 {'password': 'testpassword2', 'domain': 'example.com', 'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('username' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail3(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': '', 'domain': 'example.com',
                                  'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('password' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail4(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'domain': 'example.com', 'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('password' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail5(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'domain': '',
                                  'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('domain' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail6(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('domain' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail7(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'domain': 'example.com',
                                  'email': ''})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('email' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_fail8(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'domain': 'example.com'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('email' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_existing_user(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser2', 'password': 'testpassword2', 'domain': 'example.com',
                                  'email': 'test3@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        # TODO: check for sensible error message
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_foreign_domain(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'domain': 'example.org',
                                  'email': 'test@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('domain' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)

    def test_registration_reuse_email(self):
        reply = self.client.post('/auth/register/',
                                 {'username': 'testuser', 'password': 'testpassword2', 'domain': 'example.com',
                                  'email': 'test2@abc.de'})
        self.assertEqual(reply.status_code, 400)
        self.assertTrue('errors' in reply.json())
        self.assertTrue('email' in reply.json()['errors'])
        self.assertEqual(ToolshedUser.objects.all().count(), 3)
