
    hi7                        d dl Z d dlZej                  j                  d e j                  j	                  e j                  j                  e      d             d dlmZm	Z	m
Z
mZ d dl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ddede	fdZddededefdZ G d d      Z G d d      Z G d d      Zy)    Nz..)	AsyncMock	MagicMockcallpatchuser_idis_botusernamereturnc                 D    t               }| |_        ||_        ||_        |S N)r   idr   r	   )r   r   r	   users       G/home/jay/workspace/services/multimodel-bot/tests/test_thinking_mode.py
_make_userr      s#    ;DDGDKDMK    text	from_userchat_id	chat_typec                     t               }| |_        ||_        t               |_        ||j                  _        ||j                  _        ||_        |xs g |_        t               |_	        |S r   )
r   r   r   chatr   typereply_to_messageentitiesr   
reply_text)r   r   r   r   r   r   msgs          r   _make_messager      sY     +CCHCM{CHCHHKCHHM+C>rCL[CNJr   messagec                 X    t               }| |_        | |_        | j                  |_        |S r   )r   r   effective_messager   effective_user)r   updates     r   _make_updater#   ,   s+    [FFN&F#--FMr   bot_usernamec                 h    t               }t               |_        | |j                  _        i |_        |S r   )r   botr	   bot_data)r$   ctxs     r   _make_contextr)   4   s*    
+CkCG#CGGCLJr   bot_idc                     t               }| |_        ||_        t               }d|_        t	        |      |_        t	               |_        |S )uJ   send_message / edit_message_text를 AsyncMock으로 가진 봇 목 객체.90  return_value)r   r   r	   
message_idr   send_messageedit_message_text)r*   r	   r&   sent_msgs       r   _make_async_botr3   <   sB    
+CCFCL{HH h7C%KCJr   c                       e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	y)TestThinkingMessageHelpersuD   bot_utils.send_thinking_message / replace_thinking_message 테스트c                    K   ddl m} t               }d} |||       d{   }|j                  j	                  |d       |dk(  sJ y7 )w)u   send_thinking_message() 호출 시 '🤔 생각 중...' 텍스트로
        bot.send_message가 호출되고, message_id가 반환되어야 한다.r   )send_thinking_messaged   Nu   🤔 생각 중...)r   r   r,   )	bot_utilsr7   r3   r0   assert_called_once_with)selfr7   r&   r   results        r   test_send_thinking_messagez5TestThinkingMessageHelpers.test_send_thinking_messageW   sR      	4,S'::00G[0\ ;s   AA*Ac                    K   ddl m} t               }d}d}d} |||||       d{    |j                  j	                  |||       |j
                  j                          y7 =w)u   replace_thinking_message()에 4096자 이하 텍스트를 전달하면
        bot.edit_message_text가 한 번 호출되어야 한다.r   replace_thinking_messager8   r,   u   짧은 응답입니다.N)r   r/   r   )r9   r@   r3   r1   r:   r0   assert_not_called)r;   r@   r&   r   r/   
short_texts         r   )test_replace_thinking_with_short_responsezDTestThinkingMessageHelpers.test_replace_thinking_with_short_responsee   sr      	7
.
&sGZLLL55! 	6 	

 	**, 	Ms   %A'A%>A'c                   K   ddl m} t               }d}d}ddz  } |||||       d{    |j                  j                  dk(  sJ |j                  j
                  j                  }|d	   |k(  sJ |d
   |k(  sJ t        |d         dk  sJ |j                  j                  dk\  sJ |j                  j                  D ]+  }|j                  }|d	   |k(  sJ t        |d         dk  r+J  y7 ƭw)u   replace_thinking_message()에 4096자 초과 텍스트를 전달하면
        첫 청크는 edit_message_text로, 나머지 청크는 send_message로 전송해야 한다.r   r?   r8   r,   u   가i  N   r   r/   r   i   )
