
    jF                        d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
mZmZmZmZmZmZmZ dZdZdZd Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(y)uT  tests.regression.test_gemini_evidence_freshness_checker — task-2641 Track A.

회장 verbatim §10 (2026-05-23) 1:1 정합 — PR HEAD SHA vs Gemini review commit_id
정합 검증 helper 회귀.

본 회귀는 Layer A / NO-CRON: subprocess / cokacdir / merge / cron 호출 0.
github_api 는 callable inject 로 mock — live gh 호출 0.
    )annotationsN)GEMINI_BOT_LOGINRESULT_FRESHRESULT_NO_REVIEWRESULT_STALEFreshnessCheckerErrorcheck_gemini_evidence_freshis_gemini_trigger_comment(0000000000000000000000000000000000000000(0000000000000000000000000000000000000001(abc0000000000000000000000000000000000000c                (     g  fd}|_         |S )Nc                .    j                  | |f       S )N)append)methodpathcapturedpayloads     N/home/jay/workspace/tests/regression/test_gemini_evidence_freshness_checker.py_apiz_mock_api.<locals>._api!   s    '    )r   )r   r   r   s   ` @r   	_mock_apir      s    H DMKr   c                    dt         it        dg} t        dt        t        |       dd      }|j                  }|t
        k(  }|st        j                  d|fd|t
        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
t        j                         v st        j                  t
              rt        j                  t
              nd
dz  }dd|iz  }t        t        j                  |            d x}}|j                  }|t        k(  }|st        j                  d|fd|t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            d x}}|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 )Nloginuser	commit_id   or	pr_numbercurrent_head_sha
github_apiownerrepo==z.%(py2)s
{%(py2)s = %(py0)s.status
} == %(py4)sresultr   py0py2py4assert %(py6)spy6zA%(py2)s
{%(py2)s = %(py0)s.gemini_commit_id_observed
} == %(py4)sHEAD_A   z9%(py2)s
{%(py2)s = %(py0)s.reviews_inspected
} == %(py5)sr,   r-   py5assert %(py7)spy7)r   r2   r	   r   statusr   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationgemini_commit_id_observedreviews_inspected	r   r*   @py_assert1@py_assert3@py_format5@py_format7@py_assert4@py_format6@py_format8s	            r   1test_fresh_when_gemini_latest_commit_matches_headrL   ,   s   +,6BG )W%F ==(=L((((=L((((((6(((6(((=((((((L(((L(((((((++5+v5555+v55555565556555+555555v555v5555555##(q(#q((((#q((((((6(((6(((#(((q(((((((r   c                 b   dt         it        dg} t        dt        t	        |       dd      }|j
                  }|t        k(  }|st        j                  d|fd|t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                  |            d x}}|j                  }|t        k(  }|st        j                  d|fd|t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            d x}}y )Nr   r   r   r   r    r!   r'   r)   r*   r   r+   r/   r0   r1   HEAD_B)r   rN   r	   r2   r   r9   r   r:   r;   r<   r=   r>   r?   r@   rA   rB   r   r*   rE   rF   rG   rH   s         r   ,test_stale_when_gemini_latest_commit_differsrP   <   s6   +,6BG )W%F ==(=L((((=L((((((6(((6(((=((((((L(((L(((((((++5+v5555+v55555565556555+555555v555v5555555r   c                    ddit         dddit         dg} t        dt         t        |       dd      }|j                  }|t        k(  }|st        j                  d	|fd
|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            d x}}|j                  }d }||u }|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}}|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 )Nr   zhuman-reviewerr   Jeon-Jonghyukr   r   r    r!   r'   r)   r*   r   r+   r/   r0   iszA%(py2)s
{%(py2)s = %(py0)s.gemini_commit_id_observed
} is %(py5)sr5   r7   r8      r4   )r2   r	   r   r9   r   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   s	            r   0test_no_review_when_no_gemini_bot_review_presentrW   K   s   +,6B?+&AG )W%F ==,=,,,,,=,,,,,,,6,,,6,,,=,,,,,,,,,,,,,,,,,,++3t3+t3333+t33333363336333+333t3333333##(q(#q((((#q((((((6(((6(((#(((q(((((((r   c                    t        dt        t        g       dd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndd	z  }d
d|iz  }t        t        j                  |            d x}}| j                  }d }||u }|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 )Nr   r   r    r!   r'   r)   r*   r   r+   r/   r0   rS   rU   r5   r7   r8   )r	   r2   r   r9   r   r:   r;   r<   r=   r>   r?   r@   rA   rB   )r*   rE   rF   rG   rH   rI   rJ   rK   s           r   &test_no_review_when_payload_empty_listrY   \   s   (R=F ==,=,,,,,=,,,,,,,6,,,6,,,=,,,,,,,,,,,,,,,,,,++3t3+t3333+t33333363336333+333t3333333r   c                 @   t        dt        t        d       dd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndd	z  }d
d|iz  }t        t        j                  |            d x}}y )Nr   r   r    r!   r'   r)   r*   r   r+   r/   r0   )r	   r2   r   r9   r   r:   r;   r<   r=   r>   r?   r@   rA   )r*   rE   rF   rG   rH   s        r   +test_no_review_when_github_api_returns_noner[   h   s    (T?F ==,=,,,,,=,,,,,,,6,,,6,,,=,,,,,,,,,,,,,,,,,,r   c                 ~   dt         it        ddt         it        dg} t        dt        t	        |       dd      }|j
                  }|t        k(  }|st        j                  d|fd|t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                  |            dx}}|j                  }|t        k(  }|st        j                  d|fd|t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            dx}}y)u1   list end = 최신 (GitHub API order). spec §3.1.r   r   r   r   r    r!   r'   r)   r*   r   r+   r/   r0   Nr1   r2   )r   rN   r2   r	   r   r9   r   r:   r;   r<   r=   r>   r?   r@   rA   rB   rO   s         r   4test_latest_gemini_review_wins_when_multiple_presentr]   s   sF    +,6B+,6BG )W%F ==(=L((((=L((((((6(((6(((=((((((L(((L(((((((++5+v5555+v55555565556555+555555v555v5555555r   c                    t         j                         } dt        it         dg}t        d| t	        |      dd      }|j
                  }|t         k(  }|st        j                  d|fd|t         f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
