from datetime import datetime import pytest from src.models import ( AppConfig, Article, ProcessingResult, ProcessingStats, ProcessingStatus, SimplifyCommand, ) class TestAppConfig: def test_default_values(self): with pytest.raises(ValueError): AppConfig() def test_valid_config(self): config = AppConfig( openai_api_key="test_key", db_path="./test.db", ) assert config.openai_api_key == "test_key" assert config.openai_model == "gpt-4o-mini" assert config.openai_temperature == 0.0 assert config.max_concurrent_llm == 5 assert config.openai_rpm == 200 def test_db_url_generation(self): config = AppConfig( openai_api_key="test_key", db_path="./test.db", ) assert config.db_url == "sqlite+aiosqlite:///test.db" assert config.sync_db_url == "sqlite:///test.db" def test_validation_constraints(self): with pytest.raises(ValueError): AppConfig( openai_api_key="test_key", openai_temperature=3.0, ) with pytest.raises(ValueError): AppConfig( openai_api_key="test_key", max_concurrent_llm=100, ) class TestArticle: def test_article_creation(self, sample_article_data): article = Article( url=sample_article_data.url, title=sample_article_data.title, raw_text=sample_article_data.raw_text, ) assert article.url == sample_article_data.url assert article.title == sample_article_data.title assert article.status == ProcessingStatus.PENDING assert article.simplified_text is None assert isinstance(article.created_at, datetime) def test_mark_processing(self, sample_article): article = sample_article original_updated = article.updated_at article.mark_processing() assert article.status == ProcessingStatus.PROCESSING assert article.updated_at != original_updated def test_mark_completed(self, sample_article): article = sample_article simplified_text = "Упрощённый текст" article.mark_completed( simplified_text=simplified_text, token_count_raw=100, token_count_simplified=50, processing_time=2.5, ) assert article.status == ProcessingStatus.COMPLETED assert article.simplified_text == simplified_text assert article.token_count_raw == 100 assert article.token_count_simplified == 50 assert article.processing_time_seconds == 2.5 assert article.error_message is None assert article.updated_at is not None def test_mark_failed(self, sample_article): article = sample_article error_message = "Тестовая ошибка" article.mark_failed(error_message) assert article.status == ProcessingStatus.FAILED assert article.error_message == error_message assert article.updated_at is not None def test_mark_failed_long_error(self, sample_article): article = sample_article long_error = "x" * 1500 article.mark_failed(long_error) assert len(article.error_message) == 1000 assert article.error_message == "x" * 1000 class TestSimplifyCommand: def test_command_creation(self): url = "https://ru.wikipedia.org/wiki/Тест" command = SimplifyCommand(url=url) assert command.url == url assert command.force_reprocess is False def test_command_with_force(self): url = "https://ru.wikipedia.org/wiki/Тест" command = SimplifyCommand(url=url, force_reprocess=True) assert command.url == url assert command.force_reprocess is True def test_command_string_representation(self): url = "https://ru.wikipedia.org/wiki/Тест" command = SimplifyCommand(url=url, force_reprocess=True) expected = f"SimplifyCommand(url='{url}', force=True)" assert str(command) == expected class TestProcessingResult: def test_success_result_creation(self): result = ProcessingResult.success_result( url="https://ru.wikipedia.org/wiki/Тест", title="Тест", raw_text="Исходный текст", simplified_text="Упрощённый текст", token_count_raw=100, token_count_simplified=50, processing_time_seconds=2.5, ) assert result.success is True assert result.url == "https://ru.wikipedia.org/wiki/Тест" assert result.title == "Тест" assert result.raw_text == "Исходный текст" assert result.simplified_text == "Упрощённый текст" assert result.token_count_raw == 100 assert result.token_count_simplified == 50 assert result.processing_time_seconds == 2.5 assert result.error_message is None def test_failure_result_creation(self): result = ProcessingResult.failure_result( url="https://ru.wikipedia.org/wiki/Тест", error_message="Тестовая ошибка", ) assert result.success is False assert result.url == "https://ru.wikipedia.org/wiki/Тест" assert result.error_message == "Тестовая ошибка" assert result.title is None assert result.raw_text is None assert result.simplified_text is None class TestProcessingStats: def test_initial_stats(self): stats = ProcessingStats() assert stats.total_processed == 0 assert stats.successful == 0 assert stats.failed == 0 assert stats.skipped == 0 assert stats.success_rate == 0.0 assert stats.average_processing_time == 0.0 def test_add_successful_result(self): stats = ProcessingStats() result = ProcessingResult.success_result( url="test", title="Test", raw_text="text", simplified_text="simple", token_count_raw=100, token_count_simplified=50, processing_time_seconds=2.0, ) stats.add_result(result) assert stats.total_processed == 1 assert stats.successful == 1 assert stats.failed == 0 assert stats.success_rate == 100.0 assert stats.average_processing_time == 2.0 def test_add_failed_result(self): stats = ProcessingStats() result = ProcessingResult.failure_result("test", "error") stats.add_result(result) assert stats.total_processed == 1 assert stats.successful == 0 assert stats.failed == 1 assert stats.success_rate == 0.0 def test_mixed_results(self): stats = ProcessingStats() success_result = ProcessingResult.success_result( url="test1", title="Test1", raw_text="text", simplified_text="simple", token_count_raw=100, token_count_simplified=50, processing_time_seconds=3.0, ) stats.add_result(success_result) failure_result = ProcessingResult.failure_result("test2", "error") stats.add_result(failure_result) success_result2 = ProcessingResult.success_result( url="test3", title="Test3", raw_text="text", simplified_text="simple", token_count_raw=100, token_count_simplified=50, processing_time_seconds=1.0, ) stats.add_result(success_result2) assert stats.total_processed == 3 assert stats.successful == 2 assert stats.failed == 1 assert stats.success_rate == pytest.approx(66.67, rel=1e-2) assert stats.average_processing_time == 2.0 def test_add_skipped(self): stats = ProcessingStats() stats.add_skipped() stats.add_skipped() assert stats.skipped == 2