1+ """Test the deterministic patching functionality in pytest_plugin.py.
2+
3+ This test verifies that all sources of randomness and non-determinism are properly
4+ mocked/patched to ensure reproducible test execution for CodeFlash optimization.
5+
6+ Key functionality tested:
7+ - time.time() returns fixed timestamp (1609459200.0 = 2021-01-01 00:00:00 UTC)
8+ - time.perf_counter() returns incrementing values (maintaining relative timing)
9+ - uuid.uuid4() and uuid.uuid1() return fixed UUID (12345678-1234-5678-9abc-123456789012)
10+ - random.random() returns fixed value (0.123456789)
11+ - random module is seeded deterministically (seed=42)
12+ - os.urandom() returns fixed bytes (0x42 repeated)
13+ - numpy.random is seeded if available (seed=42)
14+ - Performance characteristics are maintained (original functions called internally)
15+ - datetime mock functions are properly stored in builtins
16+ - All patches work consistently across multiple calls
17+ - Integration with real optimization scenarios
18+
19+ This ensures that CodeFlash optimization correctness checks will pass by eliminating
20+ all sources of non-determinism that could cause object comparison failures.
21+ """
22+
23+ import datetime
24+ import os
25+ import random
26+ import sys
27+ import time
28+ import uuid
29+ from unittest .mock import patch
30+
31+ import pytest
32+
33+
34+ class TestDeterministicPatches :
35+ """Test suite for deterministic patching functionality."""
36+
37+ @pytest .fixture (autouse = True )
38+ def setup_and_teardown (self ):
39+ """Setup and teardown for each test."""
40+ # Import plugin to apply patches (patches are applied at module level)
41+ import codeflash .verification .pytest_plugin # noqa: F401
42+
43+ # Note: Original functions are already patched by the time we get here
44+ # This is expected behavior since patches are applied at module import
45+
46+ yield
47+
48+ # Note: In practice, these patches should remain for the entire test session
49+
50+ def test_time_time_deterministic (self ):
51+ """Test that time.time() returns a fixed deterministic value."""
52+ expected_timestamp = 1609459200.0 # 2021-01-01 00:00:00 UTC
53+
54+ # Call multiple times and verify consistent results
55+ result1 = time .time ()
56+ result2 = time .time ()
57+ result3 = time .time ()
58+
59+ assert result1 == expected_timestamp
60+ assert result2 == expected_timestamp
61+ assert result3 == expected_timestamp
62+ assert result1 == result2 == result3
63+
64+ def test_perf_counter_incremental (self ):
65+ """Test that time.perf_counter() returns incrementing values."""
66+ # Call multiple times and verify incrementing behavior
67+ result1 = time .perf_counter ()
68+ result2 = time .perf_counter ()
69+ result3 = time .perf_counter ()
70+
71+ # Verify they're different and incrementing by approximately 0.001
72+ assert result1 < result2 < result3
73+ assert abs ((result2 - result1 ) - 0.001 ) < 1e-6 # Use reasonable epsilon for float comparison
74+ assert abs ((result3 - result2 ) - 0.001 ) < 1e-6
75+
76+ def test_uuid4_deterministic (self ):
77+ """Test that uuid.uuid4() returns a fixed deterministic UUID."""
78+ expected_uuid = uuid .UUID ('12345678-1234-5678-9abc-123456789012' )
79+
80+ # Call multiple times and verify consistent results
81+ result1 = uuid .uuid4 ()
82+ result2 = uuid .uuid4 ()
83+ result3 = uuid .uuid4 ()
84+
85+ assert result1 == expected_uuid
86+ assert result2 == expected_uuid
87+ assert result3 == expected_uuid
88+ assert result1 == result2 == result3
89+ assert isinstance (result1 , uuid .UUID )
90+
91+ def test_uuid1_deterministic (self ):
92+ """Test that uuid.uuid1() returns a fixed deterministic UUID."""
93+ expected_uuid = uuid .UUID ('12345678-1234-5678-9abc-123456789012' )
94+
95+ # Call multiple times with different parameters
96+ result1 = uuid .uuid1 ()
97+ result2 = uuid .uuid1 (node = 123456 )
98+ result3 = uuid .uuid1 (clock_seq = 789 )
99+
100+ assert result1 == expected_uuid
101+ assert result2 == expected_uuid
102+ assert result3 == expected_uuid
103+ assert isinstance (result1 , uuid .UUID )
104+
105+ def test_random_random_deterministic (self ):
106+ """Test that random.random() returns a fixed deterministic value."""
107+ expected_value = 0.123456789
108+
109+ # Call multiple times and verify consistent results
110+ result1 = random .random ()
111+ result2 = random .random ()
112+ result3 = random .random ()
113+
114+ assert result1 == expected_value
115+ assert result2 == expected_value
116+ assert result3 == expected_value
117+ assert 0.0 <= result1 <= 1.0 # Should still be a valid random float
118+
119+ def test_random_seed_deterministic (self ):
120+ """Test that random module is seeded deterministically."""
121+ # The plugin should have already seeded with 42
122+ # Test other random functions for consistency
123+
124+ # Note: random.random() is patched to always return the same value
125+ # So we test that the random module behaves deterministically
126+ # by testing that random.seed() affects other functions consistently
127+
128+ # First, test that our patched random.random always returns the same value
129+ assert random .random () == 0.123456789
130+ assert random .random () == 0.123456789
131+
132+ # Test that seeding affects other random functions consistently
133+ random .seed (42 )
134+ result1_int = random .randint (1 , 100 )
135+ result1_choice = random .choice ([1 , 2 , 3 , 4 , 5 ])
136+
137+ # Re-seed and get same results
138+ random .seed (42 )
139+ result2_int = random .randint (1 , 100 )
140+ result2_choice = random .choice ([1 , 2 , 3 , 4 , 5 ])
141+
142+ assert result1_int == result2_int
143+ assert result1_choice == result2_choice
144+
145+ def test_os_urandom_deterministic (self ):
146+ """Test that os.urandom() returns deterministic bytes."""
147+ # Test various byte lengths
148+ for n in [1 , 8 , 16 , 32 ]:
149+ result1 = os .urandom (n )
150+ result2 = os .urandom (n )
151+
152+ # Should return fixed bytes (0x42 repeated)
153+ expected = b'\x42 ' * n
154+ assert result1 == expected
155+ assert result2 == expected
156+ assert len (result1 ) == n
157+ assert isinstance (result1 , bytes )
158+
159+ def test_numpy_seeding (self ):
160+ """Test that numpy.random is seeded if available."""
161+ try :
162+ import numpy as np
163+
164+ # Generate some random numbers
165+ result1 = np .random .random (5 )
166+
167+ # Re-seed and generate again
168+ np .random .seed (42 )
169+ result2 = np .random .random (5 )
170+
171+ # Should be deterministic due to seeding
172+ assert np .array_equal (result1 , result2 )
173+
174+ except ImportError :
175+ # numpy not available, test should pass
176+ pytest .skip ("NumPy not available" )
177+
178+ def test_performance_characteristics_maintained (self ):
179+ """Test that performance characteristics are maintained."""
180+ # Test that they still execute quickly (performance check)
181+ start = time .perf_counter ()
182+ for _ in range (1000 ):
183+ time .time ()
184+ uuid .uuid4 ()
185+ random .random ()
186+ end = time .perf_counter ()
187+
188+ # Should complete quickly (less than 1 second for 1000 calls)
189+ duration = end - start
190+ assert duration < 1.0 , f"Performance degraded: { duration } s for 1000 calls"
191+
192+ def test_builtins_datetime_mocks_stored (self ):
193+ """Test that datetime mock functions are stored in builtins."""
194+ import builtins
195+
196+ # Verify that the mock functions are stored
197+ assert hasattr (builtins , '_original_datetime_now' )
198+ assert hasattr (builtins , '_original_datetime_utcnow' )
199+ assert hasattr (builtins , '_mock_datetime_now' )
200+ assert hasattr (builtins , '_mock_datetime_utcnow' )
201+
202+ # Test that the mock functions work
203+ mock_now = builtins ._mock_datetime_now
204+ mock_utcnow = builtins ._mock_datetime_utcnow
205+
206+ result1 = mock_now ()
207+ result2 = mock_utcnow ()
208+
209+ expected_dt = datetime .datetime (2021 , 1 , 1 , 0 , 0 , 0 , tzinfo = datetime .timezone .utc )
210+ assert result1 == expected_dt
211+ assert result2 == expected_dt
212+
213+ def test_consistency_across_multiple_calls (self ):
214+ """Test that all patched functions remain consistent across many calls."""
215+ # Store initial results
216+ initial_time = time .time ()
217+ initial_uuid = uuid .uuid4 ()
218+ initial_random = random .random ()
219+ initial_urandom = os .urandom (8 )
220+
221+ # Call functions many times (but not perf_counter since it increments)
222+ for _ in range (5 ):
223+ assert time .time () == initial_time
224+ assert uuid .uuid4 () == initial_uuid
225+ assert random .random () == initial_random
226+ assert os .urandom (8 ) == initial_urandom
227+
228+ def test_perf_counter_state_management (self ):
229+ """Test that perf_counter maintains its own internal state correctly."""
230+ # Get a baseline
231+ base = time .perf_counter ()
232+
233+ # Call several times and verify incrementing
234+ results = [time .perf_counter () for _ in range (5 )]
235+
236+ # Each call should increment by approximately 0.001
237+ for i , result in enumerate (results ):
238+ expected = base + ((i + 1 ) * 0.001 )
239+ assert abs (result - expected ) < 1e-6 , f"Expected { expected } , got { result } "
240+
241+ def test_different_uuid_functions_same_result (self ):
242+ """Test that both uuid4 and uuid1 return the same deterministic UUID."""
243+ uuid4_result = uuid .uuid4 ()
244+ uuid1_result = uuid .uuid1 ()
245+
246+ # Both should return the same fixed UUID
247+ assert uuid4_result == uuid1_result
248+ assert str (uuid4_result ) == '12345678-1234-5678-9abc-123456789012'
249+
250+ def test_patches_applied_at_module_level (self ):
251+ """Test that patches are applied when the module is imported."""
252+ # Test that functions return expected deterministic values
253+ # (This indirectly confirms they are patched)
254+ assert time .time () == 1609459200.0
255+ assert uuid .uuid4 () == uuid .UUID ('12345678-1234-5678-9abc-123456789012' )
256+ assert random .random () == 0.123456789
257+
258+ # Test that function names indicate they are mock functions
259+ assert 'mock' in time .time .__name__
260+ assert 'mock' in uuid .uuid4 .__name__
261+ assert 'mock' in random .random .__name__
262+
263+ def test_edge_cases (self ):
264+ """Test edge cases and boundary conditions."""
265+ # Test uuid functions with edge case parameters
266+ assert uuid .uuid1 (node = 0 ) == uuid .UUID ('12345678-1234-5678-9abc-123456789012' )
267+ assert uuid .uuid1 (clock_seq = 0 ) == uuid .UUID ('12345678-1234-5678-9abc-123456789012' )
268+
269+ # Test urandom with edge cases
270+ assert os .urandom (0 ) == b''
271+ assert os .urandom (1 ) == b'\x42 '
272+
273+ # Test datetime mock with timezone
274+ import builtins
275+ mock_now = builtins ._mock_datetime_now
276+
277+ # Test with different timezone
278+ utc_tz = datetime .timezone .utc
279+ result_with_tz = mock_now (utc_tz )
280+ expected_with_tz = datetime .datetime (2021 , 1 , 1 , 0 , 0 , 0 , tzinfo = utc_tz )
281+ assert result_with_tz == expected_with_tz
282+
283+ def test_integration_with_actual_optimization_scenario (self ):
284+ """Test the patching in a scenario similar to actual optimization."""
285+ # Simulate what happens during optimization - multiple function calls
286+ # that would normally produce different results but should now be deterministic
287+
288+ class MockOptimizedFunction :
289+ """Mock function that uses various sources of randomness."""
290+
291+ def __init__ (self ):
292+ self .id = uuid .uuid4 ()
293+ self .created_at = time .time ()
294+ self .random_factor = random .random ()
295+ self .random_bytes = os .urandom (4 )
296+
297+ def execute (self ):
298+ execution_time = time .perf_counter ()
299+ random_choice = random .randint (1 , 100 )
300+ return {
301+ 'id' : self .id ,
302+ 'created_at' : self .created_at ,
303+ 'execution_time' : execution_time ,
304+ 'random_factor' : self .random_factor ,
305+ 'random_choice' : random_choice ,
306+ 'random_bytes' : self .random_bytes
307+ }
308+
309+ # Create two instances and execute them
310+ func1 = MockOptimizedFunction ()
311+ func2 = MockOptimizedFunction ()
312+
313+ result1 = func1 .execute ()
314+ result2 = func2 .execute ()
315+
316+ # All values should be identical due to deterministic patching
317+ assert result1 ['id' ] == result2 ['id' ]
318+ assert result1 ['created_at' ] == result2 ['created_at' ]
319+ assert result1 ['random_factor' ] == result2 ['random_factor' ]
320+ assert result1 ['random_bytes' ] == result2 ['random_bytes' ]
321+
322+ # Only execution_time should be different (incremental)
323+ assert result1 ['execution_time' ] != result2 ['execution_time' ]
324+ assert result2 ['execution_time' ] > result1 ['execution_time' ]
325+
326+
327+ if __name__ == '__main__' :
328+ pytest .main ([__file__ , '-v' ])
0 commit comments