BuddAI/tests/test_fallback_logging.py
JamesTheGiblet d4e09f6d13 Add unit tests for analytics, fallback client, and refactored validators
- Implemented comprehensive unit tests for the BuddAI Analytics module, covering fallback statistics calculations.
- Created tests for the FallbackClient to ensure proper escalation to various AI models and handling of missing API keys.
- Developed unit tests for the refactored validator system, validating various hardware and coding standards.
- Established a base validator interface and implemented specific validators for ESP32, Arduino, motor control, memory safety, and more.
- Enhanced the validator registry to auto-discover and manage validators effectively.
- Included detailed validation logic for common issues in embedded systems programming, such as unused variables, safety timeouts, and coding style violations.
2026-01-08 17:43:11 +00:00

105 lines
No EOL
4 KiB
Python

#!/usr/bin/env python3
"""
Unit tests for BuddAI Fallback Logging
Verifies that fallback prompts are logged to file.
"""
import unittest
from unittest.mock import MagicMock, patch, mock_open
import sys
from pathlib import Path
# Setup path
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_shared import DATA_DIR
class TestFallbackLogging(unittest.TestCase):
@patch('buddai_executive.OllamaClient')
@patch('buddai_executive.StorageManager')
@patch('buddai_executive.RepoManager')
def setUp(self, MockRepo, MockStorage, MockOllama):
# Suppress prints
with patch('builtins.print'):
self.ai = BuddAI(user_id="test_logging", server_mode=True)
# Mock dependencies
self.ai.llm = MockOllama()
self.ai.storage = MockStorage()
self.ai.confidence_scorer = MagicMock()
self.ai.personality_manager = MagicMock()
self.ai.validator = MagicMock()
self.ai.hardware_profile = MagicMock()
self.ai.shadow_engine = MagicMock()
self.ai.shadow_engine.get_all_suggestions.return_value = []
# Mock FallbackClient
self.ai.fallback_client = MagicMock()
self.ai.fallback_client.is_available.return_value = True
# Setup default mocks
self.ai.validator.validate.return_value = (True, [])
self.ai.hardware_profile.detect_hardware.return_value = "ESP32"
self.ai.hardware_profile.apply_hardware_rules.return_value = "mocked_code_response"
self.ai.extract_code = MagicMock(return_value=["void setup() {}"])
def test_fallback_logging(self):
"""Test that fallback prompts are written to log file"""
# Configure Personality
self.ai.personality_manager.get_value.side_effect = lambda key, default=None: {
"enabled": True,
"confidence_threshold": 80,
"fallback_models": ["claude"],
"prompts": {
"claude": "Claude Prompt: {context}"
}
} if key == "ai_fallback" else default
# Low confidence
self.ai.confidence_scorer.calculate_confidence.return_value = 50
self.ai.confidence_scorer.should_escalate.return_value = True
# Mock LLM
self.ai.llm.query.return_value = "Code: ```cpp\nvoid setup() {}\n```"
# Simulate file write in mock escalate since we mocked the client
def escalate_side_effect(*args, **kwargs):
with open(DATA_DIR / "external_prompts.log", "a", encoding="utf-8") as f:
f.write("Claude Prompt: fix logic\nMODEL: CLAUDE")
return "Fallback response"
self.ai.fallback_client.escalate.side_effect = escalate_side_effect
# Mock file opening
m = mock_open()
with patch('builtins.open', m):
self.ai.chat("fix logic")
# Verify file write
log_path = DATA_DIR / "external_prompts.log"
m.assert_called_with(log_path, "a", encoding="utf-8")
handle = m()
# Check if any write call contained the prompt
written_content = "".join(call.args[0] for call in handle.write.call_args_list)
self.assertIn("Claude Prompt: fix logic", written_content)
self.assertIn("MODEL: CLAUDE", written_content)
def test_logs_command(self):
"""Test /logs command retrieves content"""
# Mock file existence and content
m = mock_open(read_data="Log Entry 1\nLog Entry 2")
# We need to patch Path.exists as well since the code checks it
with patch('pathlib.Path.exists', return_value=True), \
patch('builtins.open', m):
response = self.ai.handle_slash_command("/logs")
self.assertIn("Log Entry 2", response)
self.assertIn("External Prompts Log", response)
if __name__ == '__main__':
unittest.main()