
    Ajs                       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ZddlmZmZ ddlmZ  ee      j#                         j$                  d   Z ee      ej*                  vr"ej*                  j-                  d ee             ddlmZmZmZ dZd	Zd
ZdZd!dZ	 	 	 d"	 	 	 	 	 	 	 d#dZ eeeef	 	 	 	 	 	 	 	 	 d$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Z)d&dZ*d&dZ+d&dZ,d&dZ-d&dZ.d&dZ/d&dZ0d&dZ1d&dZ2d&d Z3y)'u[  회귀 테스트 17건 — anu_v2.worktree_cleanup (task-2550).

pytest 사용. 외부 부수효과(subprocess / file write / clock)는
모두 fake callable로 주입.

⚠️ 테스트 코드 내 "ghp_faketoken123abc" 등 raw token placeholder는
   실제 토큰이 아닌 테스트 fake 값임 — leak detector 오탐 방지를 위해 명시.
    )annotationsN)datetimetimezone)Path   )DEFAULT_CHAT_IDWorktreeCandidateWorktreeCleanup(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa	task-2550ztask/task-2550-dev5-/home/jay/workspace/.worktrees/task-2550-dev5c            	     B    t        ddddddt        j                        S )u4   고정 시각 반환 — 테스트 결정론 보장.i           r   )tzinfo)r   r   utc     X/home/jay/workspace/.worktrees/task-2550-dev5/anu_v2/tests/test_worktree_cleanup_2550.py_fake_clockr   $   s    D!RQ(,,??r   c                4    t        j                  g | ||      S )N)args
returncodestdoutstderr)
subprocessCompletedProcess)r   r   r   s      r   _make_completed_processr   )   s#    
 &&	 r   c                     t        | |||      S )Npathbranchtask_idhead_sha)r	   r!   s       r   _make_candidater&   6   s     $vwQYZZr   c                     ~ ~t        d      S )ue   기본 fake subprocess runner — rc=0, no output. unused parameter는 명시적으로 del로 처리.r   r   )_args_kwargss     r   _noop_runnerr+   ?   s    w"1%%r   c                   | dz  dz  }|j                  dd       |t         dz  j                          t        t        t
        |       }|j                  t              }|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$                  }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*   .done.acked 마커 존재 → passed=True.memoryeventsTparentsexist_ok.done.ackedsubprocess_runnerclockworkspace_root   ==z1%(py2)s
{%(py2)s = %(py0)s.condition
} == %(py5)sresultpy0py2py5assert %(py7)spy7N
done_ackedz,%(py2)s
{%(py2)s = %(py0)s.name
} == %(py5)sisz.%(py2)s
{%(py2)s = %(py0)s.passed
} is %(py5)sokz.%(py2)s
{%(py2)s = %(py0)s.detail
} == %(py5)s)mkdirFAKE_TASK_IDtouchr
   r+   r   check_safety_1_done_acked	condition
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationnamepasseddetail	tmp_path
events_dircleanupr;   @py_assert1@py_assert4@py_assert3@py_format6@py_format8s	            r   test_safety_1_done_acked_passrb   H   s    H$x/JTD1\N+..557&G
 ..|<F q q    q      6   6      q       ;;&,&;,&&&&;,&&&&&&6&&&6&&&;&&&,&&&&&&&== D =D    =D      6   6   =   D       == D =D    =D      6   6   =   D       r   c                   t        t        t        |       }|j                  t              }|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}}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   마커 없음 → passed=False.r3   r7   r8   r:   r;   r<   r@   rA   NrB   rC   FrD   rF   missinginz.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.detail
}py1py3r?   )r
   r+   r   rL   rJ   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   )
