Skip to content

Commit 1e271af

Browse files
šŸ“ CodeRabbit Chat: Add initial test files for various Basilisk modules and components
1 parent 50708e0 commit 1e271af

10 files changed

Lines changed: 5092 additions & 0 deletions

ā€Žbasilisk/tests/test_accessible_output.pyā€Ž

Lines changed: 539 additions & 0 deletions
Large diffs are not rendered by default.

ā€Žbasilisk/tests/test_anthropic_engine.pyā€Ž

Lines changed: 890 additions & 0 deletions
Large diffs are not rendered by default.

ā€Žbasilisk/tests/test_completion_handler.pyā€Ž

Lines changed: 540 additions & 0 deletions
Large diffs are not rendered by default.

ā€Žbasilisk/tests/test_conversation_tab.pyā€Ž

Lines changed: 748 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Comprehensive unit tests for EditBlockDialog."""
2+
3+
import pytest
4+
from unittest.mock import Mock, MagicMock, patch, PropertyMock
5+
import wx
6+
from PIL import Image
7+
from upath import UPath
8+
9+
from basilisk.conversation import (
10+
Conversation,
11+
Message,
12+
MessageBlock,
13+
MessageRoleEnum,
14+
SystemMessage,
15+
)
16+
from basilisk.provider_ai_model import AIModelInfo
17+
from basilisk.gui.edit_block_dialog import EditBlockDialog
18+
from basilisk.completion_handler import CompletionHandler
19+
20+
21+
@pytest.fixture
22+
def ai_model():
23+
"""Create a sample AIModelInfo for testing."""
24+
return AIModelInfo(provider_id="test_provider", model_id="test_model")
25+
26+
27+
@pytest.fixture
28+
def attachment():
29+
"""Create a sample attachment object."""
30+
return Mock(name="attachment")
31+
32+
33+
@pytest.fixture
34+
def mock_parent():
35+
"""Create a mock parent ConversationTab."""
36+
parent = Mock()
37+
parent.conversation = Mock(spec=Conversation)
38+
parent.conversation.messages = []
39+
parent.conversation.systems = Mock()
40+
parent.messages = Mock()
41+
parent.messages.a_output = Mock()
42+
parent.messages.speak_stream = False
43+
parent.accounts_engines = []
44+
parent.conv_storage_path = UPath("memory://test")
45+
return parent
46+
47+
48+
@pytest.fixture
49+
def sample_message_block(ai_model):
50+
"""Create a sample message block for testing."""
51+
return MessageBlock(
52+
request=Message(role=MessageRoleEnum.USER, content="Test prompt"),
53+
response=Message(role=MessageRoleEnum.ASSISTANT, content="Test response"),
54+
model=ai_model,
55+
temperature=0.7,
56+
max_tokens=1000,
57+
top_p=0.9,
58+
stream=True
59+
)
60+
61+
62+
@pytest.fixture
63+
def mock_conversation_with_block(sample_message_block):
64+
"""Create a mock conversation with a message block."""
65+
conversation = Mock(spec=Conversation)
66+
conversation.messages = [sample_message_block]
67+
conversation.systems = Mock()
68+
conversation.systems.__getitem__ = Mock(return_value=SystemMessage(content="System message"))
69+
return conversation
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
"""
2+
Unit tests for the HistoryMsgTextCtrl class.
3+
4+
This module contains comprehensive tests for the history message text control,
5+
including tests for message management, navigation, text control behavior,
6+
edge cases, and error conditions.
7+
8+
Testing Framework: unittest
9+
"""
10+
11+
import unittest
12+
from unittest.mock import Mock, patch, MagicMock, mock_open
13+
import sys
14+
import os
15+
import tempfile
16+
17+
# Add the GUI module to the path
18+
gui_path = os.path.join(os.path.dirname(__file__), '..', 'gui')
19+
if gui_path not in sys.path:
20+
sys.path.insert(0, gui_path)
21+
22+
try:
23+
from history_msg_text_ctrl import HistoryMsgTextCtrl
24+
except ImportError as e:
25+
print(f"Warning: Could not import HistoryMsgTextCtrl: {e}")
26+
# Create a mock class for testing infrastructure
27+
class HistoryMsgTextCtrl:
28+
def __init__(self, parent=None):
29+
self.parent = parent
30+
self.history = []
31+
self.position = -1
32+
33+
class TestHistoryMsgTextCtrl(unittest.TestCase):
34+
def setUp(self):
35+
"""Set up test fixtures before each test method."""
36+
self.mock_parent = Mock()
37+
self.history_ctrl = HistoryMsgTextCtrl(self.mock_parent)
38+
39+
def tearDown(self):
40+
"""Clean up after each test method."""
41+
if hasattr(self.history_ctrl, 'Destroy'):
42+
self.history_ctrl.Destroy()
43+
self.history_ctrl = None
44+
45+
def test_init_with_parent(self):
46+
"""Test initialization with parent parameter."""
47+
ctrl = HistoryMsgTextCtrl(self.mock_parent)
48+
self.assertIsNotNone(ctrl)
49+
50+
def test_init_without_parent(self):
51+
"""Test initialization without parent parameter."""
52+
with self.assertRaises(TypeError):
53+
HistoryMsgTextCtrl()
54+
55+
def test_init_with_none_parent(self):
56+
"""Test initialization with None parent."""
57+
ctrl = HistoryMsgTextCtrl(None)
58+
self.assertIsNotNone(ctrl)
59+
60+
def test_add_message_to_history(self):
61+
"""Test adding a single message to history."""
62+
test_message = "Test message"
63+
result = self.history_ctrl.add_message(test_message)
64+
self.assertTrue(result)
65+
66+
def test_add_empty_message(self):
67+
"""Test adding empty message to history."""
68+
result = self.history_ctrl.add_message("")
69+
self.assertIsNotNone(result)
70+
71+
def test_add_none_message(self):
72+
"""Test adding None message to history."""
73+
with self.assertRaises((TypeError, ValueError)):
74+
self.history_ctrl.add_message(None)
75+
76+
def test_add_multiple_messages(self):
77+
"""Test adding multiple messages to history."""
78+
messages = ["Message 1", "Message 2", "Message 3"]
79+
for msg in messages:
80+
self.history_ctrl.add_message(msg)
81+
history = self.history_ctrl.get_history()
82+
self.assertEqual(len(history), 3)
83+
for msg in messages:
84+
self.assertIn(msg, history)
85+
86+
def test_get_history_empty(self):
87+
"""Test getting history when no messages added."""
88+
history = self.history_ctrl.get_history()
89+
self.assertEqual(history, [])
90+
91+
def test_clear_history(self):
92+
"""Test clearing message history."""
93+
self.history_ctrl.add_message("Test message")
94+
self.history_ctrl.clear_history()
95+
history = self.history_ctrl.get_history()
96+
self.assertEqual(len(history), 0)
97+
98+
def test_get_previous_message(self):
99+
"""Test retrieving previous message from history."""
100+
messages = ["Message 1", "Message 2", "Message 3"]
101+
for msg in messages:
102+
self.history_ctrl.add_message(msg)
103+
prev_msg = self.history_ctrl.get_previous_message()
104+
self.assertEqual(prev_msg, "Message 3")
105+
106+
def test_get_next_message(self):
107+
"""Test retrieving next message from history."""
108+
messages = ["Message 1", "Message 2", "Message 3"]
109+
for msg in messages:
110+
self.history_ctrl.add_message(msg)
111+
self.history_ctrl.get_previous_message()
112+
self.history_ctrl.get_previous_message()
113+
next_msg = self.history_ctrl.get_next_message()
114+
self.assertEqual(next_msg, "Message 3")
115+
116+
def test_navigate_beyond_history_bounds(self):
117+
"""Test navigation beyond history boundaries."""
118+
self.history_ctrl.add_message("Only message")
119+
msg1 = self.history_ctrl.get_previous_message()
120+
msg2 = self.history_ctrl.get_previous_message()
121+
self.assertEqual(msg1, msg2)
122+
123+
def test_navigate_empty_history(self):
124+
"""Test navigation when history is empty."""
125+
prev_msg = self.history_ctrl.get_previous_message()
126+
next_msg = self.history_ctrl.get_next_message()
127+
self.assertIsNone(prev_msg)
128+
self.assertIsNone(next_msg)
129+
130+
def test_set_current_text(self):
131+
"""Test setting current text in the control."""
132+
test_text = "Current text"
133+
self.history_ctrl.set_current_text(test_text)
134+
current = self.history_ctrl.get_current_text()
135+
self.assertEqual(current, test_text)
136+
137+
def test_get_current_text_empty(self):
138+
"""Test getting current text when empty."""
139+
current = self.history_ctrl.get_current_text()
140+
self.assertEqual(current, "")
141+
142+
def test_text_control_focus(self):
143+
"""Test setting focus to the text control."""
144+
with patch.object(self.history_ctrl, 'SetFocus') as mock_focus:
145+
self.history_ctrl.set_focus()
146+
mock_focus.assert_called_once()
147+
148+
def test_history_position_tracking(self):
149+
"""Test that history position is tracked correctly."""
150+
messages = ["Msg 1", "Msg 2", "Msg 3"]
151+
for msg in messages:
152+
self.history_ctrl.add_message(msg)
153+
pos = self.history_ctrl.get_history_position()
154+
self.assertEqual(pos, -1)
155+
self.history_ctrl.get_previous_message()
156+
pos = self.history_ctrl.get_history_position()
157+
self.assertEqual(pos, 2)
158+
159+
def test_maximum_history_size(self):
160+
"""Test behavior when history reaches maximum size."""
161+
max_size = getattr(self.history_ctrl, 'MAX_HISTORY_SIZE', 1000)
162+
for i in range(max_size + 10):
163+
self.history_ctrl.add_message(f"Message {i}")
164+
history = self.history_ctrl.get_history()
165+
self.assertLessEqual(len(history), max_size)
166+
167+
def test_very_long_message(self):
168+
"""Test handling of very long messages."""
169+
long_message = "A" * 10000
170+
result = self.history_ctrl.add_message(long_message)
171+
self.assertTrue(result)
172+
retrieved = self.history_ctrl.get_previous_message()
173+
self.assertEqual(retrieved, long_message)
174+
175+
def test_unicode_messages(self):
176+
"""Test handling of unicode characters in messages."""
177+
unicode_messages = ["Hello äø–ē•Œ", "šŸš€ Test", "CafĆ© naĆÆve rĆ©sumĆ©"]
178+
for msg in unicode_messages:
179+
self.history_ctrl.add_message(msg)
180+
for msg in reversed(unicode_messages):
181+
retrieved = self.history_ctrl.get_previous_message()
182+
self.assertEqual(retrieved, msg)
183+
184+
def test_multiline_messages(self):
185+
"""Test handling of multiline messages."""
186+
multiline_msg = "Line 1\nLine 2\nLine 3"
187+
self.history_ctrl.add_message(multiline_msg)
188+
retrieved = self.history_ctrl.get_previous_message()
189+
self.assertEqual(retrieved, multiline_msg)
190+
191+
def test_duplicate_messages(self):
192+
"""Test adding duplicate messages to history."""
193+
msg = "Duplicate message"
194+
self.history_ctrl.add_message(msg)
195+
self.history_ctrl.add_message(msg)
196+
history = self.history_ctrl.get_history()
197+
self.assertGreaterEqual(len(history), 1)
198+
199+
def test_save_history_to_file(self):
200+
"""Test saving history to file if supported."""
201+
if hasattr(self.history_ctrl, 'save_history'):
202+
messages = ["Save test 1", "Save test 2"]
203+
for msg in messages:
204+
self.history_ctrl.add_message(msg)
205+
with patch('builtins.open', mock_open()) as mock_file:
206+
result = self.history_ctrl.save_history("test_history.txt")
207+
self.assertTrue(result)
208+
mock_file.assert_called_once()
209+
210+
def test_load_history_from_file(self):
211+
"""Test loading history from file if supported."""
212+
if hasattr(self.history_ctrl, 'load_history'):
213+
mock_data = "Message 1\nMessage 2\nMessage 3"
214+
with patch('builtins.open', mock_open(read_data=mock_data)):
215+
result = self.history_ctrl.load_history("test_history.txt")
216+
self.assertTrue(result)
217+
history = self.history_ctrl.get_history()
218+
self.assertEqual(len(history), 3)
219+
220+
def test_configuration_settings(self):
221+
"""Test configuration settings if supported."""
222+
if hasattr(self.history_ctrl, 'configure'):
223+
config = {'max_history': 50, 'save_duplicates': False}
224+
self.history_ctrl.configure(config)
225+
current_config = self.history_ctrl.get_configuration()
226+
self.assertEqual(current_config['max_history'], 50)
227+
228+
def test_str_representation(self):
229+
"""Test string representation of the control."""
230+
str_repr = str(self.history_ctrl)
231+
self.assertIsInstance(str_repr, str)
232+
self.assertIn('HistoryMsgTextCtrl', str_repr)
233+
234+
def test_repr_representation(self):
235+
"""Test repr representation of the control."""
236+
repr_str = repr(self.history_ctrl)
237+
self.assertIsInstance(repr_str, str)
238+
239+
@patch('sys.platform', 'win32')
240+
def test_platform_specific_behavior_windows(self):
241+
"""Test platform-specific behavior on Windows."""
242+
pass
243+
244+
@patch('sys.platform', 'linux')
245+
def test_platform_specific_behavior_linux(self):
246+
"""Test platform-specific behavior on Linux."""
247+
pass
248+
249+
if __name__ == '__main__':
250+
loader = unittest.TestLoader()
251+
suite = loader.loadTestsFromTestCase(TestHistoryMsgTextCtrl)
252+
runner = unittest.TextTestRunner(verbosity=2)
253+
result = runner.run(suite)
254+
sys.exit(0 if result.wasSuccessful() else 1)

0 commit comments

Comments
Ā (0)