Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions codedog/chains/pr_summary/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion codedog/utils/langchain_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
23 changes: 21 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
9 changes: 9 additions & 0 deletions tests/integration/test_end_to_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
41 changes: 41 additions & 0 deletions tests/unit/chains/test_pr_summary_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,13 +42,25 @@ 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,
major_files=["src/main.py"]
)

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
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/unit/processors/test_pull_request_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
]
Expand Down
14 changes: 14 additions & 0 deletions tests/unit/retrievers/test_github_retriever.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions tests/unit/utils/test_langchain_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@
@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'))
self.assertTrue(hasattr(langchain_utils, 'load_gpt4_llm'))

@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
Expand Down
Loading