
    hi6                     *   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mZ ddlZ ee	j$                  j'                  dd            Z ee      e
j,                  vr"e
j,                  j/                  d ee             dedej0                  fd	Z ej4                         dedej0                  fd
       Z ej4                         dedefd       ZddgZdefdZ G d d      Z G d d      Z  G d d      Z! G d d      Z"y)ud  
test_dispatch_resume.py

dispatch.py --resume-from 옵션 단위 테스트 (스바로그 작성)

테스트 항목:
- resume_from=None이면 task_desc 변경 없음
- resume_from이 존재하는 파일 → task_desc 앞에 요약 prepend
- resume_from이 존재하지 않는 파일 → error 반환
- CLI argparse가 --resume-from 옵션을 정상 파싱
    N)Path)	MagicMockpatchWORKSPACE_ROOTz/home/jay/workspacetmp_pathreturnc                 >   t         }t        |      t        j                  vr)t        j                  j	                  dt        |             ddl}t        t        j                  j                               D ]  }|dk(  s	t        j                  |=  ddl	}| |_
        |S )uF   dispatch 모듈을 tmp_path를 WORKSPACE로 설정하여 로드한다.r   Ndispatch)
_WORKSPACEstrsyspathinsertprompts.team_promptslistmoduleskeysr
   	WORKSPACE)r   	workspacepromptsmod_name	_dispatchs        1/home/jay/workspace/tests/test_dispatch_resume.py_load_dispatch_with_workspacer   !   sx    I
9~SXX%3y>*))+, &z!H%& !"I    c                 v    | dz  j                  dd       | dz  dz  j                  dd       t        |       S )u:   격리된 WORKSPACE를 사용하는 dispatch 모듈 반환memoryT)parentsexist_oktasks)mkdirr   )r   s    r   dispatch_modr"   8   sD     t<7"))$)F(22r   c                 6    | dz  }|j                  dd       |S )u   임시 요약 파일 생성zsession_summary.mduU   이전 세션에서 A 모듈 구현 완료.
남은 작업: B 모듈 테스트 작성.utf-8encoding)
write_text)r   summarys     r   summary_filer)   @   s0     --Go  {B  CNr   zdispatch.subprocess.runzdispatch.generate_task_idc                      t               } d| j                  _        t        j                  ddi      | j                  _        d| j                  _        | S )u1   성공 응답을 반환하는 subprocess.run mockr   
session_idztest-session )r   return_value
returncodejsondumpsstdoutstderr)mocks    r   _make_mock_subprocessr4   R   sF    ;D#$D #zz<*HID!DKr   c                   8    e Zd ZdZdej
                  deddfdZy)TestResumeFromNoneu?   resume_from이 None이면 기존 동작과 동일해야 한다.r"   r   r   Nc                 2   d}g 	 d#dt         dt         dt         dt         dt        dt         ffd}t               }t        j                  |d	|
      5  t        j                  |d      5 }t        j                  |dd      5  t        d      5  d|j                  j
                  _        t        j                  ddi      |j                  j
                  _	        d|j                  j
                  _
        |j                  d|d        d d d        d d d        d d d        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   }||k(  }|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 # 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)$Nu   원래 작업 설명입니다.team_id	task_desctask_idlevelkwargsr   c                 (    j                  |       yNzfake-promptappendr8   r9   r:   r;   r<   captured_task_descs        r   _fake_build_promptz`TestResumeFromNone.test_task_desc_unchanged_when_resume_from_is_none.<locals>._fake_build_promptg        %%i0 r   build_promptside_effect
