"""Tests for QuickReplyContentService.""" import json from unittest.mock import Mock import pytest from capa_de_integracion.config import Settings from capa_de_integracion.models.quick_replies import QuickReplyScreen from capa_de_integracion.services import QuickReplyContentService @pytest.fixture def mock_settings(tmp_path): """Create mock settings for testing.""" settings = Mock(spec=Settings) # Create the quick_replies directory quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() settings.base_path = tmp_path return settings @pytest.fixture def service(mock_settings): """Create QuickReplyContentService instance with empty cache.""" return QuickReplyContentService(mock_settings) @pytest.mark.asyncio async def test_get_quick_replies_empty_screen_id(service): """Test get_quick_replies with empty screen_id.""" result = await service.get_quick_replies("") assert isinstance(result, QuickReplyScreen) assert result.header == "empty" assert result.body is None assert result.button is None assert result.header_section is None assert result.preguntas == [] @pytest.mark.asyncio async def test_get_quick_replies_none_screen_id(service): """Test get_quick_replies with None screen_id.""" result = await service.get_quick_replies(None) assert isinstance(result, QuickReplyScreen) assert result.header == "empty" assert result.preguntas == [] @pytest.mark.asyncio async def test_get_quick_replies_whitespace_screen_id(service): """Test get_quick_replies with whitespace screen_id.""" result = await service.get_quick_replies(" ") assert isinstance(result, QuickReplyScreen) assert result.header == "empty" assert result.preguntas == [] @pytest.mark.asyncio async def test_get_quick_replies_file_not_found(service): """Test get_quick_replies raises error when screen not in cache.""" # Cache is empty (no files loaded), so any screen_id should raise ValueError with pytest.raises(ValueError, match="Quick reply not found for screen_id"): await service.get_quick_replies("nonexistent") @pytest.mark.asyncio async def test_get_quick_replies_success(tmp_path): """Test get_quick_replies successfully retrieves from cache.""" # Create test JSON file BEFORE initializing service quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() test_data = { "header": "Test Header", "body": "Test Body", "button": "Test Button", "header_section": "Test Section", "preguntas": [ { "titulo": "Question 1", "descripcion": "Description 1", "respuesta": "Answer 1", }, { "titulo": "Question 2", "respuesta": "Answer 2", }, ], } test_file = quick_replies_dir / "test_screen.json" test_file.write_text(json.dumps(test_data), encoding="utf-8") # Initialize service - it will preload the file into cache settings = Mock(spec=Settings) settings.base_path = tmp_path service = QuickReplyContentService(settings) result = await service.get_quick_replies("test_screen") assert isinstance(result, QuickReplyScreen) assert result.header == "Test Header" assert result.body == "Test Body" assert result.button == "Test Button" assert result.header_section == "Test Section" assert len(result.preguntas) == 2 assert result.preguntas[0].titulo == "Question 1" assert result.preguntas[0].descripcion == "Description 1" assert result.preguntas[0].respuesta == "Answer 1" assert result.preguntas[1].titulo == "Question 2" assert result.preguntas[1].descripcion is None assert result.preguntas[1].respuesta == "Answer 2" @pytest.mark.asyncio async def test_get_quick_replies_invalid_json(tmp_path): """Test that invalid JSON files are skipped during cache preload.""" quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() # Create invalid JSON file test_file = quick_replies_dir / "invalid.json" test_file.write_text("{ invalid json }", encoding="utf-8") # Initialize service - invalid file should be logged but not crash settings = Mock(spec=Settings) settings.base_path = tmp_path service = QuickReplyContentService(settings) # Requesting the invalid screen should raise ValueError (not in cache) with pytest.raises(ValueError, match="Quick reply not found for screen_id"): await service.get_quick_replies("invalid") @pytest.mark.asyncio async def test_get_quick_replies_minimal_data(tmp_path): """Test get_quick_replies with minimal data from cache.""" quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() test_data = { "preguntas": [], } test_file = quick_replies_dir / "minimal.json" test_file.write_text(json.dumps(test_data), encoding="utf-8") # Initialize service - it will preload the file settings = Mock(spec=Settings) settings.base_path = tmp_path service = QuickReplyContentService(settings) result = await service.get_quick_replies("minimal") assert isinstance(result, QuickReplyScreen) assert result.header is None assert result.body is None assert result.button is None assert result.header_section is None assert result.preguntas == [] @pytest.mark.asyncio async def test_validate_file_exists(service, tmp_path): """Test _validate_file with existing file.""" test_file = tmp_path / "test.json" test_file.write_text("{}", encoding="utf-8") # Should not raise service._validate_file(test_file, "test") @pytest.mark.asyncio async def test_validate_file_not_exists(service, tmp_path): """Test _validate_file with non-existing file.""" test_file = tmp_path / "nonexistent.json" with pytest.raises(ValueError, match="Quick reply file not found"): service._validate_file(test_file, "test") @pytest.mark.asyncio async def test_cache_preload_multiple_files(tmp_path): """Test that cache preloads multiple files correctly.""" quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() # Create multiple test files for screen_id in ["home", "pagos", "transferencia"]: test_data = { "header": f"{screen_id} header", "preguntas": [ {"titulo": f"Q1 for {screen_id}", "respuesta": "Answer 1"}, ], } test_file = quick_replies_dir / f"{screen_id}.json" test_file.write_text(json.dumps(test_data), encoding="utf-8") # Initialize service settings = Mock(spec=Settings) settings.base_path = tmp_path service = QuickReplyContentService(settings) # Verify all screens are in cache home = await service.get_quick_replies("home") assert home.header == "home header" pagos = await service.get_quick_replies("pagos") assert pagos.header == "pagos header" transferencia = await service.get_quick_replies("transferencia") assert transferencia.header == "transferencia header" @pytest.mark.asyncio async def test_cache_preload_with_mixed_valid_invalid(tmp_path): """Test cache preload handles mix of valid and invalid files.""" quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() # Create valid file valid_data = {"header": "valid", "preguntas": []} (quick_replies_dir / "valid.json").write_text( json.dumps(valid_data), encoding="utf-8", ) # Create invalid file (quick_replies_dir / "invalid.json").write_text( "{ invalid }", encoding="utf-8", ) # Initialize service - should not crash settings = Mock(spec=Settings) settings.base_path = tmp_path service = QuickReplyContentService(settings) # Valid file should be in cache valid = await service.get_quick_replies("valid") assert valid.header == "valid" # Invalid file should not be in cache with pytest.raises(ValueError, match="Quick reply not found"): await service.get_quick_replies("invalid") @pytest.mark.asyncio async def test_cache_preload_handles_generic_exception(tmp_path, monkeypatch): """Test cache preload handles generic exceptions during file processing.""" from pathlib import Path from unittest.mock import Mock quick_replies_dir = tmp_path / "quick_replies" quick_replies_dir.mkdir() # Create valid JSON file valid_data = {"header": "test", "preguntas": []} (quick_replies_dir / "test.json").write_text( json.dumps(valid_data), encoding="utf-8", ) # Mock _parse_quick_reply_data to raise generic exception def mock_parse_error(*args, **kwargs): raise ValueError("Simulated parsing error") settings = Mock(spec=Settings) settings.base_path = tmp_path # Initialize service and patch the parsing method with monkeypatch.context() as m: service = QuickReplyContentService(settings) m.setattr(service, "_parse_quick_reply_data", mock_parse_error) # Manually call _preload_cache to trigger the exception service._cache.clear() service._preload_cache() # The file should not be in cache due to the exception with pytest.raises(ValueError, match="Quick reply not found"): await service.get_quick_replies("test")