""" Test Suite for Document Processing Pipeline Tests each module independently and the full pipeline. """ import io import sys import os import pytest # Ensure the project root is in path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # ── Text Cleaner Tests ───────────────────────────────────────────────────────── class TestTextCleaner: def setup_method(self): from app.modules.text_cleaner import TextCleaner self.cleaner = TextCleaner() def test_basic_cleaning(self): text = "Hello World\n\n\n\nThis is a test." result = self.cleaner.clean(text) assert "Hello World" in result assert "\n\n\n" not in result def test_ligature_replacement(self): text = "\ufb01le \ufb02ow" # fi fl ligatures result = self.cleaner.clean(text) assert "file flow" in result def test_noise_removal(self): text = "Important text\n1\n---\nMore text" result = self.cleaner.clean(text) assert "Important text" in result assert "More text" in result def test_empty_input(self): assert self.cleaner.clean("") == "" assert self.cleaner.clean(" ") == "" # ── Entity Extractor Tests ───────────────────────────────────────────────────── class TestEntityExtractor: def setup_method(self): from app.modules.entity_extractor import EntityExtractor self.extractor = EntityExtractor() def test_extract_persons(self): text = "John Smith and Jane Doe signed the agreement." result = self.extractor.extract(text) assert "persons" in result # At least one person should be found persons_lower = [p.lower() for p in result["persons"]] assert any("john" in p or "jane" in p for p in persons_lower) def test_extract_organizations(self): text = "Google LLC and Microsoft Corporation announced a partnership." result = self.extractor.extract(text) orgs_lower = [o.lower() for o in result["organizations"]] assert any("google" in o or "microsoft" in o for o in orgs_lower) def test_extract_money(self): text = "The deal was worth $5 million." result = self.extractor.extract(text) assert len(result["amounts"]) > 0 assert any("5" in a for a in result["amounts"]) def test_extract_dates(self): text = "The contract was signed on January 15, 2024." result = self.extractor.extract(text) assert len(result["dates"]) > 0 def test_extract_locations(self): text = "The company is headquartered in New York." result = self.extractor.extract(text) locs_lower = [l.lower() for l in result["locations"]] assert any("new york" in l for l in locs_lower) def test_empty_text(self): result = self.extractor.extract("") assert result["persons"] == [] assert result["organizations"] == [] def test_result_structure(self): result = self.extractor.extract("Test text") assert "persons" in result assert "organizations" in result assert "dates" in result assert "amounts" in result assert "locations" in result # ── Sentiment Analyzer Tests ──────────────────────────────────────────────────── class TestSentimentAnalyzer: def setup_method(self): from app.modules.sentiment_analyzer import SentimentAnalyzer self.analyzer = SentimentAnalyzer() def test_positive_sentiment(self): text = "This is an excellent product! We are very happy with the outstanding results and remarkable performance." result = self.analyzer.analyze(text) assert result in ("positive", "negative", "neutral") # Must be valid def test_negative_sentiment(self): text = "This is a terrible disaster. The project completely failed and caused enormous losses." result = self.analyzer.analyze(text) assert result in ("positive", "negative", "neutral") def test_neutral_sentiment(self): text = "The report was submitted on Monday. It includes figures from Q3 2024." result = self.analyzer.analyze(text) assert result in ("positive", "negative", "neutral") def test_empty_text(self): result = self.analyzer.analyze("") assert result == "neutral" def test_short_text(self): result = self.analyzer.analyze("ok") assert result == "neutral" # ── Summarizer Tests ──────────────────────────────────────────────────────────── class TestSummarizer: def setup_method(self): from app.modules.summarizer import Summarizer self.summarizer = Summarizer() def test_summarize_returns_string(self): text = ( "Artificial intelligence is transforming industries worldwide. " "Companies are investing billions in AI research and development. " "Machine learning models are being applied to healthcare, finance, and education. " "The technology promises to automate complex tasks and improve decision making. " "However, concerns about job displacement and ethical AI remain significant challenges." ) result = self.summarizer.summarize(text) assert isinstance(result, str) assert len(result) > 0 def test_short_text_passthrough(self): text = "Short text." result = self.summarizer.summarize(text) assert isinstance(result, str) def test_empty_text(self): result = self.summarizer.summarize("") assert result == "" # ── OCR Processor Tests ───────────────────────────────────────────────────────── class TestOCRProcessor: def setup_method(self): from app.modules.ocr_processor import OCRProcessor self.ocr = OCRProcessor() def test_preprocess_returns_array(self): from PIL import Image import numpy as np img = Image.new("RGB", (100, 100), color="white") result = self.ocr.preprocess(img) assert isinstance(result, np.ndarray) def test_clean_ocr_output(self): raw = "Hello World\n\n\n\ntest" result = self.ocr._clean_ocr_output(raw) assert "Hello World" in result # ── API Integration Test ───────────────────────────────────────────────────────── class TestAPIEndpoint: def test_health_check(self): from fastapi.testclient import TestClient from app.main import app client = TestClient(app) response = client.get("/health") assert response.status_code == 200 assert response.json()["status"] == "healthy" def test_analyze_empty_file(self): from fastapi.testclient import TestClient from app.main import app client = TestClient(app) response = client.post( "/analyze", files={"file": ("test.txt", b"", "text/plain")}, ) assert response.status_code in (400, 422) def test_analyze_text_as_pdf_structure(self): """Test that the API returns the correct response structure.""" from fastapi.testclient import TestClient from app.main import app client = TestClient(app) # Create a minimal valid DOCX in memory from docx import Document doc = Document() doc.add_paragraph( "Google and Microsoft announced a $10 million partnership in New York on January 15, 2024. " "CEO John Smith stated the collaboration would bring excellent results for both companies." ) buf = io.BytesIO() doc.save(buf) buf.seek(0) response = client.post( "/analyze", files={"file": ("test.docx", buf.read(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document")}, ) assert response.status_code == 200 data = response.json() assert "summary" in data assert "entities" in data assert "sentiment" in data assert "persons" in data["entities"] assert "organizations" in data["entities"] assert "dates" in data["entities"] assert "amounts" in data["entities"] assert "locations" in data["entities"] assert data["sentiment"] in ("positive", "negative", "neutral") if __name__ == "__main__": pytest.main([__file__, "-v", "--tb=short"])