
    UiY                     |   d dl Zd dlmc mZ 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      @/home/jay/workspace/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(  }|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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   테스트 질문입니다.==z%(py0)s == %(py3)srespy0py3assert %(py5)spy5)r   r   r   r   call_gemini
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationselfr   resultr&   @py_assert2@py_assert1@py_format4@py_format6s           r   (test_call_gemini_returns_normal_responsez7TestCallGemini.test_call_gemini_returns_normal_response%   s      	H&BC;X^A_` 	I**+GHHC	I22s22222s2222222s222s22222222222 I	I 	I.   (DC5C3 C5B/D3C55C>:Dc                   K   ddl }t        d      }t        dt        |            5  |j	                  dd	       d{   dd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}}t              }d}||kD  }|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}}fddD        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y7 t# 1 sw Y   txY ww)`   timed_out=True인 CLIResult가 반환되면 타임아웃 관련 메시지를 반환해야 한다r   Nr   r   r   r!      타임아웃 테스트   timeoutis notz%(py0)s is not %(py3)sr&   r'   r*   r+   >z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)slenr(   py1r)   py6assert %(py8)spy8c              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   rC   u   시간u   초과z	timed outu   타임아웃,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr(   py2py4)r   r   r   r   r,   r-   r.   r/   r0   r1   r2   r3   r4   rJ   r\   r6   r   r7   r8   r9   r:   r;   @py_assert5@py_assert4@py_format7@py_format9@py_assert3@py_format5r&   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s$s$ss$3x!x!|x!ss33x!v9uvvsvvvvvvvvvsvvvsvvvvvvvvvvvvvv P	P 	Ps/   'KJ8J5J8I/K5J88K=Kc                 v  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }dd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}}t        |      }d}||kD  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}d}||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7 h# 1 sw Y   hxY ww)uM   returncode != 0이면 에러 메시지를 반환해야 한다 (403 케이스)r   Nr   u
   403 에러rA   r	   r   r   r   r!   u   403 에러 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO      ❌inz%(py1)s in %(py3)srL   r)   r   r   r   r   r,   r-   r.   r/   r0   r1   r2   r3   r4   rJ   r6   r   r7   r&   r8   r9   r:   r;   ra   rb   rc   rd   @py_assert0s                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s$s$ss$3x!x!|x!ss33x!u|uu C	C 	C/   *J9J,J)J,I#J9)J,,J61J9c                 v  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }dd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}}t        |      }d}||kD  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}d}||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7 h# 1 sw Y   hxY ww)uM   returncode != 0이면 에러 메시지를 반환해야 한다 (500 케이스)r   Nr   u
   500 에러rA   ri   r   r   r!   u   500 에러 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   rj   rk   rm   rn   ro   rp   s                r   4test_call_gemini_api_error_500_returns_error_messagezCTestCallGemini.test_call_gemini_api_error_500_returns_error_messageG   rs   rt   c                 r  K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }dd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}}t        |      }d}||kD  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}d}||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7 h# 1 sw Y   hxY ww)D   stdout이 비어 있으면 fallback 메시지를 반환해야 한다r   Nr   r   r   r   r!      빈 응답 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO      ⚠️rk   rm   rn   r   r   r   r   r,   r-   r.   r/   r0   r1   r2   r3   r4   rJ   rp   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s$s$ss$3x!x!|x!ss33x!x3x3x33 C	C 	C.   (J7J*J' J*I#J7'J**J4/J7c                 r  K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }dd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}}t        |      }d}||kD  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}d}||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7 h# 1 sw Y   hxY ww)uG   stdout이 빈 문자열이면 fallback 메시지를 반환해야 한다r   Nr   r   r   r   r!   u   빈 텍스트 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   rz   rk   rm   rn   r{   rp   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s$s$ss$3x!x!|x!ss33x!x3x3x33 F	F 	Fr}   c                 v  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }dd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}}t        |      }d}||kD  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}d}||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7 h# 1 sw Y   hxY ww)uY   일반 에러(returncode != 0, stderr 있음) 시 에러 메시지를 반환해야 한다r   Nr   zunexpected errorr   ri   r   r   r!   u   예외 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   rj   rk   rm   rn   ro   rp   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	?s$s$ss$3x!x!|x!ss33x!u|uu ?	? 	?rt   N)__name__
