empathy-framework 4.6.6__py3-none-any.whl → 4.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/METADATA +7 -6
- empathy_framework-4.7.0.dist-info/RECORD +354 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/top_level.txt +0 -2
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
- empathy_llm_toolkit/agent_factory/__init__.py +6 -6
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
- empathy_llm_toolkit/agents_md/__init__.py +22 -0
- empathy_llm_toolkit/agents_md/loader.py +218 -0
- empathy_llm_toolkit/agents_md/parser.py +271 -0
- empathy_llm_toolkit/agents_md/registry.py +307 -0
- empathy_llm_toolkit/commands/__init__.py +51 -0
- empathy_llm_toolkit/commands/context.py +375 -0
- empathy_llm_toolkit/commands/loader.py +301 -0
- empathy_llm_toolkit/commands/models.py +231 -0
- empathy_llm_toolkit/commands/parser.py +371 -0
- empathy_llm_toolkit/commands/registry.py +429 -0
- empathy_llm_toolkit/config/__init__.py +8 -8
- empathy_llm_toolkit/config/unified.py +3 -7
- empathy_llm_toolkit/context/__init__.py +22 -0
- empathy_llm_toolkit/context/compaction.py +455 -0
- empathy_llm_toolkit/context/manager.py +434 -0
- empathy_llm_toolkit/hooks/__init__.py +24 -0
- empathy_llm_toolkit/hooks/config.py +306 -0
- empathy_llm_toolkit/hooks/executor.py +289 -0
- empathy_llm_toolkit/hooks/registry.py +302 -0
- empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
- empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
- empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
- empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
- empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
- empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
- empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
- empathy_llm_toolkit/learning/__init__.py +30 -0
- empathy_llm_toolkit/learning/evaluator.py +438 -0
- empathy_llm_toolkit/learning/extractor.py +514 -0
- empathy_llm_toolkit/learning/storage.py +560 -0
- empathy_llm_toolkit/providers.py +4 -11
- empathy_llm_toolkit/security/__init__.py +17 -17
- empathy_llm_toolkit/utils/tokens.py +2 -5
- empathy_os/__init__.py +202 -70
- empathy_os/cache_monitor.py +5 -3
- empathy_os/cli/__init__.py +11 -55
- empathy_os/cli/__main__.py +29 -15
- empathy_os/cli/commands/inspection.py +21 -12
- empathy_os/cli/commands/memory.py +4 -12
- empathy_os/cli/commands/profiling.py +198 -0
- empathy_os/cli/commands/utilities.py +27 -7
- empathy_os/cli.py +28 -57
- empathy_os/cli_unified.py +525 -1164
- empathy_os/cost_tracker.py +9 -3
- empathy_os/dashboard/server.py +200 -2
- empathy_os/hot_reload/__init__.py +7 -7
- empathy_os/hot_reload/config.py +6 -7
- empathy_os/hot_reload/integration.py +35 -35
- empathy_os/hot_reload/reloader.py +57 -57
- empathy_os/hot_reload/watcher.py +28 -28
- empathy_os/hot_reload/websocket.py +2 -2
- empathy_os/memory/__init__.py +11 -4
- empathy_os/memory/claude_memory.py +1 -1
- empathy_os/memory/cross_session.py +8 -12
- empathy_os/memory/edges.py +6 -6
- empathy_os/memory/file_session.py +770 -0
- empathy_os/memory/graph.py +30 -30
- empathy_os/memory/nodes.py +6 -6
- empathy_os/memory/short_term.py +15 -9
- empathy_os/memory/unified.py +606 -140
- empathy_os/meta_workflows/agent_creator.py +3 -9
- empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
- empathy_os/meta_workflows/form_engine.py +6 -18
- empathy_os/meta_workflows/intent_detector.py +64 -24
- empathy_os/meta_workflows/models.py +3 -1
- empathy_os/meta_workflows/pattern_learner.py +13 -31
- empathy_os/meta_workflows/plan_generator.py +55 -47
- empathy_os/meta_workflows/session_context.py +2 -3
- empathy_os/meta_workflows/workflow.py +20 -51
- empathy_os/models/cli.py +2 -2
- empathy_os/models/tasks.py +1 -2
- empathy_os/models/telemetry.py +4 -1
- empathy_os/models/token_estimator.py +3 -1
- empathy_os/monitoring/alerts.py +938 -9
- empathy_os/monitoring/alerts_cli.py +346 -183
- empathy_os/orchestration/execution_strategies.py +12 -29
- empathy_os/orchestration/pattern_learner.py +20 -26
- empathy_os/orchestration/real_tools.py +6 -15
- empathy_os/platform_utils.py +2 -1
- empathy_os/plugins/__init__.py +2 -2
- empathy_os/plugins/base.py +64 -64
- empathy_os/plugins/registry.py +32 -32
- empathy_os/project_index/index.py +49 -15
- empathy_os/project_index/models.py +1 -2
- empathy_os/project_index/reports.py +1 -1
- empathy_os/project_index/scanner.py +1 -0
- empathy_os/redis_memory.py +10 -7
- empathy_os/resilience/__init__.py +1 -1
- empathy_os/resilience/health.py +10 -10
- empathy_os/routing/__init__.py +7 -7
- empathy_os/routing/chain_executor.py +37 -37
- empathy_os/routing/classifier.py +36 -36
- empathy_os/routing/smart_router.py +40 -40
- empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
- empathy_os/scaffolding/__init__.py +8 -8
- empathy_os/scaffolding/__main__.py +1 -1
- empathy_os/scaffolding/cli.py +28 -28
- empathy_os/socratic/__init__.py +3 -19
- empathy_os/socratic/ab_testing.py +25 -36
- empathy_os/socratic/blueprint.py +38 -38
- empathy_os/socratic/cli.py +34 -20
- empathy_os/socratic/collaboration.py +30 -28
- empathy_os/socratic/domain_templates.py +9 -1
- empathy_os/socratic/embeddings.py +17 -13
- empathy_os/socratic/engine.py +135 -70
- empathy_os/socratic/explainer.py +70 -60
- empathy_os/socratic/feedback.py +24 -19
- empathy_os/socratic/forms.py +15 -10
- empathy_os/socratic/generator.py +51 -35
- empathy_os/socratic/llm_analyzer.py +25 -23
- empathy_os/socratic/mcp_server.py +99 -159
- empathy_os/socratic/session.py +19 -13
- empathy_os/socratic/storage.py +98 -67
- empathy_os/socratic/success.py +38 -27
- empathy_os/socratic/visual_editor.py +51 -39
- empathy_os/socratic/web_ui.py +99 -66
- empathy_os/telemetry/cli.py +3 -1
- empathy_os/telemetry/usage_tracker.py +1 -3
- empathy_os/test_generator/__init__.py +3 -3
- empathy_os/test_generator/cli.py +28 -28
- empathy_os/test_generator/generator.py +64 -66
- empathy_os/test_generator/risk_analyzer.py +11 -11
- empathy_os/vscode_bridge.py +173 -0
- empathy_os/workflows/__init__.py +212 -120
- empathy_os/workflows/batch_processing.py +8 -24
- empathy_os/workflows/bug_predict.py +1 -1
- empathy_os/workflows/code_review.py +20 -5
- empathy_os/workflows/code_review_pipeline.py +13 -8
- empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
- empathy_os/workflows/manage_documentation.py +1 -0
- empathy_os/workflows/orchestrated_health_check.py +6 -11
- empathy_os/workflows/orchestrated_release_prep.py +3 -3
- empathy_os/workflows/pr_review.py +18 -10
- empathy_os/workflows/progressive/__init__.py +2 -12
- empathy_os/workflows/progressive/cli.py +14 -37
- empathy_os/workflows/progressive/core.py +12 -12
- empathy_os/workflows/progressive/orchestrator.py +166 -144
- empathy_os/workflows/progressive/reports.py +22 -31
- empathy_os/workflows/progressive/telemetry.py +8 -14
- empathy_os/workflows/progressive/test_gen.py +29 -48
- empathy_os/workflows/progressive/workflow.py +31 -70
- empathy_os/workflows/release_prep.py +21 -6
- empathy_os/workflows/release_prep_crew.py +1 -0
- empathy_os/workflows/secure_release.py +13 -6
- empathy_os/workflows/security_audit.py +8 -3
- empathy_os/workflows/test_coverage_boost_crew.py +3 -2
- empathy_os/workflows/test_maintenance_crew.py +1 -0
- empathy_os/workflows/test_runner.py +16 -12
- empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
- empathy_software_plugin/cli.py +0 -122
- coach_wizards/__init__.py +0 -45
- coach_wizards/accessibility_wizard.py +0 -91
- coach_wizards/api_wizard.py +0 -91
- coach_wizards/base_wizard.py +0 -209
- coach_wizards/cicd_wizard.py +0 -91
- coach_wizards/code_reviewer_README.md +0 -60
- coach_wizards/code_reviewer_wizard.py +0 -180
- coach_wizards/compliance_wizard.py +0 -91
- coach_wizards/database_wizard.py +0 -91
- coach_wizards/debugging_wizard.py +0 -91
- coach_wizards/documentation_wizard.py +0 -91
- coach_wizards/generate_wizards.py +0 -347
- coach_wizards/localization_wizard.py +0 -173
- coach_wizards/migration_wizard.py +0 -91
- coach_wizards/monitoring_wizard.py +0 -91
- coach_wizards/observability_wizard.py +0 -91
- coach_wizards/performance_wizard.py +0 -91
- coach_wizards/prompt_engineering_wizard.py +0 -661
- coach_wizards/refactoring_wizard.py +0 -91
- coach_wizards/scaling_wizard.py +0 -90
- coach_wizards/security_wizard.py +0 -92
- coach_wizards/testing_wizard.py +0 -91
- empathy_framework-4.6.6.dist-info/RECORD +0 -410
- empathy_llm_toolkit/wizards/__init__.py +0 -43
- empathy_llm_toolkit/wizards/base_wizard.py +0 -364
- empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
- empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
- empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
- empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
- empathy_os/wizard_factory_cli.py +0 -170
- empathy_software_plugin/wizards/__init__.py +0 -42
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
- empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
- empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
- empathy_software_plugin/wizards/base_wizard.py +0 -288
- empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
- empathy_software_plugin/wizards/code_review_wizard.py +0 -604
- empathy_software_plugin/wizards/debugging/__init__.py +0 -50
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
- empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
- empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
- empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
- empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
- empathy_software_plugin/wizards/debugging/verification.py +0 -369
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
- empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
- empathy_software_plugin/wizards/performance/__init__.py +0 -9
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
- empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
- empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
- empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
- empathy_software_plugin/wizards/security/__init__.py +0 -32
- empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
- empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
- empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
- empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
- empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
- empathy_software_plugin/wizards/testing/__init__.py +0 -27
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
- empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
- empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
- empathy_software_plugin/wizards/testing_wizard.py +0 -274
- wizards/__init__.py +0 -82
- wizards/admission_assessment_wizard.py +0 -644
- wizards/care_plan.py +0 -321
- wizards/clinical_assessment.py +0 -769
- wizards/discharge_planning.py +0 -77
- wizards/discharge_summary_wizard.py +0 -468
- wizards/dosage_calculation.py +0 -497
- wizards/incident_report_wizard.py +0 -454
- wizards/medication_reconciliation.py +0 -85
- wizards/nursing_assessment.py +0 -171
- wizards/patient_education.py +0 -654
- wizards/quality_improvement.py +0 -705
- wizards/sbar_report.py +0 -324
- wizards/sbar_wizard.py +0 -608
- wizards/shift_handoff_wizard.py +0 -535
- wizards/soap_note_wizard.py +0 -679
- wizards/treatment_plan.py +0 -15
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/WHEEL +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/entry_points.txt +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,533 +0,0 @@
|
|
|
1
|
-
"""Test Suggester for Enhanced Testing Wizard
|
|
2
|
-
|
|
3
|
-
Generates smart test suggestions based on code analysis and coverage gaps.
|
|
4
|
-
Uses pattern recognition to suggest high-value tests.
|
|
5
|
-
|
|
6
|
-
Copyright 2025 Smart-AI-Memory
|
|
7
|
-
Licensed under Fair Source License 0.9
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import ast
|
|
11
|
-
from dataclasses import dataclass
|
|
12
|
-
from enum import Enum
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class TestPriority(Enum):
|
|
17
|
-
"""Priority levels for test suggestions"""
|
|
18
|
-
|
|
19
|
-
CRITICAL = "critical" # Untested critical paths
|
|
20
|
-
HIGH = "high" # Important functionality
|
|
21
|
-
MEDIUM = "medium" # Standard coverage
|
|
22
|
-
LOW = "low" # Nice to have
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclass
|
|
26
|
-
class TestSuggestion:
|
|
27
|
-
"""A suggested test to write"""
|
|
28
|
-
|
|
29
|
-
target_file: str
|
|
30
|
-
target_function: str
|
|
31
|
-
target_line: int
|
|
32
|
-
test_type: str # "unit", "integration", "edge_case", "error_handling"
|
|
33
|
-
priority: TestPriority
|
|
34
|
-
suggestion: str # Human-readable description
|
|
35
|
-
template: str # Code template
|
|
36
|
-
reasoning: str # Why this test is important
|
|
37
|
-
estimated_impact: float # Impact on coverage (0-100)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclass
|
|
41
|
-
class CodeElement:
|
|
42
|
-
"""Represents a code element that needs testing"""
|
|
43
|
-
|
|
44
|
-
name: str
|
|
45
|
-
type: str # "function", "class", "method"
|
|
46
|
-
file_path: str
|
|
47
|
-
line_number: int
|
|
48
|
-
is_public: bool
|
|
49
|
-
complexity: int # Cyclomatic complexity estimate
|
|
50
|
-
has_error_handling: bool
|
|
51
|
-
parameters: list[str]
|
|
52
|
-
return_type: str | None
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class TestSuggester:
|
|
56
|
-
"""Analyzes code to suggest high-value tests.
|
|
57
|
-
|
|
58
|
-
Uses static analysis to:
|
|
59
|
-
- Identify untested functions
|
|
60
|
-
- Detect edge cases
|
|
61
|
-
- Find error handling paths
|
|
62
|
-
- Suggest integration tests
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
def __init__(self):
|
|
66
|
-
self.critical_patterns = [
|
|
67
|
-
"parse",
|
|
68
|
-
"validate",
|
|
69
|
-
"authenticate",
|
|
70
|
-
"authorize",
|
|
71
|
-
"save",
|
|
72
|
-
"delete",
|
|
73
|
-
"update",
|
|
74
|
-
"create",
|
|
75
|
-
"execute",
|
|
76
|
-
"run",
|
|
77
|
-
"process",
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
def analyze_file(self, file_path: Path) -> list[CodeElement]:
|
|
81
|
-
"""Analyze a Python file to extract testable elements
|
|
82
|
-
|
|
83
|
-
Args:
|
|
84
|
-
file_path: Path to Python file
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
List of CodeElement objects
|
|
88
|
-
|
|
89
|
-
Raises:
|
|
90
|
-
FileNotFoundError: If file doesn't exist
|
|
91
|
-
SyntaxError: If file has syntax errors
|
|
92
|
-
|
|
93
|
-
"""
|
|
94
|
-
if not file_path.exists():
|
|
95
|
-
raise FileNotFoundError(f"File not found: {file_path}")
|
|
96
|
-
|
|
97
|
-
with open(file_path, encoding="utf-8") as f:
|
|
98
|
-
content = f.read()
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
tree = ast.parse(content)
|
|
102
|
-
except SyntaxError as e:
|
|
103
|
-
raise SyntaxError(f"Syntax error in {file_path}: {e}") from e
|
|
104
|
-
|
|
105
|
-
return self._extract_code_elements(tree, str(file_path))
|
|
106
|
-
|
|
107
|
-
def _extract_code_elements(self, tree: ast.AST, file_path: str) -> list[CodeElement]:
|
|
108
|
-
"""Extract testable code elements from AST"""
|
|
109
|
-
elements = []
|
|
110
|
-
|
|
111
|
-
for node in ast.walk(tree):
|
|
112
|
-
# Extract functions
|
|
113
|
-
if isinstance(node, ast.FunctionDef):
|
|
114
|
-
element = self._analyze_function(node, file_path)
|
|
115
|
-
elements.append(element)
|
|
116
|
-
|
|
117
|
-
# Extract class methods
|
|
118
|
-
elif isinstance(node, ast.ClassDef):
|
|
119
|
-
for item in node.body:
|
|
120
|
-
if isinstance(item, ast.FunctionDef):
|
|
121
|
-
element = self._analyze_method(item, node.name, file_path)
|
|
122
|
-
elements.append(element)
|
|
123
|
-
|
|
124
|
-
return elements
|
|
125
|
-
|
|
126
|
-
def _analyze_function(self, node: ast.FunctionDef, file_path: str) -> CodeElement:
|
|
127
|
-
"""Analyze a function node"""
|
|
128
|
-
# Check if public (not starting with _)
|
|
129
|
-
is_public = not node.name.startswith("_")
|
|
130
|
-
|
|
131
|
-
# Extract parameters
|
|
132
|
-
parameters = [arg.arg for arg in node.args.args]
|
|
133
|
-
|
|
134
|
-
# Estimate complexity (simple heuristic)
|
|
135
|
-
complexity = self._estimate_complexity(node)
|
|
136
|
-
|
|
137
|
-
# Check for error handling
|
|
138
|
-
has_error_handling = self._has_error_handling(node)
|
|
139
|
-
|
|
140
|
-
# Extract return type
|
|
141
|
-
return_type = None
|
|
142
|
-
if node.returns:
|
|
143
|
-
return_type = ast.unparse(node.returns)
|
|
144
|
-
|
|
145
|
-
return CodeElement(
|
|
146
|
-
name=node.name,
|
|
147
|
-
type="function",
|
|
148
|
-
file_path=file_path,
|
|
149
|
-
line_number=node.lineno,
|
|
150
|
-
is_public=is_public,
|
|
151
|
-
complexity=complexity,
|
|
152
|
-
has_error_handling=has_error_handling,
|
|
153
|
-
parameters=parameters,
|
|
154
|
-
return_type=return_type,
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
def _analyze_method(
|
|
158
|
-
self,
|
|
159
|
-
node: ast.FunctionDef,
|
|
160
|
-
class_name: str,
|
|
161
|
-
file_path: str,
|
|
162
|
-
) -> CodeElement:
|
|
163
|
-
"""Analyze a class method"""
|
|
164
|
-
element = self._analyze_function(node, file_path)
|
|
165
|
-
element.name = f"{class_name}.{node.name}"
|
|
166
|
-
element.type = "method"
|
|
167
|
-
return element
|
|
168
|
-
|
|
169
|
-
def _estimate_complexity(self, node: ast.FunctionDef) -> int:
|
|
170
|
-
"""Estimate cyclomatic complexity
|
|
171
|
-
|
|
172
|
-
Counts decision points: if, for, while, and, or, except
|
|
173
|
-
"""
|
|
174
|
-
complexity = 1 # Base complexity
|
|
175
|
-
|
|
176
|
-
for child in ast.walk(node):
|
|
177
|
-
if isinstance(child, ast.If | ast.For | ast.While | ast.ExceptHandler):
|
|
178
|
-
complexity += 1
|
|
179
|
-
elif isinstance(child, ast.BoolOp):
|
|
180
|
-
# Count 'and'/'or' operations
|
|
181
|
-
complexity += len(child.values) - 1
|
|
182
|
-
|
|
183
|
-
return complexity
|
|
184
|
-
|
|
185
|
-
def _has_error_handling(self, node: ast.FunctionDef) -> bool:
|
|
186
|
-
"""Check if function has try/except blocks"""
|
|
187
|
-
for child in ast.walk(node):
|
|
188
|
-
if isinstance(child, ast.Try):
|
|
189
|
-
return True
|
|
190
|
-
return False
|
|
191
|
-
|
|
192
|
-
def suggest_tests(
|
|
193
|
-
self,
|
|
194
|
-
code_elements: list[CodeElement],
|
|
195
|
-
covered_lines: set[int],
|
|
196
|
-
) -> list[TestSuggestion]:
|
|
197
|
-
"""Generate test suggestions for code elements
|
|
198
|
-
|
|
199
|
-
Args:
|
|
200
|
-
code_elements: List of code elements from analysis
|
|
201
|
-
covered_lines: Set of line numbers already covered by tests
|
|
202
|
-
|
|
203
|
-
Returns:
|
|
204
|
-
List of TestSuggestion objects, sorted by priority
|
|
205
|
-
|
|
206
|
-
"""
|
|
207
|
-
suggestions = []
|
|
208
|
-
|
|
209
|
-
for element in code_elements:
|
|
210
|
-
# Skip private elements unless they're complex
|
|
211
|
-
if not element.is_public and element.complexity < 3:
|
|
212
|
-
continue
|
|
213
|
-
|
|
214
|
-
# Check if already tested
|
|
215
|
-
is_covered = element.line_number in covered_lines
|
|
216
|
-
|
|
217
|
-
# Generate suggestions based on element characteristics
|
|
218
|
-
element_suggestions = self._generate_element_suggestions(element, is_covered)
|
|
219
|
-
|
|
220
|
-
suggestions.extend(element_suggestions)
|
|
221
|
-
|
|
222
|
-
# Sort by priority and impact
|
|
223
|
-
suggestions.sort(key=lambda s: (s.priority.value, -s.estimated_impact))
|
|
224
|
-
|
|
225
|
-
return suggestions
|
|
226
|
-
|
|
227
|
-
def _generate_element_suggestions(
|
|
228
|
-
self,
|
|
229
|
-
element: CodeElement,
|
|
230
|
-
is_covered: bool,
|
|
231
|
-
) -> list[TestSuggestion]:
|
|
232
|
-
"""Generate suggestions for a single code element"""
|
|
233
|
-
suggestions = []
|
|
234
|
-
|
|
235
|
-
# Determine base priority
|
|
236
|
-
base_priority = self._determine_priority(element, is_covered)
|
|
237
|
-
|
|
238
|
-
# 1. Basic functionality test
|
|
239
|
-
if not is_covered:
|
|
240
|
-
suggestions.append(self._suggest_basic_test(element, base_priority))
|
|
241
|
-
|
|
242
|
-
# 2. Edge case tests
|
|
243
|
-
if element.complexity > 2:
|
|
244
|
-
suggestions.append(self._suggest_edge_case_tests(element, base_priority))
|
|
245
|
-
|
|
246
|
-
# 3. Error handling tests
|
|
247
|
-
if element.has_error_handling or self._should_have_error_handling(element):
|
|
248
|
-
suggestions.append(self._suggest_error_test(element, base_priority))
|
|
249
|
-
|
|
250
|
-
# 4. Parameter validation tests
|
|
251
|
-
if len(element.parameters) > 0:
|
|
252
|
-
suggestions.append(self._suggest_parameter_tests(element, base_priority))
|
|
253
|
-
|
|
254
|
-
return suggestions
|
|
255
|
-
|
|
256
|
-
def _determine_priority(self, element: CodeElement, is_covered: bool) -> TestPriority:
|
|
257
|
-
"""Determine test priority based on element characteristics"""
|
|
258
|
-
# Critical if untested and matches critical patterns
|
|
259
|
-
if not is_covered:
|
|
260
|
-
for pattern in self.critical_patterns:
|
|
261
|
-
if pattern in element.name.lower():
|
|
262
|
-
return TestPriority.CRITICAL
|
|
263
|
-
|
|
264
|
-
# High priority if complex or has error handling
|
|
265
|
-
if element.complexity > 5 or element.has_error_handling:
|
|
266
|
-
return TestPriority.HIGH if not is_covered else TestPriority.MEDIUM
|
|
267
|
-
|
|
268
|
-
# Medium priority if public
|
|
269
|
-
if element.is_public:
|
|
270
|
-
return TestPriority.MEDIUM if not is_covered else TestPriority.LOW
|
|
271
|
-
|
|
272
|
-
return TestPriority.LOW
|
|
273
|
-
|
|
274
|
-
def _should_have_error_handling(self, element: CodeElement) -> bool:
|
|
275
|
-
"""Determine if element should have error handling"""
|
|
276
|
-
# Functions that interact with external systems
|
|
277
|
-
error_prone_patterns = [
|
|
278
|
-
"parse",
|
|
279
|
-
"load",
|
|
280
|
-
"save",
|
|
281
|
-
"fetch",
|
|
282
|
-
"request",
|
|
283
|
-
"connect",
|
|
284
|
-
"execute",
|
|
285
|
-
"validate",
|
|
286
|
-
"convert",
|
|
287
|
-
]
|
|
288
|
-
|
|
289
|
-
return any(pattern in element.name.lower() for pattern in error_prone_patterns)
|
|
290
|
-
|
|
291
|
-
def _suggest_basic_test(self, element: CodeElement, priority: TestPriority) -> TestSuggestion:
|
|
292
|
-
"""Generate basic functionality test suggestion"""
|
|
293
|
-
# Generate test template
|
|
294
|
-
template = self._generate_basic_template(element)
|
|
295
|
-
|
|
296
|
-
# Calculate impact (uncovered function = high impact)
|
|
297
|
-
impact = 50.0 if element.is_public else 30.0
|
|
298
|
-
|
|
299
|
-
return TestSuggestion(
|
|
300
|
-
target_file=element.file_path,
|
|
301
|
-
target_function=element.name,
|
|
302
|
-
target_line=element.line_number,
|
|
303
|
-
test_type="unit",
|
|
304
|
-
priority=priority,
|
|
305
|
-
suggestion=f"Test basic functionality of {element.name}",
|
|
306
|
-
template=template,
|
|
307
|
-
reasoning=f"Function {element.name} is currently untested",
|
|
308
|
-
estimated_impact=impact,
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
def _suggest_edge_case_tests(
|
|
312
|
-
self,
|
|
313
|
-
element: CodeElement,
|
|
314
|
-
priority: TestPriority,
|
|
315
|
-
) -> TestSuggestion:
|
|
316
|
-
"""Generate edge case test suggestions"""
|
|
317
|
-
edge_cases = self._identify_edge_cases(element)
|
|
318
|
-
|
|
319
|
-
template = self._generate_edge_case_template(element, edge_cases)
|
|
320
|
-
|
|
321
|
-
return TestSuggestion(
|
|
322
|
-
target_file=element.file_path,
|
|
323
|
-
target_function=element.name,
|
|
324
|
-
target_line=element.line_number,
|
|
325
|
-
test_type="edge_case",
|
|
326
|
-
priority=priority,
|
|
327
|
-
suggestion=f"Test edge cases: {', '.join(edge_cases)}",
|
|
328
|
-
template=template,
|
|
329
|
-
reasoning=f"Complex function (complexity {element.complexity}) needs edge case coverage",
|
|
330
|
-
estimated_impact=25.0,
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
def _suggest_error_test(self, element: CodeElement, priority: TestPriority) -> TestSuggestion:
|
|
334
|
-
"""Generate error handling test suggestion"""
|
|
335
|
-
template = self._generate_error_template(element)
|
|
336
|
-
|
|
337
|
-
return TestSuggestion(
|
|
338
|
-
target_file=element.file_path,
|
|
339
|
-
target_function=element.name,
|
|
340
|
-
target_line=element.line_number,
|
|
341
|
-
test_type="error_handling",
|
|
342
|
-
priority=priority,
|
|
343
|
-
suggestion=f"Test error handling for {element.name}",
|
|
344
|
-
template=template,
|
|
345
|
-
reasoning="Function should handle errors gracefully",
|
|
346
|
-
estimated_impact=20.0,
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
def _suggest_parameter_tests(
|
|
350
|
-
self,
|
|
351
|
-
element: CodeElement,
|
|
352
|
-
priority: TestPriority,
|
|
353
|
-
) -> TestSuggestion:
|
|
354
|
-
"""Generate parameter validation test suggestion"""
|
|
355
|
-
template = self._generate_parameter_template(element)
|
|
356
|
-
|
|
357
|
-
return TestSuggestion(
|
|
358
|
-
target_file=element.file_path,
|
|
359
|
-
target_function=element.name,
|
|
360
|
-
target_line=element.line_number,
|
|
361
|
-
test_type="unit",
|
|
362
|
-
priority=priority,
|
|
363
|
-
suggestion="Test with various parameter combinations",
|
|
364
|
-
template=template,
|
|
365
|
-
reasoning=f"Function takes {len(element.parameters)} parameters - test combinations",
|
|
366
|
-
estimated_impact=15.0,
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
def _identify_edge_cases(self, element: CodeElement) -> list[str]:
|
|
370
|
-
"""Identify likely edge cases based on function name and parameters"""
|
|
371
|
-
edge_cases = []
|
|
372
|
-
|
|
373
|
-
name_lower = element.name.lower()
|
|
374
|
-
|
|
375
|
-
# List/collection operations
|
|
376
|
-
if any(word in name_lower for word in ["list", "array", "collection"]):
|
|
377
|
-
edge_cases.extend(["empty list", "single item", "large list"])
|
|
378
|
-
|
|
379
|
-
# String operations
|
|
380
|
-
if any(word in name_lower for word in ["string", "text", "name"]):
|
|
381
|
-
edge_cases.extend(["empty string", "unicode", "very long string"])
|
|
382
|
-
|
|
383
|
-
# Numeric operations
|
|
384
|
-
if any(word in name_lower for word in ["count", "size", "number", "calculate"]):
|
|
385
|
-
edge_cases.extend(["zero", "negative", "very large number"])
|
|
386
|
-
|
|
387
|
-
# File/path operations
|
|
388
|
-
if any(word in name_lower for word in ["file", "path", "directory"]):
|
|
389
|
-
edge_cases.extend(["nonexistent path", "invalid path", "permissions"])
|
|
390
|
-
|
|
391
|
-
# Default edge cases
|
|
392
|
-
if not edge_cases:
|
|
393
|
-
edge_cases = ["None input", "invalid type", "boundary values"]
|
|
394
|
-
|
|
395
|
-
return edge_cases[:3] # Limit to top 3
|
|
396
|
-
|
|
397
|
-
def _generate_basic_template(self, element: CodeElement) -> str:
|
|
398
|
-
"""Generate basic test template"""
|
|
399
|
-
func_name = element.name.split(".")[-1] # Get last part for methods
|
|
400
|
-
test_name = f"test_{func_name}_basic"
|
|
401
|
-
|
|
402
|
-
# Generate parameter examples
|
|
403
|
-
params = []
|
|
404
|
-
for param in element.parameters:
|
|
405
|
-
if param in ["self", "cls"]:
|
|
406
|
-
continue
|
|
407
|
-
params.append(f"{param}=...") # Placeholder
|
|
408
|
-
|
|
409
|
-
param_str = ", ".join(params) if params else ""
|
|
410
|
-
|
|
411
|
-
template = f"""
|
|
412
|
-
def {test_name}():
|
|
413
|
-
'''Test basic functionality of {element.name}'''
|
|
414
|
-
# Arrange
|
|
415
|
-
{param_str}
|
|
416
|
-
|
|
417
|
-
# Act
|
|
418
|
-
result = {element.name}({param_str})
|
|
419
|
-
|
|
420
|
-
# Assert
|
|
421
|
-
assert result is not None
|
|
422
|
-
# TODO: Add specific assertions
|
|
423
|
-
"""
|
|
424
|
-
return template.strip()
|
|
425
|
-
|
|
426
|
-
def _generate_edge_case_template(self, element: CodeElement, edge_cases: list[str]) -> str:
|
|
427
|
-
"""Generate edge case test template"""
|
|
428
|
-
func_name = element.name.split(".")[-1]
|
|
429
|
-
test_name = f"test_{func_name}_edge_cases"
|
|
430
|
-
|
|
431
|
-
cases_str = "\n # - ".join(edge_cases)
|
|
432
|
-
|
|
433
|
-
template = f"""
|
|
434
|
-
def {test_name}():
|
|
435
|
-
'''Test edge cases for {element.name}'''
|
|
436
|
-
# Edge cases to test:
|
|
437
|
-
# - {cases_str}
|
|
438
|
-
|
|
439
|
-
# Test case 1: {edge_cases[0]}
|
|
440
|
-
# TODO: Implement test
|
|
441
|
-
|
|
442
|
-
# Test case 2: {edge_cases[1] if len(edge_cases) > 1 else "Add more"}
|
|
443
|
-
# TODO: Implement test
|
|
444
|
-
"""
|
|
445
|
-
return template.strip()
|
|
446
|
-
|
|
447
|
-
def _generate_error_template(self, element: CodeElement) -> str:
|
|
448
|
-
"""Generate error handling test template"""
|
|
449
|
-
func_name = element.name.split(".")[-1]
|
|
450
|
-
test_name = f"test_{func_name}_error_handling"
|
|
451
|
-
|
|
452
|
-
template = f"""
|
|
453
|
-
def {test_name}():
|
|
454
|
-
'''Test error handling for {element.name}'''
|
|
455
|
-
# Test invalid input
|
|
456
|
-
with pytest.raises(ValueError):
|
|
457
|
-
{element.name}(invalid_input)
|
|
458
|
-
|
|
459
|
-
# Test None input
|
|
460
|
-
with pytest.raises(TypeError):
|
|
461
|
-
{element.name}(None)
|
|
462
|
-
|
|
463
|
-
# TODO: Add more error cases
|
|
464
|
-
"""
|
|
465
|
-
return template.strip()
|
|
466
|
-
|
|
467
|
-
def _generate_parameter_template(self, element: CodeElement) -> str:
|
|
468
|
-
"""Generate parameter validation test template"""
|
|
469
|
-
func_name = element.name.split(".")[-1]
|
|
470
|
-
test_name = f"test_{func_name}_parameters"
|
|
471
|
-
|
|
472
|
-
params_str = ", ".join(p for p in element.parameters if p not in ["self", "cls"])
|
|
473
|
-
|
|
474
|
-
template = f"""
|
|
475
|
-
@pytest.mark.parametrize("{params_str}", [
|
|
476
|
-
# Add test cases here
|
|
477
|
-
# Example: (value1, value2, expected_result)
|
|
478
|
-
])
|
|
479
|
-
def {test_name}({params_str}):
|
|
480
|
-
'''Test {element.name} with various parameter combinations'''
|
|
481
|
-
result = {element.name}({params_str})
|
|
482
|
-
# TODO: Add assertions
|
|
483
|
-
"""
|
|
484
|
-
return template.strip()
|
|
485
|
-
|
|
486
|
-
def generate_summary(self, suggestions: list[TestSuggestion]) -> str:
|
|
487
|
-
"""Generate human-readable suggestions summary"""
|
|
488
|
-
if not suggestions:
|
|
489
|
-
return "No test suggestions - coverage looks good!"
|
|
490
|
-
|
|
491
|
-
summary = []
|
|
492
|
-
summary.append("=" * 60)
|
|
493
|
-
summary.append("TEST SUGGESTIONS")
|
|
494
|
-
summary.append("=" * 60)
|
|
495
|
-
|
|
496
|
-
# Group by priority
|
|
497
|
-
by_priority: dict[TestPriority, list[TestSuggestion]] = {
|
|
498
|
-
TestPriority.CRITICAL: [],
|
|
499
|
-
TestPriority.HIGH: [],
|
|
500
|
-
TestPriority.MEDIUM: [],
|
|
501
|
-
TestPriority.LOW: [],
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
for suggestion in suggestions:
|
|
505
|
-
by_priority[suggestion.priority].append(suggestion)
|
|
506
|
-
|
|
507
|
-
# Display by priority
|
|
508
|
-
for priority in [TestPriority.CRITICAL, TestPriority.HIGH, TestPriority.MEDIUM]:
|
|
509
|
-
suggestions_list = by_priority[priority]
|
|
510
|
-
if not suggestions_list:
|
|
511
|
-
continue
|
|
512
|
-
|
|
513
|
-
icon = {"critical": "🔴", "high": "🟡", "medium": "🔵"}
|
|
514
|
-
summary.append(f"\n{icon[priority.value]} {priority.value.upper()} Priority:")
|
|
515
|
-
|
|
516
|
-
for i, sug in enumerate(suggestions_list[:5], 1):
|
|
517
|
-
summary.append(f"\n{i}. {sug.suggestion}")
|
|
518
|
-
summary.append(f" File: {sug.target_file}:{sug.target_line}")
|
|
519
|
-
summary.append(f" Type: {sug.test_type}")
|
|
520
|
-
summary.append(f" Impact: +{sug.estimated_impact:.1f}% coverage")
|
|
521
|
-
summary.append(f" Reason: {sug.reasoning}")
|
|
522
|
-
|
|
523
|
-
if len(suggestions_list) > 5:
|
|
524
|
-
summary.append(f"\n ... and {len(suggestions_list) - 5} more")
|
|
525
|
-
|
|
526
|
-
summary.append("\n" + "=" * 60)
|
|
527
|
-
summary.append(f"Total Suggestions: {len(suggestions)}")
|
|
528
|
-
summary.append(f" Critical: {len(by_priority[TestPriority.CRITICAL])}")
|
|
529
|
-
summary.append(f" High: {len(by_priority[TestPriority.HIGH])}")
|
|
530
|
-
summary.append(f" Medium: {len(by_priority[TestPriority.MEDIUM])}")
|
|
531
|
-
summary.append("=" * 60)
|
|
532
|
-
|
|
533
|
-
return "\n".join(summary)
|