From db58cf6fb1020b263c91558db5fc05dcb300b60c Mon Sep 17 00:00:00 2001 From: Sagar Maheshwari Date: Sat, 11 Jul 2026 20:14:08 +0530 Subject: [PATCH 1/2] test: add unit tests for LocalRepoLoader and UrlRepoLoader functionality --- tests/test_loader.py | 166 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 tests/test_loader.py diff --git a/tests/test_loader.py b/tests/test_loader.py new file mode 100644 index 0000000..e70ef76 --- /dev/null +++ b/tests/test_loader.py @@ -0,0 +1,166 @@ +import os +from unittest.mock import MagicMock, patch + +import pytest +from langchain_core.documents import Document + +from repo2readme.loaders.loader import LocalRepoLoader, UrlRepoLoader + + +def test_local_repo_loader_init(): + loader = LocalRepoLoader( + folder_path="repo", + include_patterns=["*.py"], + exclude_patterns=["tests/*"], + max_file_size_kb=100, + ) + + assert loader.folder_path == "repo" + assert loader.include_patterns == ["*.py"] + assert loader.exclude_patterns == ["tests/*"] + assert loader.max_file_size_kb == 100 + + +def test_local_loader_missing_folder(): + loader = LocalRepoLoader("does_not_exist") + + with pytest.raises(FileNotFoundError): + loader.load() + + +@patch("repo2readme.loaders.loader.github_file_filter") +def test_should_include(mock_filter, tmp_path): + mock_filter.return_value = True + + loader = LocalRepoLoader(str(tmp_path)) + + file = tmp_path / "a.py" + file.write_text("print('hi')") + + assert loader._should_include(str(file)) + + mock_filter.assert_called_once() + + +@patch("repo2readme.loaders.loader.TextLoader") +def test_load_adds_metadata(mock_loader, tmp_path): + file = tmp_path / "main.py" + file.write_text("print('hello')") + + mock_loader.return_value.load.return_value = [ + Document(page_content="hello", metadata={}) + ] + + loader = LocalRepoLoader(str(tmp_path)) + + docs, root = loader.load() + + assert root == str(tmp_path) + assert len(docs) == 1 + + metadata = docs[0].metadata + + assert metadata["file_name"] == "main.py" + assert metadata["file_type"] == ".py" + assert metadata["relative_path"] == "main.py" + assert metadata["file_path"].endswith("main.py") + + +@patch("repo2readme.loaders.loader.TextLoader") +def test_load_handles_loader_exception(mock_loader, tmp_path, capsys): + file = tmp_path / "bad.py" + file.write_text("print('bad')") + + mock_loader.return_value.load.side_effect = Exception("boom") + + loader = LocalRepoLoader(str(tmp_path)) + + docs, _ = loader.load() + + assert docs == [] + + captured = capsys.readouterr() + assert "[ERROR]" in captured.out + + +def test_url_loader_init(): + loader = UrlRepoLoader( + clone_url="https://github.com/user/repo.git", + branch="dev", + include_patterns=["*.py"], + exclude_patterns=["tests/*"], + max_file_size_kb=50, + ) + + assert loader.clone_url.endswith("repo.git") + assert loader.branch == "dev" + assert loader.include_patterns == ["*.py"] + assert loader.exclude_patterns == ["tests/*"] + assert loader.max_file_size_kb == 50 + assert loader.temp_dir is None + + +@pytest.mark.parametrize( + "url,expected", + [ + ("https://github.com/user/repo.git", "repo"), + ("https://github.com/user/repo", "repo"), + ("git@github.com:user/repo.git", "repo"), + ], +) +def test_get_repo_name(url, expected): + loader = UrlRepoLoader(url) + + assert loader.get_repo_name() == expected + + +@patch("repo2readme.loaders.loader.github_file_filter") +def test_url_should_include(mock_filter): + mock_filter.return_value = True + + loader = UrlRepoLoader("https://github.com/user/repo.git") + loader.temp_dir = "/tmp/repo" + + assert loader._should_include("/tmp/repo/src/main.py") + + mock_filter.assert_called_once() + + +@patch("repo2readme.loaders.loader.GitLoader") +def test_url_load_metadata(mock_gitloader): + document = Document( + page_content="hello", + metadata={"source": "src/main.py"}, + ) + + mock_gitloader.return_value.load.return_value = [document] + + loader = UrlRepoLoader( + "https://github.com/user/repo.git", + branch="main", + ) + + docs, temp_dir = loader.load() + + assert len(docs) == 1 + + metadata = docs[0].metadata + + assert metadata["file_name"] == "main.py" + assert metadata["file_type"] == ".py" + assert metadata["relative_path"] == "src/main.py" + assert metadata["file_path"].endswith("src/main.py") + + mock_gitloader.assert_called_once() + + +def test_cleanup(tmp_path): + loader = UrlRepoLoader("https://github.com/user/repo.git") + + loader.temp_dir = str(tmp_path) + + assert os.path.exists(loader.temp_dir) + + loader.cleanup() + + assert not os.path.exists(loader.temp_dir) \ No newline at end of file From 29a3295a6b8d0c87aa74fd346e66dd19e08908e8 Mon Sep 17 00:00:00 2001 From: Sagar Maheshwari Date: Sat, 11 Jul 2026 22:53:13 +0530 Subject: [PATCH 2/2] test: update url load metadata test to include loader cleanup logic --- tests/test_loader.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/test_loader.py b/tests/test_loader.py index e70ef76..222a1b1 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -125,7 +125,6 @@ def test_url_should_include(mock_filter): mock_filter.assert_called_once() - @patch("repo2readme.loaders.loader.GitLoader") def test_url_load_metadata(mock_gitloader): document = Document( @@ -140,19 +139,21 @@ def test_url_load_metadata(mock_gitloader): branch="main", ) - docs, temp_dir = loader.load() + docs, _ = loader.load() - assert len(docs) == 1 + try: + assert len(docs) == 1 - metadata = docs[0].metadata - - assert metadata["file_name"] == "main.py" - assert metadata["file_type"] == ".py" - assert metadata["relative_path"] == "src/main.py" - assert metadata["file_path"].endswith("src/main.py") + metadata = docs[0].metadata - mock_gitloader.assert_called_once() + assert metadata["file_name"] == "main.py" + assert metadata["file_type"] == ".py" + assert metadata["relative_path"] == "src/main.py" + assert metadata["file_path"].endswith("src/main.py") + mock_gitloader.assert_called_once() + finally: + loader.cleanup() def test_cleanup(tmp_path): loader = UrlRepoLoader("https://github.com/user/repo.git")