diff --git a/app/tests/test_message_generator.py b/app/tests/test_message_generator.py new file mode 100644 index 0000000..85d0a8c --- /dev/null +++ b/app/tests/test_message_generator.py @@ -0,0 +1,133 @@ +"""Tests for message_generator.py.""" +from unittest.mock import MagicMock, patch + +import pytest + +from git_commit_generator.message_generator import MessageGenerator + + +class TestMessageGenerator: + """Test cases for MessageGenerator.""" + + @pytest.fixture + def message_generator(self): + """Create a MessageGenerator instance with mocked dependencies.""" + with patch("git_commit_generator.message_generator.get_config") as mock_config: + with patch("git_commit_generator.message_generator.get_ollama_client") as mock_ollama: + config = MagicMock() + config.ollama_host = "http://localhost:11434" + config.ollama_model = "llama3" + config.read_prompt.return_value = "Generate a commit message." + mock_config.return_value = config + + ollama_client = MagicMock() + ollama_client.generate_commit_message.return_value = "feat(core): test feature" + mock_ollama.return_value = ollama_client + + with patch("git_commit_generator.message_generator.get_git_utils") as mock_git: + git_utils = MagicMock() + git_utils.get_all_changes.return_value = "diff content" + mock_git.return_value = git_utils + + generator = MessageGenerator( + config=config, + ollama_client=ollama_client, + ) + generator.git_utils = git_utils + yield generator + + def test_detect_change_type_feature(self, message_generator): + """Test change type detection for features.""" + diff = "+def new_function():\n return 'hello'" + result = message_generator.detect_change_type(diff) + assert result == "feat" + + def test_detect_change_type_fix(self, message_generator): + """Test change type detection for fixes.""" + diff = "-def old_function():\n bug fix" + result = message_generator.detect_change_type(diff) + assert result == "fix" + + def test_detect_change_type_test(self, message_generator): + """Test change type detection for tests.""" + diff = "+def test_function():\n assert True" + result = message_generator.detect_change_type(diff) + assert result == "test" + + def test_detect_change_type_docs(self, message_generator): + """Test change type detection for documentation.""" + diff = "update readme documentation" + result = message_generator.detect_change_type(diff) + assert result == "docs" + + def test_detect_scope_files(self, message_generator): + """Test scope detection from file paths.""" + files = ["api/main.py", "api/routes.py"] + result = message_generator.detect_scope(files) + assert result == "api" + + def test_detect_scope_root_files(self, message_generator): + """Test scope detection for root files.""" + files = ["main.py", "config.py"] + result = message_generator.detect_scope(files) + assert result == "core" + + def test_parse_conventional_message_full(self, message_generator): + """Test parsing a full conventional commit message.""" + message = "feat(auth): add login functionality" + result = message_generator.parse_conventional_message(message) + assert result["type"] == "feat" + assert result["scope"] == "auth" + assert result["description"] == "add login functionality" + assert result["full_message"] == message + + def test_parse_conventional_message_no_scope(self, message_generator): + """Test parsing a conventional message without scope.""" + message = "fix: resolve memory leak" + result = message_generator.parse_conventional_message(message) + assert result["type"] == "fix" + assert result["scope"] == "" + assert result["description"] == "resolve memory leak" + + def test_format_conventional_message_with_scope(self, message_generator): + """Test formatting a message with scope.""" + message = message_generator.format_conventional_message( + message_type="feat", + scope="api", + description="add new endpoint" + ) + assert message == "feat(api): add new endpoint" + + def test_format_conventional_message_no_scope(self, message_generator): + """Test formatting a message without scope.""" + message = message_generator.format_conventional_message( + message_type="fix", + scope="", + description="fix bug" + ) + assert message == "fix: fix bug" + + def test_clean_message_removes_quotes(self, message_generator): + """Test that clean_message removes surrounding quotes.""" + message = '"feat(core): test message"' + result = message_generator._clean_message(message) + assert result == "feat(core): test message" + + def test_clean_message_strips_whitespace(self, message_generator): + """Test that clean_message strips whitespace.""" + message = " feat(core): test message \n" + result = message_generator._clean_message(message) + assert result == "feat(core): test message" + + def test_generate_success(self, message_generator): + """Test successful message generation.""" + with patch.object(message_generator, 'ollama_client') as mock_client: + mock_client.generate_commit_message.return_value = "feat(core): test" + result = message_generator.generate() + assert result == "feat(core): test" + + def test_generate_no_changes_raises_error(self, message_generator): + """Test that generate raises error when no changes.""" + message_generator.git_utils.get_all_changes.return_value = "" + with pytest.raises(ValueError, match="No changes detected"): + message_generator.generate()