
    \i$                     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ZddlmZ ddlmZ ddlZ ee
j"                  j%                  dd            dz  dz  Zd	 Z e       Zej,                  Z ej.                         d
        Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z ejB                  Z"ejF                  Z$d Z% G d d      Z& G d d      Z' G d  d!      Z( G d" d#      Z) G d$ d%      Z* G d& d'      Z+ejX                  Z,ejZ                  Z- G d( d)      Z. G d* d+      Z/ G d, d-      Z0 G d. d/      Z1 G d0 d1      Z2 G d2 d3      Z3 G d4 d5      Z4 G d6 d7      Z5 G d8 d9      Z6y):u  
test_task_timer.py

memory/task-timer.py 단위 테스트 (아르고스 작성)

테스트 항목:
- start_task(): 올바른 JSON 구조 반환 (status="started")
- end_task(): 올바른 JSON 구조 반환 (status="completed", duration 포함)
- end_task() 존재하지 않는 task_id → status="error"
- list_tasks(): 전체 / 상태별 조회
- _format_duration(): 초/분/시간 변환
- add_log_entry(): 일일 로그 파일 생성 확인

격리: TaskTimer(workspace_path=str(tmp_path)) 로 파일시스템 완전 격리
    N)datetime)PathWORKSPACE_ROOTz/home/jay/workspacememorytask-timer.pyc                      t         j                  j                  dt              } d}| |u}|st	        j
                  d|fd| |f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      dz  }t	        j                  dt               dz   d	|iz  }t        t	        j                  |            dx}}t         j                  j                  |       }| 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  }t	        j                  d      dz   d|iz  }t        t	        j                  |            dx}x}}| j                  j                  |       |S )u<   하이픈이 포함된 파일명을 importlib.util로 로드
task_timerNis notz%(py0)s is not %(py3)sspecpy0py3u$   모듈 스펙을 찾을 수 없음: z
>assert %(py5)spy5)z2%(py2)s
{%(py2)s = %(py0)s.loader
} is not %(py5)sr   py2r   u   모듈 로더가 없음z
>assert %(py7)spy7)	importlibutilspec_from_file_location_TIMER_MODULE_PATH
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationmodule_from_specloaderexec_module)	r   @py_assert2@py_assert1@py_format4@py_format6module@py_assert4@py_assert3@py_format8s	            ,/home/jay/workspace/tests/test_task_timer.py_load_task_timer_moduler.   #   s(   >>11,@RSDX4tXXX4tXXXXXX4XXX4XXXtXXXCDVCWXXXXXXX^^,,T2F;;=d=;d"===;d======4===4===;===d===$========KKF#M    c                 X    | dz  j                  dd       t        t        |             S )u<   tmp_path를 workspace로 사용하는 TaskTimer 인스턴스r   Tparentsexist_okworkspace_path)mkdir	TaskTimerstr)tmp_paths    r-   timerr:   6   s+     t<CM22r/   c                   F    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zy)TestStartTasku?   start_task()가 올바른 JSON 구조를 반환하는지 확인c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )	Ntask-1.1statusstarted==z%(py1)s == %(py4)spy1py4assert %(py6)spy6
start_taskr   r   r   r    r!   selfr:   result@py_assert0r+   r%   @py_format5@py_format7s           r-   test_returns_status_startedz)TestStartTask.test_returns_status_startedE   d    !!*-h,9,9,,,,9,,,,,,9,,,,,,,r/   c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y Nr>   task_idrA   rC   rD   rG   rH   rI   rK   s           r-   test_returns_task_idz"TestStartTask.test_returns_task_idI   sd    !!*-i .J. J.... J... ...J.......r/   c                    |j                  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}}t        j                  |d          y 	Nr>   
start_timeinz%(py1)s in %(py3)srM   rE   r   assert %(py5)sr   )rJ   r   r   r   r   r   r   r    r!   r   fromisoformatrL   r:   rM   rN   r%   r'   r(   s          r-   test_returns_start_timez%TestStartTask.test_returns_start_timeM   s~    !!*-%|v%%%%|v%%%|%%%%%%v%%%v%%%%%%%vl34r/   c                    |j                  ddd       |dz  dz  }|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}}t        j                  |j                               }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}	}y )Nr>   	dev1-team   테스트 작업team_iddescriptionr   task-timers.jsonAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}
timer_filer   r   rF   tasksrZ   z%(py1)s in %(py4)srD   rG   rH   )rJ   existsr   r   r   r   r   r    r!   jsonloads	read_textr   )rL   r:   r9   rj   r&   r+   rO   datarN   r%   rP   s              r-   test_task_written_to_timer_filez-TestStartTask.test_task_written_to_timer_fileS   s    [FXY(+==
  " """"""""z"""z""" """"""""""zz*..01*T']*z]****z]***z***]*******r/   c                    |j                  d       |dz  dz  }t        j                  |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}}y )Ntask-2.1r   rh   rl   r?   runningrA   rC   rD   rG   rH   	rJ   ro   rp   rq   r   r   r   r    r!   
rL   r:   r9   rj   rr   rN   r+   r%   rO   rP   s
             r-   #test_task_status_is_running_in_filez1TestStartTask.test_task_status_is_running_in_fileZ   s    $(+==
zz*..01G}Z(2?i?2i????2i???2???i???????r/   c                 ,   |j                  d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 )Nr>   	dev2-teamu
   API 개발re   r?   r@   rA   rC   rD   rG   rH   rI   rK   s           r-   )test_start_task_with_team_and_descriptionz7TestStartTask.test_start_task_with_team_and_description`   sk    !!*k|!\h,9,9,,,,9,,,,,,9,,,,,,,r/   c                    |j                  dddd       |dz  dz  }t        j                  |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}}y )Nr>   rc   u   작업myproj)rf   rg   
project_idr   rh   rl   r   rA   rC   rD   rG   rH   rw   rx   s
             r-   test_start_task_with_project_idz-TestStartTask.test_start_task_with_project_idd   s    [h[cd(+==
zz*..01G}Z(6B(B6(BBBB6(BBB6BBB(BBBBBBBr/   c                    |j                  d       |dz  dz  }t        j                  |j                               }|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}}y )Nr>   r   rh   rl   end_timeisz%(py1)s is %(py4)srD   rG   rH   rw   rx   s
             r-   *test_start_task_end_time_is_none_initiallyz8TestStartTask.test_start_task_end_time_is_none_initiallyj   s    $(+==
zz*..01G}Z(4<<4<<<<4<<<4<<<<<<<<<<r/   c                    |j                  d       |dz  dz  }t        j                  |j                               }|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}}y )Nr>   r   rh   rl   duration_secondsr   r   rD   rG   rH   rw   rx   s
             r-   *test_start_task_duration_is_none_initiallyz8TestStartTask.test_start_task_duration_is_none_initiallyp   s    $(+==
zz*..01G}Z();<DD<DDDD<DDD<DDDDDDDDDDr/   N)__name__
__module____qualname____doc__rQ   rV   ra   rs   ry   r|   r   r   r    r/   r-   r<   r<   B   s5    I-/5+@-C=Er/   r<   c                   "    e Zd ZdZd Zd Zd Zy)TestStartTaskCompletedGuardu@   completed 상태 task 덮어쓰기 방지 테스트 (task-464.1)c                    |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}g }d
}|d   }	|	j                  }
 |
       }||v }|}|s d}|d   }|j                  } |       }||v }|}|sNt        j                  d|fd||f      t        j                  |      t        j                  |	      t        j                  |
      t        j                  |      dz  }dd|iz  }|j                  |       |st        j                  dfdf      t        j                  |      t        j                        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}x}x}x}}y	)u<   이미 completed된 task_id로 start 시도 → error 반환r>   r?   errorrA   rC   rD   rG   rH   N	completedreasonzalready completedrZ   zF%(py3)s in %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py6)s.lower
}()
}r   rH   py8py10%(py12)spy12zJ%(py15)s in %(py22)s
{%(py22)s = %(py20)s
{%(py20)s = %(py18)s.lower
}()
}py15py18py20py22%(py24)spy24   assert %(py27)spy27)
rJ   end_taskr   r   r   r    r!   lowerappend_format_booloprL   r:   rM   rN   r+   r%   rO   rP   r&   @py_assert5@py_assert7@py_assert9r*   @py_assert14@py_assert17@py_assert19@py_assert21@py_assert16@py_format11@py_format13@py_format23@py_format25@py_format26@py_format28s                           r-   'test_start_completed_task_returns_errorzCTestStartTaskCompletedGuard.test_start_completed_task_returns_errorz   s   $z"!!*-h*7*7****7******7*******i{ifX.i.44i46i{66i:MiQWX`QaiQaQgQgiQgQii:MQi:iiiii{6iii{iii.iii4iii6iiiiiii:MQiiii:MiiiQaiiiQgiiiQiiiiiiiiiiiiiiiir/   c                    |j                  ddd       |j                  d       |j                  ddd       |dz  dz  }d	d
l} |j                  |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   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
)u7   completed task start 시도 후 원본 데이터 유지r>   rc   u   원본 작업re   r{      덮어쓰기 시도r   rh   r   Nrl   r?   r   rA   rC   rD   rG   rH   rf   
rJ   r   ro   rp   rq   r   r   r   r    r!   )rL   r:   r9   rj   ro   rr   rN   r+   r%   rO   rP   s              r-   ,test_start_completed_task_preserves_originalzHTestStartTaskCompletedGuard.test_start_completed_task_preserves_original   s   [oVz"[F[\(+==
tzz*..01G}Z(2AkA2kAAAA2kAAA2AAAkAAAAAAAG}Z(3B{B3{BBBB3{BBB3BBB{BBBBBBBr/   c                 H   |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d	x}x}}y	)
u1   기존 running 중복 등록 거부 동작 유지r>   r?   already_runningrA   rC   rD   rG   rH   NrI   rK   s           r-    test_running_task_still_rejectedz<TestStartTaskCompletedGuard.test_running_task_still_rejected   sv    $!!*-h4#44#44444#4444444#44444444r/   N)r   r   r   r   r   r   r   r   r/   r-   r   r   w   s    Jj
C5r/   r   c                   L    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zy)TestEndTasku=   end_task()가 올바른 JSON 구조를 반환하는지 확인c                 H   |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y 	Nr>   r?   r   rA   rC   rD   rG   rH   rJ   r   r   r   r   r    r!   rK   s           r-   test_returns_status_completedz)TestEndTask.test_returns_status_completed   sp    $
+h.;.;....;......;.......r/   c                 H   |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y rT   r   rK   s           r-   rV   z TestEndTask.test_returns_task_id   sp    $
+i .J. J.... J... ...J.......r/   c                    |j                  d       |j                  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}}t        j                  |d          y rX   rJ   r   r   r   r   r   r   r   r    r!   r   r_   r`   s          r-   ra   z#TestEndTask.test_returns_start_time   s    $
+%|v%%%%|v%%%|%%%%%%v%%%v%%%%%%%vl34r/   c                    |j                  d       |j                  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}}t        j                  |d          y )	Nr>   r   rZ   r\   rM   r]   r^   r   r   r`   s          r-   test_returns_end_timez!TestEndTask.test_returns_end_time   s    $
+#zV####zV###z######V###V#######vj12r/   c                 .   |j                  d       |j                  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}}|d   }t        t        f}t        ||      }	|	sd	d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      t        j                  |      t        j                  |	      d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 )Nr>   r   rZ   r\   rM   r]   r^   r   z5assert %(py6)s
{%(py6)s = %(py0)s(%(py2)s, %(py4)s)
}
isinstancer   r   rF   rH   r   >=)z%(py1)s >= %(py4)srD   rG   rH   )rJ   r   r   r   r   r   r   r   r    r!   intfloatr   )rL   r:   rM   rN   r%   r'   r(   r&   r+   r   rP   rO   s               r-   test_returns_duration_secondsz)TestEndTask.test_returns_duration_seconds   sC   $
+!+!V++++!V+++!++++++V+++V+++++++ !34CsElCz4lCCCCCCCCzCCCzCCC4CCClCCCCCCCCCC().Q.)Q....)Q...)...Q.......r/   c                 X   |j                  d       |j                  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}}|d   }t        |t              }|sd	d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d x}}|d   }t        |      }	d}
|	|
kD  }|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 )Nr>   duration_humanrZ   r\   rM   r]   r^   r   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}r   r8   )r   r   r   r   r   )>)z/%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} > %(py7)slenr   r   rF   r   assert %(py9)spy9)rJ   r   r   r   r   r   r   r   r    r!   r   r8   r   )rL   r:   rM   rN   r%   r'   r(   r&   r*   r+   @py_assert6r   r,   @py_format10s                 r-   test_returns_duration_humanz'TestEndTask.test_returns_duration_human   s   $
+)6))))6)))))))))6)))6))))))) !128z2C88888888z888z8882888888C888C8888888888*+0s+,0q0,q0000,q000000s000s000+000,000q0000000r/   c                    |j                  d       |j                  d       |dz  dz  }t        j                  |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}}y )Nr>   r   rh   rl   r?   r   rA   rC   rD   rG   rH   r   rx   s
             r-    test_task_status_updated_in_filez,TestEndTask.test_task_status_updated_in_file   s    $z"(+==
