@@ -769,17 +769,19 @@ def test_anon_fix_permissions_command():
769769 output = str (mock_stdout .write .call_args_list )
770770 assert "No roles found" in output or "no roles" in output .lower ()
771771
772- # Test with --all option when roles exist
772+ # Test with --all option when roles exist - test both success paths
773773 MaskedRole .objects .create (role_name = "test_role_1" )
774774 MaskedRole .objects .create (role_name = "test_role_2" )
775+ MaskedRole .objects .create (role_name = "test_role_3" )
775776
776777 with patch ("django_postgres_anon.management.commands.anon_fix_permissions.create_masked_role" ) as mock_create :
777- mock_create .return_value = True
778+ # First two succeed, third fails - this covers the success_count increment
779+ mock_create .side_effect = [True , True , False ]
778780 with patch ("sys.stdout" , new_callable = MagicMock ) as mock_stdout :
779781 call_command ("anon_fix_permissions" , "--all" )
780- assert mock_create .call_count == 2
781- mock_create . assert_any_call ( "test_role_1" )
782- mock_create . assert_any_call ( "test_role_2" )
782+ assert mock_create .call_count == 3
783+ output = str ( mock_stdout . write . call_args_list )
784+ assert "Fixed permissions for 2/3 roles" in output
783785
784786 # Test with failed permission fix
785787 with patch ("django_postgres_anon.management.commands.anon_fix_permissions.create_masked_role" ) as mock_create :
@@ -921,3 +923,61 @@ def mock_execute_side_effect(sql, params=None):
921923 # Test with auto_create=False
922924 result = switch_to_role ("test_role" , auto_create = False )
923925 assert result is False
926+
927+
928+ @pytest .mark .django_db
929+ def test_context_manager_coverage ():
930+ """Test uncovered lines in context managers"""
931+ from unittest .mock import patch
932+
933+ from django_postgres_anon .context_managers import _update_masked_role_record
934+ from django_postgres_anon .models import MaskedRole
935+
936+ # Test early return when role already exists and is applied
937+ MaskedRole .objects .create (role_name = "test_role" , is_applied = True )
938+ _update_masked_role_record ("test_role" ) # Should return early without creating new record
939+ assert MaskedRole .objects .filter (role_name = "test_role" ).count () == 1
940+
941+ # Test exception handling in _update_masked_role_record
942+ with patch ("django_postgres_anon.context_managers.logger.warning" ) as mock_warning :
943+ with patch ("django_postgres_anon.models.MaskedRole.objects.get_or_create" ) as mock_create :
944+ mock_create .side_effect = Exception ("Database error" )
945+
946+ # Should not raise exception, just log warning
947+ _update_masked_role_record ("error_role" )
948+ mock_warning .assert_called_once ()
949+
950+ # Cleanup
951+ MaskedRole .objects .all ().delete ()
952+
953+
954+ @pytest .mark .django_db
955+ def test_utils_uncovered_lines ():
956+ """Test uncovered lines in utils.py"""
957+ from unittest .mock import MagicMock , patch
958+
959+ from django_postgres_anon .utils import create_masked_role , switch_to_role
960+
961+ # Test inheritance path when base role exists
962+ with patch ("django.db.connection.cursor" ) as mock_cursor_ctx :
963+ mock_cursor = MagicMock ()
964+ mock_cursor_ctx .return_value .__enter__ .return_value = mock_cursor
965+
966+ # Set up fetchone to return None for test_role check, then True for base_role check
967+ # Need multiple calls: role exists check, inherit_from role check, table checks...
968+ mock_cursor .fetchone .side_effect = [None , True , None , None , None , None , None ]
969+ mock_cursor .fetchall .return_value = [] # No tables
970+
971+ result = create_masked_role ("test_role" , inherit_from = "base_role" )
972+ assert result is True
973+
974+ # Test masked role search path setting
975+ with patch ("django.db.connection.cursor" ) as mock_cursor_ctx :
976+ mock_cursor = MagicMock ()
977+ mock_cursor_ctx .return_value .__enter__ .return_value = mock_cursor
978+
979+ result = switch_to_role ("masked_reader" , auto_create = False )
980+ # Should set search_path because role name contains "mask"
981+ calls = mock_cursor .execute .call_args_list
982+ search_path_calls = [call for call in calls if "SET search_path" in str (call )]
983+ assert len (search_path_calls ) > 0
0 commit comments