
    (<iY                     b   d dl Z d dlZej                  j                  d e j                  j	                  e j                  j                  e      d             d dlZd dlm	Z	m
Z
 d dlZd dlmZ ddedededefd	Zddededed
edef
dZdedefdZ G d d      Z G d d      Z G d d      Zy)    Nz..)	AsyncMockpatch	CLIResultenginestdoutstderrreturnc                      t        ||d|       S )Nr   r   r	   
returncoder   r   )r   r   r	   s      Z/home/jay/workspace/.worktrees/task-2057-dev2/services/multimodel-bot/tests/test_engine.py
_ok_resultr      s    F6aOO    r   c                      t        ||||       S )Nr   r   )r   r   r	   r   s       r   _err_resultr      s    F6jQWXXr   c                 "    t        ddd| d      S )N TimeoutT)r   r	   r   r   	timed_outr   )r   s    r   _timeout_resultr      s    ByRZ^__r   c                      e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	ej
                  j                  d        Z
ej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zy	)
TestCallGeminiuH   call_gemini() CLIRunner 기반 동작 검증 (engine.py redirect 경유)c                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)	C   정상 응답 시 CLIResult.stdout을 그대로 반환해야 한다r   Ngeminiu   Gemini의 응답입니다.&engine_v2.bot_api.CLIRunner.run_geminireturn_valuenewu   테스트 질문입니다.)r   r   r   r   call_geminiselfr   resultress       r   (test_call_gemini_returns_normal_responsez7TestCallGemini.test_call_gemini_returns_normal_response%   sk      	H&BC;X^A_` 	I**+GHHC	I2222 I	I 	I-   (A"AA AA"AAA"c                   K   ddl }t        d      }t        dt        |            5  |j	                  dd	       d{   ddd       J t              dkD  sJ t        fd
dD              sJ y7 7# 1 sw Y   6xY ww)`   timed_out=True인 CLIResult가 반환되면 타임아웃 관련 메시지를 반환해야 한다r   Nr   r   r   r!      타임아웃 테스트   timeoutc              3   B   K   | ]  }|j                         v   y wNlower.0keywordr'   s     r   	<genexpr>zPTestCallGemini.test_call_gemini_timeout_returns_error_message.<locals>.<genexpr>9        vg7ciik)v   r/   u   시간u   초과z	timed outu   타임아웃)r   r   r   r   r#   lenanyr$   s      @r   .test_call_gemini_timeout_returns_error_messagez=TestCallGemini.test_call_gemini_timeout_returns_error_message/   s      	 *;X^A_` 	P**+CQ*OOC	P3x!||v9uvvvv P	P 	Ps.   'BA;A9A;3B9A;;B Bc                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       J t        |      dkD  sJ d|v sJ y7 '# 1 sw Y   &xY ww)uM   returncode != 0이면 에러 메시지를 반환해야 한다 (403 케이스)r   Nr   u
   403 에러r-   r	   r   r   r   r!   u   403 에러 테스트   ❌r   r   r   r   r#   r;   r$   s       r   4test_call_gemini_api_error_403_returns_error_messagezCTestCallGemini.test_call_gemini_api_error_403_returns_error_message;         	XlqI;X^A_` 	C**+ABBC	C3x!|||| C	C 	C.   *A7A+A)A+#A7)A++A40A7c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       J t        |      dkD  sJ d|v sJ y7 '# 1 sw Y   &xY ww)uM   returncode != 0이면 에러 메시지를 반환해야 한다 (500 케이스)r   Nr   u
   500 에러r-   r?   r   r   r!   u   500 에러 테스트r@   rA   r$   s       r   4test_call_gemini_api_error_500_returns_error_messagezCTestCallGemini.test_call_gemini_api_error_500_returns_error_messageG   rC   rD   c                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       J t        |      dkD  sJ d	|v sJ y7 '# 1 sw Y   &xY ww)
