@@ -55,38 +55,24 @@ class WindowSnapshot:
5555 panes : list [PaneSnapshot ] = dataclasses .field (default_factory = list )
5656
5757
58- def test_basic_functionality () -> None :
59- """Test that the base class is mutable but the snapshot is not."""
60- # Create a regular mutable pane
61- pane = BasePane (pane_id = "pane123" , width = 80 , height = 24 )
62-
63- # Should be mutable
64- pane .width = 100
65- assert pane .width == 100
66- pane .resize (120 , 30 )
67- assert pane .width == 120
68- assert pane .height == 30
69-
70- # Create a frozen snapshot with our decorator
71- snapshot = PaneSnapshot (
72- pane_id = pane .pane_id ,
73- width = pane .width ,
74- height = pane .height ,
75- captured_content = ["Line1" , "Line2" ],
58+ # Core behavior tests
59+ # ------------------
60+
61+ def test_snapshot_initialization () -> None :
62+ """Test proper initialization of fields in a frozen dataclass."""
63+ pane = PaneSnapshot (
64+ pane_id = "pane123" ,
65+ width = 80 ,
66+ height = 24 ,
67+ captured_content = ["Line1" , "Line2" ]
7668 )
77-
78- # Test type checking
79- assert isinstance (snapshot , PaneSnapshot )
80-
81- # Should maintain the inheritance relationship
82- assert isinstance (snapshot , BasePane )
83-
69+
8470 # Values should be correctly assigned
85- assert snapshot .pane_id == pane . pane_id
86- assert snapshot .width == pane . width
87- assert snapshot .height == pane . height
88- assert snapshot .captured_content == ["Line1" , "Line2" ]
89- assert isinstance (snapshot .created_at , datetime )
71+ assert pane .pane_id == "pane123"
72+ assert pane .width == 80
73+ assert pane .height == 24
74+ assert pane .captured_content == ["Line1" , "Line2" ]
75+ assert isinstance (pane .created_at , datetime )
9076
9177
9278def test_immutability () -> None :
@@ -96,33 +82,82 @@ def test_immutability() -> None:
9682 )
9783
9884 # Attempting to modify a field should raise AttributeError
99- with pytest .raises (AttributeError ) as excinfo :
85+ with pytest .raises (AttributeError , match = "immutable.*cannot modify field 'width'" ) :
10086 snapshot .width = 200 # type: ignore
101- assert "immutable" in str (excinfo .value )
10287
10388 # Attempting to add a new field should raise AttributeError
104- with pytest .raises (AttributeError ) as excinfo :
89+ with pytest .raises (AttributeError , match = "immutable.*cannot modify field 'new_field'" ) :
10590 snapshot .new_field = "value" # type: ignore
106- assert "immutable" in str (excinfo .value )
10791
10892 # Attempting to delete a field should raise AttributeError
109- with pytest .raises (AttributeError ) as excinfo :
93+ with pytest .raises (AttributeError , match = "immutable.*cannot delete field 'width'" ) :
11094 del snapshot .width
111- assert "immutable" in str (excinfo .value )
11295
11396 # Calling a method that tries to modify state should fail
114- # Use separate variable for the NotImplementedError exception info
115- with pytest .raises (NotImplementedError ) as resize_excinfo :
97+ with pytest .raises (NotImplementedError , match = "immutable" ):
11698 snapshot .resize (200 , 50 )
117- assert "immutable" in str (resize_excinfo .value )
11899
119100
120- def test_nested_references () -> None :
121- """Test that nested structures work properly."""
101+ def test_inheritance () -> None :
102+ """Test that frozen classes correctly inherit from mutable base classes."""
103+ # Create instances of both classes
104+ base_pane = BasePane (pane_id = "base1" , width = 80 , height = 24 )
105+ snapshot = PaneSnapshot (pane_id = "snap1" , width = 80 , height = 24 )
106+
107+ # Verify inheritance relationship
108+ assert isinstance (snapshot , BasePane )
109+ assert isinstance (snapshot , PaneSnapshot )
110+
111+ # Base class remains mutable
112+ base_pane .width = 100
113+ assert base_pane .width == 100
114+
115+ # Derived class is immutable
116+ with pytest .raises (AttributeError , match = "immutable" ):
117+ snapshot .width = 100
118+
119+
120+ # Edge case tests
121+ # --------------
122+
123+ def test_internal_attributes () -> None :
124+ """Test that internal attributes (starting with _) can be modified."""
125+ snapshot = PaneSnapshot (
126+ pane_id = "pane123" ,
127+ width = 80 ,
128+ height = 24 ,
129+ )
130+
131+ # Should be able to set internal attributes
132+ snapshot ._internal_cache = {"test" : "value" } # type: ignore
133+ assert snapshot ._internal_cache == {"test" : "value" } # type: ignore
134+
135+
136+ def test_nested_mutability_leak () -> None :
137+ """Test the known limitation that nested mutable fields can still be modified."""
138+ # Create a frozen dataclass with a mutable field
139+ snapshot = PaneSnapshot (
140+ pane_id = "pane123" ,
141+ width = 80 ,
142+ height = 24 ,
143+ captured_content = ["initial" ]
144+ )
145+
146+ # Can't reassign the field itself
147+ with pytest .raises (AttributeError , match = "immutable" ):
148+ snapshot .captured_content = ["new" ] # type: ignore
149+
150+ # But we can modify its contents (limitation of Python immutability)
151+ snapshot .captured_content .append ("mutated" )
152+ assert "mutated" in snapshot .captured_content
153+ assert snapshot .captured_content == ["initial" , "mutated" ]
154+
155+
156+ def test_bidirectional_references () -> None :
157+ """Test that nested structures with bidirectional references work properly."""
122158 # Create temporary panes (will be re-created with the window)
123159 temp_panes : list [PaneSnapshot ] = []
124160
125- # We need to create objects in a specific order to handle bi-directional references
126161 # First, create a window with an empty panes list
127162 window = WindowSnapshot (window_id = "win1" , name = "Test Window" , panes = temp_panes )
128163
@@ -131,8 +166,6 @@ def test_nested_references() -> None:
131166 pane2 = PaneSnapshot (pane_id = "pane2" , width = 80 , height = 24 , parent_window = window )
132167
133168 # Update the panes list before it gets frozen
134- # This is a bit of a hack, but that's how you'd need to handle bi-directional
135- # references with immutable objects in real code
136169 temp_panes .append (pane1 )
137170 temp_panes .append (pane2 )
138171
@@ -142,26 +175,11 @@ def test_nested_references() -> None:
142175 assert pane1 in window .panes
143176 assert pane2 in window .panes
144177
145- # Can't test by trying to reassign since we'll hit a type error first
146- # But we can still modify the contents of lists (limitation of Python)
147- # Let's verify this limitation exists:
178+ # Can still modify the contents of mutable collections
148179 pane3 = PaneSnapshot (pane_id = "pane3" , width = 100 , height = 30 )
149180 window .panes .append (pane3 )
150181 assert len (window .panes ) == 3 # Successfully modified
151182
152183 # This is a "leaky abstraction" in Python's immutability model
153184 # In real code, consider using immutable collections (tuple, frozenset)
154185 # or deep freezing containers
155-
156-
157- def test_internal_attributes () -> None :
158- """Test that internal attributes (starting with _) can be modified."""
159- snapshot = PaneSnapshot (
160- pane_id = "pane123" ,
161- width = 80 ,
162- height = 24 ,
163- )
164-
165- # Should be able to set internal attributes
166- snapshot ._internal_cache = {"test" : "value" } # type: ignore
167- assert snapshot ._internal_cache == {"test" : "value" } # type: ignore
0 commit comments