""" Tests for IssueWriter functionality. """ import json import subprocess import pytest 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.""" 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(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.""" config = self._get_test_config() with patch.dict('os.environ', {}, clear=True): writer = IssueWriter(config=config, auth_token=None) with pytest.raises(IssueError, match="Authentication token required"): writer.update_issue(1, {'title': 'New Title'}) @patch('tddai.issue_writer.subprocess.run') def test_update_issue_success(self, mock_run): """Test successful issue update via PATCH.""" # Mock successful response mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({ 'number': 1, 'title': 'Updated Title', 'body': 'Updated body', 'state': 'open' }) mock_result.stderr = '' mock_run.return_value = mock_result 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 assert result['title'] == 'Updated Title' # Verify curl command was called correctly mock_run.assert_called_once() call_args = mock_run.call_args[0][0] assert 'curl' in call_args assert '-X' in call_args assert 'PATCH' in call_args assert 'Authorization: token test-token' in ' '.join(call_args) @patch('tddai.issue_writer.subprocess.run') def test_update_issue_with_error_response(self, mock_run): """Test issue update with API error response.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({'message': 'Issue not found'}) mock_result.stderr = '' mock_run.return_value = mock_result 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'}) @patch('tddai.issue_writer.subprocess.run') def test_update_issue_subprocess_error(self, mock_run): """Test issue update with subprocess error.""" mock_run.side_effect = subprocess.CalledProcessError(1, 'curl') 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'}) @patch('tddai.issue_writer.subprocess.run') def test_update_issue_json_decode_error(self, mock_run): """Test issue update with invalid JSON response.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = "invalid json" mock_result.stderr = '' mock_run.return_value = mock_result 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'}) @patch('tddai.issue_writer.subprocess.run') def test_update_issue_title(self, mock_run): """Test updating only issue title.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({'number': 1, 'title': 'New Title'}) mock_result.stderr = '' mock_run.return_value = mock_result 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' # Verify the correct data was sent call_args = mock_run.call_args[0][0] json_data_index = call_args.index('-d') + 1 sent_data = json.loads(call_args[json_data_index]) assert sent_data == {'title': 'New Title'} @patch('tddai.issue_writer.subprocess.run') def test_update_issue_body(self, mock_run): """Test updating only issue body.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({'number': 1, 'body': 'New body content'}) mock_result.stderr = '' mock_run.return_value = mock_result 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' @patch('tddai.issue_writer.subprocess.run') def test_update_issue_state_valid(self, mock_run): """Test updating issue state with valid state.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({'number': 1, 'state': 'closed'}) mock_result.stderr = '' mock_run.return_value = mock_result 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.""" 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') @patch('tddai.issue_writer.subprocess.run') def test_close_issue(self, mock_run): """Test closing an issue.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({'number': 1, 'state': 'closed'}) mock_result.stderr = '' mock_run.return_value = mock_result config = self._get_test_config() writer = IssueWriter(config=config, auth_token="test-token") result = writer.close_issue(1) assert result['state'] == 'closed' @patch('tddai.issue_writer.subprocess.run') def test_reopen_issue(self, mock_run): """Test reopening an issue.""" mock_result = MagicMock() mock_result.returncode = 0 mock_result.stdout = json.dumps({'number': 1, 'state': 'open'}) mock_result.stderr = '' mock_run.return_value = mock_result config = self._get_test_config() writer = IssueWriter(config=config, auth_token="test-token") result = writer.reopen_issue(1) assert result['state'] == 'open'