diff --git a/tests/test_workflow_utf8_clean.py b/tests/test_workflow_utf8_clean.py deleted file mode 100644 index c66be17..0000000 --- a/tests/test_workflow_utf8_clean.py +++ /dev/null @@ -1,308 +0,0 @@ -""" -Unit tests to validate UTF-8 encoding in workflow tools -and the generation of properly encoded JSON responses. -""" - -import json -import os -import unittest -from unittest.mock import AsyncMock, Mock, patch - -from tools.analyze import AnalyzeTool -from tools.codereview import CodeReviewTool -from tools.debug import DebugIssueTool - - -class TestWorkflowToolsUTF8(unittest.IsolatedAsyncioTestCase): - """Tests for UTF-8 encoding in workflow tools.""" - - def setUp(self): - """Test setup.""" - self.original_locale = os.getenv("LOCALE") - # Default to French for tests - os.environ["LOCALE"] = "fr-FR" - - def tearDown(self): - """Cleanup after tests.""" - if self.original_locale is not None: - os.environ["LOCALE"] = self.original_locale - else: - os.environ.pop("LOCALE", None) - - def test_workflow_json_response_structure(self): - """Test the structure of JSON responses from workflow tools.""" - # Mock response with UTF-8 characters - test_response = { - "status": "pause_for_analysis", - "step_number": 1, - "total_steps": 3, - "next_step_required": True, - "findings": "Code analysis reveals performance issues 🔍", - "files_checked": ["/src/main.py"], - "relevant_files": ["/src/main.py"], - "issues_found": [ - { - "severity": "high", - "description": "Function too complex - refactoring needed" - } - ], - "investigation_required": True, - "required_actions": [ - "Review code dependencies", - "Analyze architectural patterns" - ], - } - - # Test JSON serialization with ensure_ascii=False - json_str = json.dumps(test_response, indent=2, ensure_ascii=False) - - # Check UTF-8 characters are preserved - self.assertIn("🔍", json_str) - - # No escaped characters - self.assertNotIn("\\u", json_str) - - # Test parsing - parsed = json.loads(json_str) - self.assertEqual(parsed["findings"], test_response["findings"]) - self.assertEqual(len(parsed["issues_found"]), 1) - - @patch("tools.shared.base_tool.BaseTool.get_model_provider") - async def test_analyze_tool_utf8_response(self, mock_get_provider): - """Test that the analyze tool returns correct UTF-8 responses.""" - # Mock provider with more complete setup - mock_provider = Mock() - mock_provider.get_provider_type.return_value = Mock(value="test") - mock_provider.supports_thinking_mode.return_value = False - mock_provider.generate_content = AsyncMock( - return_value=Mock( - content=json.dumps({ - "status": "analysis_complete", - "step_number": 1, - "total_steps": 2, - "next_step_required": True, - "findings": "Architectural analysis completed successfully", - "relevant_files": ["/test/main.py"], - "issues_found": [], - "confidence": "high" - }, ensure_ascii=False), - usage={}, - model_name="test-model", - metadata={}, - ) - ) - mock_get_provider.return_value = mock_provider - - # Test the tool - analyze_tool = AnalyzeTool() - result = await analyze_tool.execute( - { - "step": "Analyze system architecture to identify issues", - "step_number": 1, - "total_steps": 2, - "next_step_required": True, - "findings": "Starting architectural analysis of Python code", - "relevant_files": ["/test/main.py"], - "model": "test-model", - } - ) - - # Checks - self.assertIsNotNone(result) - self.assertEqual(len(result), 1) - - # Parse the response - must be valid UTF-8 JSON - response_text = result[0].text - response_data = json.loads(response_text) - - # Structure checks - self.assertIn("status", response_data) - self.assertIn("step_number", response_data) - - # Check that the French instruction was added - mock_provider.generate_content.assert_called() - call_args = mock_provider.generate_content.call_args - system_prompt = call_args.kwargs.get("system_prompt", "") - self.assertIn("fr-FR", system_prompt) - - @patch("tools.shared.base_tool.BaseTool.get_model_provider") - async def test_codereview_tool_french_findings(self, mock_get_provider): - """Test that the codereview tool produces findings in French.""" - # Mock with analysis in French - mock_provider = Mock() - mock_provider.get_provider_type.return_value = Mock(value="test") - mock_provider.supports_thinking_mode.return_value = False - mock_provider.generate_content = AsyncMock( - return_value=Mock( - content=json.dumps( - { - "status": "analysis_complete", - "raw_analysis": """ -🔴 CRITIQUE: Aucun problème critique trouvé. - -🟠 ÉLEVÉ: Fichier example.py:42 - Fonction trop complexe -→ Problème: La fonction process_data() contient trop de responsabilités -→ Solution: Décomposer en fonctions plus petites et spécialisées - -🟡 MOYEN: Gestion d'erreurs insuffisante -→ Problème: Plusieurs fonctions n'ont pas de gestion d'erreurs appropriée -→ Solution: Ajouter des try-catch et validation des paramètres - -✅ Points positifs: -• Code bien commenté et lisible -• Nomenclature cohérente -• Tests unitaires présents -""", - }, - ensure_ascii=False, - ), - usage={}, - model_name="test-model", - metadata={}, - ) - ) - mock_get_provider.return_value = mock_provider - - # Test the tool - codereview_tool = CodeReviewTool() - result = await codereview_tool.execute( - { - "step": "Complete review of Python code", - "step_number": 1, - "total_steps": 1, - "next_step_required": False, - "findings": "Code review complete", - "relevant_files": ["/test/example.py"], - "model": "test-model", - } - ) - - # Checks - self.assertIsNotNone(result) - response_text = result[0].text - response_data = json.loads(response_text) - - # Check UTF-8 characters in analysis - if "expert_analysis" in response_data: - analysis = response_data["expert_analysis"]["raw_analysis"] - # Check for French characters - self.assertIn("ÉLEVÉ", analysis) - self.assertIn("problème", analysis) - self.assertIn("spécialisées", analysis) - self.assertIn("appropriée", analysis) - self.assertIn("paramètres", analysis) - self.assertIn("présents", analysis) - # Check for emojis - self.assertIn("🔴", analysis) - self.assertIn("🟠", analysis) - self.assertIn("🟡", analysis) - self.assertIn("✅", analysis) - - @patch("tools.shared.base_tool.BaseTool.get_model_provider") - async def test_debug_tool_french_error_analysis(self, mock_get_provider): - """Test that the debug tool analyzes errors in French.""" - # Mock provider - mock_provider = Mock() - mock_provider.get_provider_type.return_value = Mock(value="test") - mock_provider.supports_thinking_mode.return_value = False - mock_provider.generate_content = AsyncMock( - return_value=Mock( - content=json.dumps({ - "status": "pause_for_investigation", - "step_number": 1, - "total_steps": 2, - "next_step_required": True, - "findings": "Erreur analysée: variable 'données' non définie. Cause probable: import manquant.", - "files_checked": ["/src/data_processor.py"], - "relevant_files": ["/src/data_processor.py"], - "hypothesis": "Variable 'données' not defined - missing import", - "confidence": "medium", - "investigation_status": "in_progress", - "error_analysis": "L'erreur concerne la variable 'données' qui n'est pas définie.", - }, ensure_ascii=False), - usage={}, - model_name="test-model", - metadata={}, - ) - ) - mock_get_provider.return_value = mock_provider - - # Test the debug tool - debug_tool = DebugIssueTool() - result = await debug_tool.execute( - { - "step": "Analyze NameError in data processing file", - "step_number": 1, - "total_steps": 2, - "next_step_required": True, - "findings": "Error detected during script execution", - "files_checked": ["/src/data_processor.py"], - "relevant_files": ["/src/data_processor.py"], - "hypothesis": "Variable 'données' not defined - missing import", - "confidence": "medium", - "model": "test-model", - } - ) - - # Checks - self.assertIsNotNone(result) - response_text = result[0].text - response_data = json.loads(response_text) - - # Check response structure - self.assertIn("status", response_data) - self.assertIn("investigation_status", response_data) - - # Check that UTF-8 characters are preserved - response_str = json.dumps(response_data, ensure_ascii=False) - self.assertIn("données", response_str) - - def test_utf8_emoji_preservation_in_workflow_responses(self): - """Test that emojis are preserved in workflow tool responses.""" - # Mock workflow response with various emojis - test_data = { - "status": "analysis_complete", - "severity_indicators": { - "critical": "🔴", - "high": "🟠", - "medium": "🟡", - "low": "🟢", - "success": "✅", - "error": "❌", - "warning": "⚠️", - }, - "progress": "Analysis completed 🎉", - "recommendations": [ - "Optimize performance 🚀", - "Improve documentation 📚", - "Add unit tests 🧪", - ], - } - - # Test JSON encoding with ensure_ascii=False - json_str = json.dumps(test_data, ensure_ascii=False, indent=2) - - # Check emojis are preserved - self.assertIn("🔴", json_str) - self.assertIn("🟠", json_str) - self.assertIn("🟡", json_str) - self.assertIn("🟢", json_str) - self.assertIn("✅", json_str) - self.assertIn("❌", json_str) - self.assertIn("⚠️", json_str) - self.assertIn("🎉", json_str) - self.assertIn("🚀", json_str) - self.assertIn("📚", json_str) - self.assertIn("🧪", json_str) - - # No escaped Unicode - self.assertNotIn("\\u", json_str) - - # Test parsing preserves emojis - parsed = json.loads(json_str) - self.assertEqual(parsed["severity_indicators"]["critical"], "🔴") - self.assertEqual(parsed["progress"], "Analysis completed 🎉") - - -if __name__ == "__main__": - unittest.main(verbosity=2)