55from allauth .account .models import EmailAddress
66from allauth .socialaccount .models import SocialAccount
77from core .util .thread_local import thread_local
8+ from django .apps import apps
89from django .contrib .contenttypes .models import ContentType
910from shop .order .models import Order
1011from user .models import UserExt
@@ -47,6 +48,26 @@ def _merge(source, target, actor=None) -> UserMergeHistory:
4748 return history
4849
4950
51+ def test_no_unhandled_user_m2m_relations (db ):
52+ """merge 는 M2M 를 이관하지 않는다 — user 를 건드리는 새 M2M 가 추가되면 조용히 누락되므로 여기서 잡는다."""
53+ allowed = {(UserExt ._meta .label , "groups" ), (UserExt ._meta .label , "user_permissions" )}
54+ found = {
55+ (model ._meta .label , field .name )
56+ for model in apps .get_models ()
57+ for field in model ._meta .local_many_to_many
58+ if field .related_model is UserExt or model is UserExt
59+ }
60+ assert found <= allowed , f"merge 가 이관하지 않는 user M2M: { found - allowed } "
61+
62+
63+ def test_create_user_creates_verified_email (db ):
64+ user = UserExt .objects .create_user (username = "u" , email = "U@Example.com" )
65+
66+ ea = EmailAddress .objects .get (user = user )
67+ assert ea .email == "u@example.com"
68+ assert ea .verified is True and ea .primary is True
69+
70+
5071def test_merge_repoints_owned_business_fk (source_user , target_user ):
5172 order = Order .objects .create (user = source_user , name = "src-order" )
5273
@@ -99,7 +120,6 @@ def test_untracked_model_is_repointed(source_user, target_user):
99120
100121def test_allauth_accounts_are_moved (source_user , target_user ):
101122 SocialAccount .objects .create (user = source_user , provider = "google" , uid = "src-google" , extra_data = {})
102- EmailAddress .objects .create (user = source_user , email = "source@example.com" , verified = True , primary = True )
103123
104124 _merge (source_user , target_user )
105125
@@ -130,9 +150,6 @@ def test_audit_fields_are_not_moved(source_user, target_user):
130150def test_source_email_moves_and_demotes_when_target_has_primary (source_user , target_user ):
131151 """target 이 이미 primary 를 가지면, source 의 (중복 아닌) 이메일은 source 에 남기지 않고 target 으로
132152 옮기며 primary 를 강등한다 — 죽은 계정에 주소가 갇히지 않게."""
133- EmailAddress .objects .create (user = source_user , email = "source@example.com" , verified = True , primary = True )
134- EmailAddress .objects .create (user = target_user , email = "target@example.com" , verified = True , primary = True )
135-
136153 _merge (source_user , target_user )
137154
138155 assert not EmailAddress .objects .filter (user = source_user ).exists ()
@@ -143,9 +160,8 @@ def test_source_email_moves_and_demotes_when_target_has_primary(source_user, tar
143160
144161def test_duplicate_email_consolidates_verification_and_demotes_source (source_user , target_user ):
145162 """양쪽이 같은 주소를 가지면 삭제 없이: target 사본을 verified 로 승격하고 source 사본은 미검증으로 강등해 남긴다."""
146- EmailAddress .objects .create (user = source_user , email = "dup@example.com" , verified = True , primary = True )
163+ EmailAddress .objects .filter (user = source_user ). update ( email = "dup@example.com" ) # source 의 유일 이메일을 dup 으로
147164 EmailAddress .objects .create (user = target_user , email = "dup@example.com" , verified = False , primary = False )
148- EmailAddress .objects .create (user = target_user , email = "target@example.com" , verified = True , primary = True )
149165
150166 _merge (source_user , target_user )
151167
@@ -156,7 +172,8 @@ def test_duplicate_email_consolidates_verification_and_demotes_source(source_use
156172
157173def test_target_primary_assigned_when_missing (source_user , target_user ):
158174 """규칙3: 병합 후 target 에 primary 가 없으면 하나(verified 우선)를 지정한다."""
159- EmailAddress .objects .create (user = target_user , email = "target@example.com" , verified = True , primary = False )
175+ EmailAddress .objects .filter (user = source_user ).delete () # source 이메일 없음
176+ EmailAddress .objects .filter (user = target_user ).update (primary = False ) # target 은 primary 없는 verified 이메일만
160177
161178 _merge (source_user , target_user )
162179
@@ -167,10 +184,8 @@ def test_target_primary_assigned_when_missing(source_user, target_user):
167184
168185def test_unmerge_restores_email_state (source_user , target_user ):
169186 """규칙1(옮김+강등)·규칙2(검증통합) 모두 before-image replay 로 정확히 복원된다."""
170- EmailAddress .objects .create (user = source_user , email = "source@example.com" , verified = True , primary = True )
171187 EmailAddress .objects .create (user = source_user , email = "dup@example.com" , verified = True , primary = False )
172188 EmailAddress .objects .create (user = target_user , email = "dup@example.com" , verified = False , primary = False )
173- EmailAddress .objects .create (user = target_user , email = "target@example.com" , verified = True , primary = True )
174189
175190 merge = _merge (source_user , target_user )
176191 merge .unmerge ()
@@ -282,42 +297,32 @@ def test_double_unmerge_rejected(source_user, target_user):
282297# ---- assert_self_mergeable (본인 병합 사전검증) --------------------------------
283298
284299
285- def _verified_email (user , email ):
286- return EmailAddress .objects .create (user = user , email = email , verified = True , primary = True )
287-
288-
289300def test_self_mergeable_passes_when_both_verified (source_user , target_user ):
290- _verified_email (source_user , "source@example.com" )
291- _verified_email (target_user , "target@example.com" )
292-
293- UserMergeHistory .assert_self_mergeable (source_user , target_user ) # no raise
301+ UserMergeHistory .assert_self_mergeable (source_user , target_user ) # 둘 다 fixture 로 verified 이메일 보유 → no raise
294302
295303
296304def test_self_mergeable_allows_email_less_source (source_user , target_user ):
297- _verified_email ( target_user , "target@example.com" ) # source 는 이메일 없음 → 허용
305+ EmailAddress . objects . filter ( user = source_user ). delete ( ) # source 는 이메일 없음 → 허용
298306
299307 UserMergeHistory .assert_self_mergeable (source_user , target_user ) # no raise
300308
301309
302310def test_self_mergeable_rejects_email_less_target (source_user , target_user ):
303- _verified_email ( source_user , "source@example.com" )
311+ EmailAddress . objects . filter ( user = target_user ). delete () # target 에 인증 이메일 없음 → 거부
304312
305313 with pytest .raises (ValueError ):
306314 UserMergeHistory .assert_self_mergeable (source_user , target_user )
307315
308316
309317def test_self_mergeable_rejects_unverified_target_email (source_user , target_user ):
310- _verified_email (source_user , "source@example.com" )
311- _verified_email (target_user , "target@example.com" )
312318 EmailAddress .objects .create (user = target_user , email = "extra@example.com" , verified = False )
313319
314320 with pytest .raises (ValueError ):
315321 UserMergeHistory .assert_self_mergeable (source_user , target_user )
316322
317323
318324def test_self_mergeable_rejects_unverified_source_email (source_user , target_user ):
319- _verified_email (target_user , "target@example.com" )
320- EmailAddress .objects .create (user = source_user , email = "source@example.com" , verified = False )
325+ EmailAddress .objects .create (user = source_user , email = "extra@example.com" , verified = False )
321326
322327 with pytest .raises (ValueError ):
323328 UserMergeHistory .assert_self_mergeable (source_user , target_user )
0 commit comments