
    ]i,                     P   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
mZ ddlmZ ej                  j                  dd       ej                  j                  dd       ddlZddlm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ede!fdZ"dede!fdZ#ddlm$Z$ y)uj   
통합 테스트: cross_model_review.py, scripts/worktree_manager.py
task-1837_5.1 - 닌기르수 작성
    N)Path)patchz/home/jay/workspacez/home/jay/workspace/scripts)_check_rate_limitc                 V   |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  t        dt        |       dz  dz         |j                  t        dt        |       dz  dz  dz         |j                  d	d	
       |dz  j	                  dd       t        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}}d}|j                  } |       }	||	v }|st        j                  d|fd||	f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      dz  }
dd|
iz  }t        t        j                  |            dx}x}x}}	y)u_   review 모드: 'CRITICAL', 'INFORMATIONAL' 키워드가 프롬프트에 포함되어야 한다.	WORKSPACEmemoryreportsREPORTS_DIR
EVENTS_DIReventsDECISIONS_DIR	decisionsTparentsexist_okztask-test-review.mdu   # 테스트 보고서
내용utf-8encodingztask-test-reviewreviewCRITICALinz%(py1)s in %(py3)spromptpy1py3assert %(py5)spy5NINFORMATIONAL)zD%(py1)s in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.lower
}()
})r   r   r   py7zassert %(py9)spy9)setattrcmrr   mkdir
write_textbuild_review_prompt
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_nameAssertionError_format_explanationlower)tmp_pathmonkeypatchreports_dirr   @py_assert0@py_assert2@py_format4@py_format6@py_assert4@py_assert6@py_format8@py_format10s               ;/home/jay/workspace/tests/integration/test_gemini_review.py$test_build_review_prompt_review_moder=      sQ   [$x.9x.8+i7K]K8\4>H+Dx+OP_d8nx.G(.RU`.`adT2((445T_f4g$$%7BF:::$?f$$$$?f$$$?$$$$$$f$$$f$$$$$$$''''''''''''''''''''''''%v||%|~%8~%%%%8~%%%8%%%%%%v%%%v%%%|%%%~%%%%%%%    c                 D   |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  t        dt        |       dz  dz         |j                  t        dt        |       dz  dz  dz         |j                  d	d	
       |dz  j	                  dd       t        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}}y)ug   challenge 모드: '적대적', '보안 취약점' 등 챌린지 지시사항이 포함되어야 한다.r   r   r	   r
   r   r   r   r   Tr   ztask-test-challenge.md   # 보고서r   r   ztask-test-challenge	challengeu	   챌린지r   r   r   r   r   r   Nu   보안 취약점)r#   r$   r   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r1   r2   r3   r   r4   r5   r6   r7   s           r<   'test_build_review_prompt_challenge_moderC   '   sx   [$x.9x.8+i7K]K8\4>H+Dx+OP_d8nx.G(.RU`.`adT2++77PW7X$$%:KHF ;&    ;&   ;      &   &       ''''''''''''''''''''''''r>   c                    |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  t        dt        |       dz  dz         |j                  t        dt        |       dz  dz  dz         |j                  d	d	
       |dz  j	                  dd       d}t        j
                  dd|      }||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        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) uU   consult 모드: 전달된 질문이 프롬프트에 그대로 포함되어야 한다.r   r   r	   r
   r   r   r   r   Tr   ztask-test-consult.mdr@   r   r   u/   이 설계에서 캐시 전략은 적합한가?ztask-test-consultconsult)questionr   )z%(py0)s in %(py2)srF   r   py0py2assert %(py4)spy4Nu	   컨설팅r   r   r   r   )r#   r$   r   r%   r&   r'   r(   r)   r+   r,   r-   r*   r.   r/   )r1   r2   r3   rF   r   @py_assert1@py_format3@py_format5r4   r5   r6   r7   s               r<   7test_build_review_prompt_consult_mode_includes_questionrO   7   s   [$x.9x.8+i7K]K8\4>H+Dx+OP_d8nx.G(.RU`.`adT2))55mg5V@H$$%8)hWFv8v88vv ;&    ;&   ;      &   &       r>   c                    |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  t        dt        |       dz  dz         |j                  t        dt        |       dz  dz  dz         |j                  d	d	
       t        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}}y)uW   보고서가 없으면 '보고서 없음' 플레이스홀더가 포함되어야 한다.r   r   r	   r
   r   r   r   r   Tr   ztask-no-reportr   u   보고서 없음r   r   r   r   r   r   N)r#   r$   r   r%   r'   r(   r)   r*   r+   r,   r-   r.   r/   rB   s           r<   4test_build_review_prompt_no_report_shows_placeholderrQ   H   s   [$x.9x.8+i7K]K8\4>H+Dx+OP_d8nx.G(.RU`.`adT2 $$%5x@F''''''''''''''''''''''''r>   c                    |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  dd       d}|dz  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)u?   보고서 파일이 존재하면 내용을 반환해야 한다.r   r   r	   r
   Tr   u&   # 보고서
