diff --git a/tests/conftest.py b/tests/conftest.py index 78491e9..c05ebcc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,6 +25,7 @@ def sample_query() -> dict[str, Any]: @pytest.fixture def temp_directory(tmp_path: Path) -> Path: + """ # Creates the following structure: # test_repo/ # ├── file1.txt @@ -39,6 +40,7 @@ def temp_directory(tmp_path: Path) -> Path: # | └── file_dir1.txt # └── dir2/ # └── file_dir2.txt + """ test_dir = tmp_path / "test_repo" test_dir.mkdir() diff --git a/tests/test_clone.py b/tests/test_clone.py index 2e58a0f..67f59a8 100644 --- a/tests/test_clone.py +++ b/tests/test_clone.py @@ -9,6 +9,10 @@ @pytest.mark.asyncio async def test_clone_repo_with_commit() -> None: + """ + Test the `clone_repo` function when a specific commit hash is provided. + Verifies that the repository is cloned and checked out to the specified commit. + """ clone_config = CloneConfig( url="https://github.com/user/repo", local_path="/tmp/repo", @@ -28,6 +32,10 @@ async def test_clone_repo_with_commit() -> None: @pytest.mark.asyncio async def test_clone_repo_without_commit() -> None: + """ + Test the `clone_repo` function when no commit hash is provided. + Verifies that only the repository clone operation is performed. + """ query = CloneConfig(url="https://github.com/user/repo", local_path="/tmp/repo", commit=None, branch="main") with patch("gitingest.clone._check_repo_exists", return_value=True) as mock_check: @@ -43,6 +51,10 @@ async def test_clone_repo_without_commit() -> None: @pytest.mark.asyncio async def test_clone_repo_nonexistent_repository() -> None: + """ + Test the `clone_repo` function when the repository does not exist. + Verifies that a ValueError is raised with an appropriate error message. + """ clone_config = CloneConfig( url="https://github.com/user/nonexistent-repo", local_path="/tmp/repo", @@ -57,6 +69,10 @@ async def test_clone_repo_nonexistent_repository() -> None: @pytest.mark.asyncio async def test_check_repo_exists() -> None: + """ + Test the `_check_repo_exists` function to verify if a repository exists. + Covers cases for existing repositories, non-existing repositories (404), and failed requests. + """ url = "https://github.com/user/repo" with patch("asyncio.create_subprocess_exec", new_callable=AsyncMock) as mock_exec: @@ -80,6 +96,10 @@ async def test_check_repo_exists() -> None: @pytest.mark.asyncio async def test_clone_repo_invalid_url() -> None: + """ + Test the `clone_repo` function when an invalid or empty URL is provided. + Verifies that a ValueError is raised with an appropriate error message. + """ clone_config = CloneConfig( url="", local_path="/tmp/repo", @@ -90,6 +110,10 @@ async def test_clone_repo_invalid_url() -> None: @pytest.mark.asyncio async def test_clone_repo_invalid_local_path() -> None: + """ + Test the `clone_repo` function when an invalid or empty local path is provided. + Verifies that a ValueError is raised with an appropriate error message. + """ clone_config = CloneConfig( url="https://github.com/user/repo", local_path="", @@ -100,6 +124,10 @@ async def test_clone_repo_invalid_local_path() -> None: @pytest.mark.asyncio async def test_clone_repo_with_custom_branch() -> None: + """ + Test the `clone_repo` function when a custom branch is specified. + Verifies that the repository is cloned with the specified branch using a shallow clone. + """ clone_config = CloneConfig( url="https://github.com/user/repo", local_path="/tmp/repo", @@ -122,6 +150,10 @@ async def test_clone_repo_with_custom_branch() -> None: @pytest.mark.asyncio async def test_git_command_failure() -> None: + """ + Test the `clone_repo` function when a Git command fails during execution. + Verifies that a RuntimeError is raised with an appropriate error message. + """ clone_config = CloneConfig( url="https://github.com/user/repo", local_path="/tmp/repo", @@ -134,6 +166,10 @@ async def test_git_command_failure() -> None: @pytest.mark.asyncio async def test_clone_repo_default_shallow_clone() -> None: + """ + Test the `clone_repo` function with default shallow clone behavior. + Verifies that the repository is cloned with `--depth=1` and `--single-branch` options. + """ clone_config = CloneConfig( url="https://github.com/user/repo", local_path="/tmp/repo", @@ -148,6 +184,10 @@ async def test_clone_repo_default_shallow_clone() -> None: @pytest.mark.asyncio async def test_clone_repo_commit_without_branch() -> None: + """ + Test the `clone_repo` function when a commit hash is provided but no branch is specified. + Verifies that the repository is cloned and checked out to the specified commit. + """ clone_config = CloneConfig( url="https://github.com/user/repo", local_path="/tmp/repo", @@ -163,6 +203,10 @@ async def test_clone_repo_commit_without_branch() -> None: @pytest.mark.asyncio async def test_check_repo_exists_with_redirect() -> None: + """ + Test the `_check_repo_exists` function for handling HTTP redirects (302 Found). + Verifies that it correctly identifies the repository's existence. + """ url = "https://github.com/user/repo" with patch("asyncio.create_subprocess_exec", new_callable=AsyncMock) as mock_exec: mock_process = AsyncMock() diff --git a/tests/test_parse_query.py b/tests/test_parse_query.py index 1c35efa..fed1887 100644 --- a/tests/test_parse_query.py +++ b/tests/test_parse_query.py @@ -9,6 +9,10 @@ def test_parse_url_valid_https() -> None: + """ + Test `_parse_url` with valid HTTPS URLs from supported platforms (GitHub, GitLab, Bitbucket). + Verifies that user and repository names are correctly extracted. + """ test_cases = [ "https://github.com/user/repo", "https://gitlab.com/user/repo", @@ -22,6 +26,10 @@ def test_parse_url_valid_https() -> None: def test_parse_url_valid_http() -> None: + """ + Test `_parse_url` with valid HTTP URLs from supported platforms. + Verifies that user and repository names, as well as the slug, are correctly extracted. + """ test_cases = [ "http://github.com/user/repo", "http://gitlab.com/user/repo", @@ -35,12 +43,20 @@ def test_parse_url_valid_http() -> None: def test_parse_url_invalid() -> None: + """ + Test `_parse_url` with an invalid URL that does not include a repository structure. + Verifies that a ValueError is raised with an appropriate error message. + """ url = "https://only-domain.com" with pytest.raises(ValueError, match="Invalid repository URL"): _parse_url(url) def test_parse_query_basic() -> None: + """ + Test `parse_query` with basic inputs including valid repository URLs. + Verifies that user and repository names, URL, and ignore patterns are correctly parsed. + """ test_cases = ["https://github.com/user/repo", "https://gitlab.com/user/repo"] for url in test_cases: result = parse_query(url, max_file_size=50, from_web=True, ignore_patterns="*.txt") @@ -51,6 +67,10 @@ def test_parse_query_basic() -> None: def test_parse_query_include_pattern() -> None: + """ + Test `parse_query` with an include pattern. + Verifies that the include pattern is set correctly and default ignore patterns are applied. + """ url = "https://github.com/user/repo" result = parse_query(url, max_file_size=50, from_web=True, include_patterns="*.py") assert result["include_patterns"] == ["*.py"] @@ -58,12 +78,20 @@ def test_parse_query_include_pattern() -> None: def test_parse_query_invalid_pattern() -> None: + """ + Test `parse_query` with an invalid pattern containing special characters. + Verifies that a ValueError is raised with an appropriate error message. + """ url = "https://github.com/user/repo" with pytest.raises(ValueError, match="Pattern.*contains invalid characters"): parse_query(url, max_file_size=50, from_web=True, include_patterns="*.py;rm -rf") def test_parse_url_with_subpaths() -> None: + """ + Test `_parse_url` with a URL containing a branch and subpath. + Verifies that user name, repository name, branch, and subpath are correctly extracted. + """ url = "https://github.com/user/repo/tree/main/subdir/file" result = _parse_url(url) assert result["user_name"] == "user" @@ -73,24 +101,40 @@ def test_parse_url_with_subpaths() -> None: def test_parse_url_invalid_repo_structure() -> None: + """ + Test `_parse_url` with an invalid repository structure in the URL. + Verifies that a ValueError is raised with an appropriate error message. + """ url = "https://github.com/user" with pytest.raises(ValueError, match="Invalid repository URL"): _parse_url(url) def test_parse_patterns_valid() -> None: + """ + Test `_parse_patterns` with valid patterns separated by commas. + Verifies that the patterns are correctly parsed into a list. + """ patterns = "*.py, *.md, docs/*" result = _parse_patterns(patterns) assert result == ["*.py", "*.md", "docs/*"] def test_parse_patterns_invalid_characters() -> None: + """ + Test `_parse_patterns` with invalid patterns containing special characters. + Verifies that a ValueError is raised with an appropriate error message. + """ patterns = "*.py;rm -rf" with pytest.raises(ValueError, match="Pattern.*contains invalid characters"): _parse_patterns(patterns) def test_parse_query_with_large_file_size() -> None: + """ + Test `parse_query` with a very large file size limit. + Verifies that the file size limit and default ignore patterns are set correctly. + """ url = "https://github.com/user/repo" result = parse_query(url, max_file_size=10**9, from_web=True) assert result["max_file_size"] == 10**9 @@ -98,6 +142,10 @@ def test_parse_query_with_large_file_size() -> None: def test_parse_query_empty_patterns() -> None: + """ + Test `parse_query` with empty include and ignore patterns. + Verifies that the include patterns are set to None and default ignore patterns are applied. + """ url = "https://github.com/user/repo" result = parse_query(url, max_file_size=50, from_web=True, include_patterns="", ignore_patterns="") assert result["include_patterns"] is None @@ -105,6 +153,10 @@ def test_parse_query_empty_patterns() -> None: def test_parse_query_include_and_ignore_overlap() -> None: + """ + Test `parse_query` with overlapping include and ignore patterns. + Verifies that overlapping patterns are removed from the ignore patterns. + """ url = "https://github.com/user/repo" result = parse_query( url, @@ -119,6 +171,10 @@ def test_parse_query_include_and_ignore_overlap() -> None: def test_parse_query_local_path() -> None: + """ + Test `parse_query` with a local file path. + Verifies that the local path is set, a unique ID is generated, and the slug is correctly created. + """ path = "/home/user/project" result = parse_query(path, max_file_size=100, from_web=False) tail = Path("home/user/project") @@ -128,6 +184,10 @@ def test_parse_query_local_path() -> None: def test_parse_query_relative_path() -> None: + """ + Test `parse_query` with a relative file path. + Verifies that the local path and slug are correctly resolved. + """ path = "./project" result = parse_query(path, max_file_size=100, from_web=False) tail = Path("project") @@ -136,11 +196,19 @@ def test_parse_query_relative_path() -> None: def test_parse_query_empty_source() -> None: + """ + Test `parse_query` with an empty source input. + Verifies that a ValueError is raised with an appropriate error message. + """ with pytest.raises(ValueError, match="Invalid repository URL"): parse_query("", max_file_size=100, from_web=True) def test_parse_url_branch_and_commit_distinction() -> None: + """ + Test `_parse_url` with URLs containing either a branch name or a commit hash. + Verifies that the branch and commit are correctly distinguished. + """ url_branch = "https://github.com/user/repo/tree/main" url_commit = "https://github.com/user/repo/tree/abcd1234abcd1234abcd1234abcd1234abcd1234" @@ -155,6 +223,9 @@ def test_parse_url_branch_and_commit_distinction() -> None: def test_parse_query_uuid_uniqueness() -> None: + """ + Test `parse_query` to ensure that each call generates a unique UUID for the query result. + """ path = "/home/user/project" result1 = parse_query(path, max_file_size=100, from_web=False) result2 = parse_query(path, max_file_size=100, from_web=False) @@ -162,6 +233,10 @@ def test_parse_query_uuid_uniqueness() -> None: def test_parse_url_with_query_and_fragment() -> None: + """ + Test `_parse_url` with a URL containing query parameters and a fragment. + Verifies that the URL is cleaned and other fields are correctly extracted. + """ url = "https://github.com/user/repo?arg=value#fragment" result = _parse_url(url) assert result["user_name"] == "user"