
     ja                    h   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
Z
ddlmZ ddlmZmZmZ ddlZ ee      j'                         j(                  d   Z ee      e
j.                  vr"e
j.                  j1                  d ee             ddlmZmZmZ ddlmZmZm Z m!Z!m"Z" d!d"d	Z# G d
 d      Z$ G d de$      Z% G d d      Z&dddddd	 	 	 	 	 	 	 	 	 	 	 d#dZ'dZ(d$dZ)d$dZ*d$dZ+d%dZ,d&dZ-d'dZ.d$dZ/	 	 	 	 	 	 d&dZ0	 	 	 	 d'dZ1	 	 	 	 	 	 d&dZ2	 	 	 	 	 	 d&dZ3	 	 	 	 	 	 d&dZ4	 	 	 	 d'd Z5y)(u%  anu_v2.tests.test_replacement_pr_runner_2537 — 회귀 7건 (회장 §명시 1:1).

회귀 케이스 (회장 §명시):
  1. clean PR contamination 0       — expected_files == diff → contaminated=False
  2. extra files contamination       — expected_files 외 파일 존재 → contaminated=True
  3. missing files contamination     — expected_files 일부 부재 → contaminated=True
  4. original PR 보존                — preserve 후 close/abort gh 호출 0 + OPEN 유지
  5. clean replacement 생성          — clean branch + 새 PR + queue ready
  6. replacement 실패 → Critical 7종 — 단계별 classify_failure 매핑 정확
  7. executor 인터페이스 contract    — replacement_pr_required 키 제공