subprocessgenerate_task_idtask-1.1r-   !utils.bot_activity.set_bot_statusr   r+   testr,   	dev6-teamr8   r9   resume_from   ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenrB   py0py1py3py6assert %(py8)spy8z%(py1)s == %(py3)soriginal_task_descrX   rY   assert %(py5)spy5normal)r   objectr4   r   runr-   r.   r/   r0   r1   r2   r
   rU   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)selfr"   r   r^   rC   mock_subprocessmock_sp@py_assert2@py_assert5@py_assert4@py_format7@py_format9@py_assert0@py_format4@py_format6rB   s                  @r   1test_task_desc_unchanged_when_resume_from_is_nonezDTestResumeFromNone.test_task_desc_unchanged_when_resume_from_is_nonec   sK   =(* "		!	!	! 	! 		!
 	! 	! 01 LL~CUV	LL|4	8?LL'9
S	 56		 34GKK$$/.2jj,9O.PGKK$$+.0GKK$$+!!#,  " 	 	 	 	  %&+!+&!++++&!++++++s+++s++++++%+++%+++&+++!+++++++!!$:$(:::::$(::::$::::::(::::(::::::::#	 	 	 	 	 	 	 	sU   L+K?K2A;K%	K2K?L%K/*K22K<7K??L		LL)__name__
__module____qualname____doc__types
ModuleTyper   ry    r   r   r6   r6   `   s'    I!;eN^N^ !;jn !;sw !;r   r6   c                   `    e Zd ZdZdej
                  deddfdZdej
                  deddfdZy)TestResumeFromExistingFileuR   resume_from이 존재하는 파일이면 task_desc 앞에 요약을 prepend한다.r"   r)   r   Nc                    d}|j                  d      }d| d}g 	 d'dt        dt        dt        d	t        d
t        dt        ffd}t        j                  |d|      5  t        j                  |d      5 }t        j                  |dd      5  t        d      5  d|j                  j
                  _        t        j                  ddi      |j                  j
                  _	        d|j                  j
                  _
        |j                  d|t        |             d d d        d d d        d d d        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   }|j*                  } ||      }	|	sd"t        j$                  |      t        j$                  |      d#t        j                          v st        j"                  |      rt        j$                  |      nd#t        j$                  |	      d$z  }t'        t        j(                  |            d x}x}}	d   }|j,                  } ||      }	|	sd%t        j$                  |      t        j$                  |      d&t        j                          v st        j"                  |      rt        j$                  |      nd&t        j$                  |	      d$z  }t'        t        j(                  |            d x}x}}	y # 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)(Nu&   새 작업: B 모듈 테스트 작성.r$   r%   L   ## 이전 세션 요약
아래 요약을 읽고 이어서 작업하세요.



---

r8   r9   r:   r;   r<   r   c                 (    j                  |       yr>   r?   rA   s        r   rC   zZTestResumeFromExistingFile.test_summary_prepended_to_task_desc.<locals>._fake_build_prompt   rD   r   rE   rF   rH   rI   rJ   rK   rL   r   r+   rM   r,   rN   rO   rQ   rR   rT   rU   rB   rV   r[   r\   zLassert %(py6)s
{%(py6)s = %(py3)s
{%(py3)s = %(py1)s.startswith
}(%(py4)s)
}expected_prefix)rX   rY   py4rZ   zJassert %(py6)s
{%(py6)s = %(py3)s
{%(py3)s = %(py1)s.endswith
}(%(py4)s)
}r^   rb   )	read_textr   rd   r   re   r-   r.   r/   r0   r1   r2   r
   rU   rf   rg   rh   ri   rj   rk   rl   rm   
startswithendswith)rn   r"   r)   r^   summary_contentr   rC   rp   rq   rr   rs   rt   ru   rv   rB   s                 @r   #test_summary_prepended_to_task_descz>TestResumeFromExistingFile.test_summary_prepended_to_task_desc   s   
 F&00'0Bafuev  wF  G 	 )+ "		!	!	! 	! 		!
 	! 	! LL~CUV	LL|4	8?LL'9