D   stdout이 비어 있으면 fallback 메시지를 반환해야 한다r   Nr   r   r   r   r!      빈 응답 테스트   ⚠️r   r   r   r   r#   r;   r$   s       r   :test_call_gemini_empty_candidates_returns_fallback_messagezITestCallGemini.test_call_gemini_empty_candidates_returns_fallback_messageS   s      	Hb);X^A_` 	C**+ABBC	C3x!||3 C	C 	C-   (A5A)A' A)#A5'A))A2.A5c                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       J t        |      dkD  sJ d	|v sJ y7 '# 1 sw Y   &xY ww)
uG   stdout이 빈 문자열이면 fallback 메시지를 반환해야 한다r   Nr   r   r   r   r!   u   빈 텍스트 테스트rJ   rK   r$   s       r   4test_call_gemini_empty_text_returns_fallback_messagezCTestCallGemini.test_call_gemini_empty_text_returns_fallback_message_   s      	Hb);X^A_` 	F**+DEEC	F3x!||3 F	F 	FrM   c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       J t        |      dkD  sJ d|v sJ y7 '# 1 sw Y   &xY ww)uY   일반 에러(returncode != 0, stderr 있음) 시 에러 메시지를 반환해야 한다r   Nr   zunexpected errorr   r?   r   r   r!   u   예외 테스트r@   rA   r$   s       r   8test_call_gemini_general_exception_returns_error_messagezGTestCallGemini.test_call_gemini_general_exception_returns_error_messagek   s      	X.@RP;X^A_` 	?**+=>>C	?3x!|||| ?	? 	?rD   N)__name__
__module____qualname____doc__pytestmarkasyncior(   r=   rB   rF   rL   rO   rQ    r   r   r   r   "   s    R[[3 3 [[	w 	w [[	 	 [[	 	 [[	 	 [[	 	 [[	 	r   r   c                   8   e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	ej
                  j                  d        Z
ej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d	        Zej
                  j                  d
        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zy)TestCallCodexuG   call_codex() CLIRunner 기반 동작 검증 (engine.py redirect 경유)c                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)	r   r   Ncodexu   Codex의 응답입니다.%engine_v2.bot_api.CLIRunner.run_codexr   r!   u   코드 리뷰 요청r   r   r   r   