rZ   r\   r;   r]   r^   r_   r`   ra   @py_assert0@py_assert2s
             r   test_safety_1_done_acked_failrm   _   s   &G
 ..|<F q q    q      6   6      q       ;;&,&;,&&&&;,&&&&&&6&&&6&&&;&&&,&&&&&&&==!E!=E!!!!=E!!!!!!6!!!6!!!=!!!E!!!!!!!%%9%%%%9%%%9%%%%%%%%%%%%%%%%%%%r   c                   t        j                  ddt        dg      fd}t        |t        |       }|j                  t              }|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}}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)u9   gh API mock으로 PR state=MERGED 반환 → passed=True.e   MERGEDnumberstateheadRefNamec                H    d| v rd| v rt        dd      S t        ddd      S Nprlistr    r(   r   _pr_responses     r   fake_runnerz1test_safety_2_pr_merged_pass.<locals>.fake_runnerw   .    4<FdN*1k2>>&q"b11r   r3   r   r8   r:   r;   r<   r@   rA   N	pr_mergedrC   TrD   rF   re   rg   rh   jsondumpsFAKE_BRANCHr
   r   check_safety_2_pr_mergedrJ   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rZ   r}   r\   r;   r]   r^   r_   r`   ra   rk   rl   r|   s              @r   test_safety_2_pr_merged_passr   q   s   **+F K2
 %G
 --l;F q q    q      6   6      q       ;;%+%;+%%%%;+%%%%%%6%%%6%%%;%%%+%%%%%%%== D =D    =D      6   6   =   D       $v}}$8}$$$$8}$$$8$$$$$$v$$$v$$$}$$$$$$$r   c                   t        j                  ddt        dg      fd}t        |t        |       }|j                  t              }|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}}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)u8   gh API mock으로 PR state=OPEN 반환 → passed=False.f   OPENrq   c                H    d| v rd| v rt        dd      S t        ddd      S rv   r(   rz   s     r   r}   z6test_safety_2_pr_merged_fail_open.<locals>.fake_runner   r~   r   r3   r   r8   r:   r;   r<   r@   rA   Nr   rC   FrD   rF   re   rg   rh   r   r   s              @r   !test_safety_2_pr_merged_fail_openr      s   **D K2
 %G
 --l;F q q    q      6   6      q       ;;%+%;+%%%%;+%%%%%%6%%%6%%%;%%%+%%%%%%%==!E!=E!!!!=E!!!!!!6!!!6!!!=!!!E!!!!!!!"V]]"6]""""6]"""6""""""V"""V"""]"""""""r   c                   | dz  dz  }|j                  dd       |t         dz  j                          t        t        t
        |       }|j                  t              }|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$                  }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*   .merge-done 마커 존재 → passed=True.r-   r.   Tr/   .merge-doner3      r8   r:   r;   r<   r@   rA   N
merge_donerC   rD   rF   rG   rH   )rI   rJ   rK   r
   r+   r   check_safety_3_merge_donerM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   s	            r   test_safety_3_merge_done_passr      s   H$x/JTD1\N+..557&G
 ..|<F q q    q      6   6      q       ;;&,&;,&&&&;,&&&&&&6&&&6&&&;&&&,&&&&&&&== D =D    =D      6   6   =   D       == D =D    =D      6   6   =   D       r   c                   d }t        |t        |       }|j                  t              }|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}}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
)u2   git merge-base --is-ancestor rc=0 → passed=True.c                F    d| v rd| v rt        ddd      S t        ddd      S )N
merge-base--is-ancestorr   ry   r(   r   r{   s     r   r}   z6test_safety_4_branch_in_main_pass.<locals>.fake_runner   /    4Ot$;*1b"55&q"b11r   r3      r8   r:   r;   r<   r@   rA   Nbranch_in_mainrC   TrD   rF   ancestorre   rg   rh   )r
   r   check_safety_4_branch_in_mainr   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rZ   r}   r\   r;   r]   r^   r_   r`   ra   rk   rl   s              r   !test_safety_4_branch_in_main_passr      s   2
 %G
 22;?F q q    q      6   6      q       ;;***;*****;*******6***6***;***********== D =D    =D      6   6   =   D       &&:&&&&:&&&:&&&&&&&&&&&&&&&&&&&r   c                   d }t        |t        |       }|j                  t              }|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}}g }d}	|j                  }
|	|
v }|}|s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  }|j!                  |       |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  }|j!                  |       t        j"                  |d      i z  }dd|iz  }t        t        j                  |            d
x}x}x}	x}x}
x}x}}y
)u3   git merge-base --is-ancestor rc=1 → passed=False.c                F    d| v rd| v rt        ddd      S t        ddd      S )Nr   r   r7   ry   r   r(   r   s     r   r}   z6test_safety_4_branch_in_main_fail.<locals>.fake_runner   r   r   r3   r   r8   r:   r;   r<   r@   rA   Nr   rC   FrD   rF   zNOT ancestorzrc=1re   )z.%(py3)s in %(py7)s
{%(py7)s = %(py5)s.detail
})rj   r?   rA   z%(py9)spy9)z2%(py12)s in %(py16)s
{%(py16)s = %(py14)s.detail
})py12py14py16z%(py18)spy18r7   zassert %(py21)spy21)r
   r   r   r   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   append_format_boolop)rZ   r}   r\   r;   r]   r^   r_   r`   ra   rl   @py_assert6rk   @py_assert11@py_assert15@py_assert13@py_format10@py_format17@py_format19@py_format20@py_format22s                       r   !test_safety_4_branch_in_main_failr      sk   2
 %G
 22;?F q q    q      6   6      q       ;;***;*****;*******6***6***;***********==!E!=E!!!!=E!!!!!!6!!!6!!!=!!!E!!!!!!!E>EV]]E>]*EfEEf.EEEEE>]EEE>EEEEEEVEEEVEEE]EEEEEEEfEEEfEEEEEEEEEEEEEEEEEEEEEEEEEEr   c                   d }t        |t        |       }|j                  t              }|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}}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+   pgrep rc=1 (매치 없음) → passed=True.c                >    d| v rt        ddd      S t        ddd      S )Npgrepr7   ry   r   r(   r   s     r   r}   z2test_safety_5_not_in_use_pass.<locals>.fake_runner   s'    d?*1b"55&q"b11r   r3   r   r8   r:   r;   r<   r@   rA   N
