Add tests for GitHub utilities (#438)

Co-authored-by: UltralyticsAssistant <[email protected]>
This commit is contained in:
Glenn Jocher
2025-05-10 17:44:24 +02:00
committed by GitHub
co-authored by UltralyticsAssistant
parent 0479623d9b
commit 9a71915810
6 changed files with 401 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Import CLI command modules
from actions import (
first_interaction,
summarize_pr,
summarize_release,
update_markdown_code_blocks,
)
def test_importable_modules():
"""Test that all modules can be imported without errors."""
# This is a simple test to ensure modules can be imported successfully
assert hasattr(first_interaction, "main")
assert hasattr(summarize_pr, "main")
assert hasattr(summarize_release, "main")
assert hasattr(update_markdown_code_blocks, "main")
+63
View File
@@ -0,0 +1,63 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
from unittest.mock import MagicMock, patch
from actions.utils.common_utils import (
allow_redirect,
brave_search,
clean_url,
remove_html_comments,
)
def test_remove_html_comments():
"""Test removing HTML comments from strings."""
test_str = "Before <!-- Comment --> After"
assert remove_html_comments(test_str) == "Before After"
# Multiline comment
test_str = "Before\n<!-- Comment\nline 2\nline 3 -->\nAfter"
assert remove_html_comments(test_str) == "Before\n\nAfter"
# No comments
test_str = "No comments here"
assert remove_html_comments(test_str) == "No comments here"
def test_clean_url():
"""Test cleaning URL strings."""
# Test removing quotes and trailing characters
assert clean_url('"https://example.com"') == "https://example.com"
assert clean_url("'https://example.com'") == "https://example.com"
assert clean_url("https://example.com.") == "https://example.com"
assert clean_url("https://example.com,") == "https://example.com"
# Test git URLs
assert clean_url("git+https://github.com/user/repo.git@main") == "https://github.com/user/repo"
def test_allow_redirect():
"""Test allowing URL redirects based on rules."""
# Should not allow - start ignores
assert not allow_redirect("https://youtu.be/xyz", "https://youtube.com")
# Should not allow - end ignores
assert not allow_redirect("https://example.com", "https://example.com/404")
# Empty end URL
assert not allow_redirect("https://example.com", "")
@patch("requests.get")
def test_brave_search(mock_get):
"""Test Brave search API integration."""
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"web": {"results": [{"url": "https://example.com"}, {"url": "https://example.org"}]}
}
mock_get.return_value = mock_response
results = brave_search("test query", "test-api-key", count=2)
assert results == ["https://example.com", "https://example.org"]
mock_get.assert_called_once()
+64
View File
@@ -0,0 +1,64 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
from unittest.mock import MagicMock, patch
from actions.utils.github_utils import Action, check_pypi_version, ultralytics_actions_info
def test_action_init():
"""Test Action class initialization with default values."""
with patch.dict("os.environ", {"GITHUB_TOKEN": "test-token", "GITHUB_EVENT_NAME": "push"}):
with patch(
"actions.utils.github_utils.Action._load_event_data",
return_value={"repository": {"full_name": "test/repo"}},
):
action = Action()
assert action.token == "test-token"
assert action.event_name == "push"
assert action.repository == "test/repo"
def test_action_request_methods():
"""Test Action HTTP request methods."""
with patch("requests.get") as mock_get:
mock_response = MagicMock()
mock_response.status_code = 200
mock_get.return_value = mock_response
action = Action(token="test-token")
response = action.get("https://api.github.com/test")
assert response == mock_response
mock_get.assert_called_once()
def test_load_event_data():
"""Test loading event data from file."""
with patch("pathlib.Path.exists", return_value=True):
with patch("pathlib.Path.read_text", return_value='{"test": "data"}'):
action = Action()
data = action._load_event_data("fake_path")
assert data == {"test": "data"}
def test_check_pypi_version():
"""Test check_pypi_version function."""
with patch("tomllib.load", return_value={"project": {"name": "test-package", "version": "1.0.0"}}):
with patch("requests.get") as mock_get:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"info": {"version": "0.9.0"}}
mock_get.return_value = mock_response
local_version, online_version, publish = check_pypi_version()
assert local_version == "1.0.0"
assert online_version == "0.9.0"
assert publish is True
def test_ultralytics_actions_info():
"""Test ultralytics_actions_info function."""
with patch("actions.utils.github_utils.Action.print_info") as mock_print_info:
ultralytics_actions_info()
mock_print_info.assert_called_once()
+84
View File
@@ -0,0 +1,84 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
import importlib
import re
import pytest
from actions import __version__
from actions.utils import (
GITHUB_API_URL,
GITHUB_GRAPHQL_URL,
Action,
allow_redirect,
check_pypi_version,
get_completion,
remove_html_comments,
ultralytics_actions_info,
)
def test_version_format():
"""Test that version follows the expected format."""
version_pattern = re.compile(r"^\d+\.\d+\.\d+$")
assert version_pattern.match(__version__), f"Version {__version__} does not match pattern"
def test_util_module_imports():
"""Test that all utilities can be imported from the utils module."""
# Test the utils module exports
assert GITHUB_API_URL.startswith("https://api.github.com")
assert GITHUB_GRAPHQL_URL.startswith("https://api.github.com/graphql")
# Check that Action class exists and is importable
assert hasattr(Action, "__init__")
assert hasattr(Action, "get")
assert hasattr(Action, "post")
# Check function imports
assert callable(allow_redirect)
assert callable(check_pypi_version)
assert callable(get_completion)
assert callable(remove_html_comments)
assert callable(ultralytics_actions_info)
def test_all_modules_importable():
"""Test that all modules can be imported without errors."""
modules = [
"actions",
"actions.utils",
"actions.utils.common_utils",
"actions.utils.github_utils",
"actions.utils.openai_utils",
"actions.first_interaction",
"actions.summarize_pr",
"actions.summarize_release",
"actions.update_markdown_code_blocks",
"actions.dispatch_actions",
]
for module_name in modules:
module = importlib.import_module(module_name)
assert module is not None, f"Failed to import {module_name}"
def test_cli_entry_points():
"""Test that CLI entry points are defined in pyproject.toml."""
from pathlib import Path
pyproject_path = Path(__file__).parents[1] / "pyproject.toml"
if not pyproject_path.exists():
pytest.skip("pyproject.toml not found")
content = pyproject_path.read_text()
expected_names = [
"ultralytics-actions-first-interaction",
"ultralytics-actions-summarize-pr",
"ultralytics-actions-summarize-release",
"ultralytics-actions-update-markdown-code-blocks",
"ultralytics-actions-info",
]
for name in expected_names:
assert name in content, f"Entry point {name} not found in pyproject.toml"
+65
View File
@@ -0,0 +1,65 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
from unittest.mock import MagicMock, patch
from actions.utils.openai_utils import get_completion, remove_outer_codeblocks
def test_remove_outer_codeblocks():
"""Test removing outer code block markers from strings."""
# Test with python code block
input_str = "```python\ndef test():\n return True\n```"
expected = "def test():\n return True"
assert remove_outer_codeblocks(input_str) == expected
# Test with no language specified
input_str = "```\ndef test():\n return True\n```"
expected = "def test():\n return True"
assert remove_outer_codeblocks(input_str) == expected
# Test with no code blocks
input_str = "def test():\n return True"
assert remove_outer_codeblocks(input_str) == input_str
@patch("requests.post")
def test_get_completion(mock_post):
"""Test OpenAI API completion function with mocked response."""
# Setup mock response
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"choices": [{"message": {"content": "Test response from OpenAI"}}]}
mock_post.return_value = mock_response
# Test with basic messages
messages = [{"role": "system", "content": "You are a helpful assistant"}, {"role": "user", "content": "Hello"}]
# Use a context manager for the environment variable
with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}, clear=False):
with patch("actions.utils.openai_utils.OPENAI_API_KEY", "test-key"):
result = get_completion(messages, check_links=False)
assert result == "Test response from OpenAI"
mock_post.assert_called_once()
@patch("requests.post")
@patch("actions.utils.openai_utils.check_links_in_string")
def test_get_completion_with_link_check(mock_check_links, mock_post):
"""Test get_completion with link checking."""
# Setup mocks
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"choices": [{"message": {"content": "Response with https://example.com link"}}]}
mock_post.return_value = mock_response
mock_check_links.return_value = True
messages = [{"role": "user", "content": "Hello"}]
# Use a context manager for the environment variable
with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}, clear=False):
with patch("actions.utils.openai_utils.OPENAI_API_KEY", "test-key"):
result = get_completion(messages)
assert result == "Response with https://example.com link"
mock_check_links.assert_called_once()
+106
View File
@@ -0,0 +1,106 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
from pathlib import Path
from unittest.mock import mock_open, patch
from actions.update_markdown_code_blocks import (
add_indentation,
extract_code_blocks,
generate_temp_filename,
process_markdown_file,
remove_indentation,
)
def test_extract_code_blocks():
"""Test extracting code blocks from markdown content."""
# Test with Python and Bash code blocks
markdown_content = """
# Test Markdown
```python
def test():
return True
```
And some bash code:
```bash
echo "Hello World"
```
"""
code_blocks = extract_code_blocks(markdown_content)
assert len(code_blocks["python"]) == 1
assert code_blocks["python"][0][1] == "def test():\n return True"
assert len(code_blocks["bash"]) == 1
assert code_blocks["bash"][0][1] == 'echo "Hello World"'
def test_remove_indentation():
"""Test removing indentation from code blocks."""
code_block = " line 1\n line 2\n line 3"
result = remove_indentation(code_block, 4)
assert result == "line 1\nline 2\nline 3"
# Test with mixed indentation
code_block = " line 1\n line 2\n line 3"
result = remove_indentation(code_block, 2)
assert result == " line 1\nline 2\n line 3"
def test_add_indentation():
"""Test adding indentation to code blocks."""
code_block = "line 1\nline 2\nline 3"
result = add_indentation(code_block, 4)
assert result == " line 1\n line 2\n line 3"
# Test with empty lines
code_block = "line 1\n\nline 3"
result = add_indentation(code_block, 2)
assert result == " line 1\n\n line 3"
def test_generate_temp_filename():
"""Test generating temporary filenames."""
file_path = Path("docs/guide.md")
filename = generate_temp_filename(file_path, 0, "python")
assert "guide_docs_p0_" in filename
assert filename.endswith(".py")
filename = generate_temp_filename(file_path, 1, "bash")
assert "guide_docs_b1_" in filename
assert filename.endswith(".sh")
@patch("pathlib.Path.read_text")
@patch("pathlib.Path.write_text")
@patch("builtins.open", new_callable=mock_open)
def test_process_markdown_file(mock_file, mock_write, mock_read_text):
"""Test processing markdown files."""
mock_read_text.return_value = """
# Test
```python
def test():
return True
```
"""
file_path = Path("test.md")
temp_dir = Path("temp")
markdown_content, temp_files = process_markdown_file(file_path, temp_dir)
assert markdown_content is not None
assert len(temp_files) == 1
assert temp_files[0][1] == "def test():\n return True"
mock_file.assert_called_once()