
    il                     N   d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
Z
ddlZddlmZ ddlmZ ddlZe
j$                  j'                  d e ee      j-                         j.                  j.                               ddlmZmZmZmZmZmZmZ  ee      j-                         j.                  j.                  j.                  Z  ee dz  dz        Z!de"e   d	e#e$eef   e%f   fd
Z& ejN                         ded	efd       Z( G d d      Z) G d d      Z* G d d      Z+ G d d      Z, G d d      Z-i ej\                  dddddZ/dededed	dfdZ0 G d d      Z1 G d  d!      Z2 G d" d#      Z3 G d$ d%      Z4 G d& d'      Z5 G d( d)      Z6 G d* d+      Z7 G d, d-      Z8y).u|   worktree_manager.py 통합 테스트.

임시 git repo를 생성하여 create/finish/list/status 명령어를 검증한다.
    N)Path)Any)_auto_fix_high_comments_classify_medium_comments_log_medium_comments_parse_gemini_comments_resolve_task_level
cmd_create
cmd_finishscriptszworktree_manager.pyargsreturnc                     t        j                  dt        g| dd      }t        j                  |j
                        |j                  fS )u:   worktree_manager.py를 실행하고 JSON 결과를 반환.python3Tcapture_outputtext)
subprocessrunSCRIPTjsonloadsstdout
returncode)r   results     :/home/jay/workspace/scripts/tests/test_worktree_manager.py_run_wtr       sC    ^^	F"T"F
 ::fmm$f&7&777    tmp_pathc                    | dz  }|j                          t        j                  ddgt        |      dd       t        j                  g dt        |      dd       |dz  }|j	                  d       t        j                  g d	t        |      dd       t        j                  g d
t        |      ddi t
        j                  ddddd       |S )u/   초기 커밋이 있는 임시 git repo 생성.repogitinitTcwdcheckr   )r"   checkoutz-bmainz	README.mdhellor"   add.)r"   commit-mr#   testt@tGIT_AUTHOR_NAMEGIT_COMMITTER_NAMEGIT_AUTHOR_EMAILGIT_COMMITTER_EMAILr%   r&   r   env)mkdirr   r   str
write_textosenviron)r   r!   readmes      r   git_repor>   *   s     fDJJLNNE6?D	dSNN4#d)4`deKF
gNN&CITRVWNN'I
jj
%"( %#(
 Kr   c                   4    e Zd ZdeddfdZdeddfdZddZy)