zz*..01G}Z(2AkA2kAAAA2kAAA2AAAkAAAAAAAr/   c                    |j                  d       |j                  d       |dz  dz  dz  }|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}}y)	uC   end_task() 호출 시 .done 이벤트 파일이 생성되어야 함r>   r   eventstask-1.1.doneri   	done_filerk   N)
rJ   r   rn   r   r   r   r   r   r    r!   )rL   r:   r9   r   r&   r+   rO   s          r-   test_done_event_file_createdz(TestEndTask.test_done_event_file_created   s    $z"x'(2_D	!!!!!!!!!y!!!y!!!!!!!!!!!!!r/   c                 8   |j                  d       |j                  d       |dz  dz  dz  }t        j                  |j	                               }|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      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            d x}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            d x}}y )Nr>   r   r   r   rU   rA   rC   rD   rG   rH   r   rZ   r\   
event_datar]   r^   r   r   )rJ   r   ro   rp   rq   r   r   r   r    r!   r   r   r   )rL   r:   r9   r   r   rN   r+   r%   rO   rP   r'   r(   s               r-   (test_done_event_file_contains_valid_jsonz4TestEndTask.test_done_event_file_contains_valid_json   sN   $z"x'(2_D	ZZ	 3 3 56
)$2
2$
2222$
222$222
2222222'zZ''''zZ'''z''''''Z'''Z'''''''!/!Z////!Z///!//////Z///Z///////r/   c                 F   |j                  d       |j                  d      }t        j                  |d         }t        j                  |d         }||k\  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |      rt	        j                  |      nddz  }d	d
|iz  }t        t	        j                  |            d }y )Nr>   rY   r   r   )z%(py0)s >= %(py2)sendstartr   r   assert %(py4)srF   )rJ   r   r   r_   r   r   r   r   r   r   r    r!   )rL   r:   rM   r   r   r&   @py_format3rO   s           r-   !test_end_time_is_after_start_timez-TestEndTask.test_end_time_is_after_start_time   s    $
+&&vl';<$$VJ%78e|sesseer/   N)r   r   r   r   r   rV   ra   r   r   r   r   r   r   r   r   r/   r-   r   r      s8    G/
/
53/1B"0r/   r   c                   "    e Zd ZdZd Zd Zd Zy)TestEndTaskNotFounduI   존재하지 않는 task_id로 end_task() 호출 시 에러 응답 검증c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )	Ntask-nonexistentr?   r   rA   rC   rD   rG   rH   )r   r   r   r   r    r!   rK   s           r-   test_returns_status_errorz-TestEndTaskNotFound.test_returns_status_error   sc     23h*7*7****7******7*******r/   c                 L   |j                  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}}g }d	}|d   }||v }	|	}|	s d
}
|d   }|j                  } |       }|
|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      t        j                  |
      t        j                        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}x}}y )Nr   r   rZ   r\   rM   r]   r^   r   nonexistentz	not found)z%(py3)s in %(py6)s)r   rH   z%(py8)sr   )zJ%(py11)s in %(py18)s
{%(py18)s = %(py16)s
{%(py16)s = %(py14)s.lower
}()
})py11py14py16r   z%(py20)sr   r   zassert %(py23)spy23)r   r   r   r   r   r   r   r    r!   r   r   r   )rL   r:   rM   rN   r%   r'   r(   r&   r   r*   @py_assert10@py_assert13@py_assert15r   @py_assert12rP   @py_format9@py_format19@py_format21@py_format22@py_format24s                        r-   #test_error_response_contains_reasonz7TestEndTaskNotFound.test_error_response_contains_reason   sQ    23!x6!!!!x6!!!x!!!!!!6!!!6!!!!!!![}[x 0[} 00[K[6(CS[CSCYCY[CYC[[KC[4[[[[[} 0[[[}[[[ 0[[[[[[[KC[[[[K[[[CS[[[CY[[[C[[[[[[[[[[[[[[[[r/   c                    |j                  d       |dz  dz  dz  }|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}x}}y )Nz
task-ghostr   r   ztask-ghost.donezEassert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r   rk   )	r   rn   r   r   r   r   r   r    r!   )rL   r:   r9   r   r&   r+   r   r(   s           r-   "test_no_done_file_created_on_errorz6TestEndTaskNotFound.test_no_done_file_created_on_error   s    |$x'(25FF	##%#%%%%%%%%%%%9%%%9%%%#%%%%%%%%%%r/   N)r   r   r   r   r   r  r  r   r/   r-   r   r      s    S+\
&r/   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestGetTaskStatusuF   get_task_status()가 올바른 작업 상태를 반환하는지 확인c                 p   |j                  d      }d }||u }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )Nr   r   z%(py0)s is %(py3)srM   r   r^   r   	get_task_statusr   r   r   r   r   r   r    r!   rL   r:   rM   r%   r&   r'   r(   s          r-   &test_returns_none_for_nonexistent_taskz8TestGetTaskStatus.test_returns_none_for_nonexistent_task   sk    &&'9:v~vvvr/   c                    |j                  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                  |      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 )Nr>   r
   r   rM   r   r^   r   r?   rv   rA   rC   rD   rG   rH   
rJ   r  r   r   r   r   r   r   r    r!   rL   r:   rM   r%   r&   r'   r(   rN   r+   rO   rP   s              r-   test_returns_running_statusz-TestGetTaskStatus.test_returns_running_status  s    $&&z2!!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!h,9,9,,,,9,,,,,,9,,,,,,,r/   c                 j   |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y r   )rJ   r   r  r   r   r   r    r!   rK   s           r-   test_returns_completed_statusz/TestGetTaskStatus.test_returns_completed_status	  s~    $z"&&z2h.;.;....;......;.......r/   c                 N   |j                  ddd       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            d x}x}}|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 )Nr>   rc   	   테스트re   rU   rA   rC   rD   rG   rH   rf   rg   )rJ   r  r   r   r   r    r!   rK   s           r-   test_returns_task_data_dictz-TestGetTaskStatus.test_returns_task_data_dict  s   [kR&&z2i .J. J.... J... ...J.......i /K/ K//// K/// ///K///////m$33$3333$333$3333333333r/   N)r   r   r   r   r  r  r  r  r   r/   r-   r  r     s    P-/4r/   r  c                   @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestListTasksuD   list_tasks()가 올바르게 작업 목록을 반환하는지 확인c                 $   |j                         }|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   }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totalr   rA   rC   rD   rG   rH   rl   )
list_tasksr   r   r   r    r!   rK   s           r-   test_empty_list_initiallyz'TestListTasks.test_empty_list_initially  s    !!#g#!#!####!######!#######g$"$"$$$$"$$$$$$"$$$$$$$r/   c                 h   |j                  d       |j                  d       |j                         }|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 
Nr>   ru   r     rA   rC   rD   rG   rH   rJ   r  r   r   r   r    r!   rK   s           r-   test_total_count_after_startz*TestListTasks.test_total_count_after_start$  sz    $$!!#g#!#!####!######!#######r/   c                    |j                  d       |j                  d       |j                  d       |j                         }|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 r  rJ   r   r  r   r   r   r    r!   rK   s           r-   test_list_all_tasksz!TestListTasks.test_list_all_tasks*  s    $$z"!!#g#!#!####!######!#######r/   c                    |j                  d       |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      d	z  }d
d|iz  }t        t        j                  |            d x}x}}|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 )Nr>   ru   rv   r?   r  r   rA   rC   rD   rG   rH   rl   r   rU   r#  rK   s           r-   test_list_filter_by_runningz)TestListTasks.test_list_filter_by_running1  s    $$z"!!!3g#!#!####!######!#######gq!),:
:,
::::,
:::,:::
:::::::r/   c                    |j                  d       |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      d	z  }d
d|iz  }t        t        j                  |            d x}x}}|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 )Nr>   ru   r   r&  r  r   rA   rC   rD   rG   rH   rl   r   rU   r#  rK   s           r-   test_list_filter_by_completedz+TestListTasks.test_list_filter_by_completed9  s    $$z"!!!5g#!#!####!######!#######gq!),:
:,
::::,
:::,:::
:::::::r/   c                    |j                         }d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y )	Nr  rZ   r\   rM   r]   r^   r   rl   )	r  r   r   r   r   r   r   r    r!   r`   s          r-   0test_list_returns_dict_with_total_and_tasks_keysz>TestListTasks.test_list_returns_dict_with_total_and_tasks_keysA  s    !!# w&    w&   w      &   &        w&    w&   w      &   &       r/   c                 :   |j                  ddd       |j                         }|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}}d}||v }|st        j                  d|fd	||f      t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd	||f      t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}y)u>   각 task 항목에 필수 필드가 포함되어 있어야 함r>   rc   r  re   rl   r   rU   rZ   r\   taskr]   r^   r   Nr?   rY   )
rJ   r  r   r   r   r   r   r   r    r!   )rL   r:   rM   r-  rN   r%   r'   r(   s           r-   test_list_tasks_data_structurez,TestListTasks.test_list_tasks_data_structureF  s>   [kR!!#gq! yD    yD   y      D   D       x4x4x44#|t####|t###|######t###t#######r/   c                 J   |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            d x}x}}|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 )Nr>   r   r&  r  r   rA   rC   rD   rG   rH   rl   r   rK   s           r-   /test_list_with_nonexistent_status_returns_emptyz=TestListTasks.test_list_with_nonexistent_status_returns_emptyO  s    $!!!7g#!#!####!######!#######g$"$"$$$$"$$$$$$"$$$$$$$r/   N)r   r   r   r   r  r!  r$  r'  r)  r+  r.  r0  r   r/   r-   r  r    s-    N%
$$;;!
$%r/   r  c                       e Zd ZdZ ej
                  d      d        Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zy)TestFormatDurationu_   _format_duration()이 초/분/시간을 올바른 한국어 문자열로 변환하는지 확인T)autousec                     || _         y N)r:   )rL   r:   s     r-   _timer_instancez"TestFormatDuration._timer_instance^  s	    
r/   c           	      D   | j                   }|j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}}y )	N      30초rA   zr%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.timer
}._format_duration
}(%(py6)s)
} == %(py11)srL   r   r   rF   rH   r   r   assert %(py13)spy13
r:   _format_durationr   r   r   r   r   r   r    r!   	rL   r&   r+   r   r   r   r   @py_format12@py_format14s	            r-   test_seconds_under_60z(TestFormatDuration.test_seconds_under_60b      zz9z**929*2.9'9.'9999.'999999t999t999z999*9992999.999'99999999r/   c           	      D   | j                   }|j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}}y )	Nr   u   0초rA   r:  rL   r;  r<  r=  r>  r@  s	            r-   test_seconds_zeroz$TestFormatDuration.test_seconds_zeroe  s    zz7z**717*1-77-7777-777777t777t777z777*7771777-77777777777r/   c           	      D   | j                   }|j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}}y )	N;   u   59초rA   r:  rL   r;  r<  r=  r>  r@  s	            r-   test_seconds_59z"TestFormatDuration.test_seconds_59h  rD  r/   c                    | j                   j                  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}}d	}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y )
N<   u   분rZ   r\   rM   r]   r^   r      1분
r:   r?  r   r   r   r   r   r   r    r!   rL   rM   rN   r%   r'   r(   s         r-   %test_seconds_exactly_60_is_one_minutez8TestFormatDuration.test_seconds_exactly_60_is_one_minutek  s    ,,R0uuuvvvr/   c                    | j                   j                  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}}d	}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y )
NZ   rL  rZ   r\   rM   r]   r^   r   r9  rM  rN  s         r-   test_minutes_and_secondsz+TestFormatDuration.test_minutes_and_secondsp  s    ,,R0vvv w&    w&   w      &   &       r/   c                    | j                   j                  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}}y )	Nx   u   2분rZ   r\   rM   r]   r^   r   rM  rN  s         r-   test_minutes_without_secondsz/TestFormatDuration.test_minutes_without_secondsu  so    ,,S1vvvr/   c                    | j                   j                  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}}d	}||v}|st        j                  d
|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y )Ni  u   59분rZ   r\   rM   r]   r^   r   u   시간)not in)z%(py1)s not in %(py3)srM  rN  s         r-   test_just_under_one_hourz+TestFormatDuration.test_just_under_one_houry  s    ,,T2 w&    w&   w      &   &       %xv%%%%xv%%%x%%%%%%v%%%v%%%%%%%r/   c                    | j                   j                  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}}y )	Ni     1시간rZ   r\   rM   r]   r^   r   rM  rN  s         r-   test_exactly_one_hourz(TestFormatDuration.test_exactly_one_hour~  o    ,,T2"yF""""yF"""y""""""F"""F"""""""r/   c                    | j                   j                  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}}d	}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y )
Ni  rZ  rZ   r\   rM   r]   r^   r   u   30분rM  rN  s         r-   test_one_hour_thirty_minutesz/TestFormatDuration.test_one_hour_thirty_minutes  s    ,,T2"yF""""yF"""y""""""F"""F""""""" w&    w&   w      &   &       r/   c                    | j                   j                  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}}y )	Ni   u   2시간rZ   r\   rM   r]   r^   r   rM  rN  s         r-   test_two_hoursz!TestFormatDuration.test_two_hours  r\  r/   c                 8   | j                   }|j                  }d} ||      }t        |t              }|s[ddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d x}x}x}x}}y )Nd   zassert %(py12)s
{%(py12)s = %(py0)s(%(py9)s
{%(py9)s = %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.timer
}._format_duration
}(%(py7)s)
}, %(py10)s)
}r   rL   r8   )r   rE   r   r   r   r   r   r   )r:   r?  r   r8   r   r   r   r   r   r    r!   )rL   r%   r*   r   @py_assert8@py_assert11r   s          r-   test_format_returns_stringz-TestFormatDuration.test_format_returns_string  s    **@*55@c@5c:@z:C@@@@@@@@z@@@z@@@@@@$@@@$@@@*@@@5@@@c@@@:@@@@@@C@@@C@@@@@@@@@@@r/   N)r   r   r   r   pytestfixturer6  rC  rF  rI  rO  rR  rU  rX  r[  r^  r`  re  r   r/   r-   r2  r2  [  sZ    iV^^D! ":8: 
!
 &
#!
#Ar/   r2  c                   ^    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zy)TestAddLogEntryuU   add_log_entry()가 일일 로그 파일을 올바르게 생성/추가하는지 확인c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )	N   테스트 메시지r?   loggedrA   rC   rD   rG   rH   add_log_entryr   r   r   r    r!   rK   s           r-   test_returns_status_loggedz*TestAddLogEntry.test_returns_status_logged  se    $$%:;h+8+8++++8++++++8+++++++r/   c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )Nrk  messagerA   rC   rD   rG   rH   rm  rK   s           r-   test_returns_messagez$TestAddLogEntry.test_returns_message  si    $$%:;i 9$99 $99999 $9999 999$99999999r/   c                 *   |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}}y )
Nr  note
entry_typetyperA   rC   rD   rG   rH   rm  rK   s           r-   test_returns_entry_typez'TestAddLogEntry.test_returns_entry_type  se    $$[V$Df~''~''''~'''~''''''''''r/   c                    |j                  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}}t        j                  |d          y )	Nr  	timestamprZ   r\   rM   r]   r^   r   )rn  r   r   r   r   r   r   r    r!   r   r_   r`   s          r-   test_returns_timestampz&TestAddLogEntry.test_returns_timestamp  s~    $$[1${f$$$${f$$${$$$$$$f$$$f$$$$$$$vk23r/   c                    |j                  d       |dz  dz  }t        |j                  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 )Nu   로그 항목 테스트r   daily*.mdr   rA   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   	log_filesr   rE   r   rH   assert %(py8)sr   )rn  listglobr   r   r   r   r   r   r   r    r!   
rL   r:   r9   	daily_dirr  r%   r   r*   rP   r   s
             r-   test_creates_daily_log_filez+TestAddLogEntry.test_creates_daily_log_file  s    56x''1	/0	9~""~""""~""""""s"""s""""""9"""9"""~""""""""""r/   c                    |j                  d       t        j                         j                  d      }|dz  dz  }|| dz  }|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}}y )	Nu   날짜 테스트%Y-%m-%dr   r}  .mdri   expected_filerk   )rn  r   nowstrftimern   r   r   r   r   r   r    r!   )	rL   r:   r9   	today_strr  r  r&   r+   rO   s	            r-   !test_daily_log_file_name_is_todayz1TestAddLogEntry.test_daily_log_file_name_is_today  s    ./LLN++J7	x''1	!yk$55##%#%%%%%%%%}%%%}%%%#%%%%%%%%%%r/   c                    |j                  d       t        j                         j                  d      }|dz  dz  | dz  }|j	                  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}}y )Nu!   고유한 메시지 내용 XYZ123r  r   r}  r  utf-8encodingrZ   r\   contentr]   r^   r   rn  r   r  r  rq   r   r   r   r   r   r   r    r!   
rL   r:   r9   r  log_filer  rN   r%   r'   r(   s
             r-   test_log_file_contains_messagez.TestAddLogEntry.test_log_file_contains_message  s    ?@LLN++J7	h&0i[3DD$$g$62=2g====2g===2======g===g=======r/   c                 b   |j                  d       |j                  d       t        j                         j                  d      }|dz  dz  | dz  }|j	                  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}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}y )Nu   첫 번째 메시지u   두 번째 메시지r  r   r}  r  r  r  rZ   r\   r  r]   r^   r   r  r  s
             r-   "test_multiple_log_entries_appendedz2TestAddLogEntry.test_multiple_log_entries_appended  s   2323LLN++J7	h&0i[3DD$$g$6%0%0000%000%0000000000000000%0%0000%000%0000000000000000r/   c                 *   |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   }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 )Nu   팀 위임 기록dispatchru  r?   rl  rA   rC   rD   rG   rH   rw  rm  rK   s           r-   test_dispatch_type_log_entryz,TestAddLogEntry.test_dispatch_type_log_entry  s    $$%8Z$Ph+8+8++++8++++++8+++++++f~++~++++~+++~++++++++++r/   c                    |j                  dd       t        j                         j                  d      }|dz  dz  | dz  }|j	                  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}}y )Nu   중요 의사결정 내용decisionru  r  r   r}  r  r  r  rZ   r\   r  r]   r^   r   r  r  s
             r-   test_decision_type_log_entryz,TestAddLogEntry.test_decision_type_log_entry  s    8ZPLLN++J7	h&0i[3DD$$g$6+6+w6666+w666+666666w666w6666666r/   c                    |j                  dd       t        j                         j                  d      }|dz  dz  | dz  }|j	                  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}}y )Nu   시스템 설정 변경systemru  r  r   r}  r  r  r  rZ   r\   r  r]   r^   r   r  r  s
             r-   test_system_type_log_entryz*TestAddLogEntry.test_system_type_log_entry  s    5(KLLN++J7	h&0i[3DD$$g$6(3(G3333(G333(333333G333G3333333r/   c                    |j                  ddd       |dz  dz  }t        |j                  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)uR   start_task()에 team_id 또는 description이 있으면 일일 로그에 기록됨r>   rc   u   로그 테스트re   r   r}  r~  r   rA   r  r   r  r  r  r   N)rJ   r  r  r   r   r   r   r   r   r   r    r!   r  s
             r-   #test_start_task_writes_to_daily_logz3TestAddLogEntry.test_start_task_writes_to_daily_log  s    [FXYx''1	/0	9~""~""""~""""""s"""s""""""9"""9"""~""""""""""r/   c                    |j                  ddd       |j                  d       t        j                         j	                  d      }|dz  dz  | dz  }|j                  d	
      }g }d}||v }|}	|sd}
|
|v }|}	|	sXt        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  }|j                  |       |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  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}	x}x}x}x}
}y)uM   end_task()도 team_id/description이 있으면 일일 로그에 완료 기록r>   rc   u   완료 로그 테스트re   r  r   r}  r  r  r  r   u   완료rZ   )z%(py3)s in %(py5)sr  )r   r   z%(py7)sr   )z%(py10)s in %(py12)s)r   r   z%(py14)sr   r   zassert %(py17)spy17N)rJ   r   r   r  r  rq   r   r   r   r   r   r   r   r   r    r!   )rL   r:   r9   r  r  r  r&   r%   r*   rN   r   rd  r(   r,   r   @py_format15@py_format16@py_format18s                     r-   !test_end_task_writes_to_daily_logz1TestAddLogEntry.test_end_task_writes_to_daily_log  s-   [F_`z"LLN++J7	h&0i[3DD$$g$6<{<{g%<<W)<<<<<{g<<<{<<<<<<g<<<g<<<<<<<W<<<<<<<<<W<<<W<<<<<<<<<<<<<<r/   N)r   r   r   r   ro  rr  rx  r{  r  r  r  r  r  r  r  r  r  r   r/   r-   ri  ri    sF    _,:(4
#&>1,
74#=r/   ri  c                      d fd	}|S )uB   재귀 방지를 위해 원본 __init__을 캡처한 패치 생성c                 0    t        | t                     y r5  )_original_initr8   )rL   r5   r9   s     r-   patched_initz(_make_patched_init.<locals>.patched_init  s    tS]+r/   r5  r   )r9   r  s   ` r-   _make_patched_initr    s    , r/   c                   R    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zy)TestCLIMainu/   CLI main() 함수의 주요 명령어 테스트c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                         }t        j                  |j                        }|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)u8   start 명령어가 JSON 출력을 생성하는지 확인__init__argv)r   r   r>   --teamrc   z--descu   CLI 테스트r?   r@   rA   rC   rD   rG   rH   Nsetattr_task_timer_modr7   r  sys
_main_func
readouterrro   rp   outr   r   r   r    r!   rL   r9   monkeypatchcapsyscapturedoutputrN   r+   r%   rO   rP   s              r-   test_start_commandzTestCLIMain.test_start_command  s    O55zCUV^C_`q	
 	$$&HLL)h,9,9,,,,9,,,,,,9,,,,,,,r/   c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                  t        dg d       t                |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  }d
d|iz  }	t        t        j                  |	            dx}x}}y)u8   start 후 end 명령어가 정상 동작하는지 확인r  r  )r   r   ru   )r   r   ru   r   rZ   z+%(py1)s in %(py5)s
{%(py5)s = %(py3)s.out
}r  rE   r   r   assert %(py7)sr   Nr  r  r7   r  r  r  r  r  r   r   r   r   r   r   r    r!   
rL   r9   r  r  r  rN   r*   r%   r(   r,   s
             r-   test_end_command_after_startz(TestCLIMain.test_end_command_after_start  s    O55zCUV^C_`C)OPC)MN$$&*hll*{l****{l***{******h***h***l*******r/   c                    |j                  t        j                  dt        |             |j                  t        dddg       t                |j                         }t        j                  |j                        }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndd	z  }d
d|iz  }	t!        t        j"                  |	            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndd	z  }d
d|iz  }	t!        t        j"                  |	            dx}}y)u9   list 명령어가 작업 목록을 반환하는지 확인r  r  r   r  r  rZ   r\   r  r]   r^   r   Nrl   )r  r  r7   r  r  r  r  ro   rp   r  r   r   r   r   r   r   r    r!   )
rL   r9   r  r  r  r  rN   r%   r'   r(   s
             r-   test_list_commandzTestCLIMain.test_list_command  s   O55zCUV^C_`C/6)BC$$&HLL) w&    w&   w      &   &        w&    w&   w      &   &       r/   c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                  t        dg d       t                |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  }d
d|iz  }	t        t        j                  |	            dx}x}}y)u;   status 명령어가 작업 상태를 반환하는지 확인r  r  )r   r   task-3.1)r   r?   r  rv   rZ   r  r  r  r  r   Nr  r  s
             r-   test_status_commandzTestCLIMain.test_status_command  s    O55zCUV^C_`C)OPC)PQ$$&(HLL(yL((((yL(((y((((((H(((H(((L(((((((r/   c                    |j                  t        j                  dt        |             |j                  t        dg d       t        j                  t              5 }t                ddd       j                  }|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                   |      t        j                   |      d	z  }d
d|iz  }	t#        t        j$                  |	            dx}x}x}}y# 1 sw Y   xY w)u6   존재하지 않는 task status 조회 시 sys.exit(1)r  r  )r   r?   z
task-999.9Nr   rA   zG%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.value
}.code
} == %(py7)sexc_infor   r   r   r  r  r7   r  r  rf  raises
SystemExitr  valuecoder   r   r   r   r   r   r    r!   
rL   r9   r  r  r&   r+   r   r   r,   r   s
             r-   test_status_not_found_exitsz'TestCLIMain.test_status_not_found_exits(  s    O55zCUV^C_`C)RS]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	   EE$c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                         }t        j                  |j                        }|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)u8   log 명령어가 로그 항목을 생성하는지 확인r  r  )r   logu   테스트 로그 메시지--typert  r?   rl  rA   rC   rD   rG   rH   Nr  r  s              r-   test_log_commandzTestCLIMain.test_log_command0  s    O55zCUV^C_`C)qr$$&HLL)h+8+8++++8++++++8+++++++r/   c                 x   |j                  t        ddg       t        j                  t              5 }t                ddd       j                  }|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                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}y# 1 sw Y   xY w)u$   인자 없이 실행 시 sys.exit(1)r  r   Nr   rA   r  r  r   r   r   r  r  rf  r  r  r  r  r  r   r   r   r   r   r   r    r!   	rL   r  r  r&   r+   r   r   r,   r   s	            r-   test_no_args_exitszTestCLIMain.test_no_args_exits9  s    C/):;]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	s   D00D9c                 z   |j                  t        dddg       t        j                  t              5 }t                ddd       j                  }|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                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}x}}y# 1 sw Y   xY w)u(   알 수 없는 명령어 시 sys.exit(1)r  r   invalid_cmdNr   rA   r  r  r   r   r   r  r  s	            r-   test_unknown_command_exitsz&TestCLIMain.test_unknown_command_exits@  s    C/=)IJ]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	s   D11D:c                    |j                  t        j                  dt        |             |j                  t        dg d       t        j                  t              5 }t                ddd       j                  }|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                   |      t        j                   |      d	z  }d
d|iz  }	t#        t        j$                  |	            dx}x}x}}y# 1 sw Y   xY w)u"   잘못된 log type 시 sys.exit(1)r  r  )r   r  msgr  invalid_typeNr   rA   r  r  r   r   r   r  r  s
             r-   test_log_invalid_type_exitsz'TestCLIMain.test_log_invalid_type_exitsG  s    O55zCUV^C_`C)bc]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	r  c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                         }t        j                  |j                        }|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=   CLI에서 "start task-500" → started (task-N 형식 허용)r  r  )r   r   task-500r?   r@   rA   rC   rD   rG   rH   Nr  r  s              r-    test_start_command_task_n_formatz,TestCLIMain.test_start_command_task_n_formatO  s    O55zCUV^C_`C)OP$$&HLL)h,9,9,,,,9,,,,,,9,,,,,,,r/   c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                  t        dg d       t                |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  }d
d|iz  }	t        t        j                  |	            dx}x}}y)u;   start task-500.1 후 CLI에서 "end task-500" → completedr  r  )r   r   z
task-500.1)r   r   r  r   rZ   r  r  r  r  r   Nr  r  s
             r-   test_end_command_fuzzy_matchz(TestCLIMain.test_end_command_fuzzy_matchX  s    O55zCUV^C_`C)QRC)MN$$&*hll*{l****{l***{******h***h***l*******r/   N)r   r   r   r   r  r  r  r  r  r  r  r  r  r  r  r   r/   r-   r  r    s<    9	-	+!	)(,(((-	+r/   r  c                       e Zd ZdZd Zd Zy)TestLoadTimersErroru7   _load_timers() 에러 핸들링 테스트 (lines 55-57)c                 $   |dz  j                  dd       |dz  dz  }|j                  dd       t        t        |            }|j                  }d	i i}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u'   깨진 JSON 파일 → 빈 tasks 반환r   Tr1   rh   zNOT VALID JSON {{{r  r  r4   rl   rA   z.%(py2)s
{%(py2)s = %(py0)s.timers
} == %(py5)sr:   r   r  r   N)r6   
write_textr7   r8   timersr   r   r   r   r   r   r    r!   )	rL   r9   rj   r:   r&   r*   r+   r(   r,   s	            r-   !test_corrupted_json_returns_emptyz5TestLoadTimersError.test_corrupted_json_returns_emptyl  s    	H	##D4#@(+==
2WEX7||,},|},,,,|},,,,,,u,,,u,,,|,,,},,,,,,,r/   c                    ddl }|dz  j                  dd       |dz  dz  }|j                  dd	        |j                  t	        |      d       	 t        t	        |      
      }|j                  }di i}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}} |j                  t	        |      d       y#  |j                  t	        |      d       w xY w)u0   읽기 권한 없는 파일 → 빈 tasks 반환r   Nr   Tr1   rh   z{"tasks": {}}r  r  r4   rl   rA   r  r:   r   r  r   i  )osr6   r  chmodr8   r7   r  r   r   r   r   r   r   r    r!   )
rL   r9   r  rj   r:   r&   r*   r+   r(   r,   s
             r-   "test_unreadable_file_returns_emptyz6TestLoadTimersError.test_unreadable_file_returns_emptyt  s   	H	##D4#@(+==
o@Z%(	-S];E<<0GR=0<=0000<=00000050005000<000=0000000BHHS_e,HBHHS_e,s   CE E-N)r   r   r   r   r  r  r   r/   r-   r  r  i  s    A--r/   r  c                       e Zd ZdZd Zy)TestSaveTimersErroru7   _save_timers() 에러 핸들링 테스트 (lines 72-73)c                 p   ddl }|dz  j                  dd       t        t        |            } |j                  t        |dz        d       	 dd	i|j
                  d
   d	<   |j                           |j                  t        |dz        d       y#  |j                  t        |dz        d       w xY w)uJ   읽기 전용 디렉토리에 저장 시도 → 에러 무시하고 계속r   Nr   Tr1   r4   im  r?   testrl   i  )r  r6   r7   r8   r  r  _save_timers)rL   r9   r  r:   s       r-   test_save_to_readonly_dirz-TestSaveTimersError.test_save_to_readonly_dir  s    	H	##D4#@X7X()51	6-5v,>ELL!&) BHHSH,-u5HBHHSH,-u5s   $B !B5N)r   r   r   r   r  r   r/   r-   r  r    s
    A6r/   r  c                       e Zd ZdZd Zd Zy)!TestUpdatePipelineStatusEdgeCasesuC   _update_pipeline_status() 에지 케이스 (lines 186-187, 231-233)c                 F   |dz  j                  dd       |dz  dz  }|j                  dd       t        t        |            }|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}}t        j                  |j                               }
d}||
v }|st        j                  d|fd||
f      t        j                  |      dt        j                         v st        j                  |
      rt        j                  |
      nddz  }dd|iz  }t        t        j                  |            dx}}y)uM   pipeline-status.json이 깨진 JSON → 빈 dict로 초기화 (lines 186-187)r   Tr1   zpipeline-status.jsonzINVALID{{{JSONr  r  r4   ztask-5.1rc   rf   r?   r@   rA   rC   rD   rG   rH   Nactive_tasksrZ   r\   rr   r]   r^   r   )r6   r  r7   r8   rJ   r   r   r   r    r!   ro   rp   rq   r   r   r   )rL   r9   pipeline_filer:   rM   rN   r+   r%   rO   rP   rr   r'   r(   s                r-   test_corrupted_pipeline_jsonz>TestUpdatePipelineStatusEdgeCases.test_corrupted_pipeline_json  s#   	H	##D4#@ 8+.DD  !1G DX7!!*k!Bh,9,9,,,,9,,,,,,9,,,,,,,zz-1134%~%%%%~%%%~%%%%%%%%%%%%%%%%r/   c                 Z   ddl m}m} |dz  j                  dd       t	        t        |            } |       }t        d      |j                  j                  _        d|j                  _
        |j                  |d	|      5  |j                  d
ddi       ddd       y# 1 sw Y   yxY w)uU   pipeline-status 업데이트 실패해도 task-timer 기능은 계속 (lines 231-233)r   )	MagicMockpatchr   Tr1   r4   u   강제 오류Fpipeline_status_filer   rU   z	test-taskN)unittest.mockr  r	  r6   r7   r8   OSErrorparentside_effectrn   return_valueobject_update_pipeline_status)rL   r9   r  r	  r:   	mock_paths         r-   &test_pipeline_update_exception_ignoredzHTestUpdatePipelineStatusEdgeCases.test_pipeline_update_exception_ignored  s    2	H	##D4#@X7K	-4_-E	*(-	%\\%!7C 	M))'I{3KL	M 	M 	Ms   B!!B*N)r   r   r   r   r  r  r   r/   r-   r  r    s    M&Mr/   r  c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestAppendToSectionu<   _append_to_section() 함수 상세 테스트 (lines 313-346)c                 6   t        j                         j                  d      }|dz  dz  }|j                  dd       || dz  }d| d}|j	                  |d	
       |j                  dd       |j                  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                  d      }|j                  d      }||k  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d}y)uc   기존 섹션이 있고 다음 섹션이 있을 때, 다음 섹션 직전에 삽입 (lines 324-340)r  r   r}  Tr1   r  # u    업무일지

## 완료된 작업
- 기존 항목

## 의사결정
- 기존 의사결정

## 시스템 변경
- 기존 시스템
r  r  u   - 새 의사결정 항목   의사결정u   새 의사결정 항목rZ   r\   rM   r]   r^   r   N   ## 시스템 변경)<)z%(py0)s < %(py2)sidx_new
idx_systemr   r   rF   )r   r  r  r6   r  _append_to_sectionrq   r   r   r   r   r   r   r    r!   index)rL   r:   r9   r  r  r  r  rM   rN   r%   r'   r(   r  r  r&   r   rO   s                    r-   .test_section_exists_insert_before_next_sectionzBTestAppendToSection.test_section_exists_insert_before_next_section  sv   LLN++J7	x''1	t4)C00yk  "n  oGg6  !<nM##W#5(2(F2222(F222(222222F222F2222222,,89\\"78
####w######w###w################r/   c                 T   t        j                         j                  d      }|dz  dz  }|j                  dd       || dz  }d| d}|j	                  |d	
       |j                  dd       |j                  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}}	y)uY   기존 섹션이 있고 다음 섹션이 없을 때, 파일 끝에 추가 (lines 337-338)r  r   r}  Tr1   r  r  uS    업무일지

## 완료된 작업
- 기존 항목

## 의사결정
- 기존 결정r  r  u   - 새 의사결정r  u   새 의사결정rZ   r\   rM   r]   r^   r   Nr   r  r  r6   r  r  rq   r   r   r   r   r   r   r    r!   rL   r:   r9   r  r  r  r  rM   rN   r%   r'   r(   s               r-   #test_section_exists_no_next_sectionz7TestAppendToSection.test_section_exists_no_next_section  s    LLN++J7	x''1	t4)C00yk!z{Gg6  !5~F##W#5!+!V++++!V+++!++++++V+++V+++++++r/   c                    t        j                         j                  d      }|dz  dz  }|j                  dd       || dz  }d| d}|j	                  |d	
       |j                  dd       |j                  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}}	d}||v }	|	st        j                  d|	fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            dx}}	y)uC   섹션이 없으면 파일 끝에 새 섹션 추가 (lines 343-346)r  r   r}  Tr1   r  r  2    업무일지

## 완료된 작업
- 기존 항목r  r  u   - 아키텍처 논의 내용u   아키텍처 논의u   ## 아키텍처 논의rZ   r\   rM   r]   r^   r   Nu   아키텍처 논의 내용r!  r"  s               r-   %test_new_section_created_when_missingz9TestAppendToSection.test_new_section_created_when_missing  sG   LLN++J7	x''1	t4)C00yk!VWGg6  !?AVW##W#5'1'61111'6111'111111611161111111+5+v5555+v555+555555v555v5555555r/   c                    t        j                         j                  d      }|dz  dz  }|j                  dd       || dz  }d| 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}	}
|j                  |d       |j                  dd       |j                  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}}y)u3   content가 \n으로 끝나지 않을 때 (line 344)r  r   r}  Tr1   r  r  r%  
zNassert not %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.endswith
}(%(py4)s)
}r  r   Nr  r  u   - 새 시스템 변경u   시스템 변경r  rZ   r\   rM   r]   r^   r   )r   r  r  r6   endswithr   r   r   r   r   r    r!   r  r  rq   r   )rL   r:   r9   r  r  r  r  r&   r+   r   r   r,   rM   rN   r%   r'   r(   s                    r-   #test_content_without_newline_endingz7TestAppendToSection.test_content_without_newline_ending  sf   LLN++J7	x''1	t4)C00 yk!VW##)D)#D)))))))))))7)))7)))#)))D))))))))))Gg6  !9;MN##W#5$.$....$...$................r/   c                 R   t        j                         j                  d      }|dz  dz  }|j                  dd       || dz  }d}|j	                  |d	       |j                  d
d       |j                  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}}	y)u5   날짜 헤더가 맞지 않을 때 prepend (line 318)r  r   r}  Tr1   r  u>   # 2020-01-01 업무일지

## 완료된 작업
- 옛날 항목r  r  u   - 새 항목u   위임 기록r  rZ   r\   rM   r]   r^   r   Nr!  r"  s               r-   %test_wrong_date_header_gets_prependedz9TestAppendToSection.test_wrong_date_header_gets_prepended  s    LLN++J7	x''1	t4)C00 VGg6  A##W#5I;)6))))6)))))))))6)))6)))))))r/   N)	r   r   r   r   r  r#  r&  r*  r,  r   r/   r-   r  r    s    F$&,6 /"*r/   r  c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestCLIMainEdgeCasesu,   CLI main() 추가 에지 케이스 테스트c                    |j                  t        j                  dt        |             |j                  t        dddg       t        j                  t              5 }t                ddd       j                  }|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                   |      t        j                   |      d
z  }dd|iz  }	t#        t        j$                  |	            dx}x}x}}y# 1 sw Y   xY w)uA   start 명령어에 task_id 누락 시 sys.exit(1) (lines 396-397)r  r  r   r   Nr   rA   r  r  r   r   r   r  r  s
             r-    test_start_without_task_id_exitsz5TestCLIMainEdgeCases.test_start_without_task_id_exits$  s    O55zCUV^C_`C/7)CD]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	r  c                    |j                  t        j                  dt        |             |j                  t        dddg       t        j                  t              5 }t                ddd       j                  }|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                   |      t        j                   |      d
z  }dd|iz  }	t#        t        j$                  |	            dx}x}x}}y# 1 sw Y   xY w)u?   end 명령어에 task_id 누락 시 sys.exit(1) (lines 430-431)r  r  r   r   Nr   rA   r  r  r   r   r   r  r  s
             r-   test_end_without_task_id_exitsz3TestCLIMainEdgeCases.test_end_without_task_id_exits,      O55zCUV^C_`C/5)AB]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	r  c                    |j                  t        j                  dt        |             |j                  t        dddg       t        j                  t              5 }t                ddd       j                  }|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                   |      t        j                   |      d
z  }dd|iz  }	t#        t        j$                  |	            dx}x}x}}y# 1 sw Y   xY w)uB   status 명령어에 task_id 누락 시 sys.exit(1) (lines 439-440)r  r  r   r?   Nr   rA   r  r  r   r   r   r  r  s
             r-   !test_status_without_task_id_exitsz6TestCLIMainEdgeCases.test_status_without_task_id_exits4  s    O55zCUV^C_`C/8)DE]]:& 	(L	~~'~""'a'"a''''"a''''''x'''x'''~'''"'''a'''''''	 	r  c                    |j                  t        j                  dt        |             |j                  t        dddg       t        j                  t              5 }t                ddd       j                  }|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                   |      t        j                   |      d