call_codexr$   s       r   'test_call_codex_returns_normal_responsez5TestCallCodex.test_call_codex_returns_normal_response   sk      	G%@A:	W]@^_ 	B))*@AAC	B1111 B	B 	Br)   c                    K   ddl }t        dd      }t        |      }t        d|      5  |j	                  d       d{    ddd       |j
                  \  }}|d   dk(  sJ y7 &# 1 sw Y   %xY ww)	uU   call_codex()는 프롬프트를 CLIRunner에 첫 번째 인자로 전달해야 한다r   Nr]      응답r   r^   r!   u   함수 작성해줘)r   r   r   r   r`   	call_args)r%   r   r&   mock_runargs_s         r   +test_call_codex_passes_prompt_to_subprocessz9TestCallCodex.test_call_codex_passes_prompt_to_subprocess   s}      	GX.&1:I 	;##$9:::	;$$aAw//// ;	; 	;s.   *A6A*A(A*"A6(A**A3/A6c                   K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   ddd       J t              dkD  sJ t        fddD              sJ y7 7# 1 sw Y   6xY ww)ud   stderr에 login/auth 관련 텍스트가 있으면 로그인 안내 메시지를 반환해야 한다r   Nr]   z3Error: Not authenticated. Please run `codex login`.r-   r?   r^   r   r!   u   로그인 없이 요청c              3   B   K   | ]  }|j                         v   y wr1   r2   r4   s     r   r7   zYTestCallCodex.test_call_codex_not_logged_in_returns_auth_error_message.<locals>.<genexpr>        bg7ciik)br9   loginauthu	   로그인u   인증r   r   r   r   r`   r;   r<   r$   s      @r   8test_call_codex_not_logged_in_returns_auth_error_messagezFTestCallCodex.test_call_codex_not_logged_in_returns_auth_error_message   s      	W-bopq:	W]@^_ 	E))*CDDC	E3x!||b9abbbb E	E 	E.   *BA<A:A<3B:A<<BBc                   K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   ddd       J t              dkD  sJ t        fddD              sJ y7 7# 1 sw Y   6xY ww)u\   stderr에 'auth' 키워드가 포함되면 로그인 안내 메시지를 반환해야 한다r   Nr]   zauthentication requiredr-   r?   r^   r   r!   u   auth 에러 테스트c              3   B   K   | ]  }|j                         v   y wr1   r2   r4   s     r   r7   z^TestCallCodex.test_call_codex_auth_keyword_in_stderr_triggers_login_message.<locals>.<genexpr>   rk   r9   rl   ro   r$   s      @r   =test_call_codex_auth_keyword_in_stderr_triggers_login_messagezKTestCallCodex.test_call_codex_auth_keyword_in_stderr_triggers_login_message   s      	W-FSTU:	W]@^_ 	C))*ABBC	C3x!||b9abbbb C	C 	Crq   c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       J t        |      dkD  sJ y7 !# 1 sw Y    xY ww)ud   CLIRunner가 FileNotFoundError 에러 결과를 반환하면 에러 메시지를 반환해야 한다r   Nr]   zcodex not found in PATHr   r?   r^   r   r!   u   명령어 없음 테스트r   r   r   r   r`   r;   r$   s       r   4test_call_codex_file_not_found_returns_error_messagezBTestCallCodex.test_call_codex_file_not_found_returns_error_message   sy      	W-FSUV:	W]@^_ 	H))*FGGC	H3x!|| H	H 	Hs.   *A1A%A#A%A1#A%%A.*A1c                   K   ddl }t        d      }t        dt        |            5  |j	                  d       d{   ddd       J t              dkD  sJ t        fdd	D              sJ y7 7# 1 sw Y   6xY ww)
r+   r   Nr]   r^   r   r!   r,   c              3   B   K   | ]  }|j                         v   y wr1   r2   r4   s     r   r7   zNTestCallCodex.test_call_codex_timeout_returns_error_message.<locals>.<genexpr>   r8   r9   r:   )r   r   r   r   r`   r;   r<   r$   s      @r   -test_call_codex_timeout_returns_error_messagez;TestCallCodex.test_call_codex_timeout_returns_error_message   s      	 ):	W]@^_ 	D))*BCCC	D3x!||v9uvvvv D	D 	Ds-   'BA9A7 A93B7A99B>Bc                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  d      d	k(  sJ y7 2# 1 sw Y   1xY ww)uR   call_codex()는 timeout 파라미터를 CLIRunner.run_codex에 전달해야 한다r   Nr]   rc   r   r^   r!   u   타임아웃 값 확인   r.   r/   r   r   r   r   r`   rd   getr%   r   r&   re   rg   kwargss         r   /test_call_codex_timeout_uses_configured_timeoutz=TestCallCodex.test_call_codex_timeout_uses_configured_timeout   s      	GX.&1:I 	K##$=r#JJJ	K&&	6zz)$*** K	K 	K.   *BA8A6A8.B6A88B=Bc                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)	uj   CLIRunner가 이미 strip()한 결과를 반환하므로 정상 응답이 그대로 전달되어야 한다r   Nr]   u   코드 응답r^   r   r!   u   공백 제거 테스트r_   r$   s       r   -test_call_codex_strips_whitespace_from_outputz;TestCallCodex.test_call_codex_strips_whitespace_from_output   si      	G_5:	W]@^_ 	E))*CDDC	Eo%%% E	E 	Er)   c                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       J t        |      dkD  sJ y7 !# 1 sw Y    xY ww)	rH   r   Nr]   r   r^   r   r!   rI   )r   r   r   r   r`   r;   r$   s       r   5test_call_codex_empty_output_returns_fallback_messagezCTestCallCodex.test_call_codex_empty_output_returns_fallback_message   su      	GR(:	W]@^_ 	B))*@AAC	B3x!|| B	B 	Bs-   (A/A#A! A#A/!A##A,(A/c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)ub   stderr에 'usage limit' 포함 시 사용량 한도 초과 경고 메시지를 반환해야 한다r   Nr]   zAError: You have reached your usage limit. Please try again later.r-   r?   r^   r   r!   u   사용량 한도 테스트K   ⚠️ Codex 사용량 한도 초과. 잠시 후 다시 시도해주세요.r   r   r   r   r`   r$   s       r   +test_call_codex_usage_limit_returns_warningz9TestCallCodex.test_call_codex_usage_limit_returns_warning   ss      	V

 :	W]@^_ 	H))*FGGC	Hcccc H	H 	H.   *A$AAAA$AA!A$c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)u_   stderr에 'hit your' 포함 시 사용량 한도 초과 경고 메시지를 반환해야 한다r   Nr]   z You have hit your monthly quota.r-   r?   r^   r   r!   u   hit your 에러 테스트r   r   r$   s       r   (test_call_codex_hit_your_returns_warningz6TestCallCodex.test_call_codex_hit_your_returns_warning   sn      	W-O\]^:	W]@^_ 	G))*EFFC	Gcccc G	G 	Gr   c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       dvsJ d|vsJ y7 # 1 sw Y   xY ww)uY   usage limit 에러 시 stderr 원문이 반환 메시지에 포함되지 않아야 한다r   Nr]   z6Error: usage limit reached. token=secret-api-key-12345r-   r?   r^   r   r!   u   stderr 노출 방지 테스트zsecret-api-key-12345token=r   r$   s       r   .test_call_codex_usage_limit_no_stderr_exposurez<TestCallCodex.test_call_codex_usage_limit_no_stderr_exposure   s      	K

 :	W]@^_ 	L))*JKKC	L%S000s""" L	L 	L.   *A)AAAA)AA&"A)c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       dv sJ d|vsJ d|vsJ y7 # 1 sw Y   xY ww)uo   stderr에 여러 줄이 있고 일부만 'error' 포함 시 error 줄만 필터링되어 반환되어야 한다r   Nr]   zAinfo: starting process
Error: connection refused
debug: retrying
r-   r?   r^   r   r!   u   error 필터링 테스트zError: connection refusedzinfo: starting processzdebug: retryingr   r$   s       r   .test_call_codex_error_filters_error_lines_onlyz<TestCallCodex.test_call_codex_error_filters_error_lines_only  s      	Y

 :	W]@^_ 	G))*EFFC	G*c111's222 +++ G	G 	Gs.   *A/A#A!A#A/!A##A,(A/c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       dv sJ y7 # 1 sw Y   xY ww)ua   stderr에 'error' 포함 줄이 없으면 '상세 내용 없음' 메시지를 반환해야 한다r   Nr]   z1warning: something happened
info: process exited
r-   r?   r^   r   r!      error 줄 없음 테스트   상세 내용 없음r   r$   s       r   4test_call_codex_error_no_error_lines_returns_genericzBTestCallCodex.test_call_codex_error_no_error_lines_returns_generic  sr      	H

 :	W]@^_ 	H))*FGGC	H%,,, H	H 	Hs.   *A#AAAA#AA A#c                   K   ddl }d}t        d|d      }t        dt        |      	      5  |j	                  d
       d{   }ddd       d}t        |      d }t        |      dk  sJ y7 -# 1 sw Y   ,xY ww)uC   필터링된 에러가 300자 초과 시 300자로 잘려야 한다r   Na  Error: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxr]   r-   r?   r^   r   r!   u   300자 제한 테스트u   ❌ Codex CLI 에러 (exit 1): i,  rv   )r%   r   long_error_liner&   r'   prefix
error_parts          r   ,test_call_codex_error_filtered_max_300_charsz:TestCallCodex.test_call_codex_error_filtered_max_300_chars+  s      	/W_K:	W]@^_ 	E))*CDDC	E2V'
:#%%% E	E 	Es.   ,A?A3A1A3)A?1A33A<8A?c                    K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       dvsJ d|vsJ y7 # 1 sw Y   xY ww)uM   auth 에러 메시지에서도 stderr 전문이 노출되지 않아야 한다r   Nr]   z2auth failed: token=super-secret-system-prompt-datar-   r?   r^   r   r!   u#   auth stderr 노출 방지 테스트zsuper-secret-system-prompt-datar   r   r$   s       r   -test_call_codex_auth_error_no_stderr_exposurez;TestCallCodex.test_call_codex_auth_error_no_stderr_exposure8  s{      	W-anop:	W]@^_ 	Q))*OPPC	Q0;;;s""" Q	Q 	Qr   c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  d       d{    ddd       |j
                  \  }}|j                  d	      d