테스트 내용입니다.ztask-load-test.mdr   r   ztask-load-test==z%(py0)s == %(py2)sresultexpectedrG   rJ   rK   Nr#   r$   r   r%   r&   _load_reportr(   r)   r+   r,   r-   r*   r.   r/   )r1   r2   r3   rW   rV   rL   rM   rN   s           r<   ,test_load_report_returns_content_when_existsrZ   Y   s    [$x.9x.8+i7K]K8dT28H&&228g2N./FX6X66XXr>   c                 .   |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  dd       t        j                  d      }d}||u }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)u:   보고서 파일이 없으면 None을 반환해야 한다.r   r   r	   r
   Tr   ztask-nonexistentN)is)z%(py0)s is %(py3)srV   rH   r   r   r   )r#   r$   r   r%   rY   r(   r)   r+   r,   r-   r*   r.   r/   )r1   r2   r3   rV   r5   rL   r6   r7   s           r<   *test_load_report_returns_none_when_missingr^   g   s    [$x.9x.8+i7K]K8dT201F6T>6T66Tr>   c                    |j                  t        dt        |              t        |       dz  dz  }|j                  t        d|       |j                  dd       d}|dz  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)uL   UTF-8 한글이 포함된 보고서 내용을 정확히 반환해야 한다.r   r   r	   r
   Tr   uF   ## 작업 완료 보고서

