@@ -132,19 +132,23 @@ public async Task FileCreation_ShouldTriggerCreatedEvent()
132132 {
133133 var monitor = CreateMonitor ( ) ;
134134 var createdFiles = new List < string > ( ) ;
135- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
135+ var lockObj = new object ( ) ;
136+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
136137
137138 var testFile = GetTestPath ( "test.txt" ) ;
138139 await Task . Delay ( 100 ) ;
139140 File . WriteAllText ( testFile , "content" ) ;
140141
141142 await ActiveWaitHelpers . WaitUntilAsync (
142- ( ) => createdFiles . Contains ( "test.txt" ) ,
143+ ( ) => { lock ( lockObj ) return createdFiles . Contains ( "test.txt" ) ; } ,
143144 TimeSpan . FromSeconds ( 3 ) ,
144145 TimeSpan . FromMilliseconds ( 50 ) ,
145146 "file creation event" ) ;
146147
147- Assert . Contains ( "test.txt" , createdFiles ) ;
148+ lock ( lockObj )
149+ {
150+ Assert . Contains ( "test.txt" , createdFiles ) ;
151+ }
148152 }
149153
150154 [ Fact ]
@@ -155,18 +159,22 @@ public async Task FileChange_ShouldTriggerChangedEvent()
155159
156160 var monitor = CreateMonitor ( ) ;
157161 var changedFiles = new List < string > ( ) ;
158- monitor . Changed += ( s , e ) => changedFiles . Add ( e . Name ! ) ;
162+ var lockObj = new object ( ) ;
163+ monitor . Changed += ( s , e ) => { lock ( lockObj ) changedFiles . Add ( e . Name ! ) ; } ;
159164
160165 await Task . Delay ( 200 ) ;
161166 File . WriteAllText ( testFile , "modified" ) ;
162167
163168 await ActiveWaitHelpers . WaitUntilAsync (
164- ( ) => changedFiles . Contains ( "test.txt" ) ,
169+ ( ) => { lock ( lockObj ) return changedFiles . Contains ( "test.txt" ) ; } ,
165170 TimeSpan . FromSeconds ( 3 ) ,
166171 TimeSpan . FromMilliseconds ( 50 ) ,
167172 "file change event" ) ;
168173
169- Assert . Contains ( "test.txt" , changedFiles ) ;
174+ lock ( lockObj )
175+ {
176+ Assert . Contains ( "test.txt" , changedFiles ) ;
177+ }
170178 }
171179
172180 [ Fact ]
@@ -177,18 +185,22 @@ public async Task FileDelete_ShouldTriggerDeletedEvent()
177185
178186 var monitor = CreateMonitor ( ) ;
179187 var deletedFiles = new List < string > ( ) ;
180- monitor . Deleted += ( s , e ) => deletedFiles . Add ( e . Name ! ) ;
188+ var lockObj = new object ( ) ;
189+ monitor . Deleted += ( s , e ) => { lock ( lockObj ) deletedFiles . Add ( e . Name ! ) ; } ;
181190
182191 await Task . Delay ( 200 ) ;
183192 File . Delete ( testFile ) ;
184193
185194 await ActiveWaitHelpers . WaitUntilAsync (
186- ( ) => deletedFiles . Contains ( "test.txt" ) ,
195+ ( ) => { lock ( lockObj ) return deletedFiles . Contains ( "test.txt" ) ; } ,
187196 TimeSpan . FromSeconds ( 3 ) ,
188197 TimeSpan . FromMilliseconds ( 50 ) ,
189198 "file deletion event" ) ;
190199
191- Assert . Contains ( "test.txt" , deletedFiles ) ;
200+ lock ( lockObj )
201+ {
202+ Assert . Contains ( "test.txt" , deletedFiles ) ;
203+ }
192204 }
193205
194206 [ Fact ]
@@ -222,29 +234,33 @@ public async Task Filter_OnlyMatchingFiles_ShouldTriggerEvents()
222234 {
223235 var monitor = CreateMonitor ( filter : "*.txt" ) ;
224236 var createdFiles = new List < string > ( ) ;
225- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
237+ var lockObj = new object ( ) ;
238+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
226239
227240 await Task . Delay ( 100 ) ;
228241 File . WriteAllText ( GetTestPath ( "test.txt" ) , "content" ) ;
229242 File . WriteAllText ( GetTestPath ( "test.log" ) , "content" ) ;
230243
231244 await ActiveWaitHelpers . WaitUntilAsync (
232- ( ) => createdFiles . Contains ( "test.txt" ) ,
245+ ( ) => { lock ( lockObj ) return createdFiles . Contains ( "test.txt" ) ; } ,
233246 TimeSpan . FromSeconds ( 3 ) ,
234247 TimeSpan . FromMilliseconds ( 50 ) ,
235- "filtered file creation" ) ;
248+ "txt file creation event " ) ;
236249
237- await Task . Delay ( 500 ) ;
238- Assert . Contains ( "test.txt" , createdFiles ) ;
239- Assert . DoesNotContain ( "test.log" , createdFiles ) ;
250+ lock ( lockObj )
251+ {
252+ Assert . Contains ( "test.txt" , createdFiles ) ;
253+ Assert . DoesNotContain ( "test.log" , createdFiles ) ;
254+ }
240255 }
241256
242257 [ Fact ]
243258 public async Task IncludeSubdirectories_True_ShouldMonitorSubfolders ( )
244259 {
245260 var monitor = CreateMonitor ( includeSubdirectories : true ) ;
246261 var createdFiles = new List < string > ( ) ;
247- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
262+ var lockObj = new object ( ) ;
263+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
248264
249265 var subDir = GetTestPath ( "subfolder" ) ;
250266 Directory . CreateDirectory ( subDir ) ;
@@ -253,20 +269,24 @@ public async Task IncludeSubdirectories_True_ShouldMonitorSubfolders()
253269 File . WriteAllText ( Path . Combine ( subDir , "test.txt" ) , "content" ) ;
254270
255271 await ActiveWaitHelpers . WaitUntilAsync (
256- ( ) => createdFiles . Contains ( "test.txt" ) ,
272+ ( ) => { lock ( lockObj ) return createdFiles . Contains ( "test.txt" ) ; } ,
257273 TimeSpan . FromSeconds ( 3 ) ,
258274 TimeSpan . FromMilliseconds ( 50 ) ,
259275 "subfolder file creation" ) ;
260276
261- Assert . Contains ( "test.txt" , createdFiles ) ;
277+ lock ( lockObj )
278+ {
279+ Assert . Contains ( "test.txt" , createdFiles ) ;
280+ }
262281 }
263282
264283 [ Fact ]
265284 public async Task IncludeSubdirectories_False_ShouldNotMonitorSubfolders ( )
266285 {
267286 var monitor = CreateMonitor ( includeSubdirectories : false ) ;
268287 var createdFiles = new List < string > ( ) ;
269- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
288+ var lockObj = new object ( ) ;
289+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
270290
271291 await Task . Delay ( 100 ) ;
272292 File . WriteAllText ( GetTestPath ( "root.txt" ) , "content" ) ;
@@ -278,15 +298,18 @@ public async Task IncludeSubdirectories_False_ShouldNotMonitorSubfolders()
278298 File . WriteAllText ( Path . Combine ( subDir , "sub.txt" ) , "content" ) ;
279299
280300 await ActiveWaitHelpers . WaitUntilAsync (
281- ( ) => createdFiles . Contains ( "root.txt" ) ,
301+ ( ) => { lock ( lockObj ) return createdFiles . Contains ( "root.txt" ) ; } ,
282302 TimeSpan . FromSeconds ( 3 ) ,
283303 TimeSpan . FromMilliseconds ( 50 ) ,
284304 "root file creation" ) ;
285305
286306 await Task . Delay ( 800 ) ;
287307
288- Assert . Contains ( "root.txt" , createdFiles ) ;
289- Assert . DoesNotContain ( "sub.txt" , createdFiles ) ;
308+ lock ( lockObj )
309+ {
310+ Assert . Contains ( "root.txt" , createdFiles ) ;
311+ Assert . DoesNotContain ( "sub.txt" , createdFiles ) ;
312+ }
290313 }
291314
292315 #endregion
@@ -414,8 +437,10 @@ public async Task FileModified_WhileInPollingMode_ShouldDetectChange()
414437
415438 var changedFiles = new List < string > ( ) ;
416439 var createdFiles = new List < string > ( ) ;
417- monitor . Changed += ( s , e ) => changedFiles . Add ( e . Name ! ) ;
418- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
440+ var lockObj = new object ( ) ;
441+
442+ monitor . Changed += ( s , e ) => { lock ( lockObj ) changedFiles . Add ( e . Name ! ) ; } ;
443+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
419444
420445 await ActiveWaitHelpers . WaitUntilAsync (
421446 ( ) => monitor . IsUsingWatcher ,
@@ -432,7 +457,9 @@ await ActiveWaitHelpers.WaitUntilAsync(
432457 TimeSpan . FromMilliseconds ( 50 ) ,
433458 "enter polling" ) ;
434459
435- // Recreate with modified file (this will be a "created" event since old file was deleted)
460+ // Recreate with modified file
461+ // Note: This may be detected as either Created or Changed depending on platform
462+ // macOS tends to report this as Changed, while Windows/Linux report it as Created
436463 Directory . CreateDirectory ( _testRoot ) ;
437464 File . WriteAllText ( GetTestPath ( "test.txt" ) , "v2_modified" ) ;
438465
@@ -443,14 +470,24 @@ await ActiveWaitHelpers.WaitUntilAsync(
443470 TimeSpan . FromMilliseconds ( 100 ) ,
444471 "switch back to watcher" ) ;
445472
446- // Wait for reconciliation to detect the file
473+ // Wait for reconciliation to detect the file (either as Created or Changed)
447474 await ActiveWaitHelpers . WaitUntilAsync (
448- ( ) => createdFiles . Contains ( "test.txt" ) ,
475+ ( ) => {
476+ lock ( lockObj )
477+ return createdFiles . Contains ( "test.txt" ) || changedFiles . Contains ( "test.txt" ) ;
478+ } ,
449479 TimeSpan . FromSeconds ( 3 ) ,
450480 TimeSpan . FromMilliseconds ( 100 ) ,
451481 "detect file via reconciliation" ) ;
452482
453- Assert . Contains ( "test.txt" , createdFiles ) ;
483+ // File should be detected via one of these events
484+ lock ( lockObj )
485+ {
486+ Assert . True (
487+ createdFiles . Contains ( "test.txt" ) || changedFiles . Contains ( "test.txt" ) ,
488+ $ "File 'test.txt' should be detected via Created or Changed event. " +
489+ $ "Created: [{ string . Join ( ", " , createdFiles ) } ], Changed: [{ string . Join ( ", " , changedFiles ) } ]") ;
490+ }
454491 }
455492
456493 [ Fact ]
@@ -554,7 +591,8 @@ public async Task AuditInterval_DetectsSilentChanges_ShouldReconcile()
554591 // Simulate silent changes (though in practice, events should fire)
555592 // The audit will still catch divergence if any
556593 var createdFiles = new List < string > ( ) ;
557- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
594+ var lockObj = new object ( ) ;
595+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
558596
559597 await Task . Delay ( 1500 ) ; // Let audit run
560598
@@ -575,7 +613,8 @@ public async Task PollingMode_ShouldDetectFileChanges()
575613 pollingInterval : TimeSpan . FromMilliseconds ( 300 ) ) ;
576614
577615 var createdFiles = new List < string > ( ) ;
578- monitor . Created += ( s , e ) => createdFiles . Add ( e . Name ! ) ;
616+ var lockObj = new object ( ) ;
617+ monitor . Created += ( s , e ) => { lock ( lockObj ) createdFiles . Add ( e . Name ! ) ; } ;
579618
580619 Assert . False ( monitor . IsUsingWatcher ) ;
581620
@@ -585,12 +624,15 @@ public async Task PollingMode_ShouldDetectFileChanges()
585624 File . WriteAllText ( Path . Combine ( nonExistentPath , "test.txt" ) , "content" ) ;
586625
587626 await ActiveWaitHelpers . WaitUntilAsync (
588- ( ) => createdFiles . Contains ( "test.txt" ) ,
627+ ( ) => { lock ( lockObj ) return createdFiles . Contains ( "test.txt" ) ; } ,
589628 TimeSpan . FromSeconds ( 6 ) ,
590629 TimeSpan . FromMilliseconds ( 150 ) ,
591630 "polling mode file detection" ) ;
592631
593- Assert . Contains ( "test.txt" , createdFiles ) ;
632+ lock ( lockObj )
633+ {
634+ Assert . Contains ( "test.txt" , createdFiles ) ;
635+ }
594636 }
595637
596638 [ Fact ]
0 commit comments