BuddAI/tests/test_buddai_v3_2.py
JamesTheGiblet c214b4a8ea Add unit tests for BuddAI v3.2 to verify type hints and routing logic
- Implemented tests for method annotations to ensure type hints are present.
- Added tests for routing logic to validate behavior for simple questions, complex requests, search queries, and forced model scenarios.
- Verified module extraction logic with specific test cases.
- Mocked database interactions and suppressed print statements during tests.
2025-12-29 15:45:31 +00:00

114 lines
No EOL
4.8 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for BuddAI v3.2
Verifies type hints and core functionality including the new routing logic.
"""
import unittest
import sys
import importlib.util
from pathlib import Path
from typing import List, Dict, Optional
from unittest.mock import MagicMock, patch
# Load buddai_v3.2.py dynamically due to version number in filename
REPO_ROOT = Path(__file__).parent.parent
MODULE_PATH = REPO_ROOT / "buddai_v3.2.py"
if not MODULE_PATH.exists():
print(f"Error: Could not find {MODULE_PATH}")
sys.exit(1)
spec = importlib.util.spec_from_file_location("buddai_v3_2", MODULE_PATH)
buddai_module = importlib.util.module_from_spec(spec)
sys.modules["buddai_v3_2"] = buddai_module
spec.loader.exec_module(buddai_module)
BuddAI = buddai_module.BuddAI
class TestBuddAITypesAndLogic(unittest.TestCase):
def setUp(self):
# Suppress print statements during tests
self.original_stdout = sys.stdout
sys.stdout = MagicMock()
# Initialize BuddAI in non-server mode, mocking DB interactions
with patch('sqlite3.connect') as mock_sql:
# Mock mkdir to prevent creating directories during tests
with patch('pathlib.Path.mkdir'):
self.buddai = BuddAI(server_mode=False)
self.mock_conn = mock_sql.return_value
self.mock_cursor = self.mock_conn.cursor.return_value
def tearDown(self):
sys.stdout = self.original_stdout
def test_method_annotations(self):
"""Verify type hints exist on key methods"""
# chat
chat_hints = BuddAI.chat.__annotations__
self.assertEqual(chat_hints['user_message'], str)
self.assertEqual(chat_hints['return'], str)
# is_complex
self.assertEqual(BuddAI.is_complex.__annotations__['return'], bool)
# extract_modules
self.assertEqual(BuddAI.extract_modules.__annotations__['return'], List[str])
# build_modular_plan
self.assertEqual(BuddAI.build_modular_plan.__annotations__['return'], List[Dict[str, str]])
def test_routing_simple_question(self):
"""Test that simple questions route to the FAST model"""
with patch.object(self.buddai, 'call_model', return_value="Fast response") as mock_call:
response = self.buddai._route_request("What is a servo?", force_model=None, forge_mode="2")
mock_call.assert_called_with("fast", "What is a servo?")
self.assertEqual(response, "Fast response")
def test_routing_complex_request(self):
"""Test that complex requests route to modular build"""
complex_msg = "Build a complete robot with servo and motor"
with patch.object(self.buddai, 'execute_modular_build', return_value="Modular code") as mock_build:
# Mock is_complex to ensure it returns True for this test case
with patch.object(self.buddai, 'is_complex', return_value=True):
response = self.buddai._route_request(complex_msg, force_model=None, forge_mode="2")
mock_build.assert_called()
self.assertEqual(response, "Modular code")
def test_routing_search_query(self):
"""Test that search queries route to repository search"""
search_msg = "Show me functions using applyForge"
with patch.object(self.buddai, 'search_repositories', return_value="Search results") as mock_search:
# Mock is_search_query to ensure True
with patch.object(self.buddai, 'is_search_query', return_value=True):
# Ensure is_complex is False so it doesn't preempt search
with patch.object(self.buddai, 'is_complex', return_value=False):
response = self.buddai._route_request(search_msg, force_model=None, forge_mode="2")
mock_search.assert_called_with(search_msg)
self.assertEqual(response, "Search results")
def test_routing_forced_model(self):
"""Test that force_model overrides other logic"""
with patch.object(self.buddai, 'call_model', return_value="Forced response") as mock_call:
response = self.buddai._route_request("Complex build request", force_model="balanced", forge_mode="2")
mock_call.assert_called_with("balanced", "Complex build request")
self.assertEqual(response, "Forced response")
def test_extract_modules(self):
"""Verify module extraction logic"""
msg = "I need a robot with bluetooth and a flipper weapon"
modules = self.buddai.extract_modules(msg)
self.assertIn("ble", modules)
self.assertIn("servo", modules)
self.assertNotIn("motor", modules)
if __name__ == '__main__':
unittest.main()