# -*- coding: utf-8 -*- from allauth.socialaccount.models import SocialAccount from django.db import IntegrityError, transaction from django.test import TestCase from gestioncof.models import CofProfile, User class UserTests(TestCase): def test_has_profile(self): """ A User always has a related CofProfile and a CofProfile always has a related User. """ u = User.objects.create_user("foo", "", "") # Creating a User creates a related CofProfile. self.assertTrue(hasattr(u, "profile")) # there's no point in having a cofprofile without a user associated. p = u.profile u.delete() with transaction.atomic(): with self.assertRaises(CofProfile.DoesNotExist): p.refresh_from_db() # there's no point in having a user without a cofprofile associated. u = User.objects.create_user("foo", "", "") u.profile.delete() with transaction.atomic(): with self.assertRaises(User.DoesNotExist): u.refresh_from_db() class CofProfileTests(TestCase): def setUp(self): self.u = User.objects.create_user("user", "", "") self.p = self.u.profile def test_login_clipper_sync_clipper_connections(self): """ The value of `login_clipper` is sync with the identifier of the most recently used clipper connection. """ def socialaccount_transform(o): """ Function to compare QuerySet of `SocialAccount`, instead of the default, `repr`, only depends on the involved user. """ return "{provider} {username} {uid}".format( provider=o.provider, username=o.user.username, uid=o.uid ) def assertClipperAccountQuerysetEquals(user, *args, **kwargs): kwargs.setdefault("transform", socialaccount_transform) qs = SocialAccount.objects.filter(provider="clipper", user=user).order_by( "last_login" ) self.assertQuerysetEqual(qs, *args, **kwargs) # Not saved in the database. self.assertEqual(CofProfile().login_clipper, "") # This CofProfile has been created without any value for login_clipper. u, p = self.u, self.p self.assertEqual(p.login_clipper, "") # Filling value for the first time triggers the creation of a clipper # connection (SocialAccount) for the related user. p.login_clipper = "theclipper" p.save() self.assertEqual(p.login_clipper, "theclipper") assertClipperAccountQuerysetEquals(u, ["clipper user theclipper"]) # Assigning a new value updates the existing connection. p.login_clipper = "anotherclipper" p.save() self.assertEqual(p.login_clipper, "anotherclipper") assertClipperAccountQuerysetEquals(u, ["clipper user anotherclipper"]) # Creating a clipper connection, using SocialAccount, sets the used # identifier as value. conn = SocialAccount.objects.create(provider="clipper", user=u, uid="clip") self.assertEqual(p.login_clipper, "clip") assertClipperAccountQuerysetEquals( u, ["clipper user anotherclipper", "clipper user clip"] ) # Removing a clipper connection sets the identifier most recently # used one as value. conn.delete() p.refresh_from_db() self.assertEqual(p.login_clipper, "anotherclipper") assertClipperAccountQuerysetEquals(u, ["clipper user anotherclipper"]) # If the deletion of SocialAccount(s) leaves no clipper connection, # flush the value. SocialAccount.objects.filter(provider="clipper", user=u).delete() p.refresh_from_db() self.assertEqual(p.login_clipper, "") # Assigning an identifier already in use updates the related connection # as the most recently used. SocialAccount.objects.bulk_create( [ SocialAccount(provider="clipper", user=u, uid="theclipper"), SocialAccount(provider="clipper", user=u, uid="clip"), ] ) # Note 'clip' is the most recent one, and value is empty because # bulk_create didn't trigger post_save signals. p.login_clipper = "theclipper" p.save() self.assertEqual(p.login_clipper, "theclipper") assertClipperAccountQuerysetEquals( u, ["clipper user clip", "clipper user theclipper"] ) # Flushing value removes all clipper connections, and set value to None # to avoid failure due to the unicity constraint. p.login_clipper = "" p.save() self.assertEqual(p.login_clipper, "") self.assertFalse( SocialAccount.objects.filter(provider="clipper", user=u).exists() ) # Value is unique among all CofProfile instances… p.login_clipper = "theclipper" p.save() p2 = User.objects.create_user("user2", "", "").profile p2.login_clipper = "theclipper" with transaction.atomic(): with self.assertRaises(IntegrityError): p2.save() # …except for '' (stored as NULL). p.login_clipper = "" p.save() p2.login_clipper = "" p2.save()