TestCreater>   r   Nc                 Z   t        dt        |      ddg      \  }}d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }d	d
|iz  }t        t        j                  |            d x}}|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}	||	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        |      }	|	j                  } |       }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |	      t        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}	x}}y )Ncreate
task-330.1dev2r   ==z%(py0)s == %(py3)srcpy0py3assert %(py5)spy5statuscreatedz%(py1)s == %(py4)spy1py4assert %(py6)spy6branchztask/task-330.1-dev2worktree_pathz_assert %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}.is_dir
}()
}r   )rJ   py2rS   rU   py8)r   r9   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr   is_dir)selfr>   datarH   @py_assert2@py_assert1@py_format4@py_format6@py_assert0@py_assert3@py_format5@py_format7@py_assert5@py_assert7@py_format9s                  r   test_create_newzTestCreate.test_create_newE   s   Hc(m\6JKbrQwrQrrQH~**~****~***~**********H~7!77~!77777~!7777~777!77777777)3t)*3*113133333333t333t333)333*33313333333333r   c                    t        dt        |      ddg       t        dt        |      ddg      \  }}d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }d	d
|iz  }t        t        j                  |            d x}}|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}}	y )NrB   rC   rD   r   rE   rG   rH   rI   rL   rM   rN   reusedrP   rQ   rT   rU   
r   r9   rZ   r[   r\   r]   r^   r_   r`   ra   rc   r>   rd   rH   re   rf   rg   rh   ri   rj   rk   rl   s               r   test_create_reusezTestCreate.test_create_reuseL   s    3x=,?@Hc(m\6JKbrQwrQrrQH~))~))))~)))~))))))))))r   c                 p   t        g 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  }dd|iz  }t        t        j                  |            d 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}}y )N)rB   z/nonexistent/pathztask-999dev3   rE   rG   rH   rI   rL   rM   rN   errorrP   rQ   rT   rU   )	r   rZ   r[   r\   r]   r^   r_   r`   ra   )rc   rd   rH   re   rf   rg   rh   ri   rj   rk   rl   s              r   test_create_invalid_pathz#TestCreate.test_create_invalid_pathR   s    NObrQwrQrrQH~((~((((~(((~((((((((((r   r   N)__name__
__module____qualname__r   rp   ru   rz    r   r   r@   r@   D   s-    4 4 4*$ *4 *)r   r@   c                   ,    e Zd ZdeddfdZdeddfdZy)TestListr>   r   Nc                 6   t        dt        |      g      \  }}|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}}y )Nlist	worktreesrE   rP   rQ   rT   rU   r   r9   rZ   r[   r_   r`   ra   	rc   r>   rd   _ri   rj   re   rk   rl   s	            r   test_list_emptyzTestList.test_list_emptyY   sk    63x=12aK &B& B&&&& B&&& &&&B&&&&&&&r   c                 J   t        dt        |      ddg       t        dt        |      g      \  }}|d   }t        |      }d}||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                  |      t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            d x}x}x}}|d   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}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )NrB   rC   rD   r   r   rx   rE   z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)slenrJ   rX   rS   py7assert %(py9)spy9r   task_idrP   rQ   rT   rU   team_id)r   r9   r   rZ   r[   r\   r]   r^   r_   r`   ra   )rc   r>   rd   r   rf   rj   @py_assert6rm   @py_format8@py_format10wtri   re   rk   rl   s                  r   test_list_with_worktreez TestList.test_list_with_worktree]   sa   3x=,?@63x=12a$*s$%**%****%******s***s***$***%**********+q!)},,},,,,},,,},,,,,,,,,,)}&&}&&&&}&&&}&&&&&&&&&&r   )r|   r}   r~   r   r   r   r   r   r   r   r   X   s(    ' ' '' ' 'r   r   c                   ,    e Zd ZdeddfdZdeddfdZy)
TestStatusr>   r   Nc                    t        dt        |      ddg       |dz  dz  }|dz  j                  d       t        dt        |      dg      \  }}|d	   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}}y )NrB   rC   rD   
.worktreestask-330.1-dev2znew.txtr/   rN   r   r   changed_filesrx   >=)z%(py1)s >= %(py4)srQ   rT   rU   )r   r9   r:   rZ   r[   r_   r`   ra   )
rc   r>   wt_pathrd   r   ri   rj   re   rk   rl   s
             r   test_status_changed_filesz$TestStatus.test_status_changed_filesg   s    3x=,?@\),==	9	((08S]LABaK #O49949999499949999999999r   c                 8   t        dt        |      dg      \  }}|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}}y )	NrN   ztask-nonexistentr   rE   rP   rQ   rT   rU   r   r   s	            r   test_status_no_matchzTestStatus.test_status_no_matchn   sn    8S]4FGHaK &B& B&&&& B&&& &&&B&&&&&&&r   )r|   r}   r~   r   r   r   r   r   r   r   r   f   s(    :$ :4 :'T 'd 'r   r   c                   <    e Zd ZdeddfdZdeddfdZdeddfdZy)
TestFinishr>   r   Nc                    t        dt        |      ddg       t        dt        |      ddddg      \  }}d}||k(  }|st        j                  d|fd	||f      d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}|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}}	y )NrB   rC   rD   finish--actionkeepr   rE   rG   rH   rI   rL   rM   rN   keptrP   rQ   rT   rU   rs   rt   s               r   test_finish_keepzTestFinish.test_finish_keept   s    3x=,?@Hc(m\6:W]^_brQwrQrrQH~''~''''~'''~''''''''''r   c                    t        dt        |      ddg       |dz  dz  }|dz  j                  d       t        j                  g dt        |      d	d	
       t        j                  g dt        |      d	d	i t
        j                  ddddd       t        dt        |      ddddg      \  }}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}|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}||z  }
d}|
|z  }|j                  } |       }| }|sdd t        j                         v st        j                  |      rt        j                  |      nd t        j                  |      t        j                  |      t        j                  |      t        j                  |      d!z  }t        t        j                  |            d x}x}
x}x}x}x}}d}||z  }
|
j                  } |       }|sd"d t        j                         v st        j                  |      rt        j                  |      nd t        j                  |      t        j                  |      t        j                  |      d#z  }t        t        j                  |            d x}x}
x}}y )$NrB   rC   rD   r   r   z
merged.txtmergedr*   Tr$   )r"   r-   r.   zadd merged.txtr/   r0   r1   r6   r   r   merger   rE   rG   rH   rI   rL   rM   rN   rP   rQ   rT   rU   _assert not %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = ((%(py0)s / %(py2)s) / %(py5)s).exists
}()
}r>   rJ   rX   rM   rY   py10zMassert %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = (%(py0)s / %(py2)s).exists
}()
})rJ   rX   rM   r   )r   r9   r:   r   r   r;   r<   rZ   r[   r\   r]   r^   r_   r`   ra   exists)rc   r>   r   rd   rH   re   rf   rg   rh   ri   rj   rk   rl   @py_assert4r   rn   @py_assert9@py_assert11@py_format12r   s                       r   test_finish_mergezTestFinish.test_finish_mergez   s]   3x=,?@\),==	<	++H5*GDY]^5G**#)&,$)',	
 Hc(m\6:W^_`brQwrQrrQH~))~))))~)))~))))))))))+IH|+I.?I+.??I?GGIGIIIIIIIIIIIHIIIHIII|III.?IIIGIIIIIIIIIII'1<'1'//1/111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                    t        dt        |      ddg       |dz  dz  }|dz  j                  d       t        dt        |      ddd	dg      \  }}d
}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}|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}||z  }
d}|
|z  }|j                  } |       }| }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}
x}x}x}x}}y )NrB   z
task-330.2dev1r   ztask-330.2-dev1zdiscard.txtdiscardr   r   r   rE   rG   rH   rI   rL   rM   rN   	discardedrP   rQ   rT   rU   r   r>   r   )r   r9   r:   rZ   r[   r\   r]   r^   r_   r`   ra   r   )rc   r>   r   rd   rH   re   rf   rg   rh   ri   rj   rk   rl   r   r   rn   r   r   r   s                      r   test_finish_discardzTestFinish.test_finish_discard   s   3x=,?@\),==	=	 ,,Y7Hc(m\6:W`abbrQwrQrrQH~,,~,,,,~,,,~,,,,,,,,,,+IH|+I.?I+.??I?GGIGIIIIIIIIIIIHIIIHIII|III.?IIIGIIIIIIIIIIIr   )r|   r}   r~   r   r   r   r   r   r   r   r   r   s   s>    ( ($ (2$ 24 20JD JT Jr   r   c                   <    e Zd ZdeddfdZdeddfdZdeddfdZy)TestFinishPrr>   r   Nc                    t        dt        |      ddg       t        dt        |      ddddg      \  }}g }d}||k7  }|}|s|d   }d	}	||	k(  }
|
}|s+t        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  }|j                  |       |s_t        j                  d
fd	f      t        j                  |      t        j                  |	      dz  }dd|iz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}
}	y)u?   pr 액션에서 remote가 없으면 gh 실패로 에러 처리.rB   
task-330.3r   r   r   prr   rN   ry   !=)z%(py2)s != %(py5)srH   )rX   rM   z%(py7)sr   rE   )z%(py10)s == %(py13)s)r   py13z%(py15)spy15rx   zassert %(py18)spy18N)r   r9   rZ   r[   r\   r]   r^   r_   append_format_boolopr`   ra   )rc   r>   rd   rH   rf   r   rj   ri   r   @py_assert12r   rh   r   @py_format14@py_format16@py_format17@py_format19s                    r   test_finish_pr_no_remotez%TestFinishPr.test_finish_pr_no_remote   s    3x=,?@Hc(m\6:W[\]b3Q3rQw3$x.3G3.G33333rQ333333r333r333Q3333333.G333.333G33333333333333r   c                    t        j                  dt        dt        |      ddddddd	d
ddgdd      }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#   pr 액션 CLI 인자 파싱 검증.r   r   r   r   r   r   z
--pr-titlezTest PRz	--pr-bodyz	Test bodyz--gemini-timeout60Tr   zunrecognized argumentsnot in)z2%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.stderr
}r   rR   rK   rM   assert %(py7)sr   N)r   r   r   r9   stderrrZ   r[   r_   r\   r]   r^   r`   ra   )rc   r>   r   ri   r   re   rh   r   s           r   test_finish_pr_cli_argsz$TestFinishPr.test_finish_pr_cli_args   s    H"   %
, (<v}}<'}<<<<'}<<<'<<<<<<v<<<v<<<}<<<<<<<r   c           
      |   t        j                  dt        dt        |      ddddgdd      }|j                  }d	}||k7  }|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$   잘못된 action은 argparse 에러.r   r   r   r   r   invalidTr   r   r   )z2%(py2)s
{%(py2)s = %(py0)s.returncode
} != %(py5)sr   )rJ   rX   rM   r   r   Nzinvalid choicein)z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stderr
}r   )r   r   r   r9   r   rZ   r[   r\   r]   r^   r_   r`   ra   r   )
rc   r>   r   rf   r   rj   rh   r   ri   re   s
             r   test_finish_pr_invalid_actionz*TestFinishPr.test_finish_pr_invalid_action   s   H	  
   %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%%06==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0r   )r|   r}   r~   r   r   r   r   r   r   r   r   r      s;    4 4$ 4= = =41d 1t 1r   r   r/   r0   r1   r>   r   r   c           	         | dz  | d| z  }|| dz  j                  d|        t        j                  g dt        |      dd       t        j                  dd	d
