@@ -43,36 +43,75 @@ def test_generation_cache_context():
4343
4444
4545def test_cached_proto_context ():
46+ # A dummy object to act as a visited message
47+ class MockMessage :
48+ pass
49+
4650 class Foo :
4751 def __init__ (self ):
4852 self .call_count = 0
4953
54+ # We define a signature that matches the real Proto.with_context
55+ # to ensure arguments are propagated correctly.
5056 @cache .cached_proto_context
51- def bar (self , * , collisions , other = None ):
57+ def with_context (self , collisions , * , skip_fields = False , visited_messages = None ):
5258 self .call_count += 1
53- return f"baz -{ self .call_count } "
59+ return f"val -{ self .call_count } "
5460
5561 foo = Foo ()
62+ msg_a = MockMessage ()
63+ msg_b = MockMessage ()
5664
57- # Without context, no caching
58- assert foo .bar (collisions = {"a" , "b" }) == "baz-1"
59- assert foo .bar (collisions = {"a" , "b" }) == "baz-2"
65+ # 1. Test Bypass (No Context)
66+ # The cache is not active, so every call increments the counter.
67+ assert foo .with_context (collisions = {"a" }) == "val-1"
68+ assert foo .with_context (collisions = {"a" }) == "val-2"
6069
61- # With context, caching works
70+ # 2. Test Context Activation
6271 with cache .generation_cache_context ():
63- assert foo .bar (collisions = {"a" , "b" }) == "baz-3"
64- assert foo .bar (collisions = {"a" , "b" }) == "baz-3"
72+ # Reset counter to make tracking easier
73+ foo .call_count = 0
74+
75+ # A. Basic Cache Hit
76+ assert foo .with_context ({"a" }) == "val-1"
77+ assert foo .with_context ({"a" }) == "val-1" # Hit
78+ assert foo .call_count == 1
79+
80+ # B. Collision Difference
81+ # Changing collisions creates a new key
82+ assert foo .with_context ({"b" }) == "val-2"
83+ assert foo .call_count == 2
84+
85+ # C. skip_fields Difference (The Critical Fix)
86+ # Verify that skip_fields=True is cached separately from the default (False).
87+ # This prevents the "Husk" object from poisoning the "Full" object cache.
88+ assert foo .with_context ({"a" }, skip_fields = True ) == "val-3"
89+ assert foo .with_context ({"a" }, skip_fields = True ) == "val-3" # Hit
6590 assert foo .call_count == 3
66-
67- # Different collisions, different cache entry
68- assert foo .bar (collisions = {"c" }) == "baz-4"
69- assert foo .bar (collisions = {"c" }) == "baz-4"
91+
92+ # Verify the original (skip_fields=False) is still accessible
93+ assert foo .with_context ({"a" }) == "val-1" # Hit (Still 1)
94+
95+ # D. visited_messages Difference
96+ # Verify that sets of objects are correctly distinguished.
97+
98+ # Call with msg_a
99+ assert foo .with_context ({"a" }, visited_messages = {msg_a }) == "val-4"
100+ assert foo .with_context ({"a" }, visited_messages = {msg_a }) == "val-4" # Hit
70101 assert foo .call_count == 4
71102
72- # Same collisions again, still cached
73- assert foo .bar (collisions = {"a" , "b" }) == "baz-3"
74- assert foo .call_count == 4
103+ # Call with msg_b (Should be a Miss)
104+ assert foo .with_context ({"a" }, visited_messages = {msg_b }) == "val-5"
105+ assert foo .call_count == 5
106+
107+ # E. Set Stability
108+ # Verify that the order of items in the set doesn't matter (sets are unordered).
109+ # {a, b} should cache-hit with {b, a}
110+ assert foo .with_context ({"a" }, visited_messages = {msg_a , msg_b }) == "val-6"
111+ assert foo .with_context ({"a" }, visited_messages = {msg_b , msg_a }) == "val-6" # Hit
112+ assert foo .call_count == 6
75113
76- # Context cleared
114+ # 3. Context Cleared
115+ # Everything should be forgotten now.
77116 assert cache .generation_cache .get () is None
78- assert foo .bar ( collisions = {"a" , "b" }) == "baz-5 "
117+ assert foo .with_context ( {"a" }) == "val-7 "
0 commit comments