본 회귀는 anu_v2/* 모듈만 import 한다 (one-way isolation).
    )annotationsN)Path)AnyMappingSequence   )CRITICAL_CODES CRITICAL_DIFF_REPLACEMENT_FAILEDCRITICAL_REPLACEMENT_FAILED)ContaminationReportPreservationRecordReplacementFailureReplacementPRRunnerReplacementResultc                4    t        j                  g | ||      S )N)args
returncodestdoutstderr)
subprocessCompletedProcess)r   r   r   s      C/home/jay/workspace/anu_v2/tests/test_replacement_pr_runner_2537.py_cpr   ,   s    &&B:f]cdd    c                  .    e Zd ZdZdddZ	 	 	 	 	 	 ddZy)_GitRecorderu\   git_runner mock — 각 호출의 인자/env 를 기록하고 시나리오별 응답 반환.Nc                F    g | _         |rt        |      | _        y g | _        y N)callslist
_scenarios)self	scenarioss     r   __init__z_GitRecorder.__init__3   s    CE
-6$y/Br   c                    | j                   j                  t        |      t        |xs i       f       | j                  r| j                  j                  d      S t               S )Nr   )r   appendtupledictr!   popr   )r"   r   envs      r   __call__z_GitRecorder.__call__7   sJ    
 	

5;SYB89????&&q))ur   r   )r#   z(list[subprocess.CompletedProcess] | NonereturnNone)r   zSequence[str]r*   zMapping[str, str] | Noner,   subprocess.CompletedProcess)__name__
__module____qualname____doc__r$   r+    r   r   r   r   0   s+    f? & 
%	r   r   c                      e Zd ZdZy)_GhRecorderuE   gh_runner mock — git 과 동일 패턴, 별도 클래스로 명시.N)r/   r0   r1   r2   r3   r   r   r5   r5   B   s    Or   r5   c                      e Zd ZddZddZy)_AuditRecorderc                    g | _         y r   )records)r"   s    r   r$   z_AuditRecorder.__init__G   s	    -/r   c                L    | j                   j                  t        |             y r   )r9   r&   r(   )r"   records     r   r+   z_AuditRecorder.__call__J   s    DL)r   Nr,   r-   )r;   zMapping[str, Any]r,   r-   )r/   r0   r1   r$   r+   r3   r   r   r7   r7   F   s    0*r   r7   BOT_GITHUB_TOKEN)
git_runner	gh_runneraudit_writer
audit_rootbot_token_envc                    | xs
 t               }|xs
 t               }|xs
 t               }|xs t        d      }t	        |||||      }	|	|||fS )Nz/tmp/anu_v2_audit_test)r?   r>   r@   rA   rB   )r   r5   r7   r   r   )
r>   r?   r@   rA   rB   gitghauditrootrunners
             r   _make_runnerrI   N   sc     
&C		#kmB,N,E767D #F 3E!!r   )anu_v2/replacement_pr_runner.py/anu_v2/tests/test_replacement_pr_runner_2537.pyc                 j   t               \  } }}}| j                  t        t              t        t                    }t	        |t
              }|sd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dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      dz  }t        t        j                  |            d }|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}}|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original_pr_diffexpected_files5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancereportr   py0py1py2py4Fisz4%(py2)s
{%(py2)s = %(py0)s.contaminated
} is %(py5)srT   rV   py5assert %(py7)spy7r3   ==z3%(py2)s
{%(py2)s = %(py0)s.extra_files
} == %(py5)sz5%(py2)s
{%(py2)s = %(py0)s.missing_files
} == %(py5)s)rI   detect_contaminationr    EXPECTED_FILESrQ   r   @py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanationcontaminated_call_reprcompareextra_filesmissing_files)	rH   _rR   @py_assert3@py_format5@py_assert1@py_assert4@py_format6@py_format8s	            r   0test_detect_contamination_clean_when_files_matchrw   k   s   "nOFAq!((n-N+ ) F f122222222:222:222222f222f222222122212222222222'%'%''''%''''''6'''6''''''%'''''''############6###6#############%2%2%%%%2%%%%%%6%%%6%%%%%%2%%%%%%%r   c                 4   t               \  } }}}| j                  t        t              ddgz   t        t                    }|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}}|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scripts/dispatch.pyutils/some_helper.pyrM   TrX   rZ   rR   r[   r]   r^   )ry   rz   r_   ra   r3   rb   )rI   rc   r    rd   rl   rg   rm   re   rf   rh   ri   rj   rk   rn   ro   rH   rp   rR   rs   rt   rq   ru   rv   s           r   -test_detect_contamination_extra_files_flaggedr|   x   s   "nOFAq!((n-!"1
 

 N+ ) F &$&$&&&&$&&&&&&6&&&6&&&&&&$&&&&&&&P!PP!PPPPP!PPPPPPP6PPP6PPPPPP!PPPPPPPP%2%2%%%%2%%%%%%6%%%6%%%%%%2%%%%%%%r   c                 0   t               \  } }}}| j                  t        d   gt        t                    }|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}}|j                  }t        d   f}||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   rM   TrX   rZ   rR   r[   r]   r^   r3   r_   ra      rb   )rI   rc   rd   r    rl   rg   rm   re   rf   rh   ri   rj   rk   rn   ro   r{   s           r   /test_detect_contamination_missing_files_flaggedr      s   "nOFAq!(((+,N+ ) F &$&$&&&&$&&&&&&6&&&6&&&&&&$&&&&&&&############6###6#############7N1$5#77#77777#777777767776777777#77777777r   c           
     h   t        |       \  }}}}|j                  d      }t        |t              }|sd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dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            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}}	|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}}	|j                  }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}}	|j                  }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}}	|j                  }t!        |      }	d}|	|k(  }|s
t        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                  |	      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}	x}}|j                  d   d   }d}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|j                  d   d    }d!}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|j                  d   d"   }d#}||k(  }|slt        j                  d	|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|j"                  }|j$                  }t'        |       } ||      }|s?d$dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      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                  |      d'z  }t        t        j                  |            d x}x}x}}y )(N)rA   T   )	pr_numberrP   rQ   r;   r   rS   r_   )z3%(py2)s
{%(py2)s = %(py0)s.original_pr
} == %(py5)sr[   r]   r^   OPEN)z7%(py2)s
{%(py2)s = %(py0)s.preserved_state
} == %(py5)s)z-%(py2)s
{%(py2)s = %(py0)s.calls
} == %(py5)srD   rE   r~   )zM%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.records
})
} == %(py8)slenrF   )rT   rU   py3r\   py8assert %(py10)spy10r   prz%(py1)s == %(py4)srU   rW   assert %(py6)spy6decisionORIGINAL_PR_PRESERVEDnoteu%   OPEN 유지 — close/abort 미수행zassert %(py10)s
{%(py10)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.audit_path
}.startswith
}(%(py8)s
{%(py8)s = %(py5)s(%(py6)s)
})
}strtmp_path)rT   rV   rW   r\   r   r   r   )rI   preserve_original_prrQ   r   re   rf   rg   rh   ri   rj   rk   original_prrm   preserved_stater   r9   r   
audit_path
startswithr   )r   rH   rD   rE   rF   r;   rq   rr   rs   rt   ru   rv   @py_assert2@py_assert7@py_assert6@py_format9@py_format11@py_assert0@py_format7@py_assert9s                       r   6test_preserve_original_pr_open_state_no_close_or_abortr      s   )X>FCU((2(6Ff011111111:111:111111f111f111111011101111111111############6###6#############!!+V+!V++++!V++++++6+++6+++!+++V+++++++999?933988r8r>8r228r}}"3}""""""""""""3"""3""""""u"""u"""}"""""""""""""==D!'R'!R''''!R'''!'''R'''''''==J'B+BB'+BBBBB'+BBBB'BBB+BBBBBBBB==F#N'NN#'NNNNN#'NNNN#NNN'NNNNNNNN6''6H6'6666666666666666666'666666666666666H666H6666666666666r   c           	        | j                  dd       t               t               t               t               t               t        d      g}t        d      g}t        |      }t        |      }t	        |||      \  }}}}|j                  dt        t              d	      }	t        |	t              }
|
sd
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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |
      dz  }t        t        j                   |            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}
}|	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}
}|	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}
}|	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,                  |j,                  z   D ]  \  }}|j.                  }d}
 ||
      }d}||k(  }|st        j$                  d|fd||f      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}}|j.                  }d!}
 ||
      }d}||k(  }|st        j$                  d|fd||f      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}} |j,                  |j,                  z   D ]  \  }}d"j1                  |      }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 ]  \  }}|r|d,   nd-}t3        |      d.kD  r|d.   nd-}|d/k(  s*d0}||k(  }|st        j$                  d|fd1||f      d2t        j                         v st        j                  |      rt        j                  |      nd2t        j                  |      d3z  }d(d)|iz  }t        t        j                   |            d x}} |j4                  D cg c]  }|j/                  d4      d5k(  s| }}t3        |      }d.}||k(  }|st        j$                  d|fd6||f      d7t        j                         v st        j                  t2              rt        j                  t2              nd7d8t        j                         v st        j                  |      rt        j                  |      nd8t        j                  |      t        j                  |      d9z  }d:d;|iz  } t        t        j                   |             d x}x}}|d,   d<   }d}
||
k(  }|slt        j$                  d|fd=||
f      t        j                  |      t        j                  |
      d>z  }d?d@|iz  }t        t        j                   |            d x}x}}
|d,   dA   }d}
||
k(  }|slt        j$                  d|fd=||
f      t        j                  |      t        j                  |
      d>z  }d?d@|iz  }t        t        j                   |            d x}x}}
y c c}w )BNr=   bot-test-tokenzabc1234deadbeef
r   z&https://github.com/owner/repo/pull/91
r>   r?   rA   P   task/task-2537-dev4-cleanr   rO   clean_branch_namerP   rQ   resultr   rS   [   r_   )z6%(py2)s
{%(py2)s = %(py0)s.replacement_pr
} == %(py5)sr[   r]   r^   abc1234deadbeef)z1%(py2)s
{%(py2)s = %(py0)s.clean_sha
} == %(py5)s)z4%(py2)s
{%(py2)s = %(py0)s.clean_branch
} == %(py5)sTrX   )z9%(py2)s
{%(py2)s = %(py0)s.merge_queue_ready
} is %(py5)sGH_TOKENzI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)sr*   rT   rV   rW   r   py9assert %(py11)spy11GITHUB_TOKEN z--admin)not in)z%(py1)s not in %(py3)sjoinedrU   r   assert %(py5)sr\   z--forcez--rebaser    r~   r   create)z%(py0)s == %(py3)sactionrT   r   r   REPLACEMENT_PR_CREATEDz0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   success_recordsrT   rU   r   r   assert %(py8)sr   r   r   r   r   r   replacement_pr)setenvr   r   r5   rI   create_clean_replacementr    rd   rQ   r   re   rf   rg   rh   ri   rj   rk   r   rm   	clean_shaclean_branchmerge_queue_readyr   getjoinr   r9   )!monkeypatchr   git_scenariosgh_scenariosrD   rE   rH   rp   rF   r   rq   rr   rs   rt   ru   rv   r*   @py_assert5@py_assert8r   @py_format10@py_format12r   r   r   r   @py_format4headr   rr   r   r   s!                                    r   %test_create_clean_replacement_successr      s   )+;< 	&'M 	<=L }
%C	\	"B&#PXYFAq%,,N+5 - F
 f/00000000:000:000000f000f000000/000/0000000000  &B& B&&&& B&&&&&&6&&&6&&& &&&B&&&&&&&0000000000000006000600000000000000="=="====="=======6===6======"========##+t+#t++++#t++++++6+++6+++#+++t+++++++ ))bhh& ;3ww6z6wz"6&66"&66666"&6666666s666s666w666z666"666&66666666ww:~:w~&:*::&*:::::&*:::::::s:::s:::w:::~:::&:::*:::::::::;
 99rxx' (a$&y&&&&y&&&y&&&&&&&&&&&&&&&&&y&&&&y&&&y&&&&&&&&&&&&&&&&'z''''z'''z''''''''''''''''	( 88 &atAwBIMar4<%%6X%%%%6X%%%%%%6%%%6%%%X%%%%%%%	& #(--aQ1553DH`3`qaOa$1$1$$$$1$$$$$$3$$$3$$$$$$$$$$$$$$$1$$$$$$$1m,22,2222,222,22222222221./525/25555/2555/55525555555 bs   q+qc                   t               \  }}}}|j                  t        dd            \  }}|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            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}}|t        v }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            d }|j                  t        dd            \  }}|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            d }|t        v }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            d }|j                  t        dd            \  }}|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            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}}|t        v }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            d }| j                  dd       t               t               t               t               t        dd      g}t!        |      }t        |      \  }}}}|j#                  d t%        t&              d!"      }t)        |t              }|sd#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%d&t        j                         v st	        j                  t              rt	        j                  t              nd&t	        j                  |      d'z  }t        t	        j                  |            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}}|j                  |      \  }}|t        k(  }|st	        j
                  d|fd|t        f      d,t        j                         v st	        j                  |      rt	        j                  |      nd,dt        j                         v st	        j                  t              rt	        j                  t              nddz  }d	d
|iz  }t        t	        j                  |            d }y )-Npushgit_push_failed)stagereasonr_   )z%(py0)s == %(py2)scoder   )rT   rV   zassert %(py4)srW   TrX   )z%(py0)s is %(py3)sis_criticalr   r   r\   in)z%(py0)s in %(py2)sr	   	pr_creategh_pr_create_failed	bot_tokenbot_token_unavailabler
   r=   r   r~   zremote rejectedr   r   r>   r   r   r   rP   rQ   failurer   rS   z-%(py2)s
{%(py2)s = %(py0)s.stage
} == %(py5)sr[   r]   r^   code2)rI   classify_failurer   r   rg   rm   re   rf   rh   ri   rj   rk   r	   r
   r   r   r   r   r    rd   rQ   r   )r   rH   rp   r   r   rs   @py_format3rr   r   r   ru   r   rD   runner2r   rq   rt   rv   r   s                      r   ,test_classify_failure_maps_to_critical_sevenr      s   "nOFAq!//0ABD+ .....4.......4...4..................;$;$;;$>!!!!4>!!!!!!4!!!4!!!!!!>!!!>!!!!!!! %%5JKGD! .....4.......4...4..................>!!!!4>!!!!!!4!!!4!!!!!!>!!!>!!!!!!! //5LMD+ 333334333333343334333333333333333333;$;$;;$>!!!!4>!!!!!!4!!!4!!!!!!>!!!>!!!!!!! )+;<q!23M }
%C#s3GQ1..N+5 / G
 g122222222:222:222222g222g222222122212222222222=="F"=F""""=F""""""7"""7"""="""F"""""""''0HE1/////5///////5///5//////////////////r   c            	        t        ddd      } t        j                  | dt        t              d      }|j
                  } |       }t        |      }dd	h}||k(  }|st        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                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}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   }	d}
|	|
k(  }|slt        j                  d
|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}	x}}
|d   }	t        t              }|	|k(  }|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                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}	x}}|d   }	d}
|	|
k(  }|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#g}
|	|
k(  }|slt        j                  d
|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}	x}}
t        d$dd      }t        j                  |dt        t              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 )%NT)scripts/leak.pyr3   )rl   rn   ro   r   r   )contaminationr   rO   r   replacement_pr_requiredreplacement_pr_runner_inputr_   )zb%(py7)s
{%(py7)s = %(py0)s(%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.keys
}()
})
} == %(py10)ssetcontract_dirty)rT   rU   r   r\   r^   r   zassert %(py12)spy12rX   )z%(py1)s is %(py4)sr   r   r   r   r   rO   )z0%(py1)s == %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}r    rd   )rU   r   rW   r   r   r   r   r   rl   rn   r   F)r   r   build_executor_contractr    rd   keysr   rg   rm   re   rf   rh   ri   rj   rk   )contamination_dirtyr   r   rt   r   r   r   r   @py_format13r   rq   rr   r   payloadr   r   contamination_cleancontract_cleans                     r    test_executor_contract_dict_keysr     sY   -(
 )@@)N+5	N "" "$ 3$% !%* % *    % *                        #    %    &   *        34<<4<<<<4<<<4<<<<<<<<<<:;G=!'R'!R''''!R'''!'''R'''''''#$<^(<<$(<<<<<$(<<<<$<<<<<<<<<<<<<<<^<<<^<<<(<<<<<<<<&'F+FF'+FFFFF'+FFFF'FFF+FFFFFFFF?#N3;t;3t;;;;3t;;;3;;;t;;;;;;;?#M2I7H6II26IIIII26IIII2III6IIIIIIII .
 )@@)N+5	N 34==4====4===4==========r   c                	   | j                  dd       d}t               t               t               t               t               t        d      g}t        d      g}t        |      }t        |      }t	        |||      \  }}}}|j                  dt        |      d	
      }	t        |	t              }
|
sd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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |
      dz  }t        t        j                  |            d}
d}|j                   D cg c]%  \  }}t#        |      dk\  r|d   dk(  r
|d   |k(  r|' }}}t#        |      }d}||k(  }|st        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  }t        j&                  dt#        |       d      dz   d|iz  }t        t        j                  |            dx}x}}|d   }|d   }d}
||
k(  }|slt        j$                  d|fd ||
f      t        j                  |      t        j                  |
      d!z  }d"d#|iz  }t        t        j                  |            dx}x}}
|d$d }t)        |      }
|
|k(  }|st        j$                  d|fd%|
|f      d&t        j                         v st        j                  t(              rt        j                  t(              nd&t        j                  |      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}x}
}yc c}}w )*u\  expected_files N 개를 단일 git checkout 호출로 stage 한다.

    Gemini 1차 review (review_id=4259255425, 2026-05-10) medium 권고:
      - 기존: expected_files 루프 → git checkout 개별 호출 N회
      - 개선: 단일 호출 1회 (subprocess overhead 절감)
    본 회귀는 batched 동작을 박제하여 회귀 방지.
    r=   r   )rJ   rK   zanu_v2/__init__.pyz	cafef00d
r   z&https://github.com/owner/repo/pull/92
r   r   ztask/task-2537-dev4-clean-3r   rP   rQ   r   r   rS   Nrefs/pull/80/headr   r   checkoutr~   r_   r   r   pr_head_callsr   z!expected 1 batched checkout, got u    (개별 호출 회귀)
>assert %(py8)sr   z--r   r   r   r      )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py6)sr'   expected_three)rT   rV   rW   r   r   )r   r   r   r5   rI   r   r    rQ   r   re   rf   rg   rh   ri   rj   rk   r   r   rm   _format_assertmsgr'   )r   r   r   r   r   rD   rE   rH   rp   r   rq   rr   pr_head_refr   r   r   r   rt   r   r   batched_argsr   rs   s                          r   3test_create_clean_replacement_uses_batched_checkoutr  9  s~    )+;<N 	< M 	<=L }
%C	\	"B"cRHUOFAq!,,N+7 - F
 f/00000000:000:000000f000f000000/000/0000000000 &KIIqt9>d1g3Q;8N 	M  }  "                               "#    ,C,>+??VW    
 !#L?"d"?d""""?d"""?"""d"""""""ab!45!"4"n4444"n44444454445444!444"444444n444n4444444s   *Sc                	   | j                  dd       t               t               t        dd      g}t        |      }t        |      \  }}}}|j	                  dt        t              d	      }t        |t              }|sd
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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            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}}	|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}}	|j&                  }|j(                  }d} ||      }t        t              }||k(  }|s{t        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}}y)uK   일괄 checkout 실패 시 ReplacementFailure.extra 에 paths(list) 박제.r=   r   r~   zpathspec did not match any filer   r   r   r   r   rP   rQ   r   r   rS   Nr   r_   r   r[   r]   r^   git_checkout_path_failedz.%(py2)s
{%(py2)s = %(py0)s.reason
} == %(py5)spaths)z%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.extra
}.get
}(%(py6)s)
} == %(py13)s
{%(py13)s = %(py10)s(%(py11)s)
}r    rd   )rT   rV   rW   r   r   r   r   py13zassert %(py15)spy15r   r   r   rI   r   r    rd   rQ   r   re   rf   rg   rh   ri   rj   rk   r   rm   r   extrar   )r   r   rD   rH   rp   r   rq   rr   rs   rt   ru   rv   r   r   @py_assert12r   @py_format14@py_format16s                     r   Htest_create_clean_replacement_batched_checkout_failure_reports_all_pathsr  s  s    )+;<q!BCM
 }
%C"c2OFAq!--N+5 . G
 g122222222:222:222222g222g222222122212222222222==&J&=J&&&&=J&&&&&&7&&&7&&&=&&&J&&&&&&&>>777>77777>777777777777777>77777777777=====W=W%=n)==%)=====%)=======7===7==========W===%===============n===n===)=========r   c           	        | j                  dd       t               t               t               t               t               t        d      g}t        d      g}t        |      }t        |      }t	        |||      \  }}}}|j                  dt        t              d	      }t        |t              }	|	sd
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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |	      dz  }
t        t        j                   |
            d}	|j"                  |j"                  z   D ]  \  }}|j$                  }d}	 ||	      }d}||k(  }|st        j&                  d|fd||f      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}}|j$                  }d}	 ||	      }d}||k(  }|st        j&                  d|fd||f      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}}|j$                  }d}	 ||	      }d}||k(  }|st        j&                  d|fd||f      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}}|j$                  }d}	 ||	      }d}||k(  }|st        j&                  d|fd||f      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}} |j"                  |j"                  z   D ]P  \  }}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}}S y)#u   env 에 GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL/GIT_COMMITTER_NAME/GIT_COMMITTER_EMAIL
    4개 키가 모두 주입되었는지 확인. default identity 검증.
    r=   r   z	deadbeef
r   z&https://github.com/owner/repo/pull/99
r   r   r   r   rP   rQ   r   r   rS   NGIT_AUTHOR_NAMEzjeon-jonghyuk-taskctl-botr_   r   r*   r   r   r   GIT_AUTHOR_EMAILz2jeon-jonghyuk-taskctl-bot@users.noreply.github.comGIT_COMMITTER_NAMEGIT_COMMITTER_EMAILr   r   )z%(py1)s in %(py3)sr   r   r\   r   )r   r   r   r5   rI   r   r    rd   rQ   r   re   rf   rg   rh   ri   rj   rk   r   r   rm   )r   r   r   r   rD   rE   rH   rp   r   rq   rr   r*   rs   r   r   r   r   r   r   r   r   ru   s                         r   6test_create_clean_replacement_injects_bot_git_identityr    s    )+;< 	< M 	<=L }
%C	\	"B"cRHUOFAq!,,N+5 - F
 f/00000000:000:000000f000f000000/000/0000000000 ))bhh& f3wwH(Hw()H-HH)-HHHHH)-HHHHHHHsHHHsHHHwHHH(HHH)HHH-HHHHHHHHwwb)bw)*b.bb*.bbbbb*.bbbbbbbsbbbsbbbwbbb)bbb*bbb.bbbbbbbbwwK+Kw+,K0KK,0KKKKK,0KKKKKKKsKKKsKKKwKKK+KKK,KKK0KKKKKKKKwwe,ew,-e1ee-1eeeee-1eeeeeeeseeeseeeweee,eee-eee1eeeeeeeee	f ))bhh& %3 zS    zS   z      S   S       $~$$$$~$$$~$$$$$$$$$$$$$$$$%r   c           	     *   | j                  dd       t               t               t               t               t               t        d      g}t        d      g}t        |      }t        |      }d}d}|}t	        ||t               |d||      }	|	j                  d	t        t              d
      }
t        |
t              }|sd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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t!        t        j"                  |            d}|j$                  |j$                  z   D ]  \  }}|j&                  }d} ||      }||k(  }|st        j(                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      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}x}x}}|j&                  }d} ||      }||k(  }|st        j(                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      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}x}x}}|j&                  }d} ||      }||k(  }|st        j(                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      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}x}x}}|j&                  }d} ||      }||k(  }|st        j(                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      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}x}x}} y)un   생성자 인자로 커스텀 bot_git_name/bot_git_email 주입 시 env 에 그 값이 반영되는지 확인.r=   r   z	cafebabe
r   z'https://github.com/owner/repo/pull/100
zcustom-bot-namezcustom-bot@example.com)r?   r>   r@   rA   rB   bot_git_namebot_git_emailr   r   r   rP   rQ   r   r   rS   Nr  r_   )zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py8)sr*   custom_name)rT   rV   rW   r   r   r   r   r  custom_emailr  r  )r   r   r   r5   r   r7   r   r    rd   rQ   r   re   rf   rg   rh   ri   rj   rk   r   r   rm   )r   r   r   r   rD   rE   r  r  rG   rH   r   rq   rr   rp   r*   rs   r   r   r   r   s                       r   1test_create_clean_replacement_custom_bot_identityr    s
   
 )+;< 	< M 	=>L }
%C	\	"B#K+LD #%( "F ,,N+5 - F
 f/00000000:000:000000f000f000000/000/0000000000))bhh& >3ww8(8w()8)[8888)[888888s888s888w888(888)888888[888[8888888ww:):w)*:*l::::*l::::::s:::s:::w:::):::*::::::l:::l:::::::ww;+;w+,;,;;;;,;;;;;;s;;;s;;;w;;;+;;;,;;;;;;;;;;;;;;;;ww=,=w,-=-====-======s===s===w===,===-=================	>r   c                
   | j                  dd       t               t               t               t               t               t        d      g}t        d      g}t        |      }t        |      }t	        |||      \  }}}}|j                  dt        t              d	      }t        |t              }	|	sd
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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |	      dz  }
t        t        j                   |
            d}	d}t#        |j$                        D cg c]0  \  }\  }}t'        |      dk\  r|d   dk(  r|d   dk(  r
|d   |k(  r|2 }}}}t'        |      }d}||k(  }|st        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  }t        j*                  d|       dz   d|iz  }t        t        j                   |            dx}x}}d}t#        |j$                        D cg c](  \  }\  }}t'        |      dk\  r|d   d k(  r
|d   |k(  r|* }}}}t'        |      }d}||k(  }|st        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  }t        j*                  d"|       dz   d|iz  }t        t        j                   |            dx}x}}|d   }|d   }	||	k  }|st        j(                  d#|fd$||	f      t        j                  |      t        j                  |	      d%z  }
t        j*                  d&|d    d'|d    d(      d)z   d*|
iz  }t        t        j                   |            dx}x}}	yc c}}}w c c}}}w )+ug   git_calls 시퀀스에서 fetch 호출이 checkout(PR head) 호출보다 먼저 실행되는지 확인.r=   r   z	aabbccdd
r   z'https://github.com/owner/repo/pull/101
r   r   r   r   rP   rQ   r   r   rS   Nz#refs/pull/80/head:refs/pull/80/headr   r   fetchr~   originr   r_   r   r   fetch_indicesr   u.   fetch 호출이 정확히 1회여야 함, got r   r   r   r   checkout_indicesu9   checkout PR head 호출이 정확히 1회여야 함, got )<)z%(py1)s < %(py4)sr   z
fetch(idx=u   ) 이 checkout(idx=u#   ) 보다 먼저 실행되어야 함z
>assert %(py6)sr   )r   r   r   r5   rI   r   r    rd   rQ   r   re   rf   rg   rh   ri   rj   rk   	enumerater   r   rm   r  )r   r   r   r   rD   rE   rH   rp   r   rq   rr   	fetch_refir   r   r   r   rt   r   r   r  r!  r   s                          r   ?test_create_clean_replacement_fetches_pull_head_before_checkoutr&    s   
 )+;< 	< M 	=>L }
%C	\	"B"cRHUOFAq!,,N+5 - F
 f/00000000:000:000000f000f000000/000/0000000000 6I'		2 a$t9>d1g0T!W5HTRSWXaMa 	
M  }dd"ddddddddd3ddd3dddddd}ddd}ddddddddd&TUbTc$dddddddd &K'		2 a$t9>d1g3Q;8N 	
   uAu A%uuu Auuuuuu3uuu3uuuuuuuuuuuu uuuAuuu)bcsbt'uuuuuuuu  .q1 11  1        2    ]1%&&9:J1:M9NNqr     s   5U-U&c           	     p   | j                  dd       t               t        dd      g}t        |      }t        |      \  }}}}|j	                  dt        t              d	      }t        |t              }|sd
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dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            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}}	|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}}	|j&                  }|j(                  }d} ||      }d}||k(  }|st        j"                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}}y)u   fetch 단계 returncode != 0 시 ReplacementFailure(stage="fetch",
    reason="git_fetch_pull_head_failed", extra.ref 명시) 반환 박제.
    r=   r   r~   zfatal: couldn't find remote refr   r   r   r   r   rP   rQ   r   r   rS   Nr  r_   r   r[   r]   r^   git_fetch_pull_head_failedr  refr   )ze%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.extra
}.get
}(%(py6)s)
} == %(py11)s)rT   rV   rW   r   r   r   zassert %(py13)sr	  r  )r   r   rD   rH   rp   r   rq   rr   rs   rt   ru   rv   r   r   @py_assert10r   r   r  s                     r   ?test_create_clean_replacement_fetch_failure_reports_stage_fetchr+     s    )+;<q!BCM }
%C"c2OFAq!--N+5 . G
 g122222222:222:222222g222g222222122212222222222==#G#=G####=G######7###7###=###G#######>>999>99999>999999979997999>99999999999==:=:U:U#:'::#':::::#':::::::7:::7:::=::::::U:::#:::':::::::::r   )r   r   r   )r   intr   r   r   r   r,   r.   )r>   z_GitRecorder | Noner?   z_GhRecorder | Noner@   z_AuditRecorder | NonerA   zPath | NonerB   r   r,   zEtuple[ReplacementPRRunner, _GitRecorder, _GhRecorder, _AuditRecorder]r<   )r   r   r,   r-   )r   pytest.MonkeyPatchr   r   r,   r-   )r   r-  r,   r-   )6r2   
__future__r   builtinsre   _pytest.assertion.rewrite	assertionrewriterg   r   syspathlibr   typingr   r   r   pytest__file__resolveparentsWORKSPACE_ROOTr   pathinsertanu_v2.merge_queue_executorr	   r
   r   anu_v2.replacement_pr_runnerr   r   r   r   r   r   r   r5   r7   rI   rd   rw   r|   r   r   r   r   r   r  r  r  r  r&  r+  r3   r   r   <module>r?     s   #     
  ) )  h'')11!4~chh&HHOOAs>*+ 
 e $P, P* * '+$(*."+"#" "" (	"
 " " K",	&& 87&46p,0`&>T65#6565 
65t>#>	>4*%#*%*% 
*%\->#->-> 
->b0#00 
0h;#;	;r   