refactor: Make tddai framework project-agnostic and fix test configuration
FRAMEWORK DECOUPLING: - Remove all MarkiTect-specific references from tddai core modules - Update tddai-assistant.md to use generic examples and language - Change CLI output from "MarkiTect Issues" to "Project Issues" - Update coverage_analyzer.py docstring to be project-neutral CONFIGURATION SYSTEM: - Make tddai configuration flexible via environment variables - Add comprehensive documentation for project setup in config.py - Create .env.tddai and tddai-setup.sh for MarkiTect-specific config - Support configurable workspace naming (.tddai_workspace default) TEST INFRASTRUCTURE CLEANUP: - Fix IssueWriter test failures caused by config validation changes - Implement _get_test_config() helper for isolated test configurations - Ensure all 13 IssueWriter tests pass with proper test patterns - Maintain clean test separation and project independence FRAMEWORK PORTABILITY: - TDD8 methodology now completely generic and reusable - Configuration examples for GitHub/GitLab integration - Ready for extraction to separate repository when needed - All 45 tests pass cleanly confirming successful refactoring 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,27 +9,40 @@ from unittest.mock import patch, MagicMock
|
||||
|
||||
from tddai.issue_writer import IssueWriter
|
||||
from tddai.exceptions import IssueError
|
||||
from tddai.config import TddaiConfig
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class TestIssueWriter:
|
||||
"""Test suite for IssueWriter class."""
|
||||
|
||||
def _get_test_config(self):
|
||||
"""Get a valid test configuration."""
|
||||
return TddaiConfig(
|
||||
workspace_dir=Path(".test_workspace"),
|
||||
gitea_url="http://localhost:3000",
|
||||
repo_owner="test_owner",
|
||||
repo_name="test_repo"
|
||||
)
|
||||
|
||||
def test_init_with_auth_token(self):
|
||||
"""Test IssueWriter initialization with auth token."""
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
assert writer.auth_token == "test-token"
|
||||
|
||||
def test_init_without_auth_token_uses_env(self):
|
||||
"""Test IssueWriter uses environment variable when no token provided."""
|
||||
config = self._get_test_config()
|
||||
with patch.dict('os.environ', {'GITEA_TOKEN': 'env-token'}):
|
||||
writer = IssueWriter()
|
||||
writer = IssueWriter(config=config)
|
||||
assert writer.auth_token == "env-token"
|
||||
|
||||
def test_update_issue_without_auth_token_raises_error(self):
|
||||
"""Test that updating without auth token raises IssueError."""
|
||||
writer = IssueWriter(auth_token=None)
|
||||
config = self._get_test_config()
|
||||
with patch.dict('os.environ', {}, clear=True):
|
||||
writer = IssueWriter()
|
||||
writer = IssueWriter(config=config, auth_token=None)
|
||||
with pytest.raises(IssueError, match="Authentication token required"):
|
||||
writer.update_issue(1, {'title': 'New Title'})
|
||||
|
||||
@@ -48,7 +61,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
result = writer.update_issue(1, {'title': 'Updated Title'})
|
||||
|
||||
assert result['number'] == 1
|
||||
@@ -71,7 +85,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
with pytest.raises(IssueError, match="Failed to update issue #1: Issue not found"):
|
||||
writer.update_issue(1, {'title': 'New Title'})
|
||||
|
||||
@@ -80,7 +95,8 @@ class TestIssueWriter:
|
||||
"""Test issue update with subprocess error."""
|
||||
mock_run.side_effect = subprocess.CalledProcessError(1, 'curl')
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
with pytest.raises(IssueError, match="Failed to update issue #1"):
|
||||
writer.update_issue(1, {'title': 'New Title'})
|
||||
|
||||
@@ -93,7 +109,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
with pytest.raises(IssueError, match="Failed to parse response data"):
|
||||
writer.update_issue(1, {'title': 'New Title'})
|
||||
|
||||
@@ -106,7 +123,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
result = writer.update_issue_title(1, 'New Title')
|
||||
|
||||
assert result['title'] == 'New Title'
|
||||
@@ -126,7 +144,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
result = writer.update_issue_body(1, 'New body content')
|
||||
|
||||
assert result['body'] == 'New body content'
|
||||
@@ -140,14 +159,16 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
result = writer.update_issue_state(1, 'closed')
|
||||
|
||||
assert result['state'] == 'closed'
|
||||
|
||||
def test_update_issue_state_invalid(self):
|
||||
"""Test updating issue state with invalid state."""
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
with pytest.raises(IssueError, match="Invalid state 'invalid'"):
|
||||
writer.update_issue_state(1, 'invalid')
|
||||
|
||||
@@ -160,7 +181,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
result = writer.close_issue(1)
|
||||
|
||||
assert result['state'] == 'closed'
|
||||
@@ -174,7 +196,8 @@ class TestIssueWriter:
|
||||
mock_result.stderr = ''
|
||||
mock_run.return_value = mock_result
|
||||
|
||||
writer = IssueWriter(auth_token="test-token")
|
||||
config = self._get_test_config()
|
||||
writer = IssueWriter(config=config, auth_token="test-token")
|
||||
result = writer.reopen_issue(1)
|
||||
|
||||
assert result['state'] == 'open'
|
||||
Reference in New Issue
Block a user