Skip to main content
Glama
test_utils.py7.11 kB
"""Tests for src/utils.py.""" from src.bitbucket_client import BitbucketError from src.utils import ( ensure_uuid_braces, first_line, handle_bitbucket_error, not_found_response, sanitize_search_term, truncate_hash, ) class TestEnsureUuidBraces: """Tests for ensure_uuid_braces function.""" def test_adds_braces_when_missing(self): """UUID without braces should get braces added.""" uuid = "12345678-1234-1234-1234-123456789012" result = ensure_uuid_braces(uuid) assert result == "{12345678-1234-1234-1234-123456789012}" def test_preserves_existing_braces(self): """UUID with braces should remain unchanged.""" uuid = "{12345678-1234-1234-1234-123456789012}" result = ensure_uuid_braces(uuid) assert result == "{12345678-1234-1234-1234-123456789012}" def test_handles_empty_string(self): """Empty string should get braces.""" result = ensure_uuid_braces("") assert result == "{}" def test_handles_short_uuid(self): """Short strings should still get braces.""" result = ensure_uuid_braces("abc123") assert result == "{abc123}" class TestTruncateHash: """Tests for truncate_hash function.""" def test_truncates_long_hash(self): """Long hash should be truncated to 12 chars by default.""" hash_str = "abc123def456abc123def456abc123def456" result = truncate_hash(hash_str) assert result == "abc123def456" assert len(result) == 12 def test_preserves_short_hash(self): """Hash shorter than limit should remain unchanged.""" hash_str = "abc123" result = truncate_hash(hash_str) assert result == "abc123" def test_handles_none(self): """None should return empty string.""" result = truncate_hash(None) assert result == "" def test_custom_length(self): """Should respect custom length parameter.""" hash_str = "abc123def456" result = truncate_hash(hash_str, length=7) assert result == "abc123d" class TestFirstLine: """Tests for first_line function.""" def test_extracts_first_line_from_multiline(self): """Should return first line from multiline text.""" text = "First line\nSecond line\nThird line" result = first_line(text) assert result == "First line" def test_returns_single_line_unchanged(self): """Single line text should be returned unchanged.""" text = "Just one line" result = first_line(text) assert result == "Just one line" def test_handles_none(self): """None should return empty string.""" result = first_line(None) assert result == "" def test_handles_empty_string(self): """Empty string should return empty string.""" result = first_line("") assert result == "" def test_handles_only_newlines(self): """Text with only newlines should return empty string.""" text = "\n\n\n" result = first_line(text) assert result == "" class TestHandleBitbucketError: """Tests for handle_bitbucket_error decorator.""" def test_returns_result_on_success(self): """Should return function result when no exception.""" @handle_bitbucket_error def successful_func(): return {"success": True, "data": "test"} result = successful_func() assert result == {"success": True, "data": "test"} def test_catches_bitbucket_error(self): """Should catch BitbucketError and return error dict.""" @handle_bitbucket_error def failing_func(): raise BitbucketError("Something went wrong") result = failing_func() assert result == {"success": False, "error": "Something went wrong"} def test_preserves_function_name(self): """Decorator should preserve wrapped function name.""" @handle_bitbucket_error def my_function(): return {"success": True} assert my_function.__name__ == "my_function" def test_passes_args_and_kwargs(self): """Should pass arguments to wrapped function.""" @handle_bitbucket_error def func_with_args(a, b, c=None): return {"a": a, "b": b, "c": c} result = func_with_args(1, 2, c=3) assert result == {"a": 1, "b": 2, "c": 3} class TestNotFoundResponse: """Tests for not_found_response function.""" def test_formats_message_with_repository(self): """Should format message for repository.""" result = not_found_response("Repository", "my-repo") assert result == {"error": "Repository 'my-repo' not found"} def test_formats_message_with_pr(self): """Should format message for PR.""" result = not_found_response("PR", "#123") assert result == {"error": "PR '#123' not found"} def test_formats_message_with_pipeline(self): """Should format message for pipeline.""" result = not_found_response("Pipeline", "{uuid}") assert result == {"error": "Pipeline '{uuid}' not found"} def test_formats_message_with_commit(self): """Should format message for commit.""" result = not_found_response("Commit", "abc123") assert result == {"error": "Commit 'abc123' not found"} class TestSanitizeSearchTerm: """Tests for sanitize_search_term function (BQL injection prevention).""" def test_allows_normal_search_term(self): """Normal search terms should pass through unchanged.""" result = sanitize_search_term("my-repo") assert result == "my-repo" def test_allows_alphanumeric_with_dashes(self): """Alphanumeric terms with dashes should be unchanged.""" result = sanitize_search_term("my-test-repo-123") assert result == "my-test-repo-123" def test_removes_double_quotes(self): """Double quotes should be removed to prevent BQL injection.""" result = sanitize_search_term('" OR is_private=false OR "') assert result == " OR is_private=false OR " assert '"' not in result def test_removes_backslashes(self): """Backslashes should be removed to prevent escape sequences.""" result = sanitize_search_term('test\\ninjection') assert result == "testninjection" assert '\\' not in result def test_handles_complex_injection_attempt(self): """Complex injection attempts should be sanitized.""" malicious = 'test" AND name~"admin' result = sanitize_search_term(malicious) assert result == "test AND name~admin" assert '"' not in result def test_handles_empty_string(self): """Empty string should return empty string.""" result = sanitize_search_term("") assert result == "" def test_preserves_spaces_and_underscores(self): """Spaces and underscores should be preserved.""" result = sanitize_search_term("my repo_name test") assert result == "my repo_name test"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JaviMaligno/mcp-server-bitbucket'

If you have feedback or need assistance with the MCP directory API, please join our Discord server