z  }dd|iz  }	t#        t        j$                  |	            dx}x}x}}y# 1 sw Y   xY w)uA   log 명령어에 메시지 누락 시 sys.exit(1) (lines 458-459)r  r  r   r  Nr   rA   r  r  r   r   r   r  r  s
             r-   test_log_without_message_exitsz3TestCLIMainEdgeCases.test_log_without_message_exits<  r3  r  c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                         }t        j                  |j                        }|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)uO   start 명령어에 위치 인자로 team_id, description 전달 (lines 414-423)r  r  )r   r   z	task-10.1rc   u   위치인자 설명r?   r@   rA   rC   rD   rG   rH   Nr  r  s              r-   test_start_with_positional_argsz4TestCLIMainEdgeCases.test_start_with_positional_argsD  s    O55zCUV^C_`C)tu$$&HLL)h,9,9,,,,9,,,,,,9,,,,,,,r/   c                    |j                  t        j                  dt        |             |j                  t        dg d       t                |j                         }t        j                  |j                        }|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=   start 명령어에 --project 플래그 전달 (lines 414-416)r  r  )r   r   z	task-11.1r  rc   z	--projectr~   r?   r@   rA   rC   rD   rG   rH   Nr  r  s              r-   test_start_with_project_flagz1TestCLIMainEdgeCases.test_start_with_project_flagM  s    O55zCUV^C_`n	
 	$$&HLL)h,9,9,,,,9,,,,,,9,,,,,,,r/   N)