__module____qualname____doc__pytestmarkasyncior<   rg   rr   rv   r|   r   r    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(  }|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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'   r*   r+   r   r   r   r   
call_codexr-   r.   r/   r0   r1   r2   r3   r4   r5   s           r   'test_call_codex_returns_normal_responsez5TestCallCodex.test_call_codex_returns_normal_response   s      	G%@A:	W]@^_ 	B))*@AAC	B11s11111s1111111s111s1111111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(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y7 # 1 sw Y   xY ww)uU   call_codex()는 프롬프트를 CLIRunner에 첫 번째 인자로 전달해야 한다r   Nr      응답r   r   r!   u   함수 작성해줘r#   )z%(py1)s == %(py4)s)rL   r_   zassert %(py6)srM   )r   r   r   r   r   	call_argsr-   r.   r2   r3   r4   )r6   r   r7   mock_runargs_rq   re   r8   rf   rc   s              r   +test_call_codex_passes_prompt_to_subprocessz9TestCallCodex.test_call_codex_passes_prompt_to_subprocess   s      	GX.&1:I 	;##$9:::	;$$aAw///w/////w////w/////////// ;	; 	;s/   *C,C CC BC,C  C)%C,c                   K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   dd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}}t              }d}||kD  }|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}}fddD        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y7 t# 1 sw Y   txY ww)ud   stderr에 login/auth 관련 텍스트가 있으면 로그인 안내 메시지를 반환해야 한다r   Nr   z3Error: Not authenticated. Please run `codex login`.rA   ri   r   r   r!   u   로그인 없이 요청rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   c              3   B   K   | ]  }|j                         v   y wrQ   rR   rT   s     r   rW   zYTestCallCodex.test_call_codex_not_logged_in_returns_auth_error_message.<locals>.<genexpr>        bg7ciik)brY   loginauthu	   로그인u   인증r[   r\   r]   r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   rJ   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s$s$ss$3x!x!|x!ss33x!b9abbsbbbbbbbbbsbbbsbbbbbbbbbbbbbb E	E 	E/   *KJ9J6J9I/K6J99K>Kc                   K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   dd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}}t              }d}||kD  }|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}}fddD        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y7 t# 1 sw Y   txY ww)u\   stderr에 'auth' 키워드가 포함되면 로그인 안내 메시지를 반환해야 한다r   Nr   zauthentication requiredrA   ri   r   r   r!   u   auth 에러 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   c              3   B   K   | ]  }|j                         v   y wrQ   rR   rT   s     r   rW   z^TestCallCodex.test_call_codex_auth_keyword_in_stderr_triggers_login_message.<locals>.<genexpr>   r   rY   r   r[   r\   r]   r   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s$s$ss$3x!x!|x!ss33x!b9abbsbbbbbbbbbsbbbsbbbbbbbbbbbbbb C	C 	Cr   c                 ,  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }dd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}}t        |      }d}||kD  }	|	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7 # 1 sw Y   xY ww)ud   CLIRunner가 FileNotFoundError 에러 결과를 반환하면 에러 메시지를 반환해야 한다r   Nr   zcodex not found in PATHr   ri   r   r   r!   u   명령어 없음 테스트rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   )r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   rJ   r6   r   r7   r&   r8   r9   r:   r;   ra   rb   rc   rd   s               r   4test_call_codex_file_not_found_returns_error_messagezBTestCallCodex.test_call_codex_file_not_found_returns_error_message   sB     	W-FSUV:	W]@^_ 	H))*FGGC	Hs$s$ss$3x!x!|x!ss33x! H	H 	Hs/   *HHHHF>HHHHc                   K   ddl }t        d      }t        dt        |            5  |j	                  d       d{   dd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}}t              }d}||kD  }|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}}fddD        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y7 t# 1 sw Y   txY ww)r?   r   Nr   r   r   r!   r@   rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   c              3   B   K   | ]  }|j                         v   y wrQ   rR   rT   s     r   rW   zNTestCallCodex.test_call_codex_timeout_returns_error_message.<locals>.<genexpr>   rX   rY   rZ   r[   r\   r]   )r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   rJ   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s$s$ss$3x!x!|x!ss33x!v9uvvsvvvvvvvvvsvvvsvvvvvvvvvvvvvv D	D 	Ds.   'KJ6J3 J6I/K3J66K ;Kc                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    dd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                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)uR   call_codex()는 timeout 파라미터를 CLIRunner.run_codex에 전달해야 한다r   Nr   r   r   r   r!   u   타임아웃 값 확인   rB   rC   r#   zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)skwargsr(   r^   r_   rM   py9assert %(py11)spy11r   r   r   r   r   r   getr-   r.   r/   r0   r1   r2   r3   r4   r6   r   r7   r   r   r   r9   re   ra   @py_assert8@py_assert7@py_format10@py_format12s                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*)*z)$**$****$******v***v***z***)***$*********** K	K 	K/   *E.E!EE!DE.E!!E+&E.c                   K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }ddd       d}|k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y7 # 1 sw Y   xY ww)uj   CLIRunner가 이미 strip()한 결과를 반환하므로 정상 응답이 그대로 전달되어야 한다r   Nr   u   코드 응답r   r   r!   u   공백 제거 테스트r#   r%   r&   r'   r*   r+   r   r5   s           r   -test_call_codex_strips_whitespace_from_outputz;TestCallCodex.test_call_codex_strips_whitespace_from_output   s      	G_5:	W]@^_ 	E))*CDDC	E%%so%%%%so%%%%%%s%%%s%%%o%%%%%%% E	E 	Er=   c                 (  K   ddl }t        dd      }t        dt        |            5  |j	                  d       d{   }dd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}}t        |      }d}||kD  }	|	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7 # 1 sw Y   xY ww)rx   r   Nr   r   r   r   r!   ry   rD   rF   r&   r'   r*   r+   rG   rI   rJ   rK   rN   rO   )r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   rJ   r   s               r   5test_call_codex_empty_output_returns_fallback_messagezCTestCallCodex.test_call_codex_empty_output_returns_fallback_message   s>     	GR(:	W]@^_ 	B))*@AAC	Bs$s$ss$3x!x!|x!ss33x! B	B 	Bs.   (HHH HF>HHH
Hc                 
  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       d}|k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y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.rA   ri   r   r   r!   u   사용량 한도 테스트K   ⚠️ Codex 사용량 한도 초과. 잠시 후 다시 시도해주세요.r#   r%   r&   r'   r*   r+   r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   r5   s           r   +test_call_codex_usage_limit_returns_warningz9TestCallCodex.test_call_codex_usage_limit_returns_warning   s      	V

 :	W]@^_ 	H))*FGGC	Hccscccccscccccccscccsccccccccccc H	H 	H/   *DC7C5C7B/D5C77D <Dc                 
  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }ddd       d}|k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y7 # 1 sw Y   xY ww)u_   stderr에 'hit your' 포함 시 사용량 한도 초과 경고 메시지를 반환해야 한다r   Nr   z You have hit your monthly quota.rA   ri   r   r   r!   u   hit your 에러 테스트r   r#   r%   r&   r'   r*   r+   r   r5   s           r   (test_call_codex_hit_your_returns_warningz6TestCallCodex.test_call_codex_hit_your_returns_warning   s      	W-O\]^:	W]@^_ 	G))*EFFC	Gccscccccscccccccscccsccccccccccc G	G 	Gr   c                 V  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }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}||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7 X# 1 sw Y   XxY ww)uY   usage limit 에러 시 stderr 원문이 반환 메시지에 포함되지 않아야 한다r   Nr   z6Error: usage limit reached. token=secret-api-key-12345rA   ri   r   r   r!   u   stderr 노출 방지 테스트zsecret-api-key-12345not inz%(py1)s not in %(py3)sr&   rn   r*   r+   token=r   r   r   r   r   r-   r.   r2   r/   r0   r1   r3   r4   r6   r   r7   r&   rq   r8   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%0%S0000%S000%000000S000S0000000"xs""""xs"""x""""""s"""s""""""" L	L 	L/   *F)FFFEF)FF&!F)c                   K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }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}||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7 # 1 sw Y   xY ww)uo   stderr에 여러 줄이 있고 일부만 'error' 포함 시 error 줄만 필터링되어 반환되어야 한다r   Nr   zAinfo: starting process
