Automated issue wrap-up including: - Implementation completion verification - Test execution and validation - Cost tracking and note generation - Repository state commit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
168 lines
6.1 KiB
Python
168 lines
6.1 KiB
Python
"""
|
|
Test for Issue Wrap-up Bug Fix
|
|
|
|
This test reproduces and validates the fix for the bug where
|
|
IssueWrapUpService._review_requirements() incorrectly calls .get()
|
|
on IssueActivity dataclass objects instead of using attribute access.
|
|
|
|
Bug: 'IssueActivity' object has no attribute 'get'
|
|
Location: markitect/issues/issue_wrapup_commands.py lines 135-136
|
|
"""
|
|
|
|
import pytest
|
|
import tempfile
|
|
from pathlib import Path
|
|
from datetime import date
|
|
|
|
from markitect.issues.issue_wrapup_commands import IssueWrapUpService
|
|
from markitect.issues.activity_tracker import IssueActivityTracker, ActivityType
|
|
from markitect.finance.models import FinanceModels
|
|
|
|
|
|
class TestIssueWrapUpBugFix:
|
|
"""Test suite for issue wrap-up bug fix."""
|
|
|
|
@pytest.fixture
|
|
def temp_db(self):
|
|
"""Create temporary database for testing."""
|
|
with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as f:
|
|
db_path = f.name
|
|
|
|
# Initialize schema
|
|
finance_models = FinanceModels(db_path)
|
|
finance_models.initialize_finance_schema()
|
|
|
|
yield db_path
|
|
|
|
# Cleanup
|
|
Path(db_path).unlink(missing_ok=True)
|
|
|
|
@pytest.fixture
|
|
def issue_wrapup_service(self, temp_db):
|
|
"""Create IssueWrapUpService instance for testing."""
|
|
return IssueWrapUpService(temp_db)
|
|
|
|
@pytest.fixture
|
|
def sample_issue_activities(self, temp_db):
|
|
"""Create sample issue activities that trigger the bug."""
|
|
activity_tracker = IssueActivityTracker(temp_db)
|
|
|
|
# Create activities that will be processed by _review_requirements
|
|
activity_ids = []
|
|
|
|
# Activity with implementation-related content
|
|
activity_ids.append(activity_tracker.log_activity(
|
|
issue_id=114,
|
|
activity_type=ActivityType.CREATED,
|
|
activity_date=date(2025, 10, 5),
|
|
activity_details="Implementing cost allocation engine"
|
|
))
|
|
|
|
# Activity with code-related content
|
|
activity_ids.append(activity_tracker.log_activity(
|
|
issue_id=114,
|
|
activity_type=ActivityType.MODIFIED,
|
|
activity_date=date(2025, 10, 6),
|
|
activity_details="Added code for transaction handling"
|
|
))
|
|
|
|
return activity_ids
|
|
|
|
def test_reproduce_issueactivity_get_attribute_error(self, issue_wrapup_service, sample_issue_activities):
|
|
"""
|
|
Test that reproduces the 'IssueActivity' object has no attribute 'get' error.
|
|
|
|
This test should fail with the original buggy code and pass after the fix.
|
|
"""
|
|
# This should trigger the bug in the original code where it calls:
|
|
# activity.get('activity_type', '') and activity.get('description', '')
|
|
# on IssueActivity dataclass objects instead of using proper attribute access
|
|
|
|
try:
|
|
# Call the method that contains the bug
|
|
result = issue_wrapup_service._review_requirements(
|
|
issue_number=114,
|
|
issue_details={'number': 114, 'title': 'Test Issue'},
|
|
force=False
|
|
)
|
|
|
|
# If we get here without an AttributeError, the bug is fixed
|
|
assert isinstance(result, dict)
|
|
assert 'success' in result
|
|
assert 'activities_count' in result
|
|
assert 'has_implementation_activity' in result
|
|
|
|
# The logic should find implementation activities
|
|
assert result['activities_count'] == 2
|
|
assert result['has_implementation_activity'] is True # Should find 'implement' and 'code'
|
|
assert result['success'] is True
|
|
|
|
except AttributeError as e:
|
|
if "'IssueActivity' object has no attribute 'get'" in str(e):
|
|
pytest.fail(f"Bug reproduced: {e}")
|
|
else:
|
|
# Different AttributeError, re-raise
|
|
raise
|
|
|
|
def test_review_requirements_with_no_activities(self, issue_wrapup_service):
|
|
"""Test _review_requirements when no activities exist."""
|
|
result = issue_wrapup_service._review_requirements(
|
|
issue_number=999, # Non-existent issue
|
|
issue_details={'number': 999, 'title': 'Non-existent Issue'},
|
|
force=False
|
|
)
|
|
|
|
assert result['success'] is False
|
|
assert result['activities_count'] == 0
|
|
assert result['has_implementation_activity'] is False
|
|
|
|
def test_review_requirements_with_force_flag(self, issue_wrapup_service):
|
|
"""Test _review_requirements with force flag bypasses checks."""
|
|
result = issue_wrapup_service._review_requirements(
|
|
issue_number=999, # Non-existent issue
|
|
issue_details={'number': 999, 'title': 'Non-existent Issue'},
|
|
force=True
|
|
)
|
|
|
|
assert result['success'] is True
|
|
assert result['forced'] is True
|
|
|
|
def test_activity_content_detection(self, issue_wrapup_service, temp_db):
|
|
"""Test that the fixed code correctly detects implementation activities."""
|
|
# Create activities with different content types
|
|
activity_tracker = IssueActivityTracker(temp_db)
|
|
|
|
# Create activity with 'implement' in description
|
|
activity_tracker.log_activity(
|
|
issue_id=115,
|
|
activity_type=ActivityType.CREATED,
|
|
activity_details="Need to implement the feature"
|
|
)
|
|
|
|
# Create activity with 'code' in description
|
|
activity_tracker.log_activity(
|
|
issue_id=115,
|
|
activity_type=ActivityType.MODIFIED,
|
|
activity_details="Updated code for better performance"
|
|
)
|
|
|
|
# Create activity with neither keyword
|
|
activity_tracker.log_activity(
|
|
issue_id=115,
|
|
activity_type=ActivityType.COMMENTED,
|
|
activity_details="Just a regular comment"
|
|
)
|
|
|
|
result = issue_wrapup_service._review_requirements(
|
|
issue_number=115,
|
|
issue_details={'number': 115, 'title': 'Test Issue'},
|
|
force=False
|
|
)
|
|
|
|
assert result['activities_count'] == 3
|
|
assert result['has_implementation_activity'] is True # Should find 'implement' and 'code'
|
|
assert result['success'] is True
|
|
|
|
|
|
if __name__ == '__main__':
|
|
pytest.main([__file__]) |