r   r   r   r   r0  r2  r5  r7  r9  r;  r   r/   r-   r.  r.  !  s#    6((((-	-r/   r.  c                       e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zy)TestTaskIdValidationu   task_id 형식 검증 테스트c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nr>   Tr   z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is %(py7)svalidate_task_idr   r   r   	r@  r   r   r   r   r   r   r    r!   rL   r&   r+   r   r   r,   r   s          r-   test_valid_task_id_simplez.TestTaskIdValidation.test_valid_task_id_simplee       *3
+3t3+t3333+t333333333333
333+333t3333333r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz
task-401.1Tr   r?  r@  r   r   r   rA  rB  s          r-    test_valid_task_id_large_numbersz5TestTaskIdValidation.test_valid_task_id_large_numbersh       ,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55555r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz	task-12.3Tr   r?  r@  r   r   r   rA  rB  s          r-   "test_valid_task_id_multi_digit_subz7TestTaskIdValidation.test_valid_task_id_multi_digit_subk       +4,44,4444,444444444444444,4444444444r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz401.1Fr   r?  r@  r   r   r   rA  rB  s          r-   test_invalid_task_id_no_prefixz3TestTaskIdValidation.test_invalid_task_id_no_prefixn  s     '1(1E1(E1111(E111111111111111(111E1111111r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nodin-2Fr   r?  r@  r   r   r   rA  rB  s          r-   !test_invalid_task_id_wrong_prefixz6TestTaskIdValidation.test_invalid_task_id_wrong_prefixq       (2)2U2)U2222)U222222222222222)222U2222222r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-401Tr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_no_dotz.TestTaskIdValidation.test_valid_task_id_no_dott  rD  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz	task-1000Tr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_large_no_dotz4TestTaskIdValidation.test_valid_task_id_large_no_dotw  rJ  r/   c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )	Nr  r?   r@   rA   rC   rD   rG   rH   rI   rK   s           r-   %test_start_task_accepts_task_n_formatz:TestTaskIdValidation.test_start_task_accepts_task_n_formatz  rR   r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz
task-abc.1Fr   r?  r@  r   r   r   rA  rB  s          r-   test_invalid_task_id_alphaz/TestTaskIdValidation.test_invalid_task_id_alpha~  s     ,6-66-6666-666666666666666-6666666666r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	N Fr   r?  r@  r   r   r   rA  rB  s          r-   test_invalid_task_id_emptyz/TestTaskIdValidation.test_invalid_task_id_empty  s     ",#,u,#u,,,,#u,,,,,,,,,,,,,,,#,,,u,,,,,,,r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz	task- 1.1Fr   r?  r@  r   r   r   rA  rB  s          r-   test_invalid_task_id_spacesz0TestTaskIdValidation.test_invalid_task_id_spaces  s     +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55555r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_3.3Tr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_phasez-TestTaskIdValidation.test_valid_task_id_phase       /808D80D88880D8888888888888880888D8888888r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_aTr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_parallelz0TestTaskIdValidation.test_valid_task_id_parallel       -6.6$6.$6666.$666666666666666.666$6666666r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_3.2_bTr   r?  r@  r   r   r   rA  rB  s          r-   !test_valid_task_id_phase_parallelz6TestTaskIdValidation.test_valid_task_id_phase_parallel       1: 12:d:2d::::2d:::::::::::: 1:::2:::d:::::::r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845+1Tr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_retryz-TestTaskIdValidation.test_valid_task_id_retry  rc  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_3.2_b+1Tr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_full_v2z/TestTaskIdValidation.test_valid_task_id_full_v2  s     3< 34<<4<<<<4<<<<<<<<<<<< 3<<<4<<<<<<<<<<r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_3.3+2Tr   r?  r@  r   r   r   rA  rB  s          r-   test_valid_task_id_phase_retryz3TestTaskIdValidation.test_valid_task_id_phase_retry  rf  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_a+1Tr   r?  r@  r   r   r   rA  rB  s          r-   !test_valid_task_id_parallel_retryz6TestTaskIdValidation.test_valid_task_id_parallel_retry  r`  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_AFr   r?  r@  r   r   r   rA  rB  s          r-   'test_invalid_task_id_uppercase_parallelz<TestTaskIdValidation.test_invalid_task_id_uppercase_parallel       -7.7%7.%7777.%777777777777777.777%7777777r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845_3Fr   r?  r@  r   r   r   rA  rB  s          r-   test_invalid_task_id_bad_phasez3TestTaskIdValidation.test_invalid_task_id_bad_phase  rq  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nztask-1845__3.3Fr   r?  r@  r   r   r   rA  rB  s          r-   &test_invalid_task_id_double_underscorez;TestTaskIdValidation.test_invalid_task_id_double_underscore  s     0: 01:U:1U::::1U:::::::::::: 0:::1:::U:::::::r/   c                 $   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}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}}y )Nz
invalid-idr?   r   rA   rC   rD   rG   rH   zInvalid task_idr   rZ   rm   rI   rK   s           r-   'test_start_task_rejects_invalid_task_idz<TestTaskIdValidation.test_start_task_rejects_invalid_task_id  s    !!,/h*7*7****7******7******* 4F8$44 $44444 $4444 444$44444444r/   c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d x}x}}y )	N
task-100.1r?   r@   rA   rC   rD   rG   rH   rI   rK   s           r-   %test_start_task_accepts_valid_task_idz:TestTaskIdValidation.test_start_task_accepts_valid_task_id  sd    !!,/h,9,9,,,,9,,,,,,9,,,,,,,r/   N)r   r   r   r   rC  rF  rI  rL  rO  rR  rT  rV  rX  r[  r]  r_  rb  re  rh  rj  rl  rn  rp  rs  ru  rw  rz  r   r/   r-   r=  r=  b  sx    )4652345-7-697;7=;988;5
-r/   r=  c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestFuzzyMatchEndu    end_task() fuzzy match 테스트c                 H   |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}y
)uC   task-1.1을 start한 뒤 end_task("task-1")로 종료 → completedr>   task-1r?   r   rA   rC   rD   rG   rH   Nr   rK   s           r-   #test_end_fuzzy_match_single_runningz5TestFuzzyMatchEnd.test_end_fuzzy_match_single_running  sp    $)h.;.;....;......;.......r/   c                 j   |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|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)uZ   task-1.1과 task-1.2를 start한 뒤 end_task("task-1") → task-1.2가 종료됨 (최신)r>   ztask-1.2r~  r?   r   rA   rC   rD   rG   rH   NrU   r   rK   s           r-   2test_end_fuzzy_match_multiple_running_picks_latestzDTestFuzzyMatchEnd.test_end_fuzzy_match_multiple_running_picks_latest  s    $$)h.;.;....;......;.......i .J. J.... J... ...J.......r/   c                 j   |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}|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
)ui   task-1과 task-1.1 둘 다 start한 뒤 end_task("task-1") → task-1이 종료됨 (정확 매칭 우선)r~  r>   r?   r   rA   rC   rD   rG   rH   NrU   r   rK   s           r-   )test_end_exact_match_preferred_over_fuzzyz;TestFuzzyMatchEnd.test_end_exact_match_preferred_over_fuzzy  s    "$)h.;.;....;......;.......i ,H, H,,,, H,,, ,,,H,,,,,,,r/   c                 j   |j                  d       |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}y
)uN   task-1.1을 start + end한 뒤 (completed 상태) end_task("task-1") → errorr>   r~  r?   r   rA   rC   rD   rG   rH   Nr   rK   s           r-   'test_end_fuzzy_no_running_returns_errorz9TestFuzzyMatchEnd.test_end_fuzzy_no_running_returns_error  s|    $z")h*7*7****7******7*******r/   c                 H   |j                  d       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)
uL   task-1.1 start 후 end_task("task-1.1") → completed (기존 동작 유지)r>   r?   r   rA   rC   rD   rG   rH   Nr   rK   s           r-   test_end_exact_still_worksz,TestFuzzyMatchEnd.test_end_exact_still_works  sp    $
+h.;.;....;......;.......r/   N)	r   r   r   r   r  r  r  r  r  r   r/   r-   r|  r|    s    *//-+/r/   r|  c                   "    e Zd ZdZd Zd Zd Zy)TestFuzzyMatchStatusu'   get_task_status() fuzzy match 테스트c                    |j                  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                  |      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)uF   task-1.1 start 후 get_task_status("task-1") → running 상태 반환r>   r~  Nr
   r   rM   r   r^   r   r?   rv   rA   rC   rD   rG   rH   r  r  s              r-   test_status_fuzzy_match_singlez3TestFuzzyMatchStatus.test_status_fuzzy_match_single  s    $&&x0!!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!h,9,9,,,,9,,,,,,9,,,,,,,r/   c                    |j                  d       |j                  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                  |      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)uN   task-1, task-1.1 둘 다 start 후 get_task_status("task-1") → task-1 반환r~  r>   Nr
   r   rM   r   r^   r   rU   rA   rC   rD   rG   rH   r  r  s              r-   !test_status_exact_match_preferredz6TestFuzzyMatchStatus.test_status_exact_match_preferred  s    "$&&x0!!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!i ,H, H,,,, H,,, ,,,H,,,,,,,r/   c                 p   |j                  d      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)	u$   get_task_status("task-999") → Noneztask-999Nr   r	  rM   r   r^   r   r
  r  s          r-   !test_status_no_match_returns_nonez6TestFuzzyMatchStatus.test_status_no_match_returns_none  sj    &&z2v~vvvr/   N)r   r   r   r   r  r  r  r   r/   r-   r  r    s    1--r/   r  c                   v    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zy)TestTeamIdValidationu   team_id 형식 검증 테스트c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nrc   Tr   r?  validate_team_idr   r   r   	r  r   r   r   r   r   r   r    r!   rB  s          r-   test_valid_dev1_teamz)TestTeamIdValidation.test_valid_dev1_team  rJ  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nr{   Tr   r?  r  r   r   r   r  rB  s          r-   test_valid_dev2_teamz)TestTeamIdValidation.test_valid_dev2_team  rJ  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz	dev3-teamTr   r?  r  r   r   r   r  rB  s          r-   test_valid_dev3_teamz)TestTeamIdValidation.test_valid_dev3_team  rJ  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nz