S	 56		 34GKK$$/.2jj,9O.PGKK$$+.0GKK$$+!!#,- " 	 	 	 	  %&+!+&!++++&!++++++s+++s++++++%+++%+++&+++!+++++++!!$@$//@/@@@@@$@@@/@@@@@@@@@@@@@@@@@@@!!$A$--A-.@AAAAA$AAA-AAAAAA.@AAA.@AAAAAAAAAA%	 	 	 	 	 	 	 	sU   "O>9O1O$BO	"O$*O12O>O!O$$O.)O11O;	6O>>Pc                 d   d}|j                  d      }d| d| }g 	 d(dt        dt        dt        d	t        d
t        dt        ffd}t        j                  |d|      5  t        j                  |d      5 }t        j                  |dd      5  t        d      5  d|j                  j
                  _        t        j                  ddi      |j                  j
                  _	        d|j                  j
                  _
        |j                  d|t        |             ddd       ddd       ddd       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   }||k(  }|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# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w))u,   prepend된 task_desc의 전체 형식 검증u   새 작업: C 모듈 구현.r$   r%   r   r   r8   r9   r:   r;   r<   r   c                 (    j                  |       yr>   r?   rA   s        r   rC   zZTestResumeFromExistingFile.test_full_injected_task_desc_format.<locals>._fake_build_prompt   rD   r   rE   rF   rH   rI   rJ   rK   rL   r   r+   rM   r,   rN   rO   NrQ   rR   rT   rU   rB   rV   r[   r\   r]   expected_task_descr_   r`   ra   rb   )r   r   rd   r   re   r-   r.   r/   r0   r1   r2   r
   rU   rf   rg   rh   ri   rj   rk   rl   rm   )rn   r"   r)   r^   r   r   rC   rp   rq   rr   rs   rt   ru   rv   rw   rx   rB   s                   @r   #test_full_injected_task_desc_formatz>TestResumeFromExistingFile.test_full_injected_task_desc_format   s~    <&00'0BE  !"	$ 	 )+ "		!	!	! 	! 		!
 	! 	! LL~CUV	LL|4	8?LL'9
S	 56		 34GKK$$/.2jj,9O.PGKK$$+.0GKK$$+!!#,- " 	 	 	 	  %&+!+&!++++&!++++++s+++s++++++%+++%+++&+++!+++++++!!$:$(:::::$(::::$::::::(::::(::::::::#	 	 	 	 	 	 	 	sU   $L%;LL BK>	$L,L4L%>LLLLL"	L%%L/)	rz   r{   r|   r}   r~   r   r   r   r   r   r   r   r   r      sX    \)B&&)B )B 
	)BV-;&&-; -; 
	-;r   r   c                   `    e Zd ZdZdej
                  deddfdZdej
                  deddfdZy)TestResumeFromNonExistentFileuF   resume_from이 존재하지 않는 파일이면 error를 반환한다.r"   r   r   Nc                    t        |dz        }|j                  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}}g }
d}|d   }||v }|}|s|d   }||v }|}|s+t        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }|
j                  |       |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  }|
j                  |       t        j                  |
d      i z  }dd|iz  }t        t        j                  |            d x}x}
x}x}x}x}}y )Nzno_such_file.mdrN      작업 설명rO   statuserrorrR   z%(py1)s == %(py4)srX   r   assert %(py6)srZ   rP   messagein)z%(py3)s in %(py6)s)rY   rZ   z%(py8)sr\   )z%(py10)s in %(py13)snon_existent_path)py10py13z%(py15)spy15rQ   zassert %(py18)spy18)r   r
   rf   rg   rk   rl   rm   r@   rh   ri   rj   _format_boolop)rn   r"   r   r   resultrv   @py_assert3rq   @py_format5rt   @py_assert1rr   rs   @py_assert12@py_assert11ru   @py_format14@py_format16@py_format17@py_format19s                       r   &test_returns_error_when_file_not_foundzDTestResumeFromNonExistentFile.test_returns_error_when_file_not_found   sP   +< <=&&%) ' 
 h*7*7****7******7*******[}[y 1[} 11[&QZJ[[5FJ[5[[[[[} 1[[[}[[[ 1[[[[[[[5FJ[[[[[[[5F[[[5F[[[J[[[[[[[[[[[[[[[r   c                    t        |dz        }|j                  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   }||v }
|
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 )Nzmissing_summary.mdrN   r   rO   r   r   rR   r   r   r   rZ   r   r   )z%(py0)s in %(py3)sr   )rW   rY   r`   ra   )
r   r
   rf   rg   rk   rl   rm   rh   ri   rj   )rn   r"   r   r   r   rv   r   rq   r   rt   r   rw   rx   s                r    test_error_message_contains_pathz>TestResumeFromNonExistentFile.test_error_message_contains_path   s    +? ?@&&%) ' 
 h*7*7****7******7*******$*9$55 $55555 $5555555 555 555$55555555r   )	rz   r{   r|   r}   r~   r   r   r   r   r   r   r   r   r      sM    P