d| gt        |      ddt               t        j                  g dt        |       dd       t        j                  dddd| d| gt        |       ddt               y)uM   워크트리 브랜치를 main에 머지하는 헬퍼 (cleanup 테스트용).r   -z.txtz
work from r*   Tr$   r"   r-   r.   zwork on r6   )r"   r'   r(   r   z--no-ffztask/N)r:   r   r   r9   _GIT_ENV)r>   r   r   r   s       r   _merge_worktree_to_mainr      s    %7)1WI(>>G'$++j	,BCNN&CLUYZNN	$(7) 45L NN.CM^bcNN	eG9AgY$?@Mr   c                   L    e Zd ZdeddfdZdeddfdZdeddfdZdeddfdZy)TestCleanupr>   r   Nc                 ~   t        dt        |      ddg       t        |dd       t        dt        |      g      \  }}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}}|d   }t        |      }d}	||	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                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}
}	|d   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}||z  }d}||z  }	|	j                  } |       }| }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}x}x}	x}x}}y)u1   머지된 워크트리만 정리되는지 확인.rB   z
task-400.1r   cleanupr   rE   rG   rH   rI   rL   rM   Ncleanedrx   r   r   r   r   r   r   rP   rQ   rT   rU   r   ztask-400.1-dev1r   r>   r   )r   r9   r   rZ   r[   r\   r]   r^   r_   r`   ra   r   r   )rc   r>   rd   rH   re   rf   rg   rh   rj   r   rm   r   r   ri   rk   rl   r   rn   r   r   r   s                        r   test_cleanup_removes_mergedz'TestCleanup.test_cleanup_removes_merged   s   3x=,?@,?Is8}56brQwrQrrQ	?(s?#(q(#q((((#q((((((s(((s(((?(((#(((q(((((((Iq!),<<,<<<<,<<<,<<<<<<<<<<+IH|+I.?I+.??I?GGIGIIIIIIIIIIIHIIIHIII|III.?IIIGIIIIIIIIIIIr   c                  	   t        dt        |      ddg       |dz  dz  }|dz  j                  d       t        j                  g dt        |      d	d	
       t        j                  g dt        |      d	d	t
               t        dt        |      g      \  }}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|d   }t        |      }	d}
|	|
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                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
|d   }t        |      }	d}
|	|
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                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
|d   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}||z  }	d}|	|z  }
|
j                  } |       }|sd$d%t        j                         v st        j                  |      rt        j                  |      nd%t        j                  |      t        j                  |      t        j                  |      t        j                  |      d&z  }t        t        j                  |            dx}x}	x}x}
x}}y)'uB   머지되지 않은 워크트리는 건드리지 않는지 확인.rB   z
task-400.2rD   r   ztask-400.2-dev2zwip.txtzwork in progressr*   Tr$   )r"   r-   r.   wipr6   r   r   rE   rG   rH   rI   rL   rM   Nr   r   r   r   r   r   skippedrx   reason
not_mergedrP   rQ   rT   rU   [assert %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = ((%(py0)s / %(py2)s) / %(py5)s).exists
}()
}r>   r   )r   r9   r:   r   r   r   rZ   r[   r\   r]   r^   r_   r`   ra   r   r   )rc   r>   r   rd   rH   re   rf   rg   rh   rj   r   rm   r   r   ri   rk   rl   r   rn   r   @py_format11s                        r   test_cleanup_skips_unmergedz'TestCleanup.test_cleanup_skips_unmerged   s   3x=,?@\),==	9	(();<*GDY]^*G	
 Is8}56brQwrQrrQ	?(s?#(q(#q((((#q((((((s(((s(((?(((#(((q(((((((	?(s?#(q(#q((((#q((((((s(((s(((?(((#(((q(((((((Iq!(+;|;+|;;;;+|;;;+;;;|;;;;;;;'E<'E*;E'*;;E;CCECEEEEEEEEEEEEEE<EEE*;EEECEEEEEEEEEEEr   c                 
   t        dt        |      ddg       t        |dd       t        dt        |      ddg       |dz  dz  }|dz  j                  d	       t	        j
                  g d
t        |      dd       t	        j
                  g dt        |      ddt               t        dt        |      g      \  }}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|d   }t        |      }	d}
