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:
2025-09-24 00:04:54 +02:00
parent ef81266eb1
commit 0053fa68ec
8 changed files with 134 additions and 55 deletions

View File

@@ -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'