\5CSCS 
\_c 
\hl 
\
6U=M=M 
6Y] 
6bf 
6r   r   c                   x    e Zd ZdZdej
                  fdZdeddfdZddZ	deddfdZ
deddfd	Zdeddfd
Zy)TestCliResumeParsinguH   argparse가 --resume-from 옵션을 정상 파싱하는지 확인한다.r   c                    t        j                  d      }|j                  d      }|j                  dd       |j                  dd       |j                  d      }|j                  d	d       |j                  d
d       |j                  dd       |j                  dd       |j                  dd       |j                  dd       |j                  dd       |j                  dt         j                  d       |j                  dd       |j                  dt
        d       |j                  ddd       |j                  ddd       |S )uM   dispatch.main()에서 사용하는 argparse parser를 재생성하여 반환.u   작업 위임 디스패처)descriptionF)required--teamN)defaultz--composite--task--task-filez--levelrc   z--typecodingz	--sessionz	--projectz--chainz--refresh-mapT)actionr   z	--task-idz--phases)typer   z--force
store_true--resume-fromrP   )r   dest)argparseArgumentParseradd_mutually_exclusive_groupadd_argumentBooleanOptionalActionint)rn   parserteam_or_composite
task_groups       r   _get_parserz TestCliResumeParsing._get_parser  sZ    ((5QR"???O&&x&>&&}d&C88%8H
$7t<Ix8Hh7K6K6It4OH4R4R\`aK6JS$?IlEJOTNr   r   Nc                 P   t        |dz        }| j                         }|j                  ddddd|g      }|j                  }||k(  }|st	        j
                  d|fd||f      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
dz  }dd|iz  }t        t	        j                  |            dx}}y)uC   --resume-from 값이 args.resume_from에 올바르게 저장된다.
summary.mdr   rN   r   	   테스트r   rR   z3%(py2)s
{%(py2)s = %(py0)s.resume_from
} == %(py4)sargssummary_pathrW   py2r   r   rZ   N)r   r   
parse_argsrP   rf   rg   rh   ri   rj   rk   rl   rm   )	rn   r   r   r   r   r   r   r   rt   s	            r   !test_resume_from_parsed_correctlyz6TestCliResumeParsing.test_resume_from_parsed_correctly+  s    8l23!!#  (K;P_am!no/<////<//////t///t/////////<///<///////r   c                    | j                         }|j                  g 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}}y)	u4   --resume-from 미지정 시 기본값은 None이다.)r   rN   r   r   N)is)z3%(py2)s
{%(py2)s = %(py0)s.resume_from
} is %(py5)sr   rW   r   ra   assert %(py7)spy7)r   r   rP   rf   rg   rh   ri   rj   rk   rl   rm   )rn   r   r   r   rs   r   rx   @py_format8s           r    test_resume_from_default_is_nonez5TestCliResumeParsing.test_resume_from_default_is_none2  s    !!#  !OP'4'4''''4''''''t'''t''''''4'''''''r   c                    t        |dz        }| j                         }|j                  ddddd|g      }|j                  }d}||k(  }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      t	        j                  |      d
z  }dd|iz  }	t        t	        j                  |	            dx}x}}|j                  }||k(  }|st	        j
                  d|fd||f      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dz  }
dd|
iz  }t        t	        j                  |            dx}}y)u6   --resume-from은 --task와 함께 사용 가능하다.r   r   rN   r   u   작업 내용r   rR   )z,%(py2)s
{%(py2)s = %(py0)s.task
} == %(py5)sr   r   r   r   Nr   r   r   r   rZ   )r   r   r   taskrf   rg   rh   ri   rj   rk   rl   rm   rP   )rn   r   r   r   r   r   rs   r   rx   r   r   rt   s               r   &test_resume_from_can_be_used_with_taskz;TestCliResumeParsing.test_resume_from_can_be_used_with_task8  s,   8l23!!#  (K?Tceq!rsyy+O+yO++++yO++++++t+++t+++y+++O+++++++/<////<//////t///t/////////<///<///////r   c                 N   t        |dz        }t        |dz        }| j                         }|j                  ddd|d|g      }|j                  }||k(  }|st	        j
                  d|fd||f      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
dz  }dd|iz  }	t        t	        j                  |	            dx}}|j                  }||k(  }|st	        j
                  d|fd||f      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dz  }dd|iz  }	t        t	        j                  |	            dx}}y)u;   --resume-from은 --task-file과 함께 사용 가능하다.r   ztask.mdr   rN   r   r   rR   )z1%(py2)s
{%(py2)s = %(py0)s.task_file
} == %(py4)sr   task_file_pathr   r   rZ   Nr   r   )r   r   r   	task_filerf   rg   rh   ri   rj   rk   rl   rm   rP   )
rn   r   r   r   r   r   r   r   r   rt   s
             r   +test_resume_from_can_be_used_with_task_filez@TestCliResumeParsing.test_resume_from_can_be_used_with_task_file@  sJ   8l23X	12!!#  (KXgiu!vw~~/~////~//////t///t///~/////////////////<////<//////t///t/////////<///<///////r   c                    t         }t        |      t        j                  vr)t        j                  j	                  dt        |             t        t        j                  j                               D ]  }|dk(  s	t        j                  |=  ddl}t        |dz        }t        j                  }	 ddddd	d
|gt        _	        ddl
}|j                  |j                        }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      dz   d|iz  }t)        t        j*                  |            dx}	x}}
|t        _	        y# |t        _	        w xY w)uK   실제 dispatch.main()의 argparse에 --resume-from 옵션이 존재한다.r   r
   Nr   zdispatch.pyr   rN   r   r   r   rP   r   )z2%(py1)s in %(py5)s
{%(py5)s = %(py3)s.parameters
}sig)rX   rY   ra   u>   dispatch() 함수에 resume_from 파라미터가 없습니다.z
>assert %(py7)sr   )r   r   r   r   r   r   r   r   r
   argvinspect	signature
parametersrf   rg   rk   rh   ri   rj   _format_assertmsgrl   rm   )rn   r   r   r   r   r   original_argvr   r   rv   rs   rq   rx   r   s                 r   )test_dispatch_main_has_resume_from_optionz>TestCliResumeParsing.test_dispatch_main_has_resume_from_optionI  sG   	y>)HHOOAs9~.S[[--/0 	*H:%KK)	* 	%8l23 	%CH ##I$6$67C tCNNt=N2ttt=Nttt=ttttttCtttCtttNttt4tttttttt$CH}CHs   1DG G)r   N)rz   r{   r|   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r     sh    RX44 00$ 04 0(0t 0 00D 0T 0#%$ #%4 #%r   r   )#r}   builtinsrh   _pytest.assertion.rewrite	assertionrewriterf   r   r/   osr   r~   pathlibr   unittest.mockr   r   pytestenvirongetr   r   r   r   r   r   fixturer"   r)   _MOCK_PATCHESr4   r6   r   r   r   r   r   r   <module>r      s(  
    	 
   * "**..!13HIJ
z?#(("HHOOAs:'D U5E5E . 34 3E$4$4 3 3 4 D   y $; $;X[; [;F6 6B\% \%r   