diff --git a/codedog/chains/pr_summary/base.py b/codedog/chains/pr_summary/base.py index edef023..e17d0c4 100644 --- a/codedog/chains/pr_summary/base.py +++ b/codedog/chains/pr_summary/base.py @@ -50,6 +50,14 @@ class PRSummaryChain(Chain): @property def _chain_type(self) -> str: + """ + Returns the chain type identifier. + + This method returns a constant string that identifies the chain as a pull request summary chain. + + Returns: + str: The identifier "pull_request_summary_chain". + """ return "pull_request_summary_chain" @property diff --git a/codedog/utils/langchain_utils.py b/codedog/utils/langchain_utils.py index 5954b3c..375d9d7 100644 --- a/codedog/utils/langchain_utils.py +++ b/codedog/utils/langchain_utils.py @@ -28,7 +28,15 @@ def load_gpt_llm() -> BaseChatModel: @lru_cache(maxsize=1) def load_gpt4_llm(): - """Load GPT 4 Model. Make sure your key have access to GPT 4 API. call this function won't check it.""" + """ + Load and return a GPT-4 language model instance. + + This function creates a GPT-4 model based on the environment configuration. If the + 'AZURE_OPENAI' variable is set, it initializes an AzureChatOpenAI instance configured + with Azure-specific parameters; otherwise, it creates a ChatOpenAI instance using the + OpenAI API. Note that the function does not verify if the provided API key has access + to GPT-4. + """ if env.get("AZURE_OPENAI"): llm = AzureChatOpenAI( openai_api_type="azure", diff --git a/tests/conftest.py b/tests/conftest.py index 1ba0915..28d2377 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,20 @@ @pytest.fixture def mock_pull_request(): - """Create a mock PullRequest object for testing.""" + """ + Creates and returns a mock Pull Request object for testing. + + This fixture creates a MagicMock instance configured with preset attributes: + - pull_request_id: 123 + - repository_id: 456 + - pull_request_number: 42 + - title: "Test PR" + - body: "PR description" + - url: "https://github.com/test/repo/pull/42" + - repository_name: "test/repo" + + The object's json method is set to return an empty JSON object string ("{}"). + """ mock_pr = MagicMock() mock_pr.pull_request_id = 123 mock_pr.repository_id = 456 @@ -17,7 +30,13 @@ def mock_pull_request(): @pytest.fixture def mock_llm(): - """Create a mock LLM for testing.""" + """ + Create a mock language model for unit testing. + + Returns a MagicMock instance with a stubbed invoke method that always returns a + dictionary containing a test response. This fixture simulates a language model + for testing purposes. + """ mock = MagicMock() mock.invoke.return_value = {"text": "Test response"} return mock \ No newline at end of file diff --git a/tests/integration/test_end_to_end.py b/tests/integration/test_end_to_end.py index ebd33f0..49db3a8 100644 --- a/tests/integration/test_end_to_end.py +++ b/tests/integration/test_end_to_end.py @@ -12,6 +12,15 @@ class TestEndToEndFlow(unittest.TestCase): @patch('langchain_openai.chat_models.ChatOpenAI') def test_github_to_report_flow(self, mock_chat_openai, mock_github): # Setup mocks + """ + Test the GitHub pull request flow for generating a report. + + This test simulates the end-to-end process of handling a GitHub pull request by creating mock + repository and pull request objects, configuring mocked language models, and patching the summary + and review chain factories. It verifies that the pull request is correctly summarized and reviewed, + and that the reporter compiles the report as expected. The test also asserts that the chain + factories and their respective chain calls are invoked exactly once. + """ mock_github_client = MagicMock() mock_github.return_value = mock_github_client diff --git a/tests/unit/chains/test_pr_summary_chain.py b/tests/unit/chains/test_pr_summary_chain.py index 78f455d..e9ca379 100644 --- a/tests/unit/chains/test_pr_summary_chain.py +++ b/tests/unit/chains/test_pr_summary_chain.py @@ -9,6 +9,13 @@ class TestPRSummaryChain(unittest.TestCase): def setUp(self): # Mock LLM + """ + Set up test fixtures for PRSummaryChain tests. + + Initializes mocks for the language model and chain dependencies, creates a real output + parser, and instantiates a PRSummaryChain object. Also configures a mock pull request and + patches the processor to return predefined file changes and summary materials for testing. + """ self.mock_llm = MagicMock(spec=BaseLanguageModel) # Mock chains @@ -35,6 +42,13 @@ def setUp(self): # Create a real parser instead of a MagicMock class TestParser(BaseOutputParser): def parse(self, text): + """ + Parses input text to produce a default pull request summary. + + This stub implementation ignores the input text and always returns a PRSummary + with preset values for testing. The summary has an overview of "Parser result", + a pull request type set to feature, and major files containing "src/main.py". + """ return PRSummary( overview="Parser result", pr_type=PRType.feature, @@ -42,6 +56,11 @@ def parse(self, text): ) def get_format_instructions(self): + """ + Return the format instructions. + + This method returns a static string outlining the expected format for outputs. + """ return "Format instructions" # Create chain with a real parser @@ -78,6 +97,11 @@ def test_process_code_summary_inputs(self): def test_call(self): # Mock run manager + """ + Tests the _call method of PRSummaryChain. + + Mocks a run manager and verifies that the code summary chain and PR summary chain are each invoked exactly once when calling _call with a mock pull request. The test also asserts that the returned dictionary contains 'pr_summary' and 'code_summaries' keys, with the latter holding exactly one code summary. + """ mock_run_manager = MagicMock() mock_run_manager.get_child.return_value = MagicMock() @@ -105,9 +129,26 @@ def test_output_parser_failure(self, mock_translate_chain): # Create a failing parser class FailingParser(BaseOutputParser): def parse(self, text): + """ + Parses the input text. + + This stub implementation always raises a ValueError to indicate that parsing has failed. + + Args: + text: The input text to be parsed. + + Raises: + ValueError: Always raised to signal a parsing error. + """ raise ValueError("Parsing error") def get_format_instructions(self): + """ + Return the format instructions. + + Returns: + str: A static string indicating the format instructions. + """ return "Format instructions" # Create a parser instance diff --git a/tests/unit/processors/test_pull_request_processor.py b/tests/unit/processors/test_pull_request_processor.py index e39dc4f..778a44b 100644 --- a/tests/unit/processors/test_pull_request_processor.py +++ b/tests/unit/processors/test_pull_request_processor.py @@ -64,6 +64,10 @@ def test_get_diff_code_files(self): self.assertEqual(files[0].full_name, "src/main.py") def test_build_change_summaries(self): + """Test conversion of inputs and outputs to ChangeSummary objects. + + Verifies that build_change_summaries returns a single ChangeSummary with the expected file name and summary text. + """ inputs = [ {"name": "src/main.py", "language": "python", "content": "diff content"} ] diff --git a/tests/unit/retrievers/test_github_retriever.py b/tests/unit/retrievers/test_github_retriever.py index c70bf7b..0e6c54e 100644 --- a/tests/unit/retrievers/test_github_retriever.py +++ b/tests/unit/retrievers/test_github_retriever.py @@ -9,6 +9,14 @@ class TestGithubRetriever(unittest.TestCase): def setUp(self): # Mock Github client and related objects + """ + Initializes test fixtures for GithubRetriever. + + Sets up mock objects for the GitHub client, repository, and pull request, including + simulated commit, file, and issue data. These fixtures are used to instantiate a + GithubRetriever and support various test scenarios such as verifying retriever type, + parsing issue numbers, handling errors, and processing changed files. + """ self.mock_github = MagicMock(spec=Github) self.mock_repo = MagicMock(spec=GHRepo) self.mock_pr = MagicMock(spec=GHPullRequest) @@ -146,6 +154,12 @@ def test_error_handling(self): def test_empty_pr(self): # Test PR with no files + """ + Test that retrieving changed files returns an empty list for a pull request with no files. + + Sets the internal _changed_files list to empty and confirms that the changed_files + property reflects this state by returning an empty list. + """ self.retriever._changed_files = [] # Verify files list is empty diff --git a/tests/unit/utils/test_langchain_utils.py b/tests/unit/utils/test_langchain_utils.py index bdc64bc..b12e651 100644 --- a/tests/unit/utils/test_langchain_utils.py +++ b/tests/unit/utils/test_langchain_utils.py @@ -12,7 +12,12 @@ @unittest.skipUnless(HAS_OPENAI, "OpenAI not available") class TestLangchainUtils(unittest.TestCase): def test_module_imports(self): - """Simple test to verify imports work""" + """ + Test that the langchain_utils module is importable and exposes required functions. + + This test imports the langchain_utils module from the codedog.utils package and asserts the + presence of both the load_gpt_llm and load_gpt4_llm functions to confirm the expected API. + """ # This is a basic test to check that our module exists and can be imported from codedog.utils import langchain_utils self.assertTrue(hasattr(langchain_utils, 'load_gpt_llm')) @@ -20,7 +25,12 @@ def test_module_imports(self): @patch('codedog.utils.langchain_utils.env') def test_load_gpt_llm_functions(self, mock_env): - """Test that the load functions access environment variables""" + """ + Verify that importing load_gpt_llm does not trigger any environment variable access. + + This test imports load_gpt_llm and asserts that no calls are made to env.get, ensuring + that environment variables are not accessed as a side effect of the import. + """ from codedog.utils.langchain_utils import load_gpt_llm # Mock the env.get calls