not_in_userC   TrD   rF   z
no processre   rg   rh   r
   r   check_safety_5_not_in_useFAKE_WORKTREE_PATHrM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   r   s              r   test_safety_5_not_in_use_passr      s   2
 %G
 ../ABF q q    q      6   6      q       ;;&,&;,&&&&;,&&&&&&6&&&6&&&;&&&,&&&&&&&== D =D    =D      6   6   =   D       (6==(<=((((<=(((<((((((6(((6(((=(((((((r   c                   d }t        |t        |       }|j                  t              }|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}}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,   pgrep rc=0 (매치 있음) → passed=False.c                >    d| v rt        ddd      S t        ddd      S )Nr   r   z12345
ry   r(   r   s     r   r}   z2test_safety_5_not_in_use_fail.<locals>.fake_runner  s'    d?*1i<<&q"b11r   r3   r   r8   r:   r;   r<   r@   rA   Nr   rC   FrD   rF   processre   rg   rh   r   r   s              r   test_safety_5_not_in_use_failr     s   2
 %G
 ../ABF q q    q      6   6      q       ;;&,&;,&&&&;,&&&&&&6&&&6&&&;&&&,&&&&&&&==!E!=E!!!!=E!!!!!!6!!!6!!!=!!!E!!!!!!!%%9%%%%9%%%9%%%%%%%%%%%%%%%%%%%r   c                ^   t        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}||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      }|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}}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
)u9   apply=True → passed=True; apply=False → passed=False.r3   T   r8   r:   result_truer<   r@   rA   Napply_explicitrC   rD   rF   Fresult_falsezdry-runre   rg   rh   )r
   r+   r   check_safety_6_apply_explicitrM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   )rZ   r\   r   r]   r^   r_   r`   ra   r   rk   rl   s              r   test_safety_6_apply_explicitr     s]   &G 77=K  %A% A%%%% A%%%%%%;%%%;%%% %%%A%%%%%%%///////////////;///;//////////////%%%%%%%%%%%%;%%%;%%%%%%%%%%%%%88?L!!&Q&!Q&&&&!Q&&&&&&<&&&<&&&!&&&Q&&&&&&&0 00 00000 0000000<000<000000 00000000'%'%''''%''''''<'''<''''''%'''''''++++9+++++9++++9++++++++++++++++++++r   c                   d }t        |t        |       }t        t        | dz              }|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}||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}||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}||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}}d}
|j                   }|j"                  } |       }|
|v }|st        j                  d|fd|
|f      t        j                  |
      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}x}}| dz  dz  }t%        |j'                  d            }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}}t-        j.                  |d%   j1                  d&'            }|d(   }
|
t2        k(  }|st        j                  d)|fd*|
t2        f      t        j                  |
      d+t        j                         v st        j                  t2              rt        j                  t2              nd+d,z  }t        j*                  d-t2         d.      d/z   d0|iz  }t        t        j                  |            dx}
}|d1   }
|
t4        k(  }|st        j                  d)|fd*|
t4        f      t        j                  |
      d2t        j                         v st        j                  t4              rt        j                  t4              nd2d,z  }d3d0|iz  }t        t        j                  |            dx}
}y)4ut   dirty=True인 worktree → CleanupResult.skipped=True, skip_reason 포함 "dirty", applied=False, log 파일 생성.c                F    d| v rd| v rt        ddd      S t        ddd      S )Nstatus--porcelainr   zM  modified_file.py
ry   r(   r   s     r   r}   z0test_dirty_worktree_skipped.<locals>.fake_runner7  s0    t 5*1.ErJJ&q"b11r   r3   some-worktreer"   FapplyTrD   )z-%(py2)s
{%(py2)s = %(py0)s.dirty
} is %(py5)sr;   r<   r@   rA   Nz/%(py2)s
{%(py2)s = %(py0)s.skipped
} is %(py5)sz/%(py2)s
{%(py2)s = %(py0)s.applied
} is %(py5)sis notz7%(py2)s
{%(py2)s = %(py0)s.skip_reason
} is not %(py5)sdirtyre   ze%(py1)s in %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.skip_reason
}.lower
}()
}ri   rj   r?   rA   r   assert %(py11)spy11r-   r.   worktree-cleanup-skipped-*.jsonr7   >=z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)slen	log_filesr=   ri   rj   py6u0   dirty skip 시 log 파일이 생성되어야 함
>assert %(py8)spy8r   utf-8encodingchat_idr8   z%(py1)s == %(py3)sr   ri   rj   u   chat_id가 u   이어야 함
>assert %(py5)sr?   r$   rJ   assert %(py5)s)r
   r   r&   strcleanup_worktreer   rN   rO   rP   rQ   rR   rS   rT   rU   skippedappliedskip_reasonlowerrx   globr   _format_assertmsgr   loads	read_textr   rJ   )rZ   r}   r\   	candidater;   r]   r^   r_   r`   ra   rk   r   @py_assert8rl   r   @py_format12r[   r   @py_assert5@py_format7@py_format9log_data@py_format4s                          r   test_dirty_worktree_skippedr   4  sV   2 %G
  SO)C%DEI%%iu%=F<<4<4<466<4>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!>>"U">U"""">U""""""6"""6""">"""U""""""")T)T))))T))))))6)))6))))))T)))))))0f((0(..0.00700000700007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 H$x/JZ__%FGHIy>RQR>QRRR>QRRRRRR3RRR3RRRRRRyRRRyRRR>RRRQRRR RRRRRRRR zz)A,00'0BCHI_/1___/_________/___/____[@QQ^3_______I.,....,.........,...,.......r   c                   t        t        t        |       }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}||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}||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}||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}}d}	|j"                  }|j$                  }
 |
       }|	|v }|st        j                  d|fd|	|f      t        j                  |	      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}x}
}| dz  dz  }t'        |j)                  d            }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}}t/        j0                  |d#   j3                  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-   }	|	t4        k(  }|st        j                  d(|fd.|	t4        f      t        j                  |	      d/t        j                         v st        j                  t4              rt        j                  t4              nd/d0z  }d1d2|iz  }t        t        j                  |            dx}	}y)3u   workspace_root와 동일 path → is_main=True, applied=False, skip_reason에 'main worktree' 포함.

    추가: main 차단 이벤트가 회장 가시성 확보를 위해 log 파일에 박제됨을 검증.
    r3   r   Tr   rD   )z/%(py2)s
{%(py2)s = %(py0)s.is_main
} is %(py5)sr;   r<   r@   rA   NFr   r   r   r   zmain worktreere   r   r   r   r   r-   r.   r   r7   r   r   r   r   r   uD   main 차단 시 log 파일이 박제되어야 함 (회장 가시성)r   r   r   r   r   reasonmain_worktree_protectedr8   z%(py1)s == %(py4)sri   py4assert %(py6)sr   r   r   r   r   r   r?   )r
   r+   r   r&   r   r   is_mainrN   rO   rP   rQ   rR   rS   rT   rU   r   r   r   r   rx   r   r   r   r   r   r   r   )rZ   r\   r   r;   r]   r^   r_   r`   ra   rk   r   r   rl   r   r   r[   r   r   r   r   r   @py_format5r   s                          r    test_main_worktree_never_deletedr  [  s(   
 &G  S]3I%%it%<F>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!>>"U">U"""">U""""""6"""6""">"""U""""""">>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!)T)T))))T))))))6)))6))))))T)))))))8f0080668688?88888?8888?888888f888f8880888688888888888 H$x/JZ__%FGHIy>fQf>Qfff>Qffffff3fff3ffffffyfffyfff>fffQfff ffffffffzz)A,00'0BCHH:!::!:::::!:::::::!::::::::I1/1111/111111111/111/1111111r   c                   
  dz  dz  }|j                  dd       |t         dz  j                          |t         dz  j                          t        j                  ddt
        d	g      

 fd
}t        |t               }|j                  d      }t        d |D              }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                   d| d      dz   d|iz  }	t#        t        j$                  |	            dx}}y)u@   apply=False, 모든 safety PASS여도 applied_count=0 어설션.r-   r.   Tr/   r2   r   g   rp   rq   c                $   d| v rd| v rt        ddd      S d| v rd| v rt        dd      S d| v rt        ddd      S d| v rt        d	dd      S d
| v r3d| v r/t        dz        }d| dt         dt         d}t        d|d      S t        ddd      S )Nr   r   r   ry   rw   rx   r   r   r7   worktreer   	worktree 
HEAD z
branch refs/heads/
)r   r   FAKE_SHAr   )r   r{   wt_path	porcelainr|   rZ   s       r   r}   z4test_dry_run_zero_actual_delete.<locals>.fake_runner  s    t 5*1b"554<FdN*1k2>>4*1b"55d?*1b"55&D.(_45GG9 % z "%%0M5 
 +1i<<&q"b11r   r3   Fr   c              3  :   K   | ]  }|j                   sd   yw)r7   N)r   ).0rs     r   	<genexpr>z2test_dry_run_zero_actual_delete.<locals>.<genexpr>  s     8aaii8s   r   r8   )z%(py0)s == %(py3)sapplied_count)r=   rj   u3   dry-run에서 applied_count가 0이어야 함 (got )r   r?   N)rI   rJ   rK   r   r   r   r
   r   cleanup_all_dry_runsumrN   rO   rP   rQ   rR   rS   r   rT   rU   )rZ   r[   r}   r\   resultsr  rl   r]   r   r`   r|   s   `         @r   test_dry_run_zero_actual_deleter  }  s#    H$x/JTD1\N+..557\N+..557**+F K2( %G )))6G8788M e=Aeee=Aeeeeee=eee=eeeAeee!TUbTccdeeeeeeer   c                D   | dz  dz  }|j                  dd       |t         dz  j                          |t         dz  j                          t        j                  ddt
        d	g      d
difd}t        |t        |       }t        t        | dz              }|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}||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}||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}}d
   }d}||u }|st        j                  d|fd||f      t        j"                  |      t        j"                  |      dz  }t        j,                  d      dz   d|iz  }t%        t        j&                  |            dx}x}}y)ua   apply=True, 6대 safety 모두 PASS, mock subprocess 'git worktree remove' rc=0 → applied=True.r-   r.   Tr/   r2   r   h   rp   rq   calledFc                    d| v rd| v rt        ddd      S d| v rd| v rt        dd      S d| v rt        ddd      S d| v rt        d	dd      S d
| v rd| v rdd<   t        ddd      S t        ddd      S )Nr   r   r   ry   rw   rx   r   r   r7   r	  removeTr  r(   )r   r{   r|   removeds     r   r}   z:test_apply_mode_with_all_safe_deletes.<locals>.fake_runner  s    t 5*1b"554<FdN*1k2>>4*1b"55d?*1b"55(d"2 $GH*1b"55&q"b11r   r3   r   r   r   rD   z0%(py2)s
{%(py2)s = %(py0)s.all_safe
} is %(py5)sr;   r<   r@   rA   Nr   r   )z%(py1)s is %(py4)sr   u*   git worktree remove가 호출되어야 함
>assert %(py6)sr   )rI   rJ   rK   r   r   r   r
   r   r&   r   r   all_saferN   rO   rP   rQ   rR   rS   rT   rU   r   r   r   )rZ   r[   r}   r\   r   r;   r]   r^   r_   r`   ra   rk   rl   r  r   r|   r  s                  @@r   %test_apply_mode_with_all_safe_deletesr#    sh   H$x/JTD1\N+..557\N+..557**+F K G2 %G  SO)C%DEI%%it%<F??"d"?d""""?d""""""6"""6"""?"""d""""""">>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!>>"U">U"""">U""""""6"""6""">"""U"""""""8RR$RRRRRRRRRRRR&RRRRRRRRr   c                P	   | dz  dz  }|j                  dd       |t         dz  j                          |t         dz  j                          t        j                  ddt
        d	g      fd
}t        |t        |       }t        t        | dz              }|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}||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}||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}||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 cg c]  }|j0                  r|j2                   }}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c c}w )"uY   safety_2 FAIL (PR OPEN) → cleanup_worktree all_safe=False, skipped=True, applied=False.r-   r.   Tr/   r2   r   i   r   rq   c                    d| v rd| v rt        ddd      S d| v rd| v rt        dd      S d| v rt        ddd      S d| v rt        d	dd      S t        ddd      S )
Nr   r   r   ry   rw   rx   r   r   r7   r(   rz   s     r   r}   z-test_unmerged_pr_skipped.<locals>.fake_runner  sy    t 5*1b"554<FdN*1k2>>4*1b"55d?*1b"55&q"b11r   r3   r   r   r   FrD   r   r;   r<   r@   rA   Nr   r   r   r   r   re   )z%(py1)s in %(py3)sfailed_safety_namesr   r   r?   )rI   rJ   rK   r   r   r   r
   r   r&   r   r   r"  rN   rO   rP   rQ   rR   rS   rT   rU   r   r   r   safety_resultsrW   rV   )rZ   r[   r}   r\   r   r;   r]   r^   r_   r`   ra   r  r'  rk   rl   r   r|   s                   @r   test_unmerged_pr_skippedr)    s   H$x/JTD1\N+..557\N+..557**D K	2 %G  SO)C%DEI%%it%<F??#e#?e####?e######6###6###?###e#######>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!>>"U">U"""">U""""""6"""6""">"""U""""""")T)T))))T))))))6)))6))))))T)))))))+1+@+@Qa166QQ-;-----;----;------------------ Rs   R#-R#c                   d}d| | dz  dz  }|j                  dd       |t         dz  j                          |t         dz  j                          t        j                  d	d