|	|
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                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
|d   }t        |      }	d}
|	|
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                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
d}||z  }	d }|	|z  }
|
j                   } |       }| }|sd!d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |      t        j                  |      t        j                  |      t        j                  |      d#z  }t        t        j                  |            dx}x}	x}x}
x}x}}d}||z  }	d}|	|z  }
|
j                   } |       }|sd$d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |      t        j                  |      t        j                  |      t        j                  |      d#z  }t        t        j                  |            dx}x}	x}x}
x}}y)%uC   머지된 것은 정리, 미머지는 보존 (혼합 시나리오).rB   z
task-400.3r   z
task-400.4rD   r   ztask-400.4-dev2z
active.txtactiver*   Tr$   )r"   r-   r.   zactive workr6   r   r   rE   rG   rH   rI   rL   rM   Nr   rx   r   r   r   r   r   r   ztask-400.3-dev1r   r>   r   r   )r   r9   r   r:   r   r   r   rZ   r[   r\   r]   r^   r_   r`   ra   r   r   )rc   r>   r   rd   rH   re   rf   rg   rh   rj   r   rm   r   r   r   rn   r   r   r   r   s                       r   test_cleanup_mixedzTestCleanup.test_cleanup_mixed  s5    	3x=,?@,?3x=,?@\),==	<	++H5*GDY]^2G	
 Is8}56brQwrQrrQ	?(s?#(q(#q((((#q((((((s(((s(((?(((#(((q(((((((	?(s?#(q(#q((((#q((((((s(((s(((?(((#(((q(((((((+IH|+I.?I+.??I?GGIGIIIIIIIIIIIHIIIHIII|III.?IIIGIIIIIIIIIII'E<'E*;E'*;;E;CCECEEEEEEEEEEEEEE<EEE*;EEECEEEEEEEEEEEr   c                    t        dt        |      g      \  }}d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}}|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}}	|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}}	y	)u*   정리 대상이 없을 때 정상 동작.r   r   rE   rG   rH   rI   rL   rM   Nr   rP   rQ   rT   rU   r   rs   rt   s               r   test_cleanup_no_targetsz#TestCleanup.test_cleanup_no_targets/  s    Is8}56brQwrQrrQI$"$"$$$$"$$$$$$"$$$$$$$I$"$"$$$$"$$$$$$"$$$$$$$r   )r|   r}   r~   r   r   r   r   r   r   r   r   r   r      sW    	JD 	JT 	JFD FT F,F4 FD F2% % %r   r   c                   <    e Zd ZdeddfdZdeddfdZdeddfdZy)TestSafetyDecoratorr>   r   Nc                    |dz  }g }|j                   } |       }| }|}|sd}|j                  }	 |	       }
||
v}|}|stddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }|j                  |       |st	        j                  dfd
f      t	        j                  |      dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  	      t	        j                  |
      dz  }d	d
|iz  }|j                  |       t	        j                  |d      i z  }dd|iz  }t        t	        j                  |            dx}x}x}x}x}x}x}x}	}
t        t        |      dd      }|j                  }d} ||      }d}||u }|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                   } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      d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                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}x}}y) uF   .gitignore에 .worktrees/가 없을 때 자동 추가되는지 확인.
.gitignore.worktrees/z>not %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s.exists
}()
}gitignore_path)rX   rS   rU   r   )zR%(py10)s not in %(py16)s
{%(py16)s = %(py14)s
{%(py14)s = %(py12)s.read_text
}()
})r   py12py14py16z%(py18)sr   rx   zassert %(py21)spy21Nztask-safety-1r   gitignore_updatedTis)zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} is %(py9)sr   )rJ   rX   rS   rU   r   zassert %(py11)spy11zAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}rJ   rX   rS   r   )zH%(py1)s in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.read_text
}()
})rR   rK   rM   r   r   r   )r   	read_textr\   r]   rZ   r^   r_   r   r[   r   r`   ra   r
   r9   get)rc   r>   r   rf   rj   rm   rn   ri   r   @py_assert13@py_assert15r   r   r   r   @py_format20@py_format22r   @py_assert8r   r   rk   r   r   re   s                            r   test_gitignore_auto_updatez.TestSafetyDecorator.test_gitignore_auto_update8  s    "L0]>((](*]**]*]*m]>C[C[]C[C]]mC].]]]]]]]>]]]>]]](]]]*]]]]*]]]mC]]]]m]]]]]]>]]]>]]]C[]]]C]]]]]]]]]]]]]]]]CM?FCzz6-6z-.6$6.$6666.$666666v666v666z666-666.666$6666666$$&$&&&&&&&&~&&&~&&&$&&&&&&&&&&: 8 8: 8 ::} :::::} ::::}:::::::::::: 8::: ::::::::r   c           
          |dz  }|j                  d       t        t        |      dd      }d}||v}|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      ndd	z  }d
d|iz  }t        t        j                  |            dx}}|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
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}	x}
x}x}x}}y)uJ   이미 .gitignore에 .worktrees/가 있으면 추가 안 되는지 확인.r   z.worktrees/
ztask-safety-2r   r   r   )z%(py1)s not in %(py3)sr   )rR   rK   rL   rM   Nr   rx   rE   )z%(py10)s
{%(py10)s = %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.read_text
}()
}.count
}(%(py8)s)
} == %(py13)sr   )rJ   rX   rS   rU   rY   r   r   zassert %(py15)sr   )r:   r
   r9   rZ   r[   r_   r\   r]   r^   r`   ra   r  count)rc   r>   r   r   ri   re   rg   rh   rf   rj   rm   rn   r   r   r   r   r   s                    r   test_gitignore_already_presentz2TestSafetyDecorator.test_gitignore_already_presentD  sS    "L0!!/2CM?FC"0"&0000"&000"000000&000&0000000''C')C)//CC/>C!C>!CCCC>!CCCCCC~CCC~CCC'CCC)CCC/CCCCCC>CCC!CCCCCCCCr   r   c                 Z   |dz  }|j                          t        t        |      d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}}y)u;   git repo가 아닌 디렉토리에서 에러 반환 확인.
not_a_repoztask-safety-3r   rN   ry   rE   rP   rQ   rT   rU   N)r8   r
   r9   rZ   r[   r_   r`   ra   )	rc   r   non_repor   ri   rj   re   rk   rl   s	            r   test_non_git_repo_errorz+TestSafetyDecorator.test_non_git_repo_errorO  s|     l*CM?FCh*7*7****7******7*******r   )r|   r}   r~   r   r  r  r  r   r   r   r   r   7  s>    
;4 
;D 
;	Dt 	D 	D+ + +r   r   c                       e Zd ZdeddfdZy)TestFinishPrUnitr>   r   Nc                     t        j                  t        d      5  t        t	        |      ddd       ddd       y# 1 sw Y   yxY w)u3   pr 액션에서 worktree가 없으면 RuntimeError.zworktree not found)matchz
task-999.9r   r   N)pytestraisesRuntimeErrorr   r9   )rc   r>   s     r   !test_pr_action_worktree_not_foundz2TestFinishPrUnit.test_pr_action_worktree_not_found[  s<    ]]</CD 	Bs8}lFDA	B 	B 	Bs	   =A)r|   r}   r~   r   r  r   r   r   r  r  Z  s    B$ B4 Br   r  c                   H    e Zd ZdZdeddfdZdeddfdZd
dZd
dZd
d	Z	y)TestResolveTaskLevelu,   _resolve_task_level 함수 단위 테스트.r   r   Nc                   	
 ddl 	|dz  dz  

j                  d       
dz  }|j                  d       d	t        d
t        f	
f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  }dd|iz  }t        t        j                  |            dx}}y)u;   YAML frontmatter에서 level 필드를 정확히 읽는다.r   NmemorytasksTparentsztask-test-1.mdz2---
task_id: task-test-1
level: 3
---
# Test task
r   r   c                    t        j                  |  d            t        j                  |  d            z   }|D ]{  }	 |j                  d      }|j                  d      rU|j	                  dd      }|dkD  r>j                  d|d| j                        }|rt        |j                  d	            c S } y# t        t        t        f$ r Y w xY w)
Nz.mdz*.mdutf-8encoding---   r   z^level:\s*(\d+)rx   )r   globr  
startswithfindsearch	MULTILINEintgroupOSError
ValueError	TypeError)r   
candidatespr   end_idxmre	tasks_dirs         r   patched_resolvezITestResolveTaskLevel.test_yaml_frontmatter_level.<locals>.patched_resolven  s    inny_=>innX_W``dUeFfAggJ 
	;;;8Du-"&))E1"5"Q; "		*<d1Wor|| \A '*1771: 6
   Y7 s   A5B>>CCztask-test-1r$  rE   rG   r   rI   rL   rM   )r3  r8   r:   r9   r*  rZ   r[   r\   r]   r^   r_   r`   ra   )rc   r   	task_filer5  r   re   rf   rg   rh   r3  r4  s            @@r   test_yaml_frontmatter_levelz0TestResolveTaskLevel.test_yaml_frontmatter_leveld  s    x''1	% 00	VW	S 	S 	 !/v{vvvr   c                    |dz  dz  }|j                  d       |dz  }|j                  d       |j                  d      }|j                  }d	} ||      }| }|sd
dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}x}x}}y)u4   frontmatter 없는 task 파일은 0을 반환한다.r  r  Tr  ztask-nolevel.mdz$# No frontmatter task
Just content.
r   r!  r#  zPassert not %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
}r   )rJ   rX   rS   rU   N)r8   r:   r  r&  r\   r]   rZ   r^   r_   r`   ra   )
rc   r   r4  r6  r   rf   rj   rm   rn   r   s
             r    test_no_frontmatter_returns_zeroz5TestResolveTaskLevel.test_no_frontmatter_returns_zero  s    x''1	% 11	EF""G"4??)5)?5)))))))))))4)))4)))?)))5))))))))))r   c                 f   t        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  }dd|iz  }t        t        j                  |            d	x}}y	)
u1   실제 task-1283.1.md에서 level 2를 읽는다.ztask-1283.1   rE   rG   r   rI   rL   rM   N	r	   rZ   r[   r\   r]   r^   r_   r`   ra   rc   r   re   rf   rg   rh   s         r   test_real_task_with_levelz.TestResolveTaskLevel.test_real_task_with_level  sd    $]3v{vvvr   c                 f   t        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  }dd|iz  }t        t        j                  |            d	x}}y	)
u1   존재하지 않는 task ID는 0을 반환한다.ztask-does-not-exist-99999r   rE   rG   r   rI   rL   rM   Nr<  r=  s         r   "test_nonexistent_task_returns_zeroz7TestResolveTaskLevel.test_nonexistent_task_returns_zero  se    $%@Av{vvvr   c                    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}||k\  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)uC   level 필드가 없는 task 파일은 0 또는 work_level fallback.z	task-1866z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancer   r*  )rJ   rR   rX   rS   Nr   r   )z%(py0)s >= %(py3)srI   rL   rM   )r	   rB  r*  r\   r]   rZ   r^   r_   r`   ra   r[   )rc   r   rj   rk   re   rf   rg   rh   s           r   test_task_without_level_fieldz2TestResolveTaskLevel.test_task_without_level_field  s    $[1&#&&&&&&&&z&&&z&&&&&&&&&&&&&&&&&#&&&#&&&&&&&&&&v{vvvr   r{   )
r|   r}   r~   __doc__r   r7  r9  r>  r@  rC  r   r   r   r  r  a  s:    6D T 8	* 	*$ 	*

r   r  c                   \    e Zd ZdeddfdZdeddfdZdeddfdZdeddfdZdeddfdZy)	TestParseGeminiCommentsr   r   Nc           	      >   t        j                  ddiddddg      }t        j                  j	                  d      5 }t        j                  g d|d	
      |_        t        dddt        |            }ddd       t              }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}|d   d   }
d}|
|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}|
|k(  }|slt        j                  d|fd|
|f      t        j                   |
      t        j                   |      dz  }dd|iz  }t#        t        j$                  |            dx}
x}}y# 1 sw Y   !xY w)u?   HIGH severity 코멘트가 올바르게 파싱되는지 확인.logingemini-code-assist[bot]z=severity: high
SQL injection vulnerability in query parameterz	app/db.py*   userbodypathlineworktree_manager._runr    r   r   r   r   1ownerr!   Nrx   rE   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   r   rJ   rR   rK   rU   assert %(py8)srY   severityhighrP   rQ   rT   rU   rN  r   dumpsunittestmockpatchr   CompletedProcessreturn_valuer   r9   r   rZ   r[   r\   r]   r^   r_   r`   ra   rc   r   mock_commentsmock_runr   re   rm   r   rl   ro   ri   rj   rk   s                r   test_parse_high_severityz0TestParseGeminiComments.test_parse_high_severity  s   

 %&?@\'		
 ]]  !89 	QX$.$?$?RTU^ktv$wH!+C&#h-PF	Q 6{a{a{ass66{aay$..$....$...$..........ay /K/ K//// K/// ///K///////	Q 	Qs   6JJc           	      8   t        j                  ddiddddg      }t        j                  j	                  d      5 }t        j                  g d|d	
      |_        t        dddt        |            }ddd       t              }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}|d   d   }
d}|
|k(  }|slt        j                  d|fd|
|f      t        j                   |
      t        j                   |      dz  }dd|iz  }t#        t        j$                  |            dx}
x}}y# 1 sw Y   xY w)u!   MEDIUM severity 코멘트 파싱.rH  rI  u8   severity: medium
⚠️ Consider adding input validationz
app/api.py
   rK  rP  r   rQ  rR  rS  rT  r!   Nrx   rE   rU  r   r   rV  rW  rY   rX  mediumrP   rQ   rT   rU   rZ  ra  s                r   test_parse_medium_severityz2TestParseGeminiComments.test_parse_medium_severity  sr   

 %&?@W(		
 ]]  !89 	QX$.$?$?RTU^ktv$wH!+C&#h-PF	Q 6{a{a{ass66{aay$00$0000$000$0000000000		Q 	Qs   6HHc           	      2   t        j                  ddiddddg      }t        j                  j	                  d      5 }t        j                  g d|d	
      |_        t        dddt        |            }ddd       t              }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}y# 1 sw Y   xY w)u2   Gemini가 아닌 사용자의 코멘트는 무시.rH  zhuman-reviewerz$severity: high
This is a big problemzapp/main.pyrx   rK  rP  r   rQ  rR  rS  rT  r!   NrE   rU  r   r   rV  rW  rY   rZ  )
rc   r   rb  rc  r   re   rm   r   rl   ro   s
             r   test_parse_ignores_non_geminiz5TestParseGeminiComments.test_parse_ignores_non_gemini  s   

 %&67C)		
 ]]  !89 	QX$.$?$?RTU^ktv$wH!+C&#h-PF	Q 6{a{a{ass66{a	Q 	Qs   6FFc           	      "   t         j                  j                  d      5 }t        j                  g ddd      |_        t        dddt        |            }d	d	d	       g }|k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}}y	# 1 sw Y   xY w)u$   API 실패 시 빈 리스트 반환.rP  rx   rQ  ry   rR  rS  rT  r!   NrE   rG   r   rI   rL   rM   )r\  r]  r^  r   r_  r`  r   r9   rZ   r[   r\   r]   r^   r_   r`   ra   )rc   r   rc  r   re   rf   rg   rh   s           r   test_parse_api_failurez.TestParseGeminiComments.test_parse_api_failure  s    ]]  !89 	QX$.$?$?RTU^`ip$qH!+C&#h-PF	Q v|vvv	Q 	Qs   6DDc           	         t        j                  ddiddddddiddd	dddid