Error: connection refused
debug: retrying
rA   ri   r   r   r!   u   error 필터링 테스트zError: connection refusedrk   rm   r&   rn   r*   r+   zinfo: starting processr   r   zdebug: retryingr   r   s           r   .test_call_codex_error_filters_error_lines_onlyz<TestCallCodex.test_call_codex_error_filters_error_lines_only  sx     	Y

 :	W]@^_ 	G))*EFFC	G*1*c1111*c111*111111c111c1111111'2's2222's222'222222s222s2222222 + ++++ +++ ++++++++++++++++ G	G 	Gs/   *IIH>IG8I>IIIc                   K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }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}}y7 # 1 sw Y   xY ww)ua   stderr에 'error' 포함 줄이 없으면 '상세 내용 없음' 메시지를 반환해야 한다r   Nr   z1warning: something happened
info: process exited
rA   ri   r   r   r!      error 줄 없음 테스트   상세 내용 없음rk   rm   r&   rn   r*   r+   r   r   s           r   4test_call_codex_error_no_error_lines_returns_genericzBTestCallCodex.test_call_codex_error_no_error_lines_returns_generic  s      	H

 :	W]@^_ 	H))*FGGC	H%,%,,,,%,,,%,,,,,,,,,,,,,,,, H	H 	Hs/   *DC6C4C6B.D4C66C?;D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  }	|	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7 .# 1 sw Y   .xY ww)uC   필터링된 에러가 300자 초과 시 300자로 잘려야 한다r   Na  Error: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxr   rA   ri   r   r   r!   u   300자 제한 테스트u   ❌ Codex CLI 에러 (exit 1): i,  )<=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} <= %(py6)srJ   
