"""Tests for context variables module.""" import pytest from abacus_models.core.contexts import ( ctx_user_id, get_user_id, set_user_context, ) from abacus_models.core.errors import ERROR_CTX_USER_ID_NOT_SET class TestGetUserId: """Tests for get_user_id function.""" def test_get_user_id_returns_none_when_not_set_non_strict(self): """Test get_user_id returns None when context not set (non-strict mode).""" ctx_user_id.set(None) result = get_user_id(strict=False) assert result is None def test_get_user_id_returns_value_when_set(self): """Test get_user_id returns value when context is set.""" ctx_user_id.set('user_123') result = get_user_id(strict=False) assert result == 'user_123' def test_get_user_id_strict_raises_when_not_set(self): """Test get_user_id raises ValueError in strict mode when not set.""" ctx_user_id.set(None) with pytest.raises(ValueError, match=ERROR_CTX_USER_ID_NOT_SET): get_user_id(strict=True) def test_get_user_id_strict_returns_value_when_set(self): """Test get_user_id returns value in strict mode when set.""" ctx_user_id.set('user_456') result = get_user_id(strict=True) assert result == 'user_456' def test_get_user_id_default_uses_strict_setting(self): """Test get_user_id uses STRICT_CONTEXT_VALIDATION when strict not specified.""" # When strict=None, it uses STRICT_CONTEXT_VALIDATION constant # STRICT_CONTEXT_VALIDATION is True by default, so should raise ctx_user_id.set(None) with pytest.raises(ValueError, match=ERROR_CTX_USER_ID_NOT_SET): get_user_id() def test_get_user_id_default_returns_value_when_set(self): """Test get_user_id returns value with default strict setting.""" ctx_user_id.set('user_789') result = get_user_id() assert result == 'user_789' class TestSetUserContext: """Tests for set_user_context context manager.""" def test_set_user_context_sets_value(self): """Test set_user_context sets the user ID.""" ctx_user_id.set(None) with set_user_context('context_user'): assert ctx_user_id.get() == 'context_user' def test_set_user_context_restores_previous_value(self): """Test set_user_context restores previous value after exiting.""" ctx_user_id.set('original_user') with set_user_context('temp_user'): assert ctx_user_id.get() == 'temp_user' assert ctx_user_id.get() == 'original_user' def test_set_user_context_restores_none(self): """Test set_user_context restores None after exiting.""" ctx_user_id.set(None) with set_user_context('temp_user'): assert ctx_user_id.get() == 'temp_user' assert ctx_user_id.get() is None def test_set_user_context_nested(self): """Test nested set_user_context calls.""" ctx_user_id.set('user_1') with set_user_context('user_2'): assert ctx_user_id.get() == 'user_2' with set_user_context('user_3'): assert ctx_user_id.get() == 'user_3' assert ctx_user_id.get() == 'user_2' assert ctx_user_id.get() == 'user_1' def test_set_user_context_exception_still_restores(self): """Test set_user_context restores value even if exception occurs.""" ctx_user_id.set('original') with pytest.raises(RuntimeError): with set_user_context('temp'): assert ctx_user_id.get() == 'temp' raise RuntimeError('Test exception') assert ctx_user_id.get() == 'original' def test_set_user_context_allows_get_user_id(self): """Test set_user_context allows get_user_id to work.""" with set_user_context('active_user'): user_id = get_user_id(strict=True) assert user_id == 'active_user' class TestContextEdgeCases: """Tests for edge cases and boundary conditions.""" def test_set_user_context_with_empty_string(self): """Test set_user_context with empty string (should be treated as falsy).""" ctx_user_id.set(None) with set_user_context(''): # Empty string should be set as-is assert ctx_user_id.get() == '' # But get_user_id might treat it as falsy - document current behavior result = get_user_id(strict=False) assert result == '' assert ctx_user_id.get() is None def test_set_user_context_with_none_explicitly(self): """Test set_user_context with None explicitly.""" ctx_user_id.set('original') with set_user_context(None): assert ctx_user_id.get() is None result = get_user_id(strict=False) assert result is None assert ctx_user_id.get() == 'original' def test_set_user_context_with_numeric_user_id(self): """Test set_user_context with numeric user ID.""" ctx_user_id.set(None) with set_user_context(12345): assert ctx_user_id.get() == 12345 result = get_user_id(strict=False) assert result == 12345 assert ctx_user_id.get() is None def test_set_user_context_with_whitespace_only(self): """Test set_user_context with whitespace-only string.""" ctx_user_id.set(None) with set_user_context(' '): # Whitespace should be preserved assert ctx_user_id.get() == ' ' result = get_user_id(strict=False) assert result == ' ' assert ctx_user_id.get() is None def test_get_user_id_with_empty_string_strict_mode(self): """Test get_user_id with empty string in strict mode.""" ctx_user_id.set('') # Empty string is falsy, so strict mode might raise # Document current behavior result = get_user_id(strict=False) assert result == '' def test_nested_context_inner_exception_restores_outer(self): """Test that exception in inner context doesn't affect outer context restoration.""" ctx_user_id.set('original') with set_user_context('outer'): assert ctx_user_id.get() == 'outer' try: with set_user_context('inner'): assert ctx_user_id.get() == 'inner' raise ValueError('Inner exception') except ValueError: pass # Should still be in outer context assert ctx_user_id.get() == 'outer' # Should restore to original assert ctx_user_id.get() == 'original' def test_multiple_sequential_contexts(self): """Test multiple sequential (non-nested) context managers.""" ctx_user_id.set('start') with set_user_context('first'): assert ctx_user_id.get() == 'first' assert ctx_user_id.get() == 'start' with set_user_context('second'): assert ctx_user_id.get() == 'second' assert ctx_user_id.get() == 'start' with set_user_context('third'): assert ctx_user_id.get() == 'third' assert ctx_user_id.get() == 'start' def test_context_isolation_after_exception(self): """Test that context is properly isolated after an exception.""" ctx_user_id.set('initial') # First context with exception with pytest.raises(RuntimeError): with set_user_context('error_context'): raise RuntimeError('Test') assert ctx_user_id.get() == 'initial' # Second context should work normally with set_user_context('normal_context'): assert ctx_user_id.get() == 'normal_context' assert ctx_user_id.get() == 'initial'