dddg      }t        j                  j	                  d      5 }t        j                  g d|d      |_        t        dddt        |            }ddd       t              }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }dd|iz  }	t#        t        j$                  |	            dx}x}}|D 
cg c]  }
|
d   	 }}
g d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      d z  }d!d"|iz  }t#        t        j$                  |            dx}}y# 1 sw Y   xY wc c}
w )#u,   HIGH + MEDIUM + LOW 혼합 코멘트 파싱.rH  rI  u   HIGH severity issue 🔴a.pyrx   rK  u   MEDIUM severity ⚠️b.pyr;  zMinor suggestionc.pyr$  rP  r   rQ  rR  rS  rT  r!   NrE   rU  r   r   rV  rW  rY   rX  )rY  rg  lowrG   
severitiesrI   rL   rM   rZ  )rc   r   rb  rc  r   re   rm   r   rl   ro   crr  rf   rg   rh   s                  r   test_parse_mixed_severitiesz3TestParseGeminiComments.test_parse_mixed_severities  s   

 %&?@6"	 "#<=G_ioyz{!#<=GYcistu	
 ]]  !89 	QX$.$?$?RTU^ktv$wH!+C&#h-PF	Q 6{a{a{ass66{a-34a
m4
466z66666z6666666z666z66666666666	Q 	Q 5s   6II#I )	r|   r}   r~   r   rd  rh  rj  rl  rt  r   r   r   rF  rF    sa    0 0$ 0&14 1D 1$ d  t  "t  7D 7T 7r   rF  c                   D    e Zd Zd	dZd	dZd	dZd	dZd	dZd	dZd	dZ	y)
TestClassifyMediumCommentsNc                    ddddddddddg}t        |d	
      }t        |      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d |D        }t        |      }	|	sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}}	d |D        }t        |      }	|	sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}}	y)u5   수집 모드에서 모든 MEDIUM이 DEFER로 분류.rg  zsql injection riskrn  rS  rX  rM  rN  rO  znaming convention issuero  2Tcollect_moder;  rE   rU  r   r   rV  rW  rY   Nc              3   ,   K   | ]  }|d    dk(    yw)classificationDEFERNr   .0rs  s     r   	<genexpr>zITestClassifyMediumComments.test_collect_mode_all_defer.<locals>.<genexpr>  s     Ba1%&'1B   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allr   c              3   ,   K   | ]  }|d    dk(    yw)pattern_matchedr{  Nr   r  s     r   r  zITestClassifyMediumComments.test_collect_mode_all_defer.<locals>.<genexpr>  s     Ja1&'>9Jr  r   r   rZ   r[   r\   r]   r^   r_   r`   ra   r  rc   commentsr   re   rm   r   rl   ro   rf   rj   rk   s              r   test_collect_mode_all_deferz6TestClassifyMediumComments.test_collect_mode_all_defer  s    "+?Y\]!+Df^ab
 +8$G6{a{a{ass66{aB6BBsBBBBBBBBBsBBBsBBBBBBBBBBBBBBJ6JJsJJJJJJJJJsJJJsJJJJJJJJJJJJJJr   c                    dddddddddddd	d
ddg}t        |d      }t        |      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d |D        }t        |      }	|	sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}}	|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   }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%}	||	k(  }|slt        j                  d|fd||	f      t        j                  |      t        j                  |	      dz  }
d d!|
iz  }t        t        j                  |            dx}x}}	y)&u.   FIX 패턴 매칭 확인 (collect_mode=False).rg  z$Possible sql injection in user inputdb.py10rx  zXSS vulnerability in templateztmpl.py20z race condition in counter updatez
counter.py30Frz  r$  rE   rU  r   r   rV  rW  rY   Nc              3   ,   K   | ]  }|d    dk(    ywr}  FIXNr   r  s     r   r  zETestClassifyMediumComments.test_fix_classification.<locals>.<genexpr>       @A1%&%/@r  r  r  r   r   r  sql injectionrP   rQ   rT   rU   rx   xssr;  race conditionr  )rc   r  r   re   rm   r   rl   ro   rf   rj   rk   ri   s               r   test_fix_classificationz2TestClassifyMediumComments.test_fix_classification  s:    "+Q[blpq!+JT]gkl!+MWcmqr

 +8%H6{a{a{ass66{a@@@s@@@@@@@@@s@@@s@@@@@@@@@@@@@@ay*+>>+>>>>+>>>+>>>>>>>>>>ay*+4u4+u4444+u444+444u4444444ay*+?/??+/?????+/????+???/????????r   c                    dddddddddddd	d
ddg}t        |d      }t        |      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d |D        }t        |      }	|	sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}}	y)u/   SKIP 패턴 매칭 확인 (collect_mode=False).rg  z!naming convention: use snake_casern  rS  rx  zMissing docstring for functionro  ry  zcode style: trailing whitespacerp  3Frz  r$  rE   rU  r   r   rV  rW  rY   Nc              3   ,   K   | ]  }|d    dk(    ywr}  SKIPNr   r  s     r   r  zFTestClassifyMediumComments.test_skip_classification.<locals>.<genexpr>       AQ1%&&0Ar  r  r  r   r  r  s              r   test_skip_classificationz3TestClassifyMediumComments.test_skip_classification
  s1    "+NX^hkl!+KU[ehi!+LV\fij

 +8%H6{a{a{ass66{aA&AAsAAAAAAAAAsAAAsAAAAAAAAAAAAAAr   c                 Z   dddddg}t        |d      }t        |      }d}||k(  }|st        j                  d	|fd
||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|d   d   }d}	||	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}	||	k(  }|slt        j                  d	|fd||	f      t        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}}	y)u   패턴 미매칭은 DEFER.rg  z*Consider refactoring this loop for clarityzx.pyrS  rx  Frz  rx   rE   rU  r   r   rV  rW  rY   Nr   r}  r~  rP   rQ   rT   rU   r  rQ  
r   r   rZ   r[   r\   r]   r^   r_   r`   ra   )rc   r  r   re   rm   r   rl   ro   ri   rj   rk   s              r   test_defer_classificationz4TestClassifyMediumComments.test_defer_classification  sb    "+Wagqtu
 +8%H6{a{a{ass66{aay)*5g5*g5555*g555*555g5555555ay*+1r1+r1111+r111+111r1111111r   c                 Z   ddddddddd	dg}t        |d
      }t        |      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u%   MEDIUM이 아닌 코멘트는 무시.rY  r  rn  rS  rx  rq  zminor stylero  ry  Frz  r   rE   rU  r   r   rV  rW  rY   Nr  )rc   r  r   re   rm   r   rl   ro   s           r   test_ignores_non_mediumz2TestClassifyMediumComments.test_ignores_non_medium  s      &RUVvsS
 +8%H6{a{a{ass66{ar   c           
         g d}t        |      D cg c]  \  }}dd| dd| dt        |      d }}}t        |d	      }t        |      }d
}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            dx}x}}d |D        }t        |      }|st	        j                  d|D cg c]  }|d   |d   f c}       dz   dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}|D cg c]  }|d   	 }}|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  }t	        j                  d| d       d!z   d"|iz  }t        t	        j                  |            d} yc c}}w c c}w c c}w )#u6   MEDIUM_FIX_PATTERNS 15개 패턴 전체 매칭 확인.)r  r  csrfauth
permissionznull pointerr  deadlockz	data loss
corruptionzenv variableconfigaccessibilitya11y
responsiverg  Issue about z	 detectedfile_.pyrx  Frz     rE   rU  r   r   rV  rW  rY   Nc              3   ,   K   | ]  }|d    dk(    ywr  r   r  s     r   r  zCTestClassifyMediumComments.test_all_fix_patterns.<locals>.<genexpr>7  r  r  zExpected all FIX, got: r  r}  .
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r  r   r   )z%(py0)s in %(py2)sr0  matched_patterns)rJ   rX   z	Pattern 'z' not matchedz
>assert %(py4)srS   	enumerater9   r   r   rZ   r[   r\   r]   r^   r_   r`   ra   r  _format_assertmsg)rc   fix_patternsir0  r  r   re   rm   r   rl   ro   rf   rj   rs  rk   r  @py_format3s                    r   test_all_fix_patternsz0TestClassifyMediumComments.test_all_fix_patterns(  s{   
 ",/
1 "\!I+FRWXYWZZ]P^hklmhno
 
 +8%H6{ b {b    {b      s   s      6   6   {   b       @@ 	
s@@ 	
@ 	
  &\b&cWX*;(<a@P>Q'R&c%de	
 	
	6	
 	
   	
 	
 		  	
 	
 		 A 	
 	
 		 A 	
 	
 	
 	
 	
 ;AAQA/0AA 	GA((FFF1(FFFFFF1FFF1FFFFFF(FFF(FFFFIaS*FFFFFFF	G
 'dAs   "L5?L;
7M c           
      ~   g d}t        |      D cg c]  \  }}dd| dd| dt        |      d }}}t        |d	      }t        |      }d
}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            dx}x}}d |D        }t        |      }|st	        j                  d|D cg c]  }|d   |d   f c}       dz   dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}yc c}}w c c}w )u6   MEDIUM_SKIP_PATTERNS 6개 패턴 전체 매칭 확인.)znaming conventionz
code style
formatting
whitespaceztype annotation	docstringrg  r  z in coder  r  rx  Frz     rE   rU  r   r   rV  rW  rY   Nc              3   ,   K   | ]  }|d    dk(    ywr  r   r  s     r   r  zDTestClassifyMediumComments.test_all_skip_patterns.<locals>.<genexpr>J  r  r  zExpected all SKIP, got: r  r}  r  r  r   r  )rc   skip_patternsr  r0  r  r   re   rm   r   rl   ro   rf   rj   rs  rk   s                  r   test_all_skip_patternsz1TestClassifyMediumComments.test_all_skip_patterns>  s   
 "-0
1 "\!H+EQVWXVYY\~gjklgmn
 
 +8%H6{a{a{ass66{aA&A 	
sAA 	
A 	
  ']c'dXY+<)=qAQ?R(S'd&ef	
 	
	6	
 	
   	
 	
 		  	
 	
 		 B 	
 	
 		 B 	
 	
 	
 	
 	

 (es   "H4?H:
r{   )
r|   r}   r~   r  r  r  r  r  r  r  r   r   r   rv  rv    s)    	K@	B2 G,
r   rv  c                       e Zd ZddZy)TestLogMediumCommentsNc                    t        t              j                         j                  j                  j                  dz  dz  dz  }g }|j	                         r$	 t        j                  |j                               }t        |      }dddddg}t        |       t        j                  |j                               }t        |      }d	}||z   }||k(  }	|	s7t        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"                  |      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}	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   }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)                  t        j*                  |dd             y# t
        j                  t        f$ r g }Y w xY w)uT   _log_medium_comments가 실제 로그 파일에 엔트리를 기록하는지 확인.	dashboardrd   zmedium-comments-log.jsonr~  ztest entry from unit testztest.pyr{  )r}  rM  rN  r  rx   rE   )z<%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == (%(py5)s + %(py7)s)r   updated_dataoriginal_count)rJ   rR   rK   rM   r   zassert %(py10)sr   NrM  rP   rQ   rT   rU   r}  r;  F)indentensure_ascii)r   __file__resolveparentr   r   r   r  JSONDecodeErrorr,  r   r   rZ   r[   r\   r]   r^   r_   r`   ra   r:   r[  )rc   log_pathexisting_datar  
