From 6cbb8ca073980343763e734f218b71e2454cd56e Mon Sep 17 00:00:00 2001 From: Harshad Hegde Date: Fri, 9 Feb 2024 17:50:14 -0600 Subject: [PATCH] Explainer tests added --- src/codergpt/__init__.py | 8 +++ src/codergpt/explainer/explainer.py | 10 +--- tests/test_commenter.py | 2 +- tests/test_explainer.py | 76 +++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 tests/test_explainer.py diff --git a/src/codergpt/__init__.py b/src/codergpt/__init__.py index ca8125b..0137f09 100644 --- a/src/codergpt/__init__.py +++ b/src/codergpt/__init__.py @@ -2,8 +2,16 @@ import importlib_metadata +from codergpt.commenter import CodeCommenter +from codergpt.explainer import CodeExplainer + +from .main import CoderGPT + try: __version__ = importlib_metadata.version(__name__) except importlib_metadata.PackageNotFoundError: # package is not installed __version__ = "0.0.0" # pragma: no cover + + +__all__ = ["CoderGPT", "CodeExplainer", "CodeCommenter"] diff --git a/src/codergpt/explainer/explainer.py b/src/codergpt/explainer/explainer.py index ca62544..f43dafd 100644 --- a/src/codergpt/explainer/explainer.py +++ b/src/codergpt/explainer/explainer.py @@ -1,7 +1,6 @@ """Explainer Module.""" -from pathlib import Path -from typing import Any, Dict, Optional, Union +from typing import Any, Dict, Optional from langchain_core.runnables.base import RunnableSerializable @@ -17,7 +16,7 @@ def __init__(self, chain: RunnableSerializable[Dict, Any]): """ self.chain = chain - def explain(self, path: Union[str, Path], function: Optional[str] = None, classname: Optional[str] = None): + def explain(self, code: str, function: Optional[str] = None, classname: Optional[str] = None): """ Explain the contents of the code file by invoking the runnable chain. @@ -26,20 +25,15 @@ def explain(self, path: Union[str, Path], function: Optional[str] = None, classn :param classname: The name of the class to explain. Default is None. """ if function: - code = self.get_code(filename=path, function_name=function) response = self.chain.invoke({"input": f"Explain the following code: \n\n```\n{code}\n```"}) - # Pretty print the response print(f"Explanation for '{function}':\n{response.content}") elif classname: - code = self.get_code(filename=path, class_name=classname) response = self.chain.invoke({"input": f"Explain the following code: \n\n```\n{code}\n```"}) # Pretty print the response print(f"Explanation for '{classname}':\n{response.content}") else: # Explain full code - with open(path, "r") as file: - code = file.read() response = self.chain.invoke({"input": f"Explain the following code: \n\n```\n{code}\n```"}) # Pretty print the response print(f"Explanation for the code:\n{response.content}") diff --git a/tests/test_commenter.py b/tests/test_commenter.py index d29dfa9..5507f13 100644 --- a/tests/test_commenter.py +++ b/tests/test_commenter.py @@ -4,7 +4,7 @@ import unittest from unittest.mock import MagicMock -from codergpt.commenter import CodeCommenter +from codergpt import CodeCommenter from tests.test_constants import TEST_INPUT_DIR diff --git a/tests/test_explainer.py b/tests/test_explainer.py new file mode 100644 index 0000000..45b13b6 --- /dev/null +++ b/tests/test_explainer.py @@ -0,0 +1,76 @@ +"""Test explainer.""" + +import unittest +from unittest.mock import Mock + +from codergpt import CodeExplainer + +sample_code = "def sample_function():\n pass" +sample_function_name = "sample_function" +sample_class_name = "SampleClass" + +mock_response = Mock() +mock_response.content = "This is a mock explanation." + + +class TestExplainer(unittest.TestCase): + """Test Explainer Class.""" + + def setUp(self): + """Set up for creating a mock chain object and CodeExplainer object.""" + self.mock_chain = Mock() + self.mock_response = Mock() + self.mock_response.content = "Mocked explanation content" + self.mock_chain.invoke.return_value = self.mock_response + self.code_explainer = CodeExplainer(chain=self.mock_chain) + + def test_explain_function(self): + """Test case for explaining a function.""" + sample_code = "def example(): pass" # Replace with actual code + sample_function_name = "example" # Replace with actual function name + + # Call the explain method with a sample code snippet and function name + self.code_explainer.explain(code=sample_code, function=sample_function_name) + + # Verify that invoke was called once with the correct parameters + expected_invoke_input = {"input": f"Explain the following code: \n\n```\n{sample_code}\n```"} + self.mock_chain.invoke.assert_called_once_with(expected_invoke_input) + + # Check if the expected explanation message is in the captured output + # This assumes that CodeExplainer prints the explanation to stdout + captured_out = self.mock_chain.invoke.return_value.content + expected_output = f"Explanation for '{sample_function_name}':\n{self.mock_response.content}" + self.assertIn(captured_out, expected_output) + + def test_explain_class(self): + """Test case for explaining a class.""" + sample_code = "class Example: pass" # Replace with actual code + sample_class_name = "Example" # Replace with actual class name + + # Call the explain method with a sample code snippet and class name + self.code_explainer.explain(code=sample_code, classname=sample_class_name) + + # Verify that invoke was called once with the correct parameters + expected_invoke_input = {"input": f"Explain the following code: \n\n```\n{sample_code}\n```"} + self.mock_chain.invoke.assert_called_once_with(expected_invoke_input) + + # Check if the expected explanation message is in the captured output + captured_out = self.mock_chain.invoke.return_value.content + expected_output = f"Explanation for '{sample_class_name}':\n{self.mock_response.content}" + self.assertIn(captured_out, expected_output) + + def test_explain_full_code(self): + """Test case for explaining full code.""" + sample_code = "# Your full code here" # Replace with actual code + + # Call the explain method with a sample code snippet + self.code_explainer.explain(code=sample_code) + + # Verify that invoke was called once with the correct parameters + expected_invoke_input = {"input": f"Explain the following code: \n\n```\n{sample_code}\n```"} + self.mock_chain.invoke.assert_called_once_with(expected_invoke_input) + + # Check if the expected explanation message is in the captured output + captured_out = self.mock_chain.invoke.return_value.content + expected_output = "Explanation for the code:\nMocked explanation content." + self.assertIn(captured_out, expected_output)