from dataclasses import dataclass, fields, make_dataclass from src.backend.utils import classes @dataclass class MockClass: """Mock class for testing attribute access tracking.""" attr1: str attr2: str attr3: str class TestAttributeAccessTracker: _class = classes.AccessTracker def setup_method(self): self.mock_instance = MockClass("a", "b", "c") self.tracked = self._class(self.mock_instance) self.field_names = [field.name for field in fields(MockClass)] def test_track_getattr(self): """Test tracking attribute access using getattr.""" expected = set() for i, field_name in enumerate(self.field_names): getattr(self.tracked, field_name) # Access via tracker expected.add(field_name) accessed_field_names = set(self.tracked.attrs_accessed.keys()) & set( self.field_names ) assert len(accessed_field_names) == i + 1 assert accessed_field_names == expected def test_track_dot_notation(self): """Test tracking attribute access using dot notation.""" # Create a dynamic dataclass for this test to avoid dependency on MockClass dynamic_instance = make_dataclass("DynamicMockClass", [("attr1", str)])("a") dynamic_tracked = self._class(dynamic_instance) # Access using dot notation _ = dynamic_tracked.attr1 expected = {"attr1"} accessed_field_names = set(dynamic_tracked.attrs_accessed.keys()) assert accessed_field_names == expected def test_target_direct_access_should_not_track(self): """Test that accessing attributes directly from the target object does not track. """ mock_value = "a" # Create a dynamic dataclass for this test to avoid dependency on MockClass dynamic_instance = make_dataclass("DynamicMockClass", [("attr1", str)])( mock_value ) dynamic_tracked = self._class(dynamic_instance) # Access using dot notation value = dynamic_tracked.target.attr1 accessed_field_names = list(dynamic_tracked.attrs_accessed.keys()) assert value == mock_value assert accessed_field_names == []