anu-directTr   r?  r  r   r   r   r  rB  s          r-   test_valid_anu_directz*TestTeamIdValidation.test_valid_anu_direct  rG  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	NrZ  Tr   r?  r  r   r   r   r  rB  s          r-   test_valid_empty_stringz,TestTeamIdValidation.test_valid_empty_string  s     "+#+t+#t++++#t+++++++++++++++#+++t+++++++r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	NrN  Fr   r?  r  r   r   r   r  rB  s          r-   test_invalid_odin_2z(TestTeamIdValidation.test_invalid_odin_2   rP  r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
u   dev4-team은 유효한 팀 IDz	dev4-teamTr   r?  r  r   r   r   Nr  rB  s          r-   test_valid_dev4_teamz)TestTeamIdValidation.test_valid_dev4_team       +4,44,4444,444444444444444,4444444444r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nzrandom-teamFr   r?  r  r   r   r   r  rB  s          r-   test_invalid_randomz(TestTeamIdValidation.test_invalid_random  rq  r/   c                 (   |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}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t	        t        j
                  |            d x}x}}y )Nry  rN  r  r?   r   rA   rC   rD   rG   rH   zInvalid team_idr   rZ   rm   rI   rK   s           r-   'test_start_task_rejects_invalid_team_idz<TestTeamIdValidation.test_start_task_rejects_invalid_team_id
  s    !!,!Ah*7*7****7******7******* 4F8$44 $44444 $4444 444$44444444r/   c                 *   |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}}y )Nry  rZ  r  r?   r@   rA   rC   rD   rG   rH   rI   rK   s           r-   %test_start_task_accepts_empty_team_idz:TestTeamIdValidation.test_start_task_accepts_empty_team_id  si    !!,!;h,9,9,,,,9,,,,,,9,,,,,,,r/   c                 *   |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}}y )Nry  r{   r  r?   r@   rA   rC   rD   rG   rH   rI   rK   s           r-   %test_start_task_accepts_valid_team_idz:TestTeamIdValidation.test_start_task_accepts_valid_team_id  si    !!,!Dh,9,9,,,,9,,,,,,9,,,,,,,r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
u4   design 팀 ID가 유효함을 검증 (논리적 팀)designTr   r?  r  r   r   r   Nr  rB  s          r-   test_valid_design_teamz+TestTeamIdValidation.test_valid_design_team  s     (1)1T1)T1111)T111111111111111)111T1111111r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
u8   publishing 팀 ID가 유효함을 검증 (논리적 팀)
publishingTr   r?  r  r   r   r   Nr  rB  s          r-   test_valid_publishing_teamz/TestTeamIdValidation.test_valid_publishing_team  s     ,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55555r/   c                    d}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}x}}y	)
u6   composite 팀 ID가 유효함을 검증 (복합업무)	compositeTr   r?  r  r   r   r   Nr  rB  s          r-   test_valid_composite_teamz.TestTeamIdValidation.test_valid_composite_team  r  r/   c                 *   |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}}y)u7   start_task()가 design 팀 ID를 수락하는지 검증z
task-100.2r  r  r?   r@   rA   rC   rD   rG   rH   NrI   rK   s           r-   #test_start_task_accepts_design_teamz8TestTeamIdValidation.test_start_task_accepts_design_team#  si    !!,!Ah,9,9,,,,9,,,,,,9,,,,,,,r/   c                 *   |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}}y)u;   start_task()가 publishing 팀 ID를 수락하는지 검증z
task-100.3r  r  r?   r@   rA   rC   rD   rG   rH   NrI   rK   s           r-   'test_start_task_accepts_publishing_teamz<TestTeamIdValidation.test_start_task_accepts_publishing_team(  si    !!,!Eh,9,9,,,,9,,,,,,9,,,,,,,r/   c                 *   |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}}y)u:   start_task()가 composite 팀 ID를 수락하는지 검증z
task-100.4r  r  r?   r@   rA   rC   rD   rG   rH   NrI   rK   s           r-   &test_start_task_accepts_composite_teamz;TestTeamIdValidation.test_start_task_accepts_composite_team-  si    !!,!Dh,9,9,,,,9,,,,,,9,,,,,,,r/   N)r   r   r   r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r/   r-   r  r    sZ    )5556,3585
--265-
-
-r/   r  c                   (    e Zd ZdZd Zd Zd Zd Zy)TestAtomicSaveu)   _save_timers() 원자적 쓰기 테스트c                    |j                  ddd       |dz  dz  }t        j                  |j                  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   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)u0   저장 후 파일이 유효한 JSON인지 확인r>   rc   u   원자적 저장 테스트re   r   rh   r  r  rl   rZ   rm   rD   rG   rH   Nr?   rv   rA   rC   rw   rx   s
             r-   test_save_creates_valid_jsonz+TestAtomicSave.test_save_creates_valid_json6  s    [Fbc(+==
zz*...@A*T']*z]****z]***z***]*******G}Z(2?i?2i????2i???2???i???????r/   c                    |j                  d       |dz  }t        |j                  d            }t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      d	z  }t	        j                  d
|       dz   d|iz  }	t        t	        j                  |	            dx}x}}y)u4   저장 후 .tmp 파일이 남아있지 않아야 함ru   r   z*.tmpr   rA   r  r   	tmp_filesr  u   임시 파일이 남아있음: z
>assert %(py8)sr   N)rJ   r  r  r   r   r   r   r   r   r   r   r    r!   )
rL   r:   r9   
memory_dirr  r%   r   r*   rP   r   s
             r-   "test_save_does_not_leave_tmp_filesz1TestAtomicSave.test_save_does_not_leave_tmp_files>  s    $(
