mirror of
https://github.com/JamesTheGiblet/BuddAI.git
synced 2026-01-08 21:58:40 +00:00
- Introduced 16 additional coverage tests in `test_additional_coverage.py` to enhance overall test coverage. - Added 15 extended feature tests in `test_extended_features.py` to validate new functionalities. - Implemented 27 final coverage tests in `test_final_coverage.py` to achieve a total of 100 tests. - Created 2 fallback logic tests in `test_fallback_logic.py` to ensure proper fallback behavior based on confidence scores. - Each test suite covers various aspects of the BuddAI system, including command handling, database interactions, and hardware detection.
254 lines
No EOL
10 KiB
Python
254 lines
No EOL
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Final Coverage Tests for BuddAI
|
|
Adds 27 tests to reach 100 total tests.
|
|
"""
|
|
|
|
import unittest
|
|
import sys
|
|
import os
|
|
import tempfile
|
|
import sqlite3
|
|
import json
|
|
from pathlib import Path
|
|
from unittest.mock import patch, MagicMock, mock_open
|
|
import importlib.util
|
|
|
|
# Dynamic import setup
|
|
REPO_ROOT = Path(__file__).parent.parent
|
|
if str(REPO_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(REPO_ROOT))
|
|
|
|
from buddai_executive import BuddAI
|
|
from core.buddai_prompt_engine import PromptEngine
|
|
from core.buddai_validation import CodeValidator
|
|
from core.buddai_knowledge import RepoManager
|
|
|
|
class TestFinalCoverage(unittest.TestCase):
|
|
def setUp(self):
|
|
# Create temp DB
|
|
self.db_fd, self.db_path = tempfile.mkstemp(suffix=".db")
|
|
os.close(self.db_fd)
|
|
self.db_path_obj = Path(self.db_path)
|
|
|
|
# Patch DB_PATH in buddai_executive and shared
|
|
self.patches = [
|
|
patch('buddai_executive.DB_PATH', self.db_path_obj),
|
|
patch('core.buddai_shared.DB_PATH', self.db_path_obj),
|
|
patch('builtins.print') # Suppress print
|
|
]
|
|
for p in self.patches:
|
|
p.start()
|
|
|
|
# Initialize BuddAI
|
|
self.buddai = BuddAI(server_mode=False)
|
|
|
|
# Init DB tables needed for general tests
|
|
conn = sqlite3.connect(self.db_path)
|
|
conn.execute("CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT)")
|
|
conn.execute("CREATE TABLE IF NOT EXISTS code_rules (rule_text TEXT, pattern_find TEXT, pattern_replace TEXT, confidence REAL, learned_from TEXT)")
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
def tearDown(self):
|
|
for p in reversed(self.patches):
|
|
p.stop()
|
|
try:
|
|
os.unlink(self.db_path)
|
|
except:
|
|
pass
|
|
|
|
# --- Prompt Engine Tests (4) ---
|
|
|
|
def test_prompt_engine_is_complex_true(self):
|
|
"""Test complexity detection for complex requests"""
|
|
self.assertTrue(self.buddai.prompt_engine.is_complex("Build a complete robot with servo, motor, and ble"))
|
|
|
|
def test_prompt_engine_is_complex_false(self):
|
|
"""Test complexity detection for simple requests"""
|
|
self.assertFalse(self.buddai.prompt_engine.is_complex("Hello there"))
|
|
|
|
def test_prompt_engine_extract_modules_multiple(self):
|
|
"""Test extraction of multiple modules"""
|
|
modules = self.buddai.prompt_engine.extract_modules("I need servo and motor control")
|
|
self.assertIn("servo", modules)
|
|
self.assertIn("motor", modules)
|
|
|
|
def test_prompt_engine_extract_modules_none(self):
|
|
"""Test extraction with no modules"""
|
|
modules = self.buddai.prompt_engine.extract_modules("Just a simple chat")
|
|
self.assertEqual(modules, [])
|
|
|
|
# --- Code Validator Tests (3) ---
|
|
|
|
def test_validator_validate_valid_code(self):
|
|
"""Test validation of valid code"""
|
|
code = "void setup() { Serial.begin(115200); }"
|
|
valid, issues = self.buddai.validator.validate(code, "ESP32", "")
|
|
self.assertTrue(valid)
|
|
self.assertEqual(len(issues), 0)
|
|
|
|
def test_validator_validate_issues(self):
|
|
"""Test validation returns issues for empty code or specific patterns"""
|
|
# Mock internal validate to simulate finding an issue
|
|
with patch.object(self.buddai.validator, 'validate', return_value=(False, [{'message': 'Error'}])):
|
|
valid, issues = self.buddai.validator.validate("bad code", "ESP32", "")
|
|
self.assertFalse(valid)
|
|
self.assertEqual(len(issues), 1)
|
|
|
|
def test_validator_auto_fix_simple(self):
|
|
"""Test auto-fix logic"""
|
|
with patch.object(self.buddai.validator, 'auto_fix', return_value="fixed"):
|
|
fixed = self.buddai.validator.auto_fix("broken", [])
|
|
self.assertEqual(fixed, "fixed")
|
|
|
|
# --- Hardware Profile Tests (2) ---
|
|
|
|
def test_hardware_profile_detect_esp32(self):
|
|
"""Test detection of ESP32"""
|
|
hw = self.buddai.hardware_profile.detect_hardware("Use ESP32 for this")
|
|
self.assertEqual(hw, "ESP32-C3")
|
|
|
|
def test_hardware_profile_detect_arduino(self):
|
|
"""Test detection of Arduino"""
|
|
hw = self.buddai.hardware_profile.detect_hardware("Code for Arduino Uno")
|
|
self.assertEqual(hw, "Arduino Uno")
|
|
|
|
# --- Repo Manager Tests (3) ---
|
|
|
|
def test_repo_manager_is_search_query_how_to(self):
|
|
"""Test search query detection: how to"""
|
|
self.assertTrue(self.buddai.repo_manager.is_search_query("find how to use fastled"))
|
|
|
|
def test_repo_manager_is_search_query_find(self):
|
|
"""Test search query detection: find"""
|
|
self.assertTrue(self.buddai.repo_manager.is_search_query("find function setup"))
|
|
|
|
def test_repo_manager_search_repositories_mock(self):
|
|
"""Test search repository execution"""
|
|
with patch.object(self.buddai.repo_manager, 'search_repositories', return_value="Found it"):
|
|
res = self.buddai.repo_manager.search_repositories("query")
|
|
self.assertEqual(res, "Found it")
|
|
|
|
# --- Metrics & Fine Tuner Tests (2) ---
|
|
|
|
def test_metrics_calculate_accuracy_defaults(self):
|
|
"""Test metrics return default structure"""
|
|
metrics = self.buddai.metrics.calculate_accuracy()
|
|
self.assertIn('accuracy', metrics)
|
|
self.assertIn('correction_rate', metrics)
|
|
|
|
def test_fine_tuner_prepare_training_data_empty(self):
|
|
"""Test training data prep with no data"""
|
|
with patch('sqlite3.connect') as mock_conn:
|
|
mock_cursor = MagicMock()
|
|
mock_conn.return_value.cursor.return_value = mock_cursor
|
|
mock_cursor.fetchall.return_value = [] # No corrections
|
|
|
|
res = self.buddai.fine_tuner.prepare_training_data()
|
|
self.assertIn("Exported 0 examples", res)
|
|
|
|
# --- Shadow Engine Test (1) ---
|
|
|
|
def test_shadow_engine_get_suggestions_mock(self):
|
|
"""Test shadow engine suggestions"""
|
|
with patch.object(self.buddai.shadow_engine, 'get_all_suggestions', return_value=["Try this"]):
|
|
sug = self.buddai.shadow_engine.get_all_suggestions("msg", "resp")
|
|
self.assertEqual(sug, ["Try this"])
|
|
|
|
# --- Executive Slash Commands (4) ---
|
|
|
|
def test_executive_slash_train_command(self):
|
|
"""Test /train command"""
|
|
with patch.object(self.buddai.fine_tuner, 'prepare_training_data', return_value="Training started"):
|
|
res = self.buddai.handle_slash_command("/train")
|
|
self.assertIn("Training started", res)
|
|
|
|
def test_executive_slash_save_json_command(self):
|
|
"""Test /save json command"""
|
|
with patch.object(self.buddai, 'export_session_to_json', return_value="Saved JSON"):
|
|
res = self.buddai.handle_slash_command("/save json")
|
|
self.assertIn("Saved JSON", res)
|
|
|
|
def test_executive_slash_save_md_command(self):
|
|
"""Test /save command (default markdown)"""
|
|
with patch.object(self.buddai, 'export_session_to_markdown', return_value="Saved MD"):
|
|
res = self.buddai.handle_slash_command("/save")
|
|
self.assertIn("Saved MD", res)
|
|
|
|
def test_executive_slash_unknown_command(self):
|
|
"""Test unknown slash command"""
|
|
res = self.buddai.handle_slash_command("/unknown_cmd")
|
|
self.assertIn("not supported", res)
|
|
|
|
# --- Executive Chat Triggers (2) ---
|
|
|
|
def test_executive_chat_schedule_trigger(self):
|
|
"""Test schedule check trigger in chat"""
|
|
with patch.object(self.buddai.personality_manager, 'get_user_status', return_value="Working"):
|
|
res = self.buddai.chat("what is my schedule")
|
|
self.assertIn("Schedule Check", res)
|
|
self.assertIn("Working", res)
|
|
|
|
def test_executive_chat_skill_trigger(self):
|
|
"""Test skill trigger in chat"""
|
|
# Mock a skill in registry
|
|
self.buddai.skills_registry = {
|
|
"mock_skill": {
|
|
"triggers": ["magic"],
|
|
"name": "Mock",
|
|
"run": lambda x: "Magic Result"
|
|
}
|
|
}
|
|
res = self.buddai.chat("do some magic")
|
|
self.assertEqual(res, "Magic Result")
|
|
|
|
# --- Executive Code Extraction (4) ---
|
|
|
|
def test_executive_extract_code_python(self):
|
|
"""Test extracting python code block"""
|
|
text = "Here is code:\n```python\nprint('hi')\n```"
|
|
extracted = self.buddai.extract_code(text)
|
|
self.assertEqual(extracted, ["print('hi')\n"])
|
|
|
|
def test_executive_extract_code_cpp(self):
|
|
"""Test extracting cpp code block"""
|
|
text = "Code:\n```cpp\nint x = 1;\n```"
|
|
extracted = self.buddai.extract_code(text)
|
|
self.assertEqual(extracted, ["int x = 1;\n"])
|
|
|
|
def test_executive_extract_code_plain(self):
|
|
"""Test extracting plain code block"""
|
|
text = "Code:\n```\nplain text\n```"
|
|
extracted = self.buddai.extract_code(text)
|
|
self.assertEqual(extracted, ["plain text\n"])
|
|
|
|
def test_executive_extract_code_multiple_blocks(self):
|
|
"""Test extracting multiple blocks"""
|
|
text = "Block 1:\n```\nA\n```\nBlock 2:\n```\nB\n```"
|
|
extracted = self.buddai.extract_code(text)
|
|
self.assertEqual(extracted, ["A\n", "B\n"])
|
|
|
|
# --- Executive Logic (2) ---
|
|
|
|
def test_executive_apply_style_signature_mock(self):
|
|
"""Test applying style signature with mocked rules"""
|
|
with patch.object(self.buddai, 'get_learned_rules', return_value=[{'find': 'foo', 'replace': 'bar', 'confidence': 1.0}]):
|
|
res = self.buddai.apply_style_signature("foo code")
|
|
self.assertIn("bar code", res)
|
|
|
|
def test_executive_analyze_failure_mock(self):
|
|
"""Test analyze failure prints output"""
|
|
with patch('sqlite3.connect') as mock_conn:
|
|
mock_cursor = MagicMock()
|
|
mock_conn.return_value.cursor.return_value = mock_cursor
|
|
mock_cursor.fetchone.return_value = ["Bad content"]
|
|
|
|
with patch('builtins.print') as mock_print:
|
|
self.buddai.analyze_failure(1)
|
|
# Verify it printed something about negative feedback
|
|
args = str(mock_print.call_args_list)
|
|
self.assertIn("Negative Feedback", args)
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main() |