classifiedr  re   r   r  r   ro   r   ri   rj   rk   rl   s                   r   test_log_writes_entriesz-TestLogMediumComments.test_log_writes_entriesP  sU   >))+2299@@;NQWWZtt.0??# $

8+=+=+? @ ]+ #*3!#1	

 	Z(zz("4"4"67< 6Q6NQ$66 $66666 $6666666s666s666666<666<666 666666N666N666Q6666666B'F+FF'+FFFFF'+FFFF'FFF+FFFFFFFFB 01<W<1W<<<<1W<<<1<<<W<<<<<<< 	DJJ}QUST) (('2 # "#s   #M M"!M"r{   )r|   r}   r~   r  r   r   r   r  r  O  s    Ur   r  c                   ,    e Zd ZddZddZddZddZy)TestAutoFixHighCommentsNc                    dddddg}t        |d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   }t        |      }d}	||	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                  |      t        j                  |	      dz  }dd|iz  }t	        t        j
                  |            dx}x}x}
}	d}|d   d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}|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}}y)uC   수집 모드에서는 프롬프트만 생성, 실행하지 않음.rY  SQL injection in queryr  42rx  	/tmp/fakeTrz  executedFr   z%(py1)s is %(py4)srQ   rT   rU   Npromptsrx   rE   r   r   r   r   r   r   r   )z%(py1)s in %(py4)s	diff_statrQ  rP   )
r   rZ   r[   r_   r`   ra   r   r\   r]   r^   )rc   r  r   ri   rj   re   rk   rl   rf   r   rm   r   r   s                r   test_collect_mode_no_executionz6TestAutoFixHighComments.test_collect_mode_no_executionp  s     )A7\`a
 );TRj!*U*!U****!U***!***U*******)$*s$%**%****%******s***s***$***%**********.&+A..w.....w....w...........k"(b("b(((("b((("(((b(((((((r   c                 .   dddddg}t        |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}}|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}y)u'   HIGH 코멘트가 없으면 빈 결과.rg  zstyle issuern  rS  rx  r  Trz  r  rE   rP   rQ   rT   rU   Nr  Fr   r  )r   rZ   r[   r_   r`   ra   )rc   r  r   ri   rj   re   rk   rl   s           r   test_no_high_commentsz-TestAutoFixHighComments.test_no_high_comments{  s     "=&RUV
 );TRi &B& B&&&& B&&& &&&B&&&&&&&j!*U*!U****!U***!***U*******r   c                    ddddddddddg}t        |d	d
      }|d   }t        |      }d}||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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}y)u7   여러 HIGH 코멘트에서 각각 프롬프트 생성.rY  zIssue 1rn  r  rx  zIssue 2ro  r  r  Trz  r  r;  rE   r   r   r   r   r   N)