t
        dg      fd}t        |t        |       }t        t        | dz              }|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                  }	||	v}|st        j                  d|fd||	f      dt        j                         v st        j                   |      rt        j"                  |      nddt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |	      dz  }t        j(                  d|j                         dz   d|iz  }t%        t        j&                  |            d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  }
t        j(                  d#|j                         d$z   d|
iz  }t%        t        j&                  |            dx}x}}y)%u   subprocess error 시 raw token 'ghp_faketoken123abc'가 stderr에 있어도 skip_reason에는 ***MASKED***로 출력.

    ⚠️ 'ghp_faketoken123abc'는 테스트 fake 값 (실제 토큰 아님).
    ghp_faketoken123abcz(error: authentication failed with token r-   r.   Tr/   r2   r   j   rp   rq   c                    d| v rd| v rt        ddd      S d| v rd| v rt        dd      S d| v rt        ddd      S d| v rt        d	dd      S d
| v rd| v rt        d	d      S t        ddd      S )Nr   r   r   ry   rw   rx   r   r   r7   r	  r  r(   )r   r{   fake_stderr_with_tokenr|   s     r   r}   z9test_token_not_leaked_in_skip_reason.<locals>.fake_runner  s    t 5*1b"554<FdN*1k2>>4*1b"55d?*1b"55(d"2*1b2HII&q"b11r   r3   r   r   r   Nr   r   r;   r<   r@   rA   )not in)z7%(py0)s not in %(py4)s
{%(py4)s = %(py2)s.skip_reason
}fake_raw_token)r=   r>   r  u'   skip_reason에 raw token이 노출됨: r!  r   z***MASKED***re   )z3%(py1)s in %(py5)s
{%(py5)s = %(py3)s.skip_reason
}rh   u.   skip_reason에 ***MASKED*** 처리가 없음: z
>assert %(py7)s)rI   rJ   rK   r   r   r   r
   r   r&   r   r   r   rN   rO   rP   rQ   rR   rS   rT   rU   r   )rZ   r0  r[   r}   r\   r   r;   r]   r^   r_   r`   ra   r  r   rk   rl   r.  r|   s                   @@r   $test_token_not_leaked_in_skip_reasonr1    s    +NGGWXH$x/JTD1\N+..557\N+..557**+F K2 %G  SO)C%DEI%%it%<F )T)T))))T))))))6)))6))))))T)))))))!'!3!3 >!33  >!3                "(    "(    "4    2&2D2D1EF      V// >//  >/          $    $    0    99K9K8LM     r   c                   d}d}d}d| dt          d| dd d| dd	 d
fd}t        |t        |       }|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                  |      dz  }
t        j                  dt	        |       d      dz   d|
iz  }t        t        j                  |            dx}x}	}|D ch c]  }|j                   }}||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d}||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d}||v }|st        j                  d|fd||f      d t        j                         v st        j                  |      rt        j                  |      nd dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d}|D ci c]  }|j                  |j                   }}||   }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&}||k(  }|slt        j                  d|fd"||f      t        j                  |      t        j                  |      d#z  }d$d%|iz  }
t        t        j                  |
            dx}x}}|D ci c]  }|j                  |j                    }}||   }|t         k(  }|st        j                  d|fd'|t         f      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}}||   }d,}d-}||z  }||k(  }|st        j                  d|fd.||f      t        j                  |      t        j                  |      t        j                  |      d/z  }d0d1|iz  }t        t        j                  |            dx}x}x}x}}||   }d2}d-}||z  }||k(  }|st        j                  d|fd.||f      t        j                  |      t        j                  |      t        j                  |      d/z  }d0d1|iz  }t        t        j                  |            dx}x}x}x}}yc c}w c c}w c c}w )3u9   git worktree list --porcelain mock output parsing 정상.z/home/jay/workspacer   z-/home/jay/workspace/.worktrees/task-2545-dev3r
  r  z"
branch refs/heads/main

worktree (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbz1
branch refs/heads/task/task-2550-dev5

worktree (ccccccccccccccccccccccccccccccccccccccccz'
branch refs/heads/task/task-2545-dev3
c                P    d| v rd| v rd| v rt        dd      S t        ddd      S )Nr	  rx   r   r   ry   r(   )r   r{   porcelain_outputs     r   r}   zBtest_enumerate_parses_worktree_list_porcelain.<locals>.fake_runnerP  s7    &D.]d5J*1.>CC&q"b11r   r3   r   r8   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   
candidatesr   u*   3개 worktree가 파싱되어야 함 (got r  r   r   Nre   )z%(py0)s in %(py2)s	wt_path_1paths)r=   r>   zassert %(py4)sr  	wt_path_2	wt_path_3r   r   r   r  r   z	task-2545r   r  r   r   r?   b(   )z%(py1)s == (%(py4)s * %(py6)s))ri   r  r   zassert %(py9)sr   c)r  r
   r   enumerate_worktreesr   rN   rO   rP   rQ   rR   rS   r   rT   rU   r"   r$   r%   )rZ   r8  r:  r;  r}   r\   r7  rl   r   r^   r   r   r>  r9  r]   @py_format3r  task_maprk   r_   sha_mapr   r`   @py_assert7ra   r   r6  s                             @r   -test_enumerate_parses_worktree_list_porcelainrD  <  s   %I?I?I I; z  ; z  ; z 2
	3 2
 %G ,,.Jz?`a`?a```?a``````3```3``````z```z```?```a```#McR\oM^^_!```````` ((QVV(E(999999999 ,66a		!6H6I-+-+----+------+-------I-+-+----+------+------- ,66aqvvqzz!6G69))))))))))))))))))))))))9))r)r))))))))))))))r)))))))9))r)r))))))))))))))r)))))))) ) 7
 7s    \?]']	)returnr   )r   ry   ry   )r   intr   r   r   r   rE  subprocess.CompletedProcess)
r"   r   r#   r   r$   z
str | Noner%   r   rE  r	   )r)   objectr*   rH  rE  rG  )rZ   r   rE  None)4__doc__
__future__r   builtinsrP   _pytest.assertion.rewrite	assertionrewriterN   r   r   sysr   r   pathlibr   __file__resolver0   WORKSPACE_ROOTr   r"   insertanu_v2.worktree_cleanupr   r	   r
   r  rJ   r   r   r   r   r&   r+   rb   rm   r   r   r   r   r   r   r   r   r   r  r  r#  r)  r1  rD  r   r   r   <module>rW     sn   #     
 '  h'')11!4~chh&HHOOAs>*+  #D @ 


 
 !	
 #&	[
[[ [ 	[
 [&!.&$%6#6!,'0F0)0&0,.!/N2D*f`(S\%.V0l2*r   