error_partrK   rN   rO   )r   r   r   r   r   rJ   r-   r.   r/   r0   r1   r2   r3   r4   )r6   r   long_error_liner7   r&   prefixr   r8   ra   rb   rc   rd   s               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'
:%#%#%%%%#%%%%%%s%%%s%%%%%%:%%%:%%%%%%#%%%%%%% E	E 	Es/   ,FE4E1E4D)F1E44E>9Fc                 V  K   ddl }t        ddd      }t        dt        |      	      5  |j	                  d
       d{   }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}||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7 X# 1 sw Y   XxY ww)uM   auth 에러 메시지에서도 stderr 전문이 노출되지 않아야 한다r   Nr   z2auth failed: token=super-secret-system-prompt-datarA   ri   r   r   r!   u#   auth stderr 노출 방지 테스트zsuper-secret-system-prompt-datar   r   r&   rn   r*   r+   r   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;0;;;;0;;;0;;;;;;;;;;;;;;;;"xs""""xs"""x""""""s"""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(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)u`   model 파라미터 없이 호출하면 CLIRunner에 gpt-5.1-codex-mini가 전달되어야 한다r   Nr   okr   r   r!   u   기본 모델 테스트modelzgpt-5.1-codex-minir#   r   r   r   r   r   r   r   s                r   %test_call_codex_default_model_is_miniz3TestCallCodex.test_call_codex_default_model_is_miniC  s     	GT*&1:I 	?##$=>>>	?&&	6zz:':z'":&::"&:::::"&:::::::v:::v:::z:::':::":::&::::::::: ?	? 	?/   *E,EEEDE,EE)$E,c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    dd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                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   x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   r   r   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5'5z'"5o5"o5555"o555555v555v555z555'555"555o55555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  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)uj   기본 호출 시 CLIRunner에 gpt-5.2-codex가 전달되지 않아야 한다 (하드코딩 제거 확인)r   Nr   r   r   r   r!   u   하드코딩 제거 확인r   r   )!=)zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} != %(py9)sr   r   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5'5z'"5o5"o5555"o555555v555v555z555'555"555o55555555 B	B 	B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   r   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(  }|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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'   r*   r+   )r   r   r   r   call_clauder-   r.   r/   r0   r1   r2   r3   r4   r5   s           r   (test_call_claude_returns_normal_responsez7TestCallClaude.test_call_claude_returns_normal_responsek  s      	H&BC;X^A_` 	?**+=>>C	?22s22222s2222222s222s2222222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 }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)u\   code_analysis=False(기본값)면 CLIRunner에 code_analysis=False가 전달되어야 한다r   Nr   r   r   r   r!      일반 질문code_analysisFiszI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} is %(py9)sr   r   r   r   r   r   r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   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3/3z/*3e3*e3333*e333333v333v333z333/333*333e33333333 6	6 	6/   *E+EEEDE+EE(#E+c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  }d} ||      }d	}	||	u }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)uO   code_analysis=True면 CLIRunner에 code_analysis=True가 전달되어야 한다r   Nr   zcode resultr   r   r!      코드 분석Tr   r   r   r   r   r   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2/2z/*2d2*d2222*d222222v222v222z222/222*222d22222222 J	J 	J/   *E-E EE DE-E  E*%E-c                   K   ddl }t        dd      }t        |      }t        d|      5  |j	                  dd	
       d{    ddd       |j
                  \  }}|j                  }d} ||      }d	}	||	u }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)u~   code_analysis=True면 CLIRunner 내부에서 cwd가 /home/jay/workspace로 설정되어야 한다 (파라미터 전달 검증)r   Nr   r   r   r   r!   r   Tr   r   r   r   r   r   r   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2/2z/*2d2*d2222*d222222v222v222z222/222*222d22222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 }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)u_   code_analysis=False(기본값)이면 CLIRunner에 code_analysis=False가 전달되어야 한다r   Nr   r   r   r   r!   r   r   Fr   r   r   r   r   r   r   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 }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}
}	y7 # 1 sw Y   xY ww)uU   code_analysis=True에서 code_analysis 파라미터가 True로 전달되어야 한다r   Nr   r   r   r   r!   r   Tr   r   r   r   r   r   r   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2/2z/*2d2*d2222*d222222v222v222z222/222*222d22222222 J	J 	Jr   c                 0  K   ddl }t        d      }t        dt        |            5  |j	                  d       d{   }ddd       g }d}|v }|}|sd	}|j
                  }	 |	       }
||
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  }|j                  |       |st        j                  d
fd
f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  	      t        j                  |
      dz  }dd|iz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}x}	}
y7 # 1 sw Y   xY ww)u8   타임아웃 시 에러 메시지를 반환해야 한다r   Nr   r   r   r!   r@   u   시간 초과rC   rk   )z%(py3)s in %(py5)sr&   )r)   r+   z%(py7)spy7)zJ%(py10)s in %(py16)s
{%(py16)s = %(py14)s
{%(py14)s = %(py12)s.lower
}()
})py10py12py14py16z%(py18)spy18rA   zassert %(py21)spy21)r   r   r   r   r   rS   r-   r.   r2   r/   r0   r1   append_format_boolopr3   r4   )r6   r   r7   r&   r9   r8   rb   rq   @py_assert9@py_assert13@py_assert15@py_assert11r;   @py_format8@py_format17@py_format19@py_format20@py_format22s                     r   .test_call_claude_timeout_returns_error_messagez=TestCallClaude.test_call_claude_timeout_returns_error_message  sD     	 *;X^A_` 	E**+CDDC	EAA#%AAciiAikAk)AAAAA#AAAAAAAAA#AAA#AAAAAAAkAAAAAAAAAcAAAcAAAiAAAkAAAAAAAAAAAAAA E	E 	Es-   'HH	HH	GHH		HHc                   K   ddl }t        dd      }t        |      }dt        j                  d<   	 t        d|	      5  |j                  d
       d{   }ddd       d}|k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        j                  j                  dd       y7 # 1 sw Y   x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&   r'   r*   r+   )r   r   r   osenvironr   r   r-   r.   r/   r0   r1   r2   r3   r4   pop)	r6   r   r7   r   r&   r8   r9   r:   r;   s	            r   'test_call_claude_removes_claudecode_envz6TestCallClaude.test_call_claude_removes_claudecode_env  s      	Hd+&1#/

< 	/?XN @"..??@3$;3$33$JJNN<. @@ @ JJNN<.sG   0ED7  D+D)D+B.D7 !E)D++D40D7 7"EEc                   K   ddl }t        dddd      }t        dt        |	      
      5  |j	                  d       d{   }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}||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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
rA   r   r	   r   r   r   r!   u   에러 필터링 테스트zError: authentication failedrk   rm   r&   rn   r*   r+   zinfo: startingr   r   zdebug: doner   r   r   r   r   r-   r.   r2   r/   r0   r1   r3   r4   r   s           r   ?test_call_claude_nonzero_returncode_empty_output_filters_errorszNTestCallClaude.test_call_claude_nonzero_returncode_empty_output_filters_errors  sx     	P	
 ;X^A_` 	I**+GHHC	I-4-4444-444-4444444444444444*s****s*********s***s*******'}C''''}C'''}''''''C'''C''''''' I	I 	Is/   +IIH?IG8I?IIIc                 
  K   ddl }t        dddd      }t        dt        |	      
      5  |j	                  d       d{   }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}}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   rk   rm   r&   rn   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  s      	<	
 ;X^A_` 	I**+GHHC	I%,%,,,,%,,,%,,,,,,,,,,,,,,,, I	I 	Is/   +DC7C5C7B.D5C77D <Dc                   K   ddl }t        dddd      }t        dt        |	      
      5  |j	                  d       d{   }ddd       d}|k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y7 # 1 sw Y   xY ww)u[   returncode != 0이더라도 stdout에 출력이 있으면 그 출력을 반환해야 한다r   Nr   zpartial output from claudezError: some stderr errorrA   r   r   r   r!   u   출력 있는 에러 테스트r#   r%   r&   r'   r*   r+   )r   r   r   r   r   r-   r.   r/   r0   r1   r2   r3   r4   r5   s           r   >test_call_claude_nonzero_returncode_with_output_returns_outputzMTestCallClaude.test_call_claude_nonzero_returncode_with_output_returns_output  s      	/-	
 ;X^A_` 	M**+KLLC	M22s22222s2222222s222s22222222222 M	M 	Ms/   +DC8C6C8B/D6C88D=DN)r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r"  r%  r'  r   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   rA   )builtinsr/   _pytest.assertion.rewrite	assertionrewriter-   r  syspathinsertjoindirname__file__r   unittest.mockr   r   r   engine_v2.cli_runnerr   strr   intr   r   r   r   r   r   r   r   <module>r6     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   