t        j                         v st        j                  t               rt        j                  t               nd
dz  }dd|iz  }t        t        j                  |            d x}}|j                  }|t        k(  }|st        j                  d|fd|t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            d x}}y )Nr   r   r   r   r    r!   r'   )z8%(py2)s
{%(py2)s = %(py0)s.current_head_sha
} == %(py4)sr*   HEAD_Cr+   r/   r0   r)   r   )r_   upperr   r	   r   r#   r:   r;   r<   r=   r>   r?   r@   rA   r9   r   )
upper_headr   r*   rE   rF   rG   rH   s          r   !test_head_sha_normalised_to_lowerrb      s=   J "23&IJG(#W%F "","f,,,,"f,,,,,,6,,,6,,,",,,,,,f,,,f,,,,,,,==(=L((((=L((((((6(((6(((=((((((L(((L(((((((r   c                     t        j                  t              5  t        ddt	        g       dd       d d d        y # 1 sw Y   y xY w)Nr   z	not-a-shar   r    r!   )pytestraisesr   r	   r    r   r   test_invalid_head_sha_raisesrg      s?    	,	- 
#( }	

 
 
s	   =Ac                     t        j                  t              5  t        dt        t        g       dd       d d d        y # 1 sw Y   y xY w)Nr   r   r    r!   rd   re   r   r	   r2   r   rf   r   r   test_invalid_pr_number_raisesrj      s?    	,	- 
## }	

 
 
   AA
c                     t        j                  t              5  t        dt        t        g       dd       d d d        y # 1 sw Y   y xY w)NTr   r    r!   ri   rf   r   r   test_bool_pr_number_rejectedrm      s?    	,	- 
## }	

 
 
rk   c                 l   dt         idddt         iddg} t        dt        t        |       dd      }|j                  }|t
        k(  }|st        j                  d	|fd
|t
        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              nddz  }dd|iz  }t        t        j                  |            dx}}y)u;   commit_id 가 hex 40-char 가 아니면 skip → NO_REVIEW.r   shortr   (ggggggggggggggggggggggggggggggggggggggggr   r   r    r!   r'   r)   r*   r   r+   r/   r0   N)r   r	   r2   r   r9   r   r:   r;   r<   r=   r>   r?   r@   rA   rO   s         r   2test_invalid_commit_id_format_treated_as_no_reviewrq      s     +,7C+,8DG )W%F ==,=,,,,,=,,,,,,,6,,,6,,,=,,,,,,,,,,,,,,,,,,r   c                     d } t        j                  t              5  t        dt        | dd       d d d        y # 1 sw Y   y xY w)Nc                    t        d      )Nznetwork down)RuntimeError)r   r   s     r   _broken_apizGtest_github_api_exception_wrapped_in_checker_error.<locals>._broken_api   s    >**r   r   r   r    r!   )rd   re   r   r	   r2   )ru   s    r   2test_github_api_exception_wrapped_in_checker_errorrv      sB    + 
,	- 
##"	

 
 
s	   ;Ac                    t        g       } t        dt        | dd       | j                  }dg}||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 )Ni  ownerXrepoYr!   )GETz%/repos/ownerX/repoY/pulls/999/reviewsr'   )z0%(py2)s
{%(py2)s = %(py0)s.captured
} == %(py5)sapir5   r7   r8   )r   r	   r2   r   r:   r;   r<   r=   r>   r?   r@   rA   )r{   rE   rI   rF   rJ   rK   s         r   )test_path_template_uses_owner_repo_and_prr|      s    
B-C <<MLMM<MMMMM<MMMMMMM3MMM3MMM<MMMMMMMMMMMr   c                 2   ddddid} t        |       }d}||u }|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}}y )Nissue_comment/gemini reviewr   rR   kindbodyr   TrS   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} is %(py6)sr
   commentr,   py1py3r0   assert %(py8)spy8	r
   r:   r;   r<   r=   r>   r?   r@   rA   r   @py_assert2@py_assert5rI   rH   @py_format9s         r   @test_is_gemini_trigger_comment_true_for_issue_comment_exact_bodyr      s     /*G
 %W-55-5555-555555$555$555555W555W555-5555555555r   c                 2   ddddid} t        |       }d}||u }|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}}y )Nr~   z  /gemini review  
r   rR   r   TrS   r   r
   r   r   r   r   r   r   s         r   ;test_is_gemini_trigger_comment_true_with_whitespace_paddingr      s    &/*G
 %W-55-5555-555555$555$555555W555W555-5555555555r   c                 6   ddddddid} t        |       }d}||u }|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}}y)uN   task-2640 사고 박제: 회장 review id=4350214991 state=COMMENTED, body="".l   O review	COMMENTED r   rR   )idr   stater   r   FrS   r   r
   r   r   r   r   Nr   r   s         r   =test_is_gemini_trigger_comment_false_for_pr_review_empty_bodyr      s     /*G %W-66-6666-666666$666$666666W666W666-6666666666r   c                 2   ddddid} t        |       }d}||u }|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}}y )Nreview_commentr   r   rR   r   FrS   r   r
   r   r   r   r   r   r   s         r   <test_is_gemini_trigger_comment_false_for_review_comment_kindr      s      /*G
 %W-66-6666-666666$666$666666W666W666-6666666666r   c                 2   ddddid} t        |       }d}||u }|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}}y )Nr~   z/gemini review pleaser   rR   r   FrS   r   r
   r   r   r   r   r   r   s         r   8test_is_gemini_trigger_comment_false_for_other_body_textr     s    '/*G
 %W-66-6666-666666$666$666666W666W666-6666666666r   c                 h   d } t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x} x}x}}d} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x} x}x}}d	} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x} x}x}}y )
NFrS   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is %(py7)sr
   )r,   r-   r.   r8   zassert %(py9)spy9z
not-a-dict*   r   )rE   rF   @py_assert6r   rK   @py_format10s         r   7test_is_gemini_trigger_comment_false_for_non_dict_inputr     s   %)3$T*3e3*e3333*e333333$333$333T333*333e3333333%1;$\2;e;2e;;;;2e;;;;;;$;;;$;;;\;;;2;;;e;;;;;;;%'1$R(1E1(E1111(E111111$111$111R111(111E1111111r   ))__doc__
__future__r   builtinsr<   _pytest.assertion.rewrite	assertionrewriter:   rd   (anu_v2.gemini_evidence_freshness_checkerr   r   r   r   r   r	   r
   r2   rN   r_   r   rL   rP   rW   rY   r[   r]   rb   rg   rj   rm   rq   rv   r|   r   r   r   r   r   r   rf   r   r   <module>r      s    #      
		) 6)"	4-6")


- 
	N66	7772r   