"""Tests for static controller.""" import pytest from fastapi.testclient import TestClient from unittest.mock import patch, MagicMock from pathlib import Path import tempfile import os from src.main import app @pytest.fixture def client(): """Create a test client.""" return TestClient(app) class TestListWidgets: """Test /static/widgets endpoint.""" def test_list_widgets_returns_200(self, client): """List widgets should return 200.""" response = client.get("/static/widgets") assert response.status_code == 200 def test_list_widgets_returns_widgets_list(self, client): """List widgets should return widgets array.""" response = client.get("/static/widgets") data = response.json() assert "widgets" in data assert "count" in data assert isinstance(data["widgets"], list) @patch("src.controllers.static_controller.StaticController") def test_list_widgets_handles_missing_directory(self, mock_controller_class, client): """List widgets should handle missing widgets directory.""" # Create a mock controller with non-existent static dir with tempfile.TemporaryDirectory() as tmpdir: mock_static_dir = Path(tmpdir) / "nonexistent" with patch.object( client.app.state if hasattr(client.app, 'state') else client.app, 'static_dir', mock_static_dir, create=True ): # The actual endpoint handles this case gracefully response = client.get("/static/widgets") # Should still return 200 with empty list or message assert response.status_code == 200 class TestGetWidget: """Test /static/widgets/{filename} endpoint.""" def test_get_widget_returns_404_for_nonexistent(self, client): """Get widget should return 404 for non-existent file.""" response = client.get("/static/widgets/nonexistent-widget.html") assert response.status_code == 404 def test_get_widget_returns_html_content_type(self, client): """Get widget should return HTML content type for existing file.""" # First check if any widgets exist list_response = client.get("/static/widgets") widgets = list_response.json().get("widgets", []) if widgets: # Test with first available widget widget_name = widgets[0]["name"] response = client.get(f"/static/widgets/{widget_name}") assert response.status_code == 200 assert "text/html" in response.headers.get("content-type", "") def test_get_widget_prevents_path_traversal(self, client): """Get widget should prevent path traversal attacks.""" # Attempt path traversal response = client.get("/static/widgets/../../../etc/passwd") # Should either return 404 or 403, not the actual file assert response.status_code in [400, 403, 404] def test_get_widget_includes_cache_headers(self, client): """Get widget should include no-cache headers.""" list_response = client.get("/static/widgets") widgets = list_response.json().get("widgets", []) if widgets: widget_name = widgets[0]["name"] response = client.get(f"/static/widgets/{widget_name}") if response.status_code == 200: assert "no-cache" in response.headers.get("cache-control", "") class TestStaticControllerInit: """Test StaticController initialization.""" def test_controller_has_static_dir(self): """Controller should have static directory configured.""" from src.controllers.static_controller import static_controller assert static_controller.static_dir is not None assert isinstance(static_controller.static_dir, Path) def test_controller_has_correct_prefix(self): """Controller should have /static prefix.""" from src.controllers.static_controller import static_controller assert static_controller.prefix == "/static" def test_controller_has_correct_tags(self): """Controller should have Static tag.""" from src.controllers.static_controller import static_controller assert "Static" in static_controller.tags