""" Unit tests for the classes under github.py. These tests ensure the functionality of GitHub issue management, issue chunking, and issue comments, including happy-path scenarios. Dependencies: pip install pytest pip install pytest-mock """ from unittest.mock import MagicMock, patch import pytest import requests from sage.github import ( GitHubIssue, GitHubIssueComment, GitHubIssuesChunker, GitHubIssuesManager, IssueChunk, ) class TestGitHubIssuesManager: @pytest.fixture(autouse=True) def setup_method(self): """Fixture to create a GitHubIssuesManager instance for each test.""" self.github_manager = GitHubIssuesManager(repo_id="random/random-repo", access_token="fake_token") @staticmethod def mock_issue_response(): """A mock response for GitHub issues.""" return MagicMock( json=lambda: [ { "url": "https://api.github.com/repos/random/random-repo/issues/1", "html_url": "https://github.com/random/random-repo/issues/1", "title": "Found a bug", "body": "I'm having a problem with this.", "comments_url": "https://api.github.com/repos/random/random-repo/issues/1/comments", "comments": 2, } ] ) @staticmethod def mock_comment_response(): """Create a mock response for GitHub issue comments.""" return MagicMock( json=lambda: [ { "url": "https://api.github.com/repos/random/random-repo/issues/comments/1", "html_url": "https://github.com/random/random-repo/issues/comments/1", "body": "This is a comment.", } ] ) @patch("github.requests.get") def test_download_issues(self, mock_get): """Test the download of issues from GitHub.""" mock_get.side_effect = [self.mock_issue_response(), self.mock_comment_response()] self.github_manager.download() assert len(self.github_manager.issues) == 1 assert self.github_manager.issues[0].title == "Found a bug" assert self.github_manager.issues[0].body == "I'm having a problem with this." assert self.github_manager.issues[0].url == "https://api.github.com/repos/random/random-repo/issues/1" @patch("github.requests.get") def test_walk_issues(self, mock_get): """Test the walking through downloaded issues.""" self.github_manager.issues = [ GitHubIssue(url="issue_url", html_url="html_issue_url", title="Test Issue", body="Test Body", comments=[]), GitHubIssue( url="issue_url_2", html_url="html_issue_url_2", title="Another Test Issue", body="Another Test Body", comments=[], ), ] issues = list(self.github_manager.walk()) assert len(issues) == 2 assert issues[0][0].title == "Test Issue" assert issues[1][0].title == "Another Test Issue" @patch("github.requests.get") def test_get_page_of_issues(self, mock_get): """Test fetching a page of issues.""" mock_response = MagicMock() mock_response.json.return_value = [ { "url": "https://api.github.com/repos/random/random-repo/issues/1", "html_url": "https://github.com/random/random-repo/issues/1", "title": "Found a bug", "body": "I'm having a problem with this.", "comments_url": "https://api.github.com/repos/random/random-repo/issues/1/comments", "comments": 2, } ] mock_get.return_value = mock_response issues = self.github_manager._get_page_of_issues( "https://api.github.com/repos/random/random-repo/issues?page=1" ).json() assert len(issues) == 1 @patch("github.requests.get") def test_get_comments(self, mock_get): """Test retrieving comments for an issue.""" mock_get.return_value.json.return_value = self.mock_comment_response().json() comments = self.github_manager._get_comments("comments_url") assert len(comments) == 1 assert comments[0].body == "This is a comment." def test_chunker(self): """Test chunking of an issue into smaller parts.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="This is a long body of the issue that needs to be chunked.", comments=[ GitHubIssueComment(url="comment_url_1", html_url="html_comment_url_1", body="First comment."), GitHubIssueComment(url="comment_url_2", html_url="html_comment_url_2", body="Second comment."), ], ) chunker = GitHubIssuesChunker(max_tokens=50) chunks = chunker.chunk(content=issue, metadata={}) assert len(chunks) > 0 assert all(isinstance(chunk, IssueChunk) for chunk in chunks) assert chunks[0].issue.title == "Test Issue" assert chunks[0].start_comment == 0 class TestGitHubIssueComment: def test_initialization(self): """Test the initialization of the GitHubIssueComment class.""" comment = GitHubIssueComment(url="comment_url", html_url="html_comment_url", body="Sample comment") assert comment.url == "comment_url" assert comment.html_url == "html_comment_url" assert comment.body == "Sample comment" def test_pretty_property(self): """Test the pretty property of the GitHubIssueComment class.""" comment = GitHubIssueComment(url="comment_url", html_url="html_comment_url", body="Sample comment") assert comment.pretty == "## Comment: Sample comment" class TestGitHubIssue: def test_initialization(self): """Test the initialization of the GitHubIssue class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="Test Body", comments=[] ) assert issue.url == "issue_url" assert issue.html_url == "html_issue_url" assert issue.title == "Test Issue" assert issue.body == "Test Body" assert issue.comments == [] def test_pretty_property(self): """Test the pretty property of the GitHubIssue class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="Test Body", comments=[] ) assert issue.pretty == "# Issue: Test Issue\nTest Body" class TestIssueChunk: def test_initialization(self): """Test the initialization of the IssueChunk class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="Test Body", comments=[] ) chunk = IssueChunk(issue=issue, start_comment=0, end_comment=1) assert chunk.issue == issue assert chunk.start_comment == 0 assert chunk.end_comment == 1 def test_content_property(self): """Test the content property of the IssueChunk class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="Test Body", comments=[] ) chunk = IssueChunk(issue=issue, start_comment=0, end_comment=1) assert chunk.content == "# Issue: Test Issue\nTest Body\n\n" def test_metadata_property(self): """Test the metadata property of the IssueChunk class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="Test Body", comments=[] ) chunk = IssueChunk(issue=issue, start_comment=0, end_comment=1) expected_metadata = { "id": "html_issue_url_0_1", "url": "html_issue_url", "start_comment": 0, "end_comment": 1, "text": "# Issue: Test Issue\nTest Body\n\n", } assert chunk.metadata == expected_metadata def test_num_tokens_property(self): """Test the num_tokens property of the IssueChunk class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="This is a test body.", comments=[] ) chunk = IssueChunk(issue=issue, start_comment=0, end_comment=1) assert chunk.num_tokens == 12 class TestGitHubIssuesChunker: def test_initialization(self): """Test the initialization of the GitHubIssuesChunker class.""" chunker = GitHubIssuesChunker(max_tokens=50) assert chunker.max_tokens == 50 def test_chunk_method(self): """Test the chunk method of the GitHubIssuesChunker class.""" issue = GitHubIssue( url="issue_url", html_url="html_issue_url", title="Test Issue", body="This is a long body of the issue that needs to be chunked.", comments=[], ) chunker = GitHubIssuesChunker(max_tokens=50) chunks = chunker.chunk(content=issue, metadata={}) assert len(chunks) > 0 assert all(isinstance(chunk, IssueChunk) for chunk in chunks) if __name__ == "__main__": pytest.main()