변경사항: 함수 추가, 버그 수정ztask-korean.mdr   r   ztask-koreanrS   rU   rV   korean_contentrG   rJ   rK   NrX   )r1   r2   r3   r`   rV   rL   rM   rN   s           r<   "test_load_report_with_utf8_contentra   r   s    [$x.9x.8+i7K]K8dT2_N##///Qm,F^####6^######6###6######^###^#######r>   c                    |j                  t        dt        |              t        |       dz  dz  dz  }|j                  t        d|       t        j                  ddd       |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)u9   결정 기록 시 JSONL 파일이 생성되어야 한다.r   r   r   r   r   ztask-record-testg1_gateapprovedztask-record-test.jsonlzAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}decisions_file)rH   rI   rK   N)r#   r$   r   _record_decisionexistsr+   r,   r(   r-   r*   r.   r/   )r1   r2   decisions_dirre   rL   @py_assert3rN   s          r<   'test_record_decision_creates_jsonl_filerj      s    [$x.9NX-8;FM_m<+Y
C"%==N  " """""""">""">""" """"""""""r>   c                    |j                  t        dt        |              t        |       dz  dz  dz  }|j                  t        d|       t        j                  dddd	
       |dz  }|j	                  d      j                         j                         d   }t        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   }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}||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   }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) uV   JSONL 파일의 각 줄은 task_id, stage, decision, timestamp를 포함해야 한다.r   r   r   r   r   ztask-struct-testcross_reviewrd   r   )modeztask-struct-test.jsonlr   r   r   task_idrS   z%(py1)s == %(py4)sr   rK   assert %(py6)spy6Nstagedecision	timestampr   r   entryr   r   r   rm   )r#   r$   r   rf   	read_textstrip
splitlinesjsonloadsr(   r)   r*   r.   r/   r+   r,   r-   )r1   r2   rh   re   linerv   r4   ri   r5   rN   @py_format7r6   r7   s                r<   ,test_record_decision_jsonl_content_structurer~      s7   [$x.9NX-8;FM_m<+^ZhW"%==N##W#5;;=HHJ1MDJJtE11111111111111111111111>+^+>^++++>^+++>+++^+++++++*
*
****
******
*******;%;%;%%=$H$=H$$$$=H$$$=$$$H$$$$$$$r>   c                    |j                  t        dt        |              t        |       dz  dz  dz  }|j                  t        d|       t        j                  ddd       t        j                  dd	d
       |dz  }|j	                  d      j                         j                         }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}}t!        j"                  |d         }
t!        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)uR   _record_decision 여러 번 호출 시 각 줄이 JSONL에 추가되어야 한다.r   r   r   r   r   z
task-multistage_1
decision_1stage_2
decision_2ztask-multi.jsonlr   r      rS   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlines)rH   r   r   rr   zassert %(py8)spy8Nr      rs   ro   rp   rq   rr   )r#   r$   r   rf   rw   rx   ry   r   r(   r)   r+   r,   r-   r*   r.   r/   rz   r{   )r1   r2   rh   re   r   r5   @py_assert5r8   r}   @py_format9entry1entry2r4   ri   rN   s                  r<   -test_record_decision_appends_multiple_entriesr      s   [$x.9NX-8;FM_m<y,?y,?"%77N$$g$6<<>IIKEu::?:33uu:ZZa!FZZa!F'?'i'?i''''?i'''?'''i''''''''?'i'?i''''?i'''?'''i'''''''r>   c                    | dz  t        j                  d      }j                  t        j                  |dd      d       ddlm} |j                  |d	fd
       |j                         }g }i }||k(  }|}|sd}	|	|v}
|
}|sXt        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }|j                  |       |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)u7   일 33건 미만이면 빈 dict를 반환해야 한다.gemini_rate_tracker.json%Y-%m-%d   datecountr   r   r   Nr   c                      t               S )N)_check_rate_limit_with_path)tracker_files   r<   <lambda>zAtest_check_rate_limit_below_limit_returns_empty.<locals>.<lambda>   s    +L9 r>   warningrS   )z%(py2)s == %(py5)srV   )rI   r   z%(py7)sr!   )not in)z%(py10)s not in %(py12)s)py10py12z%(py14)spy14r   zassert %(py17)spy17)timestrftimer&   rz   dumpsscripts.worktree_managerworktree_managerr#   r   r(   r)   r+   r,   r-   r*   append_format_boolopr.   r/   )r1   r2   todaywmrV   rL   r8   ri   r4   @py_assert9@py_assert11r7   r:   @py_format13@py_format15@py_format16@py_format18r   s                    @r<   /test_check_rate_limit_below_limit_returns_emptyr      s+   88LMM*%EDJJ'BCgV)
9
 !!#F2R26R<2929F222226R22222262226222R22222229F2229222222F222F22222222222222r>   c                 p   | dz  }t        j                  d      }|j                  t        j                  |dd      d       t        d      5 }t        |       }t               }||_        ||_	        t        |      }d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}|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# 1 sw Y   /xY w)uJ   일 33건 초과 시 warning 키를 포함한 dict를 반환해야 한다.r   r   !   r   r   r   zscripts.worktree_manager.PathNr   r   r   rV   r   r   r   34)z%(py1)s in %(py4)srp   rq   rr   )r   r   r&   rz   r   r   r   	MagicMockparentreturn_value_call_rate_limit_with_trackerr(   r)   r*   r+   r,   r-   r.   r/   )r1   r   r   mock_path_clsmock_parentmock_path_instancerV   r4   r5   r6   r7   ri   rN   r}   s                 r<   -test_check_rate_limit_exceeds_returns_warningr      s9   88LMM*%EDJJ'CDwW 
.	/ ==8n&[$/!%7" /|<= 999$6)$$4$$$$$4$$$$4$$$$$$$$$$$= =s   /F++F5c                    | dz  }|j                  t        j                  ddd      d       t        |      }i }||k(  }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
z  }dd|iz  }t        t	        j                  |            dx}}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   }d}	||	k7  }|slt	        j
                  d|fd||	f      t	        j                  |      t	        j                  |	      dz  }
dd|
iz  }t        t	        j                  |            dx}x}}	y)uO   날짜가 다르면 카운트를 0으로 리셋하고 1로 시작해야 한다.r   z
2020-01-01c   r   r   r   rS   )z%(py0)s == %(py3)srV   r]   r   r   Nr   r   ro   rp   rq   rr   r   )!=)z%(py1)s != %(py4)s)r&   rz   r   r   r(   r)   r+   r,   r-   r*   r.   r/   r{   rw   )r1   r   rV   r5   rL   r6   r7   datar4   ri   rN   r}   s               r<   *test_check_rate_limit_new_day_resets_countr      sJ   88L

L267'   +<8F6R<6R66R::l,,./D=A=A=A=A<'<'<<''''<<'''<'''<'''''''r>   tracker_pathreturnc                    t        j                  d      }i }| j                         r$	 t        j                  | j                               }|j                  d      |k7  r|dd}|dxx   dz  cc<   | j                  t        j                  |             |d   dkD  rdd	|d    d
iS i S # t        j                  t        f$ r i }Y |w xY w)uQ   _check_rate_limit 로직을 tracker_path를 인자로 직접 실행하는 헬퍼.r   r   r   r   r   r   r   r   zGemini daily limit exceeded: z/33)r   r   rg   rz   r{   rw   JSONDecodeErrorOSErrorgetr&   r   )r   r   r   s      r<   r   r      s    MM*%ED	::l4467D xx5 *MQMDJJt,-G}r:4=/MNNI $$g. 	D	s   #B+ +C	C	c                     t        |       S )uM   tracker_path를 지정해서 _check_rate_limit 로직을 실행하는 헬퍼.)r   )r   s    r<   r   r      s    (66r>   )r   )%__doc__builtinsr+   _pytest.assertion.rewrite	assertionrewriter(   rz   sysr   pathlibr   unittest.mockr   pathinsertcross_model_reviewr$   r   r   r=   rC   rO   rQ   rZ   r^   ra   rj   r~   r   r   r   r   dictr   r   r    r>   r<   <module>r      s   
   
    ( ) 0 1   6
&$( !"("$ 	#%$((3 %*("  $7d 7t 7 $r>   