import textwrap from io import StringIO from unittest.mock import MagicMock, patch import streamlit as st from backend.permissions import require_access def make_session() -> MagicMock: return MagicMock() def patch_user(username: str): mock_user = MagicMock() mock_user.user_name = username return patch.object(st, "user", mock_user) SAMPLE_CSV = textwrap.dedent("""\ username,page RBOMBERG,CCPA RBOMBERG,FAN_LOOKUP JSMITH,CCPA """) def test_require_access_grants_when_user_has_page(): with ( patch_user("RBOMBERG"), patch("builtins.open", return_value=StringIO(SAMPLE_CSV)), ): require_access(make_session(), "CCPA") # should not raise or stop def test_require_access_blocks_when_user_not_in_csv(): with ( patch_user("UNKNOWN_USER"), patch("builtins.open", return_value=StringIO(SAMPLE_CSV)), ): with patch("streamlit.stop") as mock_stop: require_access(make_session(), "CCPA") mock_stop.assert_called_once() def test_require_access_blocks_when_user_lacks_page(): with ( patch_user("JSMITH"), patch("builtins.open", return_value=StringIO(SAMPLE_CSV)), ): with patch("streamlit.stop") as mock_stop: require_access(make_session(), "FAN_LOOKUP") mock_stop.assert_called_once() def test_require_access_grants_case_insensitive_username(): with ( patch_user("rbomberg"), patch("builtins.open", return_value=StringIO(SAMPLE_CSV)), ): require_access(make_session(), "CCPA") # should not raise or stop def test_require_access_grants_case_insensitive_page(): with ( patch_user("RBOMBERG"), patch("builtins.open", return_value=StringIO(SAMPLE_CSV)), ): require_access(make_session(), "ccpa") # should not raise or stop def test_require_access_handles_empty_user(): with patch_user(""), patch("builtins.open", return_value=StringIO(SAMPLE_CSV)): with patch("streamlit.stop") as mock_stop: require_access(make_session(), "CCPA") mock_stop.assert_called_once()