r9   r@   r3   r1   
call_count	call_argskwargslenr0   call_args_list)	r;   r@   r&   r   r/   	long_textfirst_call_kwargs	send_callsent_kwargss	            r   (test_replace_thinking_with_long_responsezCTestThinkingMessageHelpers.test_replace_thinking_with_long_responsey   s      	7
DL	&sGZKKK $$//144411;;BB +w666 .*<<<$V,-555 **a///))88 	4I#**Ky)W444{6*+t333	4 	Ls   (C3C1CC3-C3N)
__name__
__module____qualname____doc__pytestmarkasyncior=   rC   rO    r   r   r5   r5   T   s]    N[[  [[- -& [[4 4r   r5   c                       e Zd ZdZd Zej                  j                  d        Zej                  j                  d        Z	ej                  j                  d        Z
y)TestSequentialResponseu(   멀티봇 순차 응답 로직 테스트c                     ddl m}  |       S )Nr   DiscussionManager)discussion_managerr\   )r;   r\   s     r   _make_discussion_managerz/TestSequentialResponse._make_discussion_manager   s    8 ""r   c                 P  K   ddl m} | j                         }d}|j                  |d       |j                  d   }|j                  d   }|j                  d   }|j                  |dd|	      d
u sJ |j                  |dd|	      du sJ |j                  |dd|	      du sJ yw)u   유저 메시지 수신 시 첫 번째 봇(gemini_view_bot)의 current_turn이
        설정되고, 나머지 봇은 should_bot_respond()에서 False를 반환해야 한다.r   r[         안녕rE      someuserFr$   sender_usernamesender_is_botr   TN)r]   r\   r^   on_user_messageBOT_USERNAMESshould_bot_respond)r;   r\   dmr   	first_bot
second_bot	third_bots          r   )test_user_message_triggers_first_bot_onlyz@TestSequentialResponse.test_user_message_triggers_first_bot_only   s      	9**,
7H-%33A6	&44Q7
%33A6	 !!& *#	 "  	
 !!' *#	 "  	
 !!& *#	 "  	
s   B$B&c                    K   ddl m} | j                         }d}|j                  |d       |j                  d   }|j                  d   }|j                  |      }||k(  sJ |j                  ||d|      du sJ yw)	uO   첫 번째 봇이 응답하면 두 번째 봇의 턴으로 넘어가야 한다.r   r[      ra   rE   Trd   N)r]   r\   r^   rg   rh   on_bot_responseri   )r;   r\   rj   r   rk   rl   next_bots          r   test_first_bot_triggers_secondz5TestSequentialResponse.test_first_bot_triggers_second   s      	9**,
7H-%33A6	&44Q7
 %%i0:%%% !!' )"	 "  	
s   A;A=c                   K   ddl m} | j                         }d}|j                  |d       |j                  d   }|j                  d   }|j                  d   }|g}|j                  |      }|J ||k(  sJ |j                  |       |j                  |      }	|	J |	|k(  sJ |j                  |	       ||||gk(  sJ |j                  |      }
|
|k(  sJ yw)u   세 봇이 순서대로 모두 응답하는 흐름이 정상 동작해야 한다.

        유저 메시지 → gemini → codex → claude → gemini(wrap-around) 순서.r   r[      ra   rE   rb   N)r]   r\   r^   rg   rh   rq   append)r;   r\   rj   r   bot_abot_bbot_cresponse_ordernext_bnext_c	next_wraps              r   &test_response_order_includes_all_threez=TestSequentialResponse.test_response_order_includes_all_three   s
    
 	9**,
