scratch_chat / tests /integration /test_programming_assistance_integration.py
WebashalarForML's picture
Upload 178 files
330b6e4 verified
"""
Integration tests for Programming Assistance Features
Tests the integration of programming assistance features with the chat agent,
including end-to-end workflows for code explanation, debugging, error analysis,
code review, and beginner help.
"""
import unittest
from unittest.mock import Mock, patch, MagicMock
import pytest
from datetime import datetime
from chat_agent.services.chat_agent import ChatAgent
from chat_agent.services.programming_assistance import ProgrammingAssistanceService, AssistanceType
from chat_agent.services.groq_client import GroqClient, ChatMessage, LanguageContext
from chat_agent.services.language_context import LanguageContextManager
from chat_agent.services.session_manager import SessionManager
from chat_agent.services.chat_history import ChatHistoryManager
from chat_agent.models.message import Message
from chat_agent.models.chat_session import ChatSession
class TestProgrammingAssistanceIntegration(unittest.TestCase):
"""Integration test cases for programming assistance features."""
def setUp(self):
"""Set up test fixtures with mocked dependencies."""
# Mock dependencies
self.mock_groq_client = Mock(spec=GroqClient)
self.mock_language_context_manager = Mock(spec=LanguageContextManager)
self.mock_session_manager = Mock(spec=SessionManager)
self.mock_chat_history_manager = Mock(spec=ChatHistoryManager)
# Create real programming assistance service
self.programming_assistance_service = ProgrammingAssistanceService()
# Create chat agent with mocked dependencies
self.chat_agent = ChatAgent(
groq_client=self.mock_groq_client,
language_context_manager=self.mock_language_context_manager,
session_manager=self.mock_session_manager,
chat_history_manager=self.mock_chat_history_manager,
programming_assistance_service=self.programming_assistance_service
)
# Common test data
self.session_id = "test-session-123"
self.test_session = Mock(spec=ChatSession)
self.test_session.id = self.session_id
self.test_session.language = "python"
# Setup common mock returns
self.mock_session_manager.get_session.return_value = self.test_session
self.mock_language_context_manager.get_language.return_value = "python"
self.mock_chat_history_manager.get_recent_history.return_value = []
self.mock_groq_client.generate_response.return_value = "Mock LLM response"
self.mock_groq_client.get_model_info.return_value = {"model": "test-model"}
# Mock message storage
mock_message = Mock(spec=Message)
mock_message.id = "msg-123"
self.mock_chat_history_manager.store_message.return_value = mock_message
def test_process_programming_assistance_code_explanation(self):
"""Test processing code explanation request."""
code = """
def greet(name):
return f"Hello, {name}!"
print(greet("Alice"))
"""
message = "Please explain this code"
result = self.chat_agent.process_programming_assistance(
self.session_id, message, code=code,
assistance_type=AssistanceType.CODE_EXPLANATION
)
# Verify result structure
self.assertIn('response', result)
self.assertIn('assistance_type', result)
self.assertIn('analysis_result', result)
self.assertEqual(result['assistance_type'], AssistanceType.CODE_EXPLANATION.value)
self.assertEqual(result['language'], 'python')
# Verify service calls
self.mock_session_manager.get_session.assert_called_with(self.session_id)
self.mock_session_manager.update_session_activity.assert_called_with(self.session_id)
self.mock_language_context_manager.get_language.assert_called_with(self.session_id)
# Verify message storage
self.assertEqual(self.mock_chat_history_manager.store_message.call_count, 2) # User + Assistant
# Verify LLM call
self.mock_groq_client.generate_response.assert_called_once()
def test_process_programming_assistance_debugging(self):
"""Test processing debugging request."""
code = """
def divide(a, b):
return a / b
result = divide(10, 0) # This will cause an error
"""
error_message = "ZeroDivisionError: division by zero"
message = "I'm getting an error with this code"
result = self.chat_agent.process_programming_assistance(
self.session_id, message, code=code, error_message=error_message,
assistance_type=AssistanceType.DEBUGGING
)
# Verify result structure
self.assertIn('response', result)
self.assertEqual(result['assistance_type'], AssistanceType.DEBUGGING.value)
self.assertIsNotNone(result['analysis_result'])
# Verify analysis was performed
analysis = result['analysis_result']
self.assertIn('error_type', analysis.__dict__)
self.assertIn('likely_causes', analysis.__dict__)
self.assertIn('solutions', analysis.__dict__)
def test_process_programming_assistance_error_analysis(self):
"""Test processing error analysis request."""
error_message = "NameError: name 'undefined_variable' is not defined"
message = "What does this error mean?"
result = self.chat_agent.process_programming_assistance(
self.session_id, message, error_message=error_message,
assistance_type=AssistanceType.ERROR_ANALYSIS
)
# Verify result structure
self.assertEqual(result['assistance_type'], AssistanceType.ERROR_ANALYSIS.value)
# Verify error analysis was performed
analysis = result['analysis_result']
self.assertEqual(analysis.error_type, 'name_error')
self.assertGreater(len(analysis.likely_causes), 0)
self.assertGreater(len(analysis.solutions), 0)
def test_process_programming_assistance_code_review(self):
"""Test processing code review request."""
code = """
def calculate_total(items):
total = 0
for item in items:
total = total + item
return total
numbers = [1, 2, 3, 4, 5]
result = calculate_total(numbers)
print(result)
"""
message = "Please review my code"
result = self.chat_agent.process_programming_assistance(
self.session_id, message, code=code,
assistance_type=AssistanceType.CODE_REVIEW
)
# Verify result structure
self.assertEqual(result['assistance_type'], AssistanceType.CODE_REVIEW.value)
# Verify code analysis was performed
analysis = result['analysis_result']
self.assertEqual(analysis.language, 'python')
self.assertIsInstance(analysis.suggestions, list)
self.assertIsInstance(analysis.issues_found, list)
def test_process_programming_assistance_beginner_help(self):
"""Test processing beginner help request."""
message = "I'm new to programming. Can you explain variables?"
result = self.chat_agent.process_programming_assistance(
self.session_id, message, assistance_type=AssistanceType.BEGINNER_HELP
)
# Verify result structure
self.assertEqual(result['assistance_type'], AssistanceType.BEGINNER_HELP.value)
# Verify beginner explanation was generated
self.assertIn('response', result)
response = result['response']
self.assertIn('variables', response.lower())
def test_process_programming_assistance_auto_detection(self):
"""Test automatic assistance type detection."""
# Test error detection
result = self.chat_agent.process_programming_assistance(
self.session_id, "I'm getting an error"
)
self.assertEqual(result['assistance_type'], AssistanceType.ERROR_ANALYSIS.value)
# Test explanation detection with code
code = "print('Hello')"
result = self.chat_agent.process_programming_assistance(
self.session_id, "What does this do?", code=code
)
self.assertEqual(result['assistance_type'], AssistanceType.CODE_EXPLANATION.value)
# Test beginner detection
result = self.chat_agent.process_programming_assistance(
self.session_id, "I'm a beginner and need help"
)
self.assertEqual(result['assistance_type'], AssistanceType.BEGINNER_HELP.value)
def test_explain_code_convenience_method(self):
"""Test the explain_code convenience method."""
code = "x = [1, 2, 3]\nprint(len(x))"
result = self.chat_agent.explain_code(self.session_id, code)
self.assertEqual(result['assistance_type'], AssistanceType.CODE_EXPLANATION.value)
self.assertIn('analysis_result', result)
def test_debug_code_convenience_method(self):
"""Test the debug_code convenience method."""
code = "print(undefined_var)"
error_message = "NameError: name 'undefined_var' is not defined"
result = self.chat_agent.debug_code(
self.session_id, code, error_message, "Help me fix this error"
)
self.assertEqual(result['assistance_type'], AssistanceType.DEBUGGING.value)
self.assertIsNotNone(result['analysis_result'])
def test_analyze_error_convenience_method(self):
"""Test the analyze_error convenience method."""
error_message = "TypeError: unsupported operand type(s) for +: 'int' and 'str'"
result = self.chat_agent.analyze_error(
self.session_id, error_message, "I don't understand this error"
)
self.assertEqual(result['assistance_type'], AssistanceType.ERROR_ANALYSIS.value)
self.assertEqual(result['analysis_result'].error_type, 'type_error')
def test_review_code_convenience_method(self):
"""Test the review_code convenience method."""
code = """
def add_numbers(a, b):
return a + b
"""
result = self.chat_agent.review_code(
self.session_id, code, focus_areas=['performance', 'readability']
)
self.assertEqual(result['assistance_type'], AssistanceType.CODE_REVIEW.value)
self.assertIn('analysis_result', result)
def test_get_beginner_help_convenience_method(self):
"""Test the get_beginner_help convenience method."""
result = self.chat_agent.get_beginner_help(
self.session_id, "functions", "How do I create a function?"
)
self.assertEqual(result['assistance_type'], AssistanceType.BEGINNER_HELP.value)
self.assertIn('functions', result['response'].lower())
def test_programming_assistance_with_language_switching(self):
"""Test programming assistance with different languages."""
# Setup for JavaScript
self.mock_language_context_manager.get_language.return_value = "javascript"
code = """
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("Bob"));
"""
result = self.chat_agent.process_programming_assistance(
self.session_id, "Explain this JavaScript code", code=code
)
self.assertEqual(result['language'], 'javascript')
analysis = result['analysis_result']
self.assertEqual(analysis.language, 'javascript')
def test_programming_assistance_with_context_metadata(self):
"""Test programming assistance with beginner context."""
message = "I'm a beginner. Can you explain this code?"
code = "print('Hello, World!')"
result = self.chat_agent.process_programming_assistance(
self.session_id, message, code=code
)
# Verify that beginner context was detected and used
self.assertIn('response', result)
# Check that user message was stored with metadata
store_calls = self.mock_chat_history_manager.store_message.call_args_list
user_message_call = store_calls[0] # First call should be user message
self.assertEqual(user_message_call[1]['role'], 'user')
self.assertIn('assistance_type', user_message_call[1]['message_metadata'])
def test_programming_assistance_error_handling(self):
"""Test error handling in programming assistance."""
# Mock session error
self.mock_session_manager.get_session.side_effect = Exception("Session error")
with self.assertRaises(Exception):
self.chat_agent.process_programming_assistance(
self.session_id, "Test message"
)
def test_programming_assistance_response_formatting(self):
"""Test that responses are properly formatted."""
code = """
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
"""
result = self.chat_agent.process_programming_assistance(
self.session_id, "Review this code", code=code,
assistance_type=AssistanceType.CODE_REVIEW
)
# Verify response contains formatted analysis
response = result['response']
self.assertIn('Code Review', response)
self.assertIn('Overall Assessment', response)
def test_programming_assistance_with_chat_history(self):
"""Test programming assistance with existing chat history."""
# Setup mock chat history
mock_history = [
Mock(role='user', content='Previous question', language='python', timestamp=datetime.utcnow()),
Mock(role='assistant', content='Previous answer', language='python', timestamp=datetime.utcnow())
]
self.mock_chat_history_manager.get_recent_history.return_value = mock_history
result = self.chat_agent.process_programming_assistance(
self.session_id, "Follow-up question about variables"
)
# Verify that chat history was retrieved and used
self.mock_chat_history_manager.get_recent_history.assert_called_with(self.session_id)
# Verify LLM was called with history context
self.mock_groq_client.generate_response.assert_called_once()
call_args = self.mock_groq_client.generate_response.call_args
chat_history = call_args[1]['chat_history']
self.assertEqual(len(chat_history), 2) # Previous messages converted to ChatMessage format
def test_programming_assistance_metadata_storage(self):
"""Test that assistance metadata is properly stored."""
code = "x = 5\nprint(x)"
result = self.chat_agent.process_programming_assistance(
self.session_id, "Explain this", code=code,
assistance_type=AssistanceType.CODE_EXPLANATION
)
# Check assistant message metadata
store_calls = self.mock_chat_history_manager.store_message.call_args_list
assistant_message_call = store_calls[1] # Second call should be assistant message
metadata = assistant_message_call[1]['message_metadata']
self.assertEqual(metadata['assistance_type'], AssistanceType.CODE_EXPLANATION.value)
self.assertTrue(metadata['analysis_performed'])
self.assertIn('processing_time', metadata)
def test_programming_assistance_session_updates(self):
"""Test that session is properly updated during assistance."""
result = self.chat_agent.process_programming_assistance(
self.session_id, "Help with Python"
)
# Verify session operations
self.mock_session_manager.get_session.assert_called_with(self.session_id)
self.mock_session_manager.update_session_activity.assert_called_with(self.session_id)
self.mock_session_manager.increment_message_count.assert_called_with(self.session_id)
def test_multiple_assistance_types_in_sequence(self):
"""Test handling multiple assistance requests in sequence."""
# First request: Code explanation
code = "def hello(): print('Hello')"
result1 = self.chat_agent.process_programming_assistance(
self.session_id, "Explain this", code=code,
assistance_type=AssistanceType.CODE_EXPLANATION
)
# Second request: Error analysis
error = "SyntaxError: invalid syntax"
result2 = self.chat_agent.process_programming_assistance(
self.session_id, "What's this error?", error_message=error,
assistance_type=AssistanceType.ERROR_ANALYSIS
)
# Verify both requests were processed correctly
self.assertEqual(result1['assistance_type'], AssistanceType.CODE_EXPLANATION.value)
self.assertEqual(result2['assistance_type'], AssistanceType.ERROR_ANALYSIS.value)
# Verify session was updated for both
self.assertEqual(self.mock_session_manager.increment_message_count.call_count, 2)
def test_programming_assistance_with_specialized_prompts(self):
"""Test that specialized prompts are used for different assistance types."""
# Mock the language context manager to capture prompt templates
self.mock_language_context_manager.get_language_prompt_template.return_value = "Base template"
result = self.chat_agent.process_programming_assistance(
self.session_id, "Debug this code", code="print(x)",
error_message="NameError", assistance_type=AssistanceType.DEBUGGING
)
# Verify that generate_response was called with specialized language context
call_args = self.mock_groq_client.generate_response.call_args
language_context = call_args[1]['language_context']
# The prompt template should contain debugging-specific instructions
self.assertIn('debug', language_context.prompt_template.lower())
self.assertIn('step-by-step solution', language_context.prompt_template)
if __name__ == '__main__':
unittest.main()