import pytest from unittest.mock import MagicMock, patch from pr_agent.git_providers.gitlab_provider import GitLabProvider from gitlab import Gitlab from gitlab.v4.objects import Project, ProjectFile from gitlab.exceptions import GitlabGetError class TestGitLabProvider: """Test suite for GitLab provider functionality.""" @pytest.fixture def mock_gitlab_client(self): client = MagicMock() return client @pytest.fixture def mock_project(self): project = MagicMock() return project @pytest.fixture def gitlab_provider(self, mock_gitlab_client, mock_project): with patch('pr_agent.git_providers.gitlab_provider.gitlab.Gitlab', return_value=mock_gitlab_client), \ patch('pr_agent.git_providers.gitlab_provider.get_settings') as mock_settings: mock_settings.return_value.get.side_effect = lambda key, default=None: { "GITLAB.URL": "https://gitlab.com", "GITLAB.PERSONAL_ACCESS_TOKEN": "fake_token" }.get(key, default) mock_gitlab_client.projects.get.return_value = mock_project provider = GitLabProvider("https://gitlab.com/test/repo/-/merge_requests/1") provider.gl = mock_gitlab_client provider.id_project = "test/repo" return provider def test_get_pr_file_content_success(self, gitlab_provider, mock_project): mock_file = MagicMock(ProjectFile) mock_file.decode.return_value = "# Changelog\n\n## v1.0.0\n- Initial release" mock_project.files.get.return_value = mock_file content = gitlab_provider.get_pr_file_content("CHANGELOG.md", "main") assert content == "# Changelog\n\n## v1.0.0\n- Initial release" mock_project.files.get.assert_called_once_with("CHANGELOG.md", "main") mock_file.decode.assert_called_once() def test_get_pr_file_content_with_bytes(self, gitlab_provider, mock_project): mock_file = MagicMock(ProjectFile) mock_file.decode.return_value = b"# Changelog\n\n## v1.0.0\n- Initial release" mock_project.files.get.return_value = mock_file content = gitlab_provider.get_pr_file_content("CHANGELOG.md", "main") assert content == "# Changelog\n\n## v1.0.0\n- Initial release" mock_project.files.get.assert_called_once_with("CHANGELOG.md", "main") def test_get_pr_file_content_file_not_found(self, gitlab_provider, mock_project): mock_project.files.get.side_effect = GitlabGetError("404 Not Found") content = gitlab_provider.get_pr_file_content("CHANGELOG.md", "main") assert content == "" mock_project.files.get.assert_called_once_with("CHANGELOG.md", "main") def test_get_pr_file_content_other_exception(self, gitlab_provider, mock_project): mock_project.files.get.side_effect = Exception("Network error") content = gitlab_provider.get_pr_file_content("CHANGELOG.md", "main") assert content == "" def test_create_or_update_pr_file_create_new(self, gitlab_provider, mock_project): mock_project.files.get.side_effect = GitlabGetError("404 Not Found") mock_file = MagicMock() mock_project.files.create.return_value = mock_file new_content = "# Changelog\n\n## v1.1.0\n- New feature" commit_message = "Add CHANGELOG.md" gitlab_provider.create_or_update_pr_file( "CHANGELOG.md", "feature-branch", new_content, commit_message ) mock_project.files.get.assert_called_once_with("CHANGELOG.md", "feature-branch") mock_project.files.create.assert_called_once_with({ 'file_path': 'CHANGELOG.md', 'branch': 'feature-branch', 'content': new_content, 'commit_message': commit_message, }) def test_create_or_update_pr_file_update_existing(self, gitlab_provider, mock_project): mock_file = MagicMock(ProjectFile) mock_file.decode.return_value = "# Old changelog content" mock_project.files.get.return_value = mock_file new_content = "# New changelog content" commit_message = "Update CHANGELOG.md" gitlab_provider.create_or_update_pr_file( "CHANGELOG.md", "feature-branch", new_content, commit_message ) mock_project.files.get.assert_called_once_with("CHANGELOG.md", "feature-branch") mock_file.content = new_content mock_file.save.assert_called_once_with(branch="feature-branch", commit_message=commit_message) def test_create_or_update_pr_file_update_exception(self, gitlab_provider, mock_project): mock_project.files.get.side_effect = Exception("Network error") with pytest.raises(Exception): gitlab_provider.create_or_update_pr_file( "CHANGELOG.md", "feature-branch", "content", "message" ) def test_has_create_or_update_pr_file_method(self, gitlab_provider): assert hasattr(gitlab_provider, "create_or_update_pr_file") assert callable(getattr(gitlab_provider, "create_or_update_pr_file")) def test_method_signature_compatibility(self, gitlab_provider): import inspect sig = inspect.signature(gitlab_provider.create_or_update_pr_file) params = list(sig.parameters.keys()) expected_params = ['file_path', 'branch', 'contents', 'message'] assert params == expected_params @pytest.mark.parametrize("content,expected", [ ("simple text", "simple text"), (b"bytes content", "bytes content"), ("", ""), (b"", ""), ("unicode: café", "unicode: café"), (b"unicode: caf\xc3\xa9", "unicode: café"), ]) def test_content_encoding_handling(self, gitlab_provider, mock_project, content, expected): mock_file = MagicMock(ProjectFile) mock_file.decode.return_value = content mock_project.files.get.return_value = mock_file result = gitlab_provider.get_pr_file_content("test.md", "main") assert result == expected