k(  sJ y7 2# 1 sw Y   1xY ww)u`   model 파라미터 없이 호출하면 CLIRunner에 gpt-5.1-codex-mini가 전달되어야 한다r   Nr]   okr   r^   r!   u   기본 모델 테스트modelzgpt-5.1-codex-minir}   r   s         r   %test_call_codex_default_model_is_miniz3TestCallCodex.test_call_codex_default_model_is_miniC  s      	GT*&1:I 	?##$=>>>	?&&	6zz'"&:::: ?	? 	?.   *BA6A4A6.B4A66A?;Bc                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  d      d	k(  sJ y7 2# 1 sw Y   1xY ww)uZ   model='gpt-5.2-codex'로 호출하면 CLIRunner에 gpt-5.2-codex가 전달되어야 한다r   Nr]   r   r   r^   r!   u   커스텀 모델 테스트gpt-5.2-codex)r   r   r}   r   s         r   *test_call_codex_custom_model_passed_to_cmdz8TestCallCodex.test_call_codex_custom_model_passed_to_cmdO  s      	GT*&1:I 	Y##$@#XXX	Y&&	6zz'"o555 Y	Y 	Yr   c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  d       d{    ddd       |j
                  \  }}|j                  d	      d
k7  sJ y7 2# 1 sw Y   1xY ww)uj   기본 호출 시 CLIRunner에 gpt-5.2-codex가 전달되지 않아야 한다 (하드코딩 제거 확인)r   Nr]   r   r   r^   r!   u   하드코딩 제거 확인r   r   r}   r   s         r   #test_call_codex_model_not_hardcodedz1TestCallCodex.test_call_codex_model_not_hardcoded[  s      	GT*&1:I 	B##$@AAA	B&&	6zz'"o555 B	B 	Br   N)rR   rS   rT   rU   rV   rW   rX   ra   rh   rp   rt   rw   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   rY   r   r   r[   r[   }   sG   Q[[2 2 [[	0 	0 [[	c 	c [[	c 	c [[  [[	w 	w [[	+ 	+ [[& & [[  [[d d [[d d [[# # [[, , [[- - [[
& 
& [[# # [[	; 	; [[	6 	6 [[	6 	6r   r[   c                   x   e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	ej
                  j                  d        Z
ej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d	        Zej
                  j                  d
        Zej
                  j                  d        Zej
                  j                  d        Zy)TestCallClaudeuH   call_claude() CLIRunner 기반 동작 검증 (engine.py redirect 경유)c                    K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)	r   r   Nclaudeu   Claude의 응답입니다.&engine_v2.bot_api.CLIRunner.run_clauder   r!   u   테스트 질문)r   r   r   r   call_clauder$   s       r   (test_call_claude_returns_normal_responsez7TestCallClaude.test_call_claude_returns_normal_responsek  sf      	H&BC;X^A_` 	?**+=>>C	?2222 ?	? 	?r)   c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  d       d{    ddd       |j
                  \  }}|j                  d	      d
u sJ y7 1# 1 sw Y   0xY ww)u\   code_analysis=False(기본값)면 CLIRunner에 code_analysis=False가 전달되어야 한다r   Nr   r   r   r   r!      일반 질문code_analysisFr   r   r   r   r   rd   r~   r   s         r   )test_call_claude_default_no_allowed_toolsz8TestCallClaude.test_call_claude_default_no_allowed_toolsu        	Hd+&1;J 	6$$_555	6&&	6zz/*e333 6	6 	6.   *BA5A3A5-B3A55A>:Bc                 
  K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  d      d	u sJ y7 1# 1 sw Y   0xY ww)uO   code_analysis=True면 CLIRunner에 code_analysis=True가 전달되어야 한다r   Nr   zcode resultr   r   r!      코드 분석Tr   r   r   r   s         r   1test_call_claude_code_analysis_adds_allowed_toolsz@TestCallClaude.test_call_claude_code_analysis_adds_allowed_tools  s      	Hm4&1;J 	J$$_D$III	J&&	6zz/*d222 J	J 	J.   *BA7A5A7-B5A77B <Bc                 
  K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  d      d	u sJ y7 1# 1 sw Y   0xY ww)u~   code_analysis=True면 CLIRunner 내부에서 cwd가 /home/jay/workspace로 설정되어야 한다 (파라미터 전달 검증)r   Nr   r   r   r   r!   r   Tr   r   r   r   s         r   *test_call_claude_code_analysis_changes_cwdz9TestCallClaude.test_call_claude_code_analysis_changes_cwd  s      	Hd+&1;J 	J$$_D$III	J&&	6zz/*d222 J	J 	Jr   c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  d       d{    ddd       |j
                  \  }}|j                  d	      d
u sJ y7 1# 1 sw Y   0xY ww)u_   code_analysis=False(기본값)이면 CLIRunner에 code_analysis=False가 전달되어야 한다r   Nr   r   r   r   r!   r   r   Fr   r   s         r   #test_call_claude_default_cwd_is_tmpz2TestCallClaude.test_call_claude_default_cwd_is_tmp  r   r   c                 
  K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  d      d	u sJ y7 1# 1 sw Y   0xY ww)uU   code_analysis=True에서 code_analysis 파라미터가 True로 전달되어야 한다r   Nr   r   r   r   r!   r   Tr   r   r   r   s         r   -test_call_claude_code_analysis_no_write_toolsz<TestCallClaude.test_call_claude_code_analysis_no_write_tools  s      	Hd+&1;J 	J$$_D$III	J&&	6zz/*d222 J	J 	Jr   c                    K   ddl }t        d      }t        dt        |            5  |j	                  d       d{   }ddd       dv sd	|j                         v sJ yy7 &# 1 sw Y   %xY ww)
u8   타임아웃 시 에러 메시지를 반환해야 한다r   Nr   r   r   r!   r,   u   시간 초과r/   )r   r   r   r   r   r3   r$   s       r   .test_call_claude_timeout_returns_error_messagez=TestCallClaude.test_call_claude_timeout_returns_error_message  sz      	 *;X^A_` 	E**+CDDC	E#%ciik)AAA)A% E	E 	Es,   'A3A'A%A'"A3%A''A0,A3c                   K   ddl }t        dd      }t        |      }dt        j                  d<   	 t        d|	      5  |j                  d
       d{   }ddd       dk(  sJ 	 t        j                  j                  dd       y7 5# 1 sw Y   4xY w# t        j                  j                  dd       w xY ww)um   CLAUDECODE 환경변수 제거가 CLIRunner 레벨에서 처리되어야 한다 (정상 응답 반환 확인)r   Nr   r   r   z
test-value
CLAUDECODEr   r!   u   env 테스트)r   r   r   osenvironr   r   pop)r%   r   r&   re   r'   s        r   'test_call_claude_removes_claudecode_envz6TestCallClaude.test_call_claude_removes_claudecode_env  s      	Hd+&1#/

