492 lines
19 KiB
Python
492 lines
19 KiB
Python
|
|
"""
|
||
|
|
Tests for ingestion.py - Document ingestion pipeline.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
import tempfile
|
||
|
|
from pathlib import Path
|
||
|
|
from unittest.mock import patch, MagicMock
|
||
|
|
import fitz # PyMuPDF
|
||
|
|
|
||
|
|
from app.core.ingestion import (
|
||
|
|
extract_text_from_file,
|
||
|
|
chunk_document,
|
||
|
|
ingest_file,
|
||
|
|
ingest_documents,
|
||
|
|
ingest_directory,
|
||
|
|
should_skip_path,
|
||
|
|
SKIP_DIRECTORIES,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestExtractTextFromFile:
|
||
|
|
"""Tests for extract_text_from_file function."""
|
||
|
|
|
||
|
|
def test_extract_text_file(self, tmp_path):
|
||
|
|
"""Test extracting text from .txt file."""
|
||
|
|
file_path = tmp_path / "test.txt"
|
||
|
|
file_path.write_text("Hello, this is a test file.\nWith multiple lines.")
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
|
||
|
|
assert "Hello, this is a test file" in result
|
||
|
|
assert "With multiple lines" in result
|
||
|
|
|
||
|
|
def test_extract_markdown_file(self, tmp_path):
|
||
|
|
"""Test extracting text from .md file."""
|
||
|
|
file_path = tmp_path / "test.md"
|
||
|
|
file_path.write_text("# Heading\n\nSome **bold** text.")
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
|
||
|
|
assert "# Heading" in result
|
||
|
|
assert "**bold**" in result
|
||
|
|
|
||
|
|
def test_extract_python_file(self, tmp_path):
|
||
|
|
"""Test extracting text from .py file."""
|
||
|
|
file_path = tmp_path / "test.py"
|
||
|
|
file_path.write_text('def hello():\n print("Hello")')
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
|
||
|
|
assert "def hello():" in result
|
||
|
|
assert 'print("Hello")' in result
|
||
|
|
|
||
|
|
def test_extract_pdf_file(self, tmp_path):
|
||
|
|
"""Test extracting text from PDF file."""
|
||
|
|
file_path = tmp_path / "test.pdf"
|
||
|
|
|
||
|
|
# Create a PDF with PyMuPDF
|
||
|
|
doc = fitz.open()
|
||
|
|
page = doc.new_page()
|
||
|
|
page.insert_text((72, 72), "PDF content here")
|
||
|
|
doc.save(str(file_path))
|
||
|
|
doc.close()
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
|
||
|
|
assert "PDF content here" in result
|
||
|
|
|
||
|
|
def test_extract_nonexistent_file(self):
|
||
|
|
"""Test extracting from non-existent file."""
|
||
|
|
result = extract_text_from_file("/nonexistent/file.txt")
|
||
|
|
assert result == ""
|
||
|
|
|
||
|
|
def test_extract_file_with_encoding_issues(self, tmp_path):
|
||
|
|
"""Test extracting file with encoding issues."""
|
||
|
|
file_path = tmp_path / "test.txt"
|
||
|
|
# Write bytes directly to create encoding issues
|
||
|
|
file_path.write_bytes(b"Hello \xff\xfe World")
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
|
||
|
|
# Should handle gracefully with errors='ignore'
|
||
|
|
assert "Hello" in result
|
||
|
|
assert "World" in result
|
||
|
|
|
||
|
|
def test_extract_empty_file(self, tmp_path):
|
||
|
|
"""Test extracting from empty file."""
|
||
|
|
file_path = tmp_path / "empty.txt"
|
||
|
|
file_path.write_text("")
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
assert result == ""
|
||
|
|
|
||
|
|
def test_extract_json_file(self, tmp_path):
|
||
|
|
"""Test extracting text from JSON file."""
|
||
|
|
file_path = tmp_path / "test.json"
|
||
|
|
file_path.write_text('{"key": "value", "number": 42}')
|
||
|
|
|
||
|
|
result = extract_text_from_file(str(file_path))
|
||
|
|
|
||
|
|
assert '"key"' in result
|
||
|
|
assert '"value"' in result
|
||
|
|
|
||
|
|
|
||
|
|
class TestChunkDocument:
|
||
|
|
"""Tests for chunk_document function."""
|
||
|
|
|
||
|
|
def test_chunk_short_document(self):
|
||
|
|
"""Test chunking a short document (single chunk)."""
|
||
|
|
text = "This is a short document."
|
||
|
|
metadata = {"filename": "test.txt"}
|
||
|
|
|
||
|
|
chunks = chunk_document(text, metadata)
|
||
|
|
|
||
|
|
assert len(chunks) >= 1
|
||
|
|
assert chunks[0].metadata["filename"] == "test.txt"
|
||
|
|
assert "chunk_index" in chunks[0].metadata
|
||
|
|
|
||
|
|
def test_chunk_long_document(self):
|
||
|
|
"""Test chunking a long document (multiple chunks)."""
|
||
|
|
# Create a long text
|
||
|
|
text = "This is a paragraph. " * 500 # ~10000 chars
|
||
|
|
metadata = {"filename": "long.txt"}
|
||
|
|
|
||
|
|
chunks = chunk_document(text, metadata)
|
||
|
|
|
||
|
|
# Should have multiple chunks
|
||
|
|
assert len(chunks) > 1
|
||
|
|
|
||
|
|
# Each chunk should have correct metadata
|
||
|
|
for i, chunk in enumerate(chunks):
|
||
|
|
assert chunk.metadata["chunk_index"] == i
|
||
|
|
assert chunk.metadata["filename"] == "long.txt"
|
||
|
|
|
||
|
|
def test_chunk_preserves_metadata(self):
|
||
|
|
"""Test that chunking preserves original metadata."""
|
||
|
|
text = "Test content"
|
||
|
|
metadata = {
|
||
|
|
"filename": "test.txt",
|
||
|
|
"file_type": ".txt",
|
||
|
|
"custom_field": "custom_value"
|
||
|
|
}
|
||
|
|
|
||
|
|
chunks = chunk_document(text, metadata)
|
||
|
|
|
||
|
|
for chunk in chunks:
|
||
|
|
assert chunk.metadata["filename"] == "test.txt"
|
||
|
|
assert chunk.metadata["file_type"] == ".txt"
|
||
|
|
assert chunk.metadata["custom_field"] == "custom_value"
|
||
|
|
|
||
|
|
def test_chunk_adds_chunk_id(self):
|
||
|
|
"""Test that chunking adds chunk_id."""
|
||
|
|
text = "Test content"
|
||
|
|
metadata = {"filename": "test.txt"}
|
||
|
|
|
||
|
|
chunks = chunk_document(text, metadata)
|
||
|
|
|
||
|
|
for chunk in chunks:
|
||
|
|
assert "chunk_id" in chunk.metadata
|
||
|
|
|
||
|
|
|
||
|
|
class TestShouldSkipPath:
|
||
|
|
"""Tests for should_skip_path function."""
|
||
|
|
|
||
|
|
def test_skip_node_modules(self):
|
||
|
|
"""Test that node_modules is skipped."""
|
||
|
|
path = Path("/project/node_modules/package/index.js")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_skip_git_directory(self):
|
||
|
|
"""Test that .git is skipped."""
|
||
|
|
path = Path("/project/.git/objects/abc123")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_skip_pycache(self):
|
||
|
|
"""Test that __pycache__ is skipped."""
|
||
|
|
path = Path("/project/src/__pycache__/module.pyc")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_skip_pytest_cache(self):
|
||
|
|
"""Test that .pytest_cache is skipped."""
|
||
|
|
path = Path("/project/.pytest_cache/v/cache/lastfailed")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_skip_egg_info(self):
|
||
|
|
"""Test that *.egg-info is skipped."""
|
||
|
|
path = Path("/project/mypackage.egg-info/PKG-INFO")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_allow_regular_path(self):
|
||
|
|
"""Test that regular paths are not skipped."""
|
||
|
|
path = Path("/project/src/main.py")
|
||
|
|
assert should_skip_path(path) is False
|
||
|
|
|
||
|
|
def test_allow_deep_path(self):
|
||
|
|
"""Test that deep regular paths are not skipped."""
|
||
|
|
path = Path("/project/src/components/ui/Button.tsx")
|
||
|
|
assert should_skip_path(path) is False
|
||
|
|
|
||
|
|
def test_skip_vscode(self):
|
||
|
|
"""Test that .vscode is skipped."""
|
||
|
|
path = Path("/project/.vscode/settings.json")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_skip_idea(self):
|
||
|
|
"""Test that .idea is skipped."""
|
||
|
|
path = Path("/project/.idea/workspace.xml")
|
||
|
|
assert should_skip_path(path) is True
|
||
|
|
|
||
|
|
def test_all_skip_directories(self):
|
||
|
|
"""Test all directories in SKIP_DIRECTORIES are handled."""
|
||
|
|
for skip_dir in SKIP_DIRECTORIES:
|
||
|
|
if '*' not in skip_dir:
|
||
|
|
path = Path(f"/project/{skip_dir}/file.txt")
|
||
|
|
assert should_skip_path(path) is True, f"{skip_dir} should be skipped"
|
||
|
|
|
||
|
|
|
||
|
|
class TestIngestFile:
|
||
|
|
"""Tests for ingest_file function."""
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_db_manager(self):
|
||
|
|
"""Create mock database manager."""
|
||
|
|
mock = MagicMock()
|
||
|
|
mock.collection_exists.return_value = True
|
||
|
|
mock.add_documents = MagicMock()
|
||
|
|
return mock
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_embed_model(self):
|
||
|
|
"""Create mock embedding model."""
|
||
|
|
mock = MagicMock()
|
||
|
|
mock.get_text_embedding.return_value = [0.1] * 768
|
||
|
|
return mock
|
||
|
|
|
||
|
|
def test_ingest_text_file_success(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test successful ingestion of text file."""
|
||
|
|
file_path = tmp_path / "test.txt"
|
||
|
|
file_path.write_text("This is test content for ingestion.")
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
result = ingest_file(str(file_path), "test_collection", "test.txt")
|
||
|
|
|
||
|
|
assert result["status"] == "success"
|
||
|
|
assert result["filename"] == "test.txt"
|
||
|
|
assert "chunks" in result
|
||
|
|
mock_db_manager.add_documents.assert_called_once()
|
||
|
|
|
||
|
|
def test_ingest_empty_file(self, tmp_path, mock_db_manager):
|
||
|
|
"""Test ingestion of empty file."""
|
||
|
|
file_path = tmp_path / "empty.txt"
|
||
|
|
file_path.write_text("")
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
result = ingest_file(str(file_path), "test_collection", "empty.txt")
|
||
|
|
|
||
|
|
assert result["status"] == "error"
|
||
|
|
assert "No text content" in result["error"]
|
||
|
|
|
||
|
|
def test_ingest_nonexistent_collection(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test ingestion to non-existent collection."""
|
||
|
|
file_path = tmp_path / "test.txt"
|
||
|
|
file_path.write_text("Content")
|
||
|
|
mock_db_manager.collection_exists.return_value = False
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
result = ingest_file(str(file_path), "nonexistent", "test.txt")
|
||
|
|
|
||
|
|
assert result["status"] == "error"
|
||
|
|
assert "not found" in result["error"]
|
||
|
|
|
||
|
|
def test_ingest_markdown_with_preprocessing(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test ingestion of markdown file with preprocessing."""
|
||
|
|
file_path = tmp_path / "test.md"
|
||
|
|
file_path.write_text("# Heading\n\nSome content here.")
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
with patch('app.core.ingestion.preprocess_markdown') as mock_preprocess:
|
||
|
|
mock_preprocess.return_value = ("Processed content", {"header": "Heading"})
|
||
|
|
|
||
|
|
result = ingest_file(str(file_path), "test_collection", "test.md")
|
||
|
|
|
||
|
|
assert result["status"] == "success"
|
||
|
|
mock_preprocess.assert_called_once()
|
||
|
|
|
||
|
|
def test_ingest_handles_embedding_failure(self, tmp_path, mock_db_manager):
|
||
|
|
"""Test ingestion handles embedding failures gracefully."""
|
||
|
|
file_path = tmp_path / "test.txt"
|
||
|
|
file_path.write_text("Content")
|
||
|
|
|
||
|
|
mock_embed = MagicMock()
|
||
|
|
mock_embed.get_text_embedding.side_effect = Exception("Embedding failed")
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed):
|
||
|
|
result = ingest_file(str(file_path), "test_collection", "test.txt")
|
||
|
|
|
||
|
|
assert result["status"] == "error"
|
||
|
|
assert "failed to generate embeddings" in result["error"]
|
||
|
|
|
||
|
|
def test_ingest_truncates_long_chunks(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test that very long chunks are truncated."""
|
||
|
|
file_path = tmp_path / "long.txt"
|
||
|
|
file_path.write_text("A" * 10000) # Very long content
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
result = ingest_file(str(file_path), "test_collection", "long.txt")
|
||
|
|
|
||
|
|
assert result["status"] == "success"
|
||
|
|
|
||
|
|
|
||
|
|
class TestIngestDocuments:
|
||
|
|
"""Tests for ingest_documents function."""
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_db_manager(self):
|
||
|
|
"""Create mock database manager."""
|
||
|
|
mock = MagicMock()
|
||
|
|
mock.collection_exists.return_value = True
|
||
|
|
mock.add_documents = MagicMock()
|
||
|
|
return mock
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_embed_model(self):
|
||
|
|
"""Create mock embedding model."""
|
||
|
|
mock = MagicMock()
|
||
|
|
mock.get_text_embedding.return_value = [0.1] * 768
|
||
|
|
return mock
|
||
|
|
|
||
|
|
def test_ingest_documents_success(self, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test successful bulk document ingestion."""
|
||
|
|
documents = ["Document 1 content", "Document 2 content"]
|
||
|
|
metadatas = [{"filename": "doc1.txt"}, {"filename": "doc2.txt"}]
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
result = ingest_documents("test_collection", documents, metadatas)
|
||
|
|
|
||
|
|
assert result["status"] == "success"
|
||
|
|
assert result["documents_processed"] == 2
|
||
|
|
mock_db_manager.add_documents.assert_called_once()
|
||
|
|
|
||
|
|
def test_ingest_documents_nonexistent_collection(self, mock_db_manager):
|
||
|
|
"""Test ingestion to non-existent collection."""
|
||
|
|
mock_db_manager.collection_exists.return_value = False
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
result = ingest_documents("nonexistent", ["doc"], [{}])
|
||
|
|
|
||
|
|
assert result["status"] == "error"
|
||
|
|
assert "not found" in result["error"]
|
||
|
|
|
||
|
|
def test_ingest_documents_skips_empty(self, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test that empty documents are skipped."""
|
||
|
|
documents = ["Valid content", "", " "]
|
||
|
|
metadatas = [{"filename": "valid.txt"}, {"filename": "empty.txt"}, {"filename": "whitespace.txt"}]
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
result = ingest_documents("test_collection", documents, metadatas)
|
||
|
|
|
||
|
|
assert result["status"] == "success"
|
||
|
|
# Only valid content should be processed
|
||
|
|
|
||
|
|
def test_ingest_documents_all_empty(self, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test ingestion when all documents are empty."""
|
||
|
|
documents = ["", " ", ""]
|
||
|
|
metadatas = [{}, {}, {}]
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
result = ingest_documents("test_collection", documents, metadatas)
|
||
|
|
|
||
|
|
assert result["status"] == "error"
|
||
|
|
assert "No valid documents" in result["error"]
|
||
|
|
|
||
|
|
|
||
|
|
class TestIngestDirectory:
|
||
|
|
"""Tests for ingest_directory function."""
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_db_manager(self):
|
||
|
|
"""Create mock database manager."""
|
||
|
|
mock = MagicMock()
|
||
|
|
mock.collection_exists.return_value = True
|
||
|
|
mock.add_documents = MagicMock()
|
||
|
|
return mock
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_embed_model(self):
|
||
|
|
"""Create mock embedding model."""
|
||
|
|
mock = MagicMock()
|
||
|
|
mock.get_text_embedding.return_value = [0.1] * 768
|
||
|
|
return mock
|
||
|
|
|
||
|
|
def test_ingest_directory_success(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test successful directory ingestion."""
|
||
|
|
# Create test files with supported extensions (.txt and .md are in ALLOWED_EXTENSIONS)
|
||
|
|
(tmp_path / "file1.txt").write_text("Content 1 for testing ingestion")
|
||
|
|
(tmp_path / "file2.md").write_text("# Content 2 for testing ingestion")
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
results = ingest_directory(str(tmp_path), "test_collection")
|
||
|
|
|
||
|
|
# Both files should be processed (txt and md are supported)
|
||
|
|
assert len(results) >= 2
|
||
|
|
# At least one should succeed (may fail if embedding mock has issues)
|
||
|
|
successful = [r for r in results if r.get("status") == "success"]
|
||
|
|
assert len(successful) >= 1
|
||
|
|
|
||
|
|
def test_ingest_directory_nonexistent(self):
|
||
|
|
"""Test ingestion of non-existent directory."""
|
||
|
|
results = ingest_directory("/nonexistent/directory", "test_collection")
|
||
|
|
|
||
|
|
assert len(results) == 1
|
||
|
|
assert results[0]["status"] == "error"
|
||
|
|
assert "not found" in results[0]["error"]
|
||
|
|
|
||
|
|
def test_ingest_directory_skips_node_modules(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test that node_modules is skipped."""
|
||
|
|
# Create files with supported extensions (.py and .js are supported)
|
||
|
|
(tmp_path / "src").mkdir()
|
||
|
|
(tmp_path / "src" / "main.py").write_text("# Main python file")
|
||
|
|
(tmp_path / "node_modules").mkdir()
|
||
|
|
(tmp_path / "node_modules" / "package" ).mkdir()
|
||
|
|
(tmp_path / "node_modules" / "package" / "index.js").write_text("// JS file in node_modules")
|
||
|
|
|
||
|
|
ingested_files = []
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
with patch('app.core.ingestion.ingest_file') as mock_ingest:
|
||
|
|
mock_ingest.side_effect = lambda path, coll, name: (
|
||
|
|
ingested_files.append(path),
|
||
|
|
{"status": "success", "filename": name}
|
||
|
|
)[1]
|
||
|
|
|
||
|
|
ingest_directory(str(tmp_path), "test_collection")
|
||
|
|
|
||
|
|
# node_modules files should not be in the list
|
||
|
|
assert not any("node_modules" in f for f in ingested_files)
|
||
|
|
|
||
|
|
def test_ingest_directory_recursive(self, tmp_path, mock_db_manager, mock_embed_model):
|
||
|
|
"""Test that directory ingestion is recursive."""
|
||
|
|
# Create nested structure with supported file types
|
||
|
|
(tmp_path / "level1").mkdir()
|
||
|
|
(tmp_path / "level1" / "level2").mkdir()
|
||
|
|
(tmp_path / "level1" / "file1.txt").write_text("Level 1 content")
|
||
|
|
(tmp_path / "level1" / "level2" / "file2.txt").write_text("Level 2 content")
|
||
|
|
|
||
|
|
with patch('app.core.ingestion.get_sqlite_manager', return_value=mock_db_manager):
|
||
|
|
with patch('app.core.ingestion.OllamaEmbedding', return_value=mock_embed_model):
|
||
|
|
results = ingest_directory(str(tmp_path), "test_collection")
|
||
|
|
|
||
|
|
# Should find files in nested directories
|
||
|
|
assert len(results) >= 2
|
||
|
|
|
||
|
|
|
||
|
|
class TestSkipDirectoriesConstant:
|
||
|
|
"""Tests for SKIP_DIRECTORIES constant."""
|
||
|
|
|
||
|
|
def test_contains_common_excludes(self):
|
||
|
|
"""Test that common directories are in skip list."""
|
||
|
|
expected_dirs = [
|
||
|
|
'node_modules', '.git', '__pycache__', '.pytest_cache',
|
||
|
|
'dist', 'build', '.vscode', '.idea'
|
||
|
|
]
|
||
|
|
|
||
|
|
for dir_name in expected_dirs:
|
||
|
|
assert dir_name in SKIP_DIRECTORIES, f"{dir_name} should be in SKIP_DIRECTORIES"
|
||
|
|
|
||
|
|
def test_contains_language_specific_excludes(self):
|
||
|
|
"""Test that language-specific directories are included."""
|
||
|
|
# Rust/Java
|
||
|
|
assert 'target' in SKIP_DIRECTORIES
|
||
|
|
|
||
|
|
# iOS
|
||
|
|
assert 'Pods' in SKIP_DIRECTORIES
|
||
|
|
|
||
|
|
# Gradle
|
||
|
|
assert '.gradle' in SKIP_DIRECTORIES
|
||
|
|
|
||
|
|
def test_skip_directories_is_set(self):
|
||
|
|
"""Test that SKIP_DIRECTORIES is a set for fast lookup."""
|
||
|
|
assert isinstance(SKIP_DIRECTORIES, set)
|