@@ -28,22 +28,26 @@ def test_compute_file_hash(mock_file_open, mock_stat, mock_sha256, mock_makedirs
28
28
mock_sha256 .return_value = mock_hasher
29
29
mock_hasher .hexdigest .return_value = "test_hash_digest"
30
30
31
- # Create file processor
32
- vector_search = MagicMock ()
33
- processor = FileProcessor (
34
- vector_search = vector_search ,
35
- project_path = "/test/project" ,
36
- ignore_patterns = [],
37
- data_dir = "/test/data" ,
38
- )
39
-
40
- # Test hash computation
41
- result = processor .compute_file_hash ("/test/file.txt" )
42
-
43
- # Verify
44
- mock_file_open .assert_called_once_with ("/test/file.txt" , "rb" )
45
- assert mock_hasher .update .called
46
- assert result == "test_hash_digest"
31
+ with patch .object (FileProcessor , 'load_state' ) as mock_load_state :
32
+ # Create file processor with mocked load_state
33
+ vector_search = MagicMock ()
34
+ processor = FileProcessor (
35
+ vector_search = vector_search ,
36
+ project_path = "/test/project" ,
37
+ ignore_patterns = [],
38
+ data_dir = "/test/data" ,
39
+ )
40
+
41
+ # Reset the mock_file_open to clear any calls from load_state
42
+ mock_file_open .reset_mock ()
43
+
44
+ # Test hash computation
45
+ result = processor .compute_file_hash ("/test/file.txt" )
46
+
47
+ # Verify
48
+ mock_file_open .assert_called_once_with ("/test/file.txt" , "rb" )
49
+ assert mock_hasher .update .called
50
+ assert result == "test_hash_digest"
47
51
48
52
49
53
@patch ("src.file_processor.os.stat" )
@@ -56,17 +60,18 @@ def test_get_file_stats(mock_file_open, mock_stat, mock_makedirs):
56
60
mock_stat_result .st_size = 1024
57
61
mock_stat .return_value = mock_stat_result
58
62
59
- # Create file processor
60
- vector_search = MagicMock ()
61
- processor = FileProcessor (
62
- vector_search = vector_search ,
63
- project_path = "/test/project" ,
64
- ignore_patterns = [],
65
- data_dir = "/test/data" ,
66
- )
67
-
68
- # Mock hash computation
69
- processor .compute_file_hash = MagicMock (return_value = "test_hash_digest" )
63
+ with patch .object (FileProcessor , 'load_state' ):
64
+ # Create file processor
65
+ vector_search = MagicMock ()
66
+ processor = FileProcessor (
67
+ vector_search = vector_search ,
68
+ project_path = "/test/project" ,
69
+ ignore_patterns = [],
70
+ data_dir = "/test/data" ,
71
+ )
72
+
73
+ # Mock hash computation
74
+ processor .compute_file_hash = MagicMock (return_value = "test_hash_digest" )
70
75
71
76
# Test getting file stats
72
77
mtime , size , file_hash = processor .get_file_stats ("/test/file.txt" )
@@ -93,16 +98,17 @@ def test_file_needs_update(mock_join, mock_isfile, mock_makedirs):
93
98
"""Test file change detection logic"""
94
99
# Set up mocks
95
100
mock_isfile .return_value = True
96
- mock_join .side_effect = lambda * args : "/" .join (args )
97
-
98
- # Create file processor
99
- vector_search = MagicMock ()
100
- processor = FileProcessor (
101
- vector_search = vector_search ,
102
- project_path = "/test/project" ,
103
- ignore_patterns = [],
104
- data_dir = "/test/data" ,
105
- )
101
+ mock_join .side_effect = lambda * args : "/" .join (str (arg ) for arg in args )
102
+
103
+ with patch .object (FileProcessor , 'load_state' ):
104
+ # Create file processor
105
+ vector_search = MagicMock ()
106
+ processor = FileProcessor (
107
+ vector_search = vector_search ,
108
+ project_path = "/test/project" ,
109
+ ignore_patterns = [],
110
+ data_dir = "/test/data" ,
111
+ )
106
112
107
113
# Mock file stats
108
114
processor .get_file_stats = MagicMock (return_value = (12345.6789 , 1024 , "test_hash_digest" ))
@@ -144,16 +150,17 @@ def test_get_modified_files(mock_relpath, mock_walk, mock_makedirs):
144
150
("/test/project" , ["src" ], ["README.md" ]),
145
151
("/test/project/src" , [], ["main.py" , "utils.py" , "config.py" ]),
146
152
]
147
- mock_relpath .side_effect = lambda path , start : path .replace (start + "/" , "" )
148
-
149
- # Create file processor
150
- vector_search = MagicMock ()
151
- processor = FileProcessor (
152
- vector_search = vector_search ,
153
- project_path = "/test/project" ,
154
- ignore_patterns = [],
155
- data_dir = "/test/data" ,
156
- )
153
+ mock_relpath .side_effect = lambda path , start : path .replace (str (start ) + "/" , "" )
154
+
155
+ with patch .object (FileProcessor , 'load_state' ):
156
+ # Create file processor
157
+ vector_search = MagicMock ()
158
+ processor = FileProcessor (
159
+ vector_search = vector_search ,
160
+ project_path = "/test/project" ,
161
+ ignore_patterns = [],
162
+ data_dir = "/test/data" ,
163
+ )
157
164
158
165
# Set up initial state with some previously indexed files
159
166
processor .last_indexed_files = {
@@ -190,14 +197,15 @@ def mock_needs_update(rel_path):
190
197
@patch ("builtins.open" , new_callable = mock_open )
191
198
def test_save_state (mock_file_open , mock_json_dump , mock_makedirs ):
192
199
"""Test state saving"""
193
- # Create file processor
194
- vector_search = MagicMock ()
195
- processor = FileProcessor (
196
- vector_search = vector_search ,
197
- project_path = "/test/project" ,
198
- ignore_patterns = [],
199
- data_dir = "/test/data" ,
200
- )
200
+ with patch .object (FileProcessor , 'load_state' ):
201
+ # Create file processor
202
+ vector_search = MagicMock ()
203
+ processor = FileProcessor (
204
+ vector_search = vector_search ,
205
+ project_path = "/test/project" ,
206
+ ignore_patterns = [],
207
+ data_dir = "/test/data" ,
208
+ )
201
209
202
210
# Set up state
203
211
processor .last_indexed_files = {"file1.py" , "file2.py" }
@@ -209,8 +217,11 @@ def test_save_state(mock_file_open, mock_json_dump, mock_makedirs):
209
217
# Save state
210
218
processor .save_state ()
211
219
212
- # Verify
213
- mock_file_open .assert_called_once_with ("/test/data/file_processor_state.json" , "w" )
220
+ # Verify - use any() to check for the file path since it might be a PosixPath object
221
+ assert any (
222
+ call .args [0 ] == "/test/data/file_processor_state.json" or str (call .args [0 ]) == "/test/data/file_processor_state.json"
223
+ for call in mock_file_open .call_args_list
224
+ )
214
225
mock_json_dump .assert_called_once ()
215
226
216
227
# Check that we're saving the right data
@@ -223,44 +234,31 @@ def test_save_state(mock_file_open, mock_json_dump, mock_makedirs):
223
234
assert saved_data ["file_metadata" ] == processor .file_metadata
224
235
225
236
226
- @patch ("json.load" )
227
- @patch ("os.path.exists" )
228
- @patch ("builtins.open" , new_callable = mock_open )
229
- def test_load_state (mock_file_open , mock_exists , mock_json_load , mock_makedirs ):
237
+ def test_load_state (mock_makedirs ):
230
238
"""Test state loading"""
231
- # Set up mocks
232
- mock_exists .return_value = True
233
- mock_json_load .return_value = {
234
- "indexed_files" : ["file1.py" , "file2.py" ],
235
- "file_metadata" : {
239
+ # Mock Path.exists() to return True
240
+ with patch ("pathlib.Path.exists" , return_value = True ), \
241
+ patch ("builtins.open" , mock_open (read_data = '{"indexed_files": ["file1.py", "file2.py"], "file_metadata": {"file1.py": {"mtime": 123.456, "size": 100, "hash": "hash1"}, "file2.py": {"mtime": 789.012, "size": 200, "hash": "hash2"}}, "last_updated": 1234567890}' )):
242
+
243
+ # First patch load_state to avoid loading during init
244
+ with patch .object (FileProcessor , 'load_state' ):
245
+ vector_search = MagicMock ()
246
+ processor = FileProcessor (
247
+ vector_search = vector_search ,
248
+ project_path = "/test/project" ,
249
+ ignore_patterns = [],
250
+ data_dir = "/test/data" ,
251
+ )
252
+
253
+ # Then manually call load_state (the real one)
254
+ processor .load_state ()
255
+
256
+ # Check that we loaded the right data
257
+ assert processor .last_indexed_files == {"file1.py" , "file2.py" }
258
+ assert processor .file_metadata == {
236
259
"file1.py" : {"mtime" : 123.456 , "size" : 100 , "hash" : "hash1" },
237
260
"file2.py" : {"mtime" : 789.012 , "size" : 200 , "hash" : "hash2" },
238
- },
239
- "last_updated" : 1234567890 ,
240
- }
241
-
242
- # Create file processor
243
- vector_search = MagicMock ()
244
- processor = FileProcessor (
245
- vector_search = vector_search ,
246
- project_path = "/test/project" ,
247
- ignore_patterns = [],
248
- data_dir = "/test/data" ,
249
- )
250
-
251
- # Explicitly call load_state (normally called by __init__)
252
- processor .load_state ()
253
-
254
- # Verify
255
- mock_file_open .assert_called_once_with ("/test/data/file_processor_state.json" , "r" )
256
- mock_json_load .assert_called_once ()
257
-
258
- # Check that we loaded the right data
259
- assert processor .last_indexed_files == {"file1.py" , "file2.py" }
260
- assert processor .file_metadata == {
261
- "file1.py" : {"mtime" : 123.456 , "size" : 100 , "hash" : "hash1" },
262
- "file2.py" : {"mtime" : 789.012 , "size" : 200 , "hash" : "hash2" },
263
- }
261
+ }
264
262
265
263
266
264
@patch ("src.file_processor.ThreadPoolExecutor" )
@@ -272,15 +270,19 @@ def test_incremental_indexing(mock_thread_pool, mock_makedirs):
272
270
mock_thread_pool .return_value .__enter__ .return_value = executor
273
271
executor .map .return_value = [True , True , False ] # 2 successful, 1 failed
274
272
275
- # Create file processor with modified_files method mocked
276
- processor = FileProcessor (
277
- vector_search = vector_search ,
278
- project_path = "/test/project" ,
279
- ignore_patterns = [],
280
- data_dir = "/test/data" ,
281
- )
273
+ with patch .object (FileProcessor , 'load_state' ):
274
+ # Create file processor
275
+ processor = FileProcessor (
276
+ vector_search = vector_search ,
277
+ project_path = "/test/project" ,
278
+ ignore_patterns = [],
279
+ data_dir = "/test/data" ,
280
+ )
281
+
282
+ # Create a replacement set of test files that exists
283
+ processor .last_indexed_files = {"file1.py" , "file2.py" , "file3.py" , "old_file.py" }
282
284
283
- # Mock methods
285
+ # Mock methods - do this AFTER initializing the processor
284
286
processor .get_modified_files = MagicMock (return_value = (
285
287
["file1.py" , "file2.py" , "file3.py" ], # files to update
286
288
["old_file.py" ], # files to remove
0 commit comments