import unittest from unittest.mock import MagicMock, patch import gradio as gr from app import switch_thread, create_new_thread_callback, build_agent_prompt, chat_agent_stream class TestUILogic(unittest.TestCase): def test_switch_thread_logic(self): """Verify switching threads returns the correct history.""" # Setup state tid1, tid2 = "uuid-1", "uuid-2" t_state = { tid1: {"title": "Chat 1", "history": [{"role": "user", "content": "Hi"}]}, tid2: {"title": "Chat 2", "history": [{"role": "user", "content": "Bye"}]} } # Test switching to tid2 history, active_id, list_update, m_list_update = switch_thread(tid2, t_state) self.assertEqual(active_id, tid2) self.assertEqual(history, [{"role": "user", "content": "Bye"}]) # Verify updates target both desktop (radio) and mobile (dropdown) self.assertEqual(list_update["value"], tid2) def test_create_new_thread(self): """Verify creating a new thread adds it to state and selects it.""" t_state = {"uuid-old": {"title": "Old", "history": []}} new_state, new_id, list_upd, history = create_new_thread_callback(t_state) self.assertNotEqual(new_id, "uuid-old") self.assertIn(new_id, new_state) self.assertEqual(new_state[new_id]["title"], "New Conversation") self.assertEqual(list_upd["value"], new_id) self.assertEqual(history, []) def test_short_answer_prompt_injection(self): """Verify the 'short_answers' flag modifies the prompt.""" # 1. False prompt_long = build_agent_prompt("Hi", [], [], short_answers=False) self.assertNotIn("Be concise", prompt_long) # 2. True prompt_short = build_agent_prompt("Hi", [], [], short_answers=True) self.assertIn("Be concise", prompt_short) @patch('app.get_llm') @patch('app.TextIteratorStreamer') @patch('app.retrieve_relevant_chunks') @patch('app.detect_language') def test_accumulative_chat_streaming(self, mock_detect, mock_rag, mock_streamer, mock_llm): """Verify that streaming yields growing strings (Accumulation) instead of chunks.""" mock_detect.return_value = "English" mock_rag.return_value = [] mock_llm.return_value = (MagicMock(), MagicMock()) # Simulate LLM emitting tokens: ["Hello", " world"] mock_inst = mock_streamer.return_value mock_inst.__iter__.return_value = iter(["Hello", " world"]) # We assume max_turns=3 so we might get this sequence multiple times or just once if we break # The accumulator logic appends clean text. gen = chat_agent_stream("hi", [], None, None) # Collect yields yields = [] try: for y in gen: yields.append(y) # Just grab first turn's yields if "world" in y: break except: pass # Logic: # 1. Yield "Hello" # 2. Yield "Hello world" (Accumulated) # Verify the second yield is longer than the first if len(yields) >= 2: self.assertTrue(len(yields[-1]) > len(yields[0])) self.assertIn("Hello world", yields[-1]) if __name__ == "__main__": unittest.main()