7H-!//2!//2!//2  ##E*!!!f%##E*!!!f% %!6666 &&u-	E!!!s   CCN)rP   rQ   rR   rS   r^   rT   rU   rV   rn   rs   r~   rW   r   r   rY   rY      se    2#
 [[*
 *
X [[
 
6 [[!" !"r   rY   c                   n    e Zd ZdZdededefdZd Zd Zd Ze	j                  j                  d	        Zy
)TestContextPromptuT   봇이 생성하는 프롬프트에 맥락이 올바르게 포함되는지 테스트previous_bot_nameprevious_messager
   c                     d| d| dS )uh   main_bot.py의 trigger_next_bot_response에서 사용하는
        프롬프트 포맷을 재현한다.u   [그룹 토론 중] u   의 발언: uH   

위 내용에 대해 당신의 의견을 간결하게 말해주세요.rW   )r;   r   r   s      r   _make_discussion_promptz)TestContextPrompt._make_discussion_prompt  s'     ##4"5\BRAS TU U	
r   c                 <    d}d}| j                  ||      }||v sJ y)uQ   프롬프트에 이전 대화 내용(previous_message)이 포함되어야 한다.gemini_view_botu.   인공지능은 인류에 도움이 됩니다.Nr   )r;   previous_botprevious_msgprompts       r   'test_context_includes_previous_messagesz9TestContextPrompt.test_context_includes_previous_messages)  s,    (G--lLIv%%%r   c                 H    d}d}| j                  ||      }||v sJ ||v sJ y)u\   두 번째 봇의 프롬프트에 첫 번째 봇의 응답 내용이 포함되어야 한다.r   u<   저는 이 문제에 대해 긍정적으로 생각합니다.Nr   )r;   first_bot_namefirst_bot_responser   s       r   'test_second_bot_sees_first_bot_responsez9TestContextPrompt.test_second_bot_sees_first_bot_response2  s>    *[--n>PQ '''!V+++r   c                 f    ddl m} |j                  D ]  }d}| j                  ||      }||v rJ  y)u^   각 봇의 페르소나(이름)가 프롬프트의 발언자 표기에 포함되어야 한다.r   r[   u   테스트 발언입니다.N)r]   r\   rh   r   )r;   r\   r$   some_messager   s        r   test_persona_included_in_promptz1TestContextPrompt.test_persona_included_in_prompt=  sA    8-;; 	*L7L11,MF  6)))	*r   c                 f  
K   g 
d}d#dt         dt         dt         f
fd}t               }||j                  _        ddd	d
}t	        j
                  d|      5  t	        d      5 }t	        d|      5  t	        d      5 }t	        d|      5  t	        dt              5  d|j                  _        d|j                  _        d|j                  j                  _
        d|j                  _        t               }t        t        d            |j                  _        t               |j                  _        t        d      |_        t        |t        d      f      |_        ddlm}  |dddd        d{    ddd       ddd       ddd       ddd       ddd       ddd       t'        
      d!k(  sJ 
d   }	|	|k(  sJ |j                  j)                  ddd"       y7 o# 1 sw Y   nxY w# 1 sw Y   rxY w# 1 sw Y   vxY w# 1 sw Y   zxY w# 1 sw Y   ~xY w# 1 sw Y   xY ww)$u   trigger_next_bot_response()가 memory.format_context()를 통해
        맥락 기반 프롬프트를 엔진 호출에 사용해야 한다.uE   코덱스의 관점에서 이전 대화를 참고하여 답변하라.gpt-5.1-codex-minir   modelr
   c                 0   K   j                  |        yw)N   모의 응답)rv   )r   r   captured_promptss     r   fake_call_codexz_TestContextPrompt.test_trigger_next_bot_response_builds_correct_prompt.<locals>.fake_call_codexS  s     ##F+"s   zfake-gemini-tokenzfake-codex-tokenzfake-claude-token)GEMINI_BOT_TOKENCODEX_BOT_TOKENCLAUDE_BOT_TOKENz
os.environzmain_bot.dmzmain_bot.memoryzmain_bot.bot_appszmain_bot.call_codex)newzasyncio.sleep)new_callableTNdiverge  )r/   r-   r   r   )trigger_next_bot_responsecodex_view_boti,  u%   이전 봇의 발언 내용입니다.r   )next_bot_usernamer   r   r   rE   )phase)r   )strr   format_contextr.   r   dictr   is_discussion_activerq   get_current_phasevalueget_codex_modelr&   r0   r1   __contains____getitem__main_botr   rI   r:   )r;   expected_context_promptr   mock_memory	env_patchmock_dmmock_bot_appsmock_appr   r   r   s             @r   4test_trigger_next_bot_response_builds_correct_promptzFTestContextPrompt.test_trigger_next_bot_response_builds_correct_promptH  s'     ')"i	## 	#c 	#UX 	#  k2I""/ !41 3
	 JJ|Y/	- 	$+#[1	 %&		 +8'_=	 /	:	 9=G((537G##0;DG%%2283GG##0 {H(1yTW?X(YHLL%-6[HLL*)2)EM&(1)apJq?r(sM%:+"2!H"3	  +	 	 	 	 	 	8 #$)))!!$0000""::3@PXa:b+	 	 	 	 	 	 	 	 	 	 	 	s   AH1H%$H1H=H	G5CG)7G'8G)<G5H	HHH%$AH1'G))G2.G55G>:H	H
HHHH"	H%%H.*H1N)rP   rQ   rR   rS   r   r   r   r   r   rT   rU   rV   r   rW   r   r   r   r     sU    ^



 

 
	

&	,	* [[6c 6cr   r   )Ftestuser)r8   groupNN)mybot)r   r   )ossyspathinsertjoindirname__file__unittest.mockr   r   r   r   rT   intboolr   r   r   r#   r)   r3   r5   rY   r   rW   r   r   <module>r      s   	 
 277<< 94@ A ; ;  T S R[  
  	 () 	  ) 	C 	 	9 	0?4 ?4Ts" s"xec ecr   