
    iM                     N   d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
Z
ddlmZ ddlmZ ddlmZ ddlZddlmZmZmZmZmZmZmZmZmZ  G d d      Z G d	 d
      Z G d d      Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d d      Z# G d d      Z$y)zBTests for utm_builder.py - TDD: Write tests first, then implement.    N)Path)Any)patch)	ALLOWED_CAMPAIGNSALLOWED_LANDING_DOMAINSALLOWED_MEDIUMSALLOWED_SOURCES	BatchItemValidationErrorbuild_utm_urlprocess_batchvalidate_paramsc                   <    e Zd ZddZddZddZddZddZddZy)	TestBuildUtmUrlNc                    t        ddddd      }d}||v }|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d} ||      }|sdd
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}x}}y)uO   source, medium, campaign, content, base 모두 정상 → 완성된 URL 반환.https://incar-top.tistory.commetacpcAB_A_snucarousel_a1basesourcemediumcampaigncontentutm_source=metainz%(py1)s in %(py3)surlpy1py3assert %(py5)spy5Nzutm_medium=cpczutm_campaign=AB_A_snuzutm_content=carousel_a1zLassert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
})py0py2py4py6)
r   
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_nameAssertionError_format_explanation
startswith)
selfr!   @py_assert0@py_assert2@py_format4@py_format6@py_assert1@py_assert3@py_assert5@py_format7s
             //home/jay/workspace/scripts/test_utm_builder.pytest_basic_url_all_paramsz)TestBuildUtmUrl.test_basic_url_all_params   s   0!
 !' C'''' C''' ''''''C'''C'''''''&3&&&&3&&&&&&&&&3&&&3&&&&&&&&-&#----&#---&------#---#-------(/(C////(C///(//////C///C///////~~>=>~=>>>>>>>>s>>>s>>>~>>>=>>>>>>>>>>    c                    t        dddd      }d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}d}||v}|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}d}||v}|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}y)u*   content, term 없이도 정상 URL 생성.r   googledisplayorg_mover   r   r   r   utm_source=googler   r    r!   r"   r%   r&   Nzutm_medium=displayzutm_campaign=org_moveutm_contentnot inz%(py1)s not in %(py3)sutm_term	r   r+   r,   r-   r.   r/   r0   r1   r2   r4   r!   r5   r6   r7   r8   s         r=    test_url_without_optional_paramsz0TestBuildUtmUrl.test_url_without_optional_params.   s   0	
 #)"c))))"c)))"))))))c)))c)))))))#*#s****#s***#******s***s*******&-&#----&#---&------#---#-------'}C''''}C'''}''''''C'''C'''''''$z$$$$z$$$z$$$$$$$$$$$$$$$$r?   c                    t        ddddd      }g }d}||v }|}|sd}||v }|}|sXt        j                  d	|fd
||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	|j                  |	       |st        j                  d	fd|f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}}y)u$   term 파라미터 포함 URL 생성.r   naver_sar   always_Au   이직준비r   r   r   r   termz-utm_term=%EC%9D%B4%EC%A7%81%EC%A4%80%EB%B9%84	utm_term=r   )z%(py3)s in %(py5)sr!   )r$   r&   z%(py7)spy7)z%(py10)s in %(py12)s)py10py12z%(py14)spy14   zassert %(py17)spy17N)r   r+   r,   r-   r.   r/   r0   append_format_boolopr1   r2   )r4   r!   r9   r6   @py_assert4r5   @py_assert9@py_assert11r8   @py_format8@py_format13@py_format15@py_format16@py_format18s                 r=   test_url_with_termz"TestBuildUtmUrl.test_url_with_term<   s    0
 	\>[>#E[[X[I[[[[[>#[[[>[[[[[[#[[[#[[[[[[[X[[[[[[[[[[X[[[[X[[[[[[[[[[[[[[[r?   c                    t        dddddd      }d}||v }|st        j                  d	|fd
||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}y)u   content + term 모두 포함.r   kakaorB   always_B	banner_01u   전직r   r   r   r   r   rR   zutm_content=banner_01r   r    r!   r"   r%   r&   NrS   rK   rL   s         r=   !test_url_with_all_optional_paramsz1TestBuildUtmUrl.test_url_with_all_optional_paramsG   s    0
 '-&#----&#---&------#---#-------!{c!!!!{c!!!{!!!!!!c!!!c!!!!!!!r?   c                    t        dddd      }d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}y)u7   긴급 랜딩페이지 (incar-top1.tistory.com) 허용.zhttps://incar-top1.tistory.comr   socialurgent_ArD   zincar-top1.tistory.comr   r    r!   r"   r%   r&   Nr   rK   rL   s         r=   test_urgent_landing_pagez(TestBuildUtmUrl.test_urgent_landing_pageT   s    1	
 (.'3....'3...'......3...3....... ' C'''' C''' ''''''C'''C'''''''r?   c                    t        dddd      }d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      d	t	        j
                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            dx}}y)uN   base URL에 이미 쿼리스트링이 있는 경우에도 올바르게 처리.z1https://incar-top.tistory.com/entry/test?ref=homer   r   r   rD   r   r   r    r!   r"   r%   r&   Nzref=homerK   rL   s         r=   !test_base_url_with_existing_queryz1TestBuildUtmUrl.test_base_url_with_existing_query_   s    D	
 !' C'''' C''' ''''''C'''C''''''' zS    zS   z      S   S       r?   returnN)	__name__
__module____qualname__r>   rM   rd   rj   rn   rp    r?   r=   r   r      s!    ?%	\"	(	!r?   r   c                   $    e Zd ZddZddZddZy)TestValidateSourceNc           
         t        j                  t              5 }t        dddd       ddd       g }d}j                  }t        |      }|j                  } |       }||v }|}	|s2d}
|j                  }t        |      }|j                  } |       }|
|v }|}	|	st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }|j                  |       |s%t        j                  d	fd
f      t        j                  |
      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                        t        j                        t        j                        t        j                  |      dz  }dd|iz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                   |            dx}	x}x}x}x}x}x}x}x}
x}x}x}x}}y# 1 sw Y   xY w)u/   허용되지 않는 source → ValidationError.invalid_sourcer   r   r   r   r   r   r   N
utm_sourcer   r   z%(py3)s in %(py14)s
{%(py14)s = %(py12)s
{%(py12)s = %(py10)s
{%(py10)s = %(py5)s(%(py8)s
{%(py8)s = %(py6)s.value
})
}.lower
}()
}strexc_infor$   r&   r*   py8rU   rV   rW   %(py16)spy16z%(py19)s in %(py30)s
{%(py30)s = %(py28)s
{%(py28)s = %(py26)s
{%(py26)s = %(py21)s(%(py24)s
{%(py24)s = %(py22)s.value
})
}.lower
}()
}py19py21py22py24py26py28py30%(py32)spy32rX   zassert %(py35)spy35pytestraisesr   r   valuer~   lowerr+   r,   r-   r.   r/   r0   rZ   r[   r1   r2   )r4   r   r9   r6   @py_assert7r]   r^   @py_assert13r\   r5   @py_assert18@py_assert23@py_assert25@py_assert27@py_assert29@py_assert20ra   @py_format17@py_format31@py_format33@py_format34@py_format36s                         r=   test_invalid_source_raisesz-TestValidateSource.test_invalid_source_raiseso   s   ]]?+ 	x'#4		 	f|e8>>es>2e288e8:e|::ehehnne#nJ]eJ]JcJceJcJeehJe>eeeee|:eee|eeeeeeseeeseeeeee8eee8eee>eee2eee8eee:eeeeeeehJeeeeheeeeee#eee#eeeeeeheeeheeeneeeJ]eeeJceeeJeeeeeeeeeeeeeeeee	 	s   MMc                    t        j                  t              5 }t        dddd       ddd       t	        j
                        fdt        D        }t        |      }|sdd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}y# 1 sw Y   xY w)u@   에러 메시지에 허용 값 목록이 포함되어야 한다.facebookr   r   r   r{   Nc              3   &   K   | ]  }|v  
 y wNrv   ).0s	error_msgs     r=   	<genexpr>zYTestValidateSource.test_invalid_source_message_contains_allowed_values.<locals>.<genexpr>        ;a1	>;   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr'   r(   r)   )r   r   r   r   r~   r   r	   r   r.   r/   r+   r0   r-   r1   r2   r4   r   r9   r:   @py_format5r   s        @r=   3test_invalid_source_message_contains_allowed_valueszFTestValidateSource.test_invalid_source_message_contains_allowed_valuesz   s    ]]?+ 	x!#4		 '	;?;;s;;;;;;;;;s;;;s;;;;;;;;;;;;;;	 	   C>>Dc                 8    t         D ]  }t        |ddd        y)u'   모든 허용 source 값 검증 통과.r   r   r   r{   N)r	   r   )r4   r   s     r=   test_valid_sources_passz*TestValidateSource.test_valid_sources_pass   s%    % 	F#4		r?   rq   )rs   rt   ru   r   r   r   rv   r?   r=   rx   rx   n   s    	f<r?   rx   c                   $    e Zd ZddZddZddZy)TestValidateMediumNc           
      b   t        j                  t              5 }t        dddd       ddd       d}j                  }t        |      }|j                  } |       }||v }|s2t        j                  d|fd	||f      t        j                  |      d
t        j                         v st        j                  t
              rt        j                  t
              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}x}x}x}}y# 1 sw Y   |xY w)u/   허용되지 않는 medium → ValidationError.r   emailr   r   r{   Nr   r   z%(py1)s in %(py12)s
{%(py12)s = %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py3)s(%(py6)s
{%(py6)s = %(py4)s.value
})
}.lower
}()
}r~   r   r#   r$   r)   r*   r   rU   rV   assert %(py14)srW   r   r   r   r   r   r~   r   r+   r,   r-   r.   r/   r0   r1   r2   
r4   r   r5   r;   r   r]   r^   r6   r`   ra   s
             r=   test_invalid_medium_raisesz-TestValidateMedium.test_invalid_medium_raises   s   ]]?+ 	x#4		 6x~~63~.6.446466x66666x6666x66666636663666666x666x666~666.6664666666666666	 	   F$$F.c                    t        j                  t              5 }t        dddd       ddd       t	        j
                        fdt        D        }t        |      }|sdd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}y# 1 sw Y   xY w)u0   에러 메시지에 허용 medium 목록 포함.r   organicr   r   r{   Nc              3   &   K   | ]  }|v  
 y wr   rv   )r   mr   s     r=   r   zYTestValidateMedium.test_invalid_medium_message_contains_allowed_values.<locals>.<genexpr>   r   r   r   r   r   )r   r   r   r   r~   r   r   r   r.   r/   r+   r0   r-   r1   r2   r   s        @r=   3test_invalid_medium_message_contains_allowed_valueszFTestValidateMedium.test_invalid_medium_message_contains_allowed_values   s    ]]?+ 	x #4		 '	;?;;s;;;;;;;;;s;;;s;;;;;;;;;;;;;;	 	r   c                 8    t         D ]  }t        d|dd        y)u'   모든 허용 medium 값 검증 통과.r   r   r   r{   N)r   r   )r4   r   s     r=   test_valid_mediums_passz*TestValidateMedium.test_valid_mediums_pass   s%    % 	F#4		r?   rq   )rs   rt   ru   r   r   r   rv   r?   r=   r   r      s    	7
<r?   r   c                   $    e Zd ZddZddZddZy)TestValidateCampaignNc           
      b   t        j                  t              5 }t        dddd       ddd       d}j                  }t        |      }|j                  } |       }||v }|s2t        j                  d|fd	||f      t        j                  |      d
t        j                         v st        j                  t
              rt        j                  t
              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}x}x}x}}y# 1 sw Y   |xY w)u1   허용되지 않는 campaign → ValidationError.r   r   random_campaignr   r{   Nr   r   r   r~   r   r   r   rW   r   r   s
             r=   test_invalid_campaign_raisesz1TestValidateCampaign.test_invalid_campaign_raises   s   ]]?+ 	x*4		 88S080668688z88888z8888z888888S888S88888888888888808886888888888888	 	r   c                    t        j                  t              5 }t        dddd       ddd       t	        j
                        fdt        D        }t        |      }|sdd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}y# 1 sw Y   xY w)u2   에러 메시지에 허용 campaign 목록 포함.r   r   test_campaignr   r{   Nc              3   &   K   | ]  }|v  
 y wr   rv   )r   cr   s     r=   r   z]TestValidateCampaign.test_invalid_campaign_message_contains_allowed_values.<locals>.<genexpr>   s     =a1	>=r   r   r   r   )r   r   r   r   r~   r   r   r   r.   r/   r+   r0   r-   r1   r2   r   s        @r=   5test_invalid_campaign_message_contains_allowed_valueszJTestValidateCampaign.test_invalid_campaign_message_contains_allowed_values   s    ]]?+ 	x(4		 '	=+<==s=========s===s==============	 	r   c                 8    t         D ]  }t        dd|d        y)u)   모든 허용 campaign 값 검증 통과.r   r   r   r{   N)r   r   )r4   r   s     r=   test_valid_campaigns_passz.TestValidateCampaign.test_valid_campaigns_pass   s%    ) 	H!4		r?   rq   )rs   rt   ru   r   r   r   rv   r?   r=   r   r      s    	9
>r?   r   c                   ,    e Zd ZddZddZddZddZy)TestValidateBaseUrlNc           
      t	   t        j                  t              5 }t        dddd       ddd       g }d}j                  }t        |      }|j                  } |       }||v }|}	|sfd}
|j                  }t        |      }|j                  } |       }|
|v }|}	|s2d	}|j                  }t        |      }|j                  } |       }||v }|}	|	st        j                  d
|fd||f      t        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }|j                  |       |sMt        j                  d
fd
f      t        j                  |
      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                        t        j                        t        j                        t        j                  |      dz  }dd|iz  }|j                  |       |s%t        j                  d
fdf      t        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                        t        j                        t        j                        t        j                  |      dz  }dd|iz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                   |            dx}	x}x}x}x}x}x}x}x}
x}x}x}x}x}x}x}x}x}x}}y# 1 sw Y   xY w)u2   허용되지 않는 도메인 → ValidationError.r   r   r   zhttps://evil.comr{   Ndomainr   landingr   r}   r~   r   r   r   r   r   r   r   r   )z%(py35)s in %(py46)s
{%(py46)s = %(py44)s
{%(py44)s = %(py42)s
{%(py42)s = %(py37)s(%(py40)s
{%(py40)s = %(py38)s.value
})
}.lower
}()
})r   py37py38py40py42py44py46z%(py48)spy48rX   zassert %(py51)spy51r   )r4   r   r9   r6   r   r]   r^   r   r\   r5   r   r   r   r   r   r   @py_assert34@py_assert39@py_assert41@py_assert43@py_assert45@py_assert36ra   r   r   r   @py_format47@py_format49@py_format50@py_format52s                                 r=   test_invalid_domain_raisesz.TestValidateBaseUrl.test_invalid_domain_raises   s   ]]?+ 	x#'			
	
$NN	
N+	
+11	
13	
33	
	
%^^	
^,	
,22	
24	
44	
 	
 !)	
  /	
 055	
 67	
 77	
 	
 		
3	
 	
 
	 	
 	
 
6		
 	
  	
 	
 
	 	
 	
 
6		
 	
  %	
 	
 
	 %	
 	
 
	 +	
 	
 
	 ,	
 	
 
	 2	
 	
 
	 4	
 	
 	
 
6		
 
		
 		
4	
 	
 
	 	
 	
 
6		
 	
  	
 	
 
	 	
 	
 
6		
 	
  &	
 	
 
	 &	
 	
 
	 ,	
 	
 
	 -	
 	
 
	 3	
 	
 
	 5	
 	
 	
 
6		
 
		
 		
 7	
 	
 
	 	
 	
 
6		
 	
   	
 	
 
	  	
 	
 
6		
 	
  !)	
 	
 
	 !)	
 	
 
	 !/	
 	
 
	 0	
 	
 
	 6	
 	
 
	 8	
 	
 	
 
6		
 
		
 		
 	
 	
 	
 		
 	
 	
 	
 	
 	
 	
	 	s   R--R7c                    t        j                  t              5 }t        dddd       ddd       t	        j
                        fdt        D        }t        |      }|sdd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}y# 1 sw Y   xY w)u3   에러 메시지에 허용 도메인 목록 포함.r   r   r   zhttps://not-allowed.tistory.comr{   Nc              3   &   K   | ]  }|v  
 y wr   rv   )r   dr   s     r=   r   z[TestValidateBaseUrl.test_invalid_domain_message_contains_allowed_domains.<locals>.<genexpr>   s     Ca1	>Cr   r   r   r   )r   r   r   r   r~   r   r   r   r.   r/   r+   r0   r-   r1   r2   r   s        @r=   4test_invalid_domain_message_contains_allowed_domainszHTestValidateBaseUrl.test_invalid_domain_message_contains_allowed_domains   s    ]]?+ 	x#6		 '	C+BCCsCCCCCCCCCsCCCsCCCCCCCCCCCCCC	 	r   c                 >    t         D ]  }t        dddd|         y)u)   허용된 모든 도메인 검증 통과.r   r   r   zhttps://r{   N)r   r   )r4   r   s     r=   test_valid_domains_passz+TestValidateBaseUrl.test_valid_domains_pass   s,    - 	F#x(		r?   c                 ~    t        j                  t              5  t        dddd       ddd       y# 1 sw Y   yxY w)u3   URL 형식이 잘못된 경우 → ValidationError.r   r   r   z	not-a-urlr{   N)r   r   r   r   )r4   s    r=   test_invalid_url_format_raisesz2TestValidateBaseUrl.test_invalid_url_format_raises  s7    ]]?+ 	# 		 	 	s   3<rq   )rs   rt   ru   r   r   r   r   rv   r?   r=   r   r      s    

Dr?   r   c                   ,    e Zd ZddZddZddZddZy)TestOptionalParamsNc                 n   t        ddddd      }d}||v}|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}y)u1   content=None → utm_content 파라미터 없음.r   r   r   r   Nr   rF   rG   rI   r!   r"   r%   r&   rK   rL   s         r=   test_content_none_not_in_urlz/TestOptionalParams.test_content_none_not_in_url  sv    0
 '}C''''}C'''}''''''C'''C'''''''r?   c                 n   t        ddddd      }d}||v}|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}y)u+   term=None → utm_term 파라미터 없음.r   r   r   r   NrQ   rJ   rG   rI   r!   r"   r%   r&   rK   rL   s         r=   test_term_none_not_in_urlz,TestOptionalParams.test_term_none_not_in_url!  sv    0
 $z$$$$z$$$z$$$$$$$$$$$$$$$$r?   c                 n   t        ddddd      }d}||v}|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}y)u/   content='' → utm_content 파라미터 없음.r   r   r   r    r   rF   rG   rI   r!   r"   r%   r&   NrK   rL   s         r=   $test_content_empty_string_not_in_urlz7TestOptionalParams.test_content_empty_string_not_in_url,  sv    0
 '}C''''}C'''}''''''C'''C'''''''r?   c                    t        dddddd      }d}||v }|st        j                  d	|fd
||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}y)u   content + term 동시 포함.r   rO   r   rP   ad_01keywordri   zutm_content=ad_01r   r    r!   r"   r%   r&   Nzutm_term=keywordrK   rL   s         r=   test_term_with_contentz)TestOptionalParams.test_term_with_content7  s    0
 #)"c))))"c)))"))))))c)))c)))))))!(!S((((!S(((!((((((S(((S(((((((r?   rq   )rs   rt   ru   r   r   r   r   rv   r?   r=   r   r     s    	(	%	()r?   r   c                   $    e Zd ZddZddZddZy)TestBatchModeNc                 d   ddddddddd	dd
g}t        |      }t        |      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|D ]  }|d   }	d}
|	|
u }|slt        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}}
|d   }	d}
|	|
u}|slt        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}}
d}	|d   }
|	|
v }|slt        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}}
 y) u2   배치 항목 모두 정상 → 모든 URL 생성.r   r   r   r   r   r   r   r   r   r   rA   rB   rC   r{      ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenresultsr'   r#   r$   r*   assert %(py8)sr   Nerrorisz%(py1)s is %(py4)sr#   r)   assert %(py6)sr*   r!   is notz%(py1)s is not %(py4)szutm_source=r   )z%(py1)s in %(py4)s
r   r	  r+   r,   r.   r/   r0   r-   r1   r2   )r4   itemsr
  r6   r;   r\   r<   @py_format9resultr5   r:   r   s               r=   test_batch_all_validz"TestBatchMode.test_batch_all_validI  s    !&(7 ##&7	"
  &7| q |q    |q      s   s      7   7   |   q        	2F'?*d*?d****?d***?***d*******%=,,=,,,,=,,,=,,,,,,,,,, 1F5M1=M1111=M111=111M1111111	2r?   c                    ddddddg}t        |      }t        |      }d}||k(  }|st        j                  d|fd	||f      d
t	        j
                         v st        j                  t              rt        j                  t              nd
dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   d   }d}||u}	|	st        j                  d|	fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}	}d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            dx}}y)u:   배치 처리 결과 URL에 올바른 파라미터 포함.rf   rl   rg   img_01r   r  rX   r  r  r	  r
  r  r  r   Nr   r!   r  )z%(py0)s is not %(py3)sr'   r$   r%   r&   zutm_source=kakaor   r    r"   zutm_medium=socialzutm_campaign=always_Bzutm_content=img_01r  )r4   r  r
  r6   r;   r\   r<   r  r!   r9   r7   r8   r5   s                r=   test_batch_url_params_correctz+TestBatchMode.test_batch_url_params_correctb  s    ""&#7"
  &7| q |q    |q      s   s      7   7   |   q       ajs$s$ss$!(!S((((!S(((!((((((S(((S(((((((")"c))))"c)))"))))))c)))c)))))))&-&#----&#---&------#---#-------#*#s****#s***#******s***s*******r?   c                 f   t        g       }g }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)u!   빈 배치 → 빈 결과 반환.r  )z%(py0)s == %(py3)sr
  r  r%   r&   N)	r   r+   r,   r.   r/   r0   r-   r1   r2   )r4   r
  r6   r9   r7   r8   s         r=   test_batch_empty_listz#TestBatchMode.test_batch_empty_listv  sd    #w"}w"ww"r?   rq   )rs   rt   ru   r  r  r   rv   r?   r=   r  r  H  s    22+(r?   r  c                       e Zd ZddZddZy)TestBatchModePartialErrorsNc                 z   ddddddddddddd	ddg}t        |      }t        |      }d
}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   d   }d}	||	u }|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	|d   d   }d}	||	u}|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	|d   d   }d}	||	u}|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	|d   d   }d}	||	u }|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	|d   d   }d}	||	u }|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	|d   d   }d}	||	u}|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	y)u^   일부 항목 잘못된 경우 → 에러 항목은 error 필드, 정상 항목은 url 반환.r   r   r   r   r{   invalid_srcrA   rB   rC      r  r  r	  r
  r  r  r   Nr   r  r  r  r  r  r*   r!   r  r  rX   r  r  r4   r  r
  r6   r;   r\   r<   r  r5   r:   r   s              r=   test_batch_partial_invalidz5TestBatchModePartialErrors.test_batch_partial_invalid  s    !&7	 (&7	 ##&7	"
(  &7| q |q    |q      s   s      7   7   |   q        qz'"*d*"d****"d***"***d*******qz% ,, ,,,, ,,, ,,,,,,,,,, qz'".$."$...."$..."...$.......qz% (D( D(((( D((( (((D((((((( qz'"*d*"d****"d***"***d*******qz% ,, ,,,, ,,, ,,,,,,,,,,r?   c                 R   dddddg}t        |      }t        |      }d}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  t              rt        j                  t              nd	d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   d   }d}	||	u}|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	|d   d   }d}	||	u }|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	y)u4   모든 항목이 잘못된 경우 → 모두 에러.
bad_source
bad_mediumbad_campaignr   r{   rX   r  r  r	  r
  r  r  r   Nr   r  r  r  r  r  r*   r!   r  r  r  r&  s              r=   test_batch_all_invalidz1TestBatchModePartialErrors.test_batch_all_invalid  s`    '&*7	"
  &7| q |q    |q      s   s      7   7   |   q       qz'".$."$...."$..."...$.......qz% (D( D(((( D((( (((D(((((((r?   rq   )rs   rt   ru   r'  r,  rv   r?   r=   r"  r"    s    #-J)r?   r"  c                   h    e Zd ZdZdee   dej                  e   fdZddZ	ddZ
ddZdd	Zdd
Zy)TestCLIz*/home/jay/workspace/scripts/utm_builder.pyargsrr   c                 j    t        j                  t        j                  | j                  g|dd      S )NT)capture_outputtext)
subprocessrunsys
executableSCRIPT)r4   r/  s     r=   _runzTestCLI._run  s.    ~~^^T[[040
 	
r?   Nc                 H   | j                  g d      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}d
}|j                  }||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)u-   정상 인자 → exit code 0, stdout에 URL.)
--sourcer   --mediumr   
--campaignr   z	--contentr   --baser   r   r  z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sr  r'   r(   r&   assert %(py7)srT   Nr   r   z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stdout
}r#   r$   r&   )r8  
returncoder+   r,   r.   r/   r0   r-   r1   r2   stdout)	r4   r  r9   r\   r:   r8   r_   r5   r6   s	            r=   test_cli_valid_args_exit_0z"TestCLI.test_cli_valid_args_exit_0  s    
   %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%% 1FMM1 M1111 M111 111111F111F111M1111111r?   c                    | j                  g d      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)
u!   잘못된 source → exit code 1.r:  invalidr;  r   r<  r   r=  r   rX   r  r>  r  r?  r@  rT   N)
r8  rC  r+   r,   r.   r/   r0   r-   r1   r2   )r4   r  r9   r\   r:   r8   r_   s          r=   test_cli_invalid_source_exit_1z&TestCLI.test_cli_invalid_source_exit_1  s    	
   %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%%r?   c                    | j                  g d      }|j                  |j                  z   g }d}j                  } |       }||v }|}|sfdt        D        }t        |      }	|	}|s|t        j                  d|fd||f      t        j                  |      dt        j                         v st        j                        rt        j                        ndt        j                  |      t        j                  |      dz  }
dd	|
iz  }|j                  |       |sd
dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                        t        j                  	      dz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}x}}	y)uD   잘못된 source → stderr에 에러 메시지 + 허용 값 목록.rG  r   c              3   &   K   | ]  }|v  
 y wr   rv   )r   r   combineds     r=   r   zATestCLI.test_cli_invalid_source_stderr_message.<locals>.<genexpr>  s     2ZQ1=2Zr   r   )zD%(py3)s in %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s.lower
}()
}rL  )r$   r&   rT   py9z%(py11)spy11z)%(py17)s
{%(py17)s = %(py13)s(%(py15)s)
}r   )py13py15rY   rX   zassert %(py20)spy20N)r8  stderrrD  r   r	   r   r+   r,   r-   r.   r/   r0   rZ   r[   r1   r2   )r4   r  r9   r6   @py_assert6@py_assert8r\   r5   @py_assert14@py_assert16@py_format10@py_format12rc   @py_format19@py_format21rL  s                  @r=   &test_cli_invalid_source_stderr_messagez.TestCLI.test_cli_invalid_source_stderr_message  s#   	
 ==6==0ZxZ8>>Z>+Zx++Z2Z/2ZZs2Z/ZZ/ZZZZx+ZZZxZZZZZZ8ZZZ8ZZZ>ZZZ+ZZZZZZZZZZsZZZsZZZ2ZZZZ/ZZZZZZZZZZZZZZZr?   c                    ddddddddd	dd
g}t        j                  ddd      5 }t        j                  ||       |j                  }ddd       | j                  dg      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}d}
|j                  }|
|v }|st        j                  d|fd|
|f      t        j                  |
      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}
x}}d}
|j                  }|
|v }|st        j                  d|fd|
|f      t        j                  |
      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}
x}}t!        |      j#                  d       y# 1 sw Y   xY w)u*   --batch JSON 파일 → 다량 URL 출력.r   r   r   r   r   r  rA   rB   rC   r{   w.jsonFmodesuffixdeleteN--batchr   r  r>  r  r?  r@  rT   r   r   rA  rB  rE   T
missing_oktempfileNamedTemporaryFilejsondumpnamer8  rC  r+   r,   r.   r/   r0   r-   r1   r2   rD  r   unlinkr4   
batch_dataftmp_pathr  r9   r\   r:   r8   r_   r5   r6   s               r=   test_cli_batch_modezTestCLI.test_cli_batch_mode  s    !&(7 ##&7	

 ((c'%P 	TUIIj!$vvH	 Ix01  %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%% 1FMM1 M1111 M111 111111F111F111M1111111"3fmm3"m3333"m333"333333f333f333m3333333X.	 	s   #KK"c                 :   ddddddddddg}t        j                  ddd	
      5 }t        j                  ||       |j                  }ddd       | j                  dg      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}d}
|j                  }|
|v }|st        j                  d|fd|
|f      t        j                  |
      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}
x}}t!        |      j#                  d       y# 1 sw Y   xY w)uL   배치 모드에서 일부 잘못된 항목 → exit code 1 (에러 있음).r   r   r   r   r{   bad_srcr]  r^  Fr_  Nrc  rX   r  r>  r  r?  r@  rT   r   r   rA  rB  Trd  rf  rm  s               r=   &test_cli_batch_partial_error_exit_codez.TestCLI.test_cli_batch_partial_error_exit_code  s~    !&7	 $&7	

 ((c'%P 	TUIIj!$vvH	 Ix01  %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%% 1FMM1 M1111 M111 111111F111F111M1111111X.	 	s   #HHrq   )rs   rt   ru   r7  listr~   r3  CompletedProcessr8  rE  rI  r[  rq  rt  rv   r?   r=   r.  r.    sC    9F
c 
z'B'B3'G 
2&& [$/8/r?   r.  )%__doc__builtinsr.   _pytest.assertion.rewrite	assertionrewriter+   ri  r3  r5  rg  pathlibr   typingr   unittest.mockr   r   utm_builderr   r   r   r	   r
   r   r   r   r   r   rx   r   r   r   r   r  r"  r.  rv   r?   r=   <module>r     s    H     
     
 
 
 J! J!`! !N   L   L. .h-) -)f1 1n3) 3)rt/ t/r?   