12	9~QQ~"QQQ~QQQQQQsQQQsQQQQQQ9QQQ9QQQ~QQQQQQ&Ei[$QQQQQQQQr/   c                 &   |dz  j                  dd       t        t        |            }|j                  dd       t        t        |            }|j                  dd	       |dz  d
z  }t	        j
                  |j                  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   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y)u[   두 TaskTimer 인스턴스가 순차적으로 저장해도 데이터가 유실되지 않음r   Tr1   r4   r>   rc   r  ru   r{   rh   r  r  rl   rZ   rm   rD   rG   rH   N)r6   r7   r8   rJ   ro   rp   rq   r   r   r   r    r!   )rL   r9   timer1timer2rj   rr   rN   r+   r%   rO   rP   s              r-   #test_concurrent_save_preserves_dataz2TestAtomicSave.test_concurrent_save_preserves_dataE  s$   	H	##D4#@#h-8*k:#h-8*k:(+==
zz*...@A*T']*z]****z]***z***]********T']*z]****z]***z***]*******r/   c                    |j                  d       |dz  dz  }|j                  } |       }|st        j                  d      dz   dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y)	u0   저장 시 .task-timers.lock 파일이 생성됨r  r   z.task-timers.locku/   .task-timers.lock 파일이 생성되어야 함zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}	lock_filerk   N)
rJ   rn   r   r   r   r   r   r   r    r!   )rL   r:   r9   r  r&   r+   rO   s          r-   test_save_uses_lock_filez'TestAtomicSave.test_save_uses_lock_fileT  s    $x'*==	T!T!TT#TTTTTTTyTTTyTTTTTT!TTTTTTr/   N)r   r   r   r   r  r  r  r  r   r/   r-   r  r  3  s    3@R+Ur/   r  c                       e Zd ZdZd Zd Zy)TestStaleGuardu9   stale 상태 task 재시작 방지 테스트 (task-486.1)c                    |j                  ddd       d|j                  d   d   d<   d|j                  d   d   d<   |j                          |j                  d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   }||v }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u:   stale 상태의 task에 start_task 호출 시 error 반환	task-99.1rc   rd   stalerl   r?   timeout_runningstale_reasonu   재시작 시도r   rA   rC   rD   rG   rH   Nr   rZ   rm   rJ   r  r  r   r   r   r    r!   rK   s           r-   test_start_task_rejects_stalez,TestStaleGuard.test_start_task_rejects_stale^  s    	k3EF7>Wk*84=NWk*>: !!+{<NOh*7*7****7******7********&**w*****w****w***********r/   c                    |j                  ddd       d|j                  d   d   d<   |j                          |j                  ddd       |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   }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)uD   stale 거부 후 기존 task 데이터가 변경되지 않아야 함r  rc   u   원래 작업r  rl   r?   r   rA   rC   rD   rG   rH   Nrg   r  )rL   r:   	task_datarN   r+   r%   rO   rP   s           r-   -test_start_task_stale_preserves_original_dataz<TestStaleGuard.test_start_task_stale_preserves_original_datal  s   k?C7>Wk*84 	k3HI LL)+6	"-g-"g----"g---"---g-------':?:'?::::'?:::':::?:::::::r/   N)r   r   r   r   r  r  r   r/   r-   r  r  [  s    C+;r/   r  c                   (    e Zd ZdZd Zd Zd Zd Zy)TestCrossStartu   cross_start 메서드 테스트c                 ,   |j                  dd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}}|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%   유효한 agent로 cross_start 성공lokiz
task-548.1u   보안 취약점 리뷰rc   r?   r@   rA   rC   rD   rG   rH   NagentrU   )cross_startr   r   r   r    r!   rK   s           r-   test_cross_start_valid_agentz+TestCrossStart.test_cross_start_valid_agent  s   ""6<9RT_`h,9,9,,,,9,,,,,,9,,,,,,,g(&(&((((&((((((&(((((((i 0L0 L0000 L000 000L0000000r/   c                    |j                  dd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   }	|	j                  }
 |
       }||v }|}|s d}|d   }|j                  } |       }||v }|}|sNt        j                  d|fd||f      t        j                  |      t        j                  |	      t        j                  |
      t        j                  |      dz  }dd|iz  }|j                  |       |st        j                  dfdf      t        j                  |      t        j                        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}x}x}x}}y)   잘못된 agent_name → 에러zunknown-agentr>      설명rc   r?   r   rA   rC   rD   rG   rH   Nr  r   unknownrZ   r   r   r   r   r   r   r   r   r   r   r   	r  r   r   r   r    r!   r   r   r   r   s                           r-   test_cross_start_invalid_agentz-TestCrossStart.test_cross_start_invalid_agent  s~   ""?J+Vh*7*7****7******7*******[w[&*[*00[02[w22[i[6(CS[CSCYCY[CYC[[iC[6[[[[[w2[[[w[[[*[[[0[[[2[[[[[[[iC[[[[i[[[CS[[[CY[[[C[[[[[[[[[[[[[[[[r/   c                    |j                  dd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   }	|	j                  }
 |
       }||v }|}|s d}|d   }|j                  } |       }||v }|}|sNt        j                  d|fd||f      t        j                  |      t        j                  |	      t        j                  |
      t        j                  |      dz  }dd|iz  }|j                  |       |st        j                  dfdf      t        j                  |      t        j                        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}x}x}x}}y)u   잘못된 task_id → 에러r  zinvalid-taskr  rc   r?   r   rA   rC   rD   rG   rH   NrU   r   invalidrZ   r   r   r   r   r   r   r   r   r   r   r   r  r   s                           r-    test_cross_start_invalid_task_idz/TestCrossStart.test_cross_start_invalid_task_id  s~   ""6>8[Qh*7*7****7******7*******]y]F8,],22]24]y44]	]VHEU]EUE[E[]E[E]]	E]8]]]]]y4]]]y]]],]]]2]]]4]]]]]]]	E]]]]	]]]EU]]]E[]]]E]]]]]]]]]]]]]]]]r/   c                    |j                  dddd       |j                  dd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}}|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}}y)u=   이미 active인 agent에 다시 cross_start → 덮어쓰기r  r>   u   첫 번째 작업rc   ru   u   두 번째 작업r{   r?   r@   rA   rC   rD   rG   rH   NrU   cross_functional)r  r   r   r   r    r!   _load_cross_status	rL   r:   rM   rN   r+   r%   rO   rP   
cross_datas	            r-   !test_cross_start_overwrite_activez0TestCrossStart.test_cross_start_overwrite_active  s?   &*.A;O""6:7JKXh,9,9,,,,9,,,,,,9,,,,,,,i .J. J.... J... ...J....... --/
,-f5i@NJN@JNNNN@JNNN@NNNJNNNNNNNr/   N)r   r   r   r   r  r  r  r  r   r/   r-   r  r    s    )1\^	Or/   r  c                   "    e Zd ZdZd Zd Zd Zy)TestCrossEndu   cross_end 메서드 테스트c                 z   |j                  dddd       |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                         }|d   d   d   }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#   active 상태 agent 종료 → idlevenusr>   u   디자인 리뷰rc   r?   endedrA   rC   rD   rG   rH   Nr  r  idle)r  	cross_endr   r   r   r    r!   r  r  s	            r-   test_cross_end_active_agentz(TestCrossEnd.test_cross_end_active_agent  s0   ':/A;O)h*7*7****7******7*******g)')'))))'))))))')))))))--/
,-g6x@JFJ@FJJJJ@FJJJ@JJJFJJJJJJJr/   c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d	x}x}}|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)   이미 idle인 agent → 멱등적 성공maatr?   r  rA   rC   rD   rG   rH   Nr  r  r   r   r   r    r!   rK   s           r-   test_cross_end_idle_agentz&TestCrossEnd.test_cross_end_idle_agent  s    (h*7*7****7******7*******g(&(&((((&((((((&(((((((r/   c                 &   |j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            d	x}x}}y	)
r  znonexistent-agentr?   r   rA   rC   rD   rG   rH   Nr  rK   s           r-   test_cross_end_invalid_agentz)TestCrossEnd.test_cross_end_invalid_agent  sc    !45h*7*7****7******7*******r/   N)r   r   r   r   r  r  r  r   r/   r-   r  r    s    'K)+r/   r  c                       e Zd ZdZd Zd Zy)TestCrossFunctionalFileu0   cross-functional-status.json 파일 IO 테스트c                    |j                  dddd       |dz  dz  }|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}}y
)u   cross_start가 파일을 생성janusr>   u   DevOps 배포rc   r   zcross-functional-status.jsonri   
cross_filerk   N)	r  rn   r   r   r   r   r   r    r!   )rL   r:   r9   r  r&   r+   rO   s          r-   test_cross_start_creates_filez5TestCrossFunctionalFile.test_cross_start_creates_file  s    ':L(+II
  " """"""""z"""z""" """"""""""r/   c                    |j                  dddd       t        t        |            }|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   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;   파일에 저장된 상태가 새 인스턴스에서 읽힘r  ry  u   보안 감사rc   r4   r  r?   activerA   rC   rD   rG   rH   NrU   )	r  r7   r8   r  r   r   r   r    r!   )
rL   r:   r9   	new_timerr  rN   r+   r%   rO   rP   s
             r-   test_cross_status_persistsz2TestCrossFunctionalFile.test_cross_status_persists  s    &,M S];	113
,-f5h?K8K?8KKKK?8KKK?KKK8KKKKKKK,-f5i@PLP@LPPPP@LPPP@PPPLPPPPPPPr/   N)r   r   r   r   r  r  r   r/   r-   r  r    s    :#Qr/   r  )7r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r   importlib.utilro   r  r  timer   pathlibr   rf  environgetr   r.   r  r7   rg  r:   r<   r   r   r   r  r  r2  ri  mainr  r  r  r  r  r  r  r  r  r.  r@  r  r=  r|  r  r  r  r  r  r  r  r   r/   r-   <module>r     s         	 
     "**..)9;PQRU]]`oo  *+%%	 3 32E 2Ej5 5FC CV& &.4 4@7% 7%~1A 1ArR= R=r !!
##g+ g+^- ->6 60M MJT* T*x5- 5-z #33 "33 J- J-Z$/ $/N 0B- B-J%U %UP; ;JO OD+ +2Q Qr/   