r   r   rZ   r[   r\   r]   r^   r_   r`   ra   )	rc   r  r   rf   rj   r   rm   r   r   s	            r   #test_multiple_high_comments_promptsz;TestAutoFixHighComments.test_multiple_high_comments_prompts  s      FDQFDQ
 );TR)$*s$%**%****%******s***s***$***%**********r   c                 
   dddddg}t         j                  j                  d      5 }t        j                  g ddd	
      |_        t        |dd      }dd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   }	t        |	      }d}
||
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                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}x}}
j                   D cg c]  }t#        |       }}d |D        }	t%        |	      }|st        j&                  d      d z   d!t        j                         v st        j                  t$              rt        j                  t$              nd!t        j                  |	      t        j                  |      d"z  }t        t        j                  |            dx}	}d# |D        }	t%        |	      }|st        j&                  d$      d z   d!t        j                         v st        j                  t$              rt        j                  t$              nd!t        j                  |	      t        j                  |      d"z  }t        t        j                  |            dx}	}y# 1 sw Y    xY wc c}w )%uK   실행 모드에서 Claude CLI 호출 + git push가 실행되는지 확인.rY  r  r  r  rx  rP  r   z1 file changedrQ  rR  r  Frz  Nr  Tr   r  rQ   rT   rU   r  rx   rE   r   r   r   r   r   c              3   $   K   | ]  }d |v  
 yw)claudeNr   r  ss     r   r  zKTestAutoFixHighComments.test_execution_mode_calls_claude.<locals>.<genexpr>  s     4Q8q=4   zClaude CLI should be calledr  anyr   c              3   $   K   | ]  }d |v  
 yw)pushNr   r  s     r   r  zKTestAutoFixHighComments.test_execution_mode_calls_claude.<locals>.<genexpr>  s     216Q;2r  zgit push should be called)r\  r]  r^  r   r_  r`  r   rZ   r[   r_   r`   ra   r   r\   r]   r^   call_args_listr9   r  r  )rc   r  rc  r   ri   rj   re   rk   rl   rf   r   rm   r   r   rs  	call_strss                   r    test_execution_mode_calls_claudez8TestAutoFixHighComments.test_execution_mode_calls_claude  sG     )A7\`a
 ]]  !89 	XX$.$?$?RTU^nwy$zH!,X{QVWF	X j!)T)!T))))!T)))!)))T))))))))$*s$%**%****%******s***s***$***%**********%-%<%<=SV=	=4)4Ss44S4SS6SSSSSSSsSSSsSSS4SSS4SSSSSS2	2Os22O2OO4OOOOOOOsOOOsOOO2OOO2OOOOOO	X 	X >s   -M3N 3M=r{   )r|   r}   r~   r  r  r  r  r   r   r   r  r  o  s    	)++Pr   r  )9rD  builtinsr\   _pytest.assertion.rewrite	assertionrewriterZ   r   r;   r   sysunittest.mockr\  pathlibr   typingr   r  rN  insertr9   r  r  r  worktree_managerr   r   r   r   r	   r
   r   _WORKSPACE_ROOTr   r   tupledictr*  r   fixturer>   r@   r   r   r   r   r<   r   r   r   r   r  r  rF  rv  r  r  r   r   r   <module>r     s  
   	  
     3tH~--/66==> ?   x.((*1188??	_y(+@@	A8$s) 8d38nc&9 : 8 t   2) )(' '
' 
'&J &JR31 31njj  d S 3 4 0@% @%F +  +FB B8 8vQ7 Q7h\
 \
~U U@+P +Pr   