< 	/?XN @"..??@$;;JJNN<. @@ @ JJNN<.sF   0B>B  BBBB *!B>BBB "B;;B>c                    K   ddl }t        dddd      }t        dt        |	      
      5  |j	                  d       d{   }ddd       dv sJ d|vsJ d|vsJ y7 # 1 sw Y   xY ww)uk   returncode != 0이고 stdout 비어있을 때 stderr에서 error 줄만 필터링하여 반환해야 한다r   Nr   r   z8info: starting
Error: authentication failed
debug: done
r-   r   r	   r   r   r   r!   u   에러 필터링 테스트zError: authentication failedzinfo: startingzdebug: doner   r   r   r   r   r$   s       r   ?test_call_claude_nonzero_returncode_empty_output_filters_errorszNTestCallClaude.test_call_claude_nonzero_returncode_empty_output_filters_errors  s      	P	
 ;X^A_` 	I**+GHHC	I-444s***C''' I	I 	Is.   +A0A$A"A$A0"A$$A-)A0c                    K   ddl }t        dddd      }t        dt        |	      
      5  |j	                  d       d{   }ddd       dv sJ y7 # 1 sw Y   xY ww)un   returncode != 0이고 stdout 비어있고 error 줄도 없으면 '상세 내용 없음'을 반환해야 한다r   Nr   r   z%warning: something odd
info: exiting
   r   r   r   r!   r   r   r   r$   s       r   ?test_call_claude_nonzero_returncode_empty_output_no_error_lineszNTestCallClaude.test_call_claude_nonzero_returncode_empty_output_no_error_lines  su      	<	
 ;X^A_` 	I**+GHHC	I%,,, I	I 	Is.   +A$AAAA$AA!A$c                    K   ddl }t        dddd      }t        dt        |	      
      5  |j	                  d       d{   }ddd       dk(  sJ y7 # 1 sw Y   xY ww)u[   returncode != 0이더라도 stdout에 출력이 있으면 그 출력을 반환해야 한다r   Nr   zpartial output from claudezError: some stderr errorr-   r   r   r   r!   u   출력 있는 에러 테스트r   r$   s       r   >test_call_claude_nonzero_returncode_with_output_returns_outputzMTestCallClaude.test_call_claude_nonzero_returncode_with_output_returns_output  sv      	/-	
 ;X^A_` 	M**+KLLC	M2222 M	M 	Ms.   +A%AAAA%AA"A%N)rR   rS   rT   rU   rV   rW   rX   r   r   r   r   r   r   r   r   r   r   r   rY   r   r   r   r   h  sO   R[[3 3 [[	4 	4 [[	3 	3 [[
3 
3 [[	4 	4 [[	3 	3 [[B B [[/ / [[( (  [[- - [[3 3r   r   )r   )r   r   r-   )r   syspathinsertjoindirname__file__rX   unittest.mockr   r   rV   engine_v2.cli_runnerr   strr   intr   r   r   r[   r   rY   r   r   <module>r      s    	 
 277<< 94@ A  *  *Ps PC P Pi PY YS Ys YS YYb Y`C `I `S Svh6 h6VP3 P3r   