@@ -83,6 +83,7 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
8383 Self . notifyPushServer. delay = 1_000_000
8484
8585 let authenticated = expectation ( description: " authenticated " )
86+ authenticated. assertForOverFulfill = false
8687
8788 NotificationCenter . default. addObserver ( forName: NotifyPushAuthenticatedNotificationName, object: nil , queue: nil ) { _ in
8889 authenticated. fulfill ( )
@@ -156,38 +157,33 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
156157 debugPrint ( db)
157158
158159 let testStartDate = Date ( )
159- let remoteInterface =
160- MockRemoteInterface ( account: Self . account, rootItem: MockRemoteItem . rootItem ( account: Self . account) )
160+ let remoteInterface = MockRemoteInterface ( account: Self . account, rootItem: MockRemoteItem . rootItem ( account: Self . account) )
161161 remoteInterface. capabilities = mockCapabilities
162162
163163 // --- DB State (What the app thinks is true) ---
164164 // A materialized file in the root that will be updated.
165- var rootFileToUpdate =
166- SendableItemMetadata ( ocId: " rootFile " , fileName: " root-file.txt " , account: Self . account)
165+ var rootFileToUpdate = SendableItemMetadata ( ocId: " rootFile " , fileName: " root-file.txt " , account: Self . account)
167166 rootFileToUpdate. downloaded = true
168167 rootFileToUpdate. etag = " ETAG_OLD_ROOTFILE "
169168 Self . dbManager. addItemMetadata ( rootFileToUpdate)
170169
171170 // A materialized folder that will have its contents changed.
172- var folderA =
173- SendableItemMetadata ( ocId: " folderA " , fileName: " FolderA " , account: Self . account)
171+ var folderA = SendableItemMetadata ( ocId: " folderA " , fileName: " FolderA " , account: Self . account)
174172 folderA. directory = true
175173 folderA. visitedDirectory = true
176174 folderA. etag = " ETAG_OLD_FOLDERA "
177175 Self . dbManager. addItemMetadata ( folderA)
178176
179177 // A materialized file inside FolderA that will be deleted.
180- var fileInAToDelete =
181- SendableItemMetadata ( ocId: " fileInA " , fileName: " file-in-a.txt " , account: Self . account)
178+ var fileInAToDelete = SendableItemMetadata ( ocId: " fileInA " , fileName: " file-in-a.txt " , account: Self . account)
182179 fileInAToDelete. downloaded = true
183180 fileInAToDelete. serverUrl = Self . account. davFilesUrl + " /FolderA "
184181 // Set an explicit old sync time to verify it gets updated during deletion
185182 fileInAToDelete. syncTime = Date ( timeIntervalSince1970: 1000 )
186183 Self . dbManager. addItemMetadata ( fileInAToDelete)
187184
188185 // A materialized folder that will be deleted entirely.
189- var folderBToDelete =
190- SendableItemMetadata ( ocId: " folderB " , fileName: " FolderB " , account: Self . account)
186+ var folderBToDelete = SendableItemMetadata ( ocId: " folderB " , fileName: " FolderB " , account: Self . account)
191187 folderBToDelete. directory = true
192188 folderBToDelete. visitedDirectory = true
193189 // Set an explicit old sync time to verify it gets updated during deletion
@@ -243,9 +239,8 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
243239 let authExpectation =
244240 XCTNSNotificationExpectation ( name: NotifyPushAuthenticatedNotificationName)
245241 let changeNotifiedExpectation = XCTestExpectation ( description: " Change Notified " )
246- let notificationInterface = MockChangeNotificationInterface ( )
247242
248- await notificationInterface. replaceChangeHandler {
243+ let notificationInterface = MockChangeNotificationInterface {
249244 changeNotifiedExpectation. fulfill ( )
250245 }
251246
@@ -303,16 +298,14 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
303298 remoteInterface. capabilities = mockCapabilities
304299
305300 let authenticated = expectation ( description: " authenticated " )
306- let notified = expectation ( description : " notified " )
301+ authenticated . assertForOverFulfill = false
307302
308303 NotificationCenter . default. addObserver ( forName: NotifyPushAuthenticatedNotificationName, object: nil , queue: nil ) { _ in
309304 authenticated. fulfill ( )
310305 }
311306
312- let notificationInterface = MockChangeNotificationInterface ( )
313-
314- await notificationInterface. replaceChangeHandler {
315- notified. fulfill ( )
307+ let notificationInterface = MockChangeNotificationInterface {
308+ XCTFail ( " This notification should not happen! " )
316309 }
317310
318311 remoteChangeObserver = RemoteChangeObserver (
@@ -329,8 +322,6 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
329322 Self . notifyPushServer. send ( message: " random " )
330323 Self . notifyPushServer. send ( message: " notify_activity " )
331324 Self . notifyPushServer. send ( message: " notify_notification " )
332-
333- await fulfillment ( of: [ notified] )
334325 }
335326
336327 func testPolling( ) async throws {
@@ -353,9 +344,8 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
353344 remoteInterface. rootItem? . children = [ serverItem]
354345
355346 let changeNotifiedExpectation = XCTestExpectation ( description: " Change Notified via Polling " )
356- let notificationInterface = MockChangeNotificationInterface ( )
357347
358- await notificationInterface. replaceChangeHandler {
348+ let notificationInterface = MockChangeNotificationInterface {
359349 changeNotifiedExpectation. fulfill ( )
360350 }
361351
@@ -365,15 +355,15 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
365355 changeNotificationInterface: notificationInterface,
366356 domain: nil ,
367357 dbManager: Self . dbManager,
358+ pollInterval: 0.5 ,
368359 log: FileProviderLogMock ( )
369360 )
370- // Set a very short poll interval for the test.
371- await remoteChangeObserver? . setPollInterval ( to: 0.5 )
372361
373362 // 2. Act & Assert
374363 // The observer will fail to connect to websocket and start polling.
375364 // We just need to wait for the poll to fire and detect the change.
376365 await wait ( for: changeNotifiedExpectation, description: " polling to trigger change " )
366+
377367 let pollingActive = await remoteChangeObserver? . pollingActive ?? false
378368 XCTAssertTrue ( pollingActive, " Polling should be active. " )
379369 }
@@ -384,26 +374,13 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
384374
385375 let authenticated = expectation ( description: " authenticated " )
386376 let reauthenticated = expectation ( description: " reauthenticated " )
387-
388- actor AuthCounter {
389- var count = 0
390- func increment( ) -> Int {
391- count += 1
392- return count
393- }
394- }
395- let authCounter = AuthCounter ( )
377+ let fulfillments = ExpectationFulfillmentCounter ( authenticated, reauthenticated)
396378
397379 NotificationCenter . default. addObserver (
398380 forName: NotifyPushAuthenticatedNotificationName, object: nil , queue: nil
399381 ) { _ in
400382 Task {
401- let count = await authCounter. increment ( )
402- if count == 1 {
403- authenticated. fulfill ( )
404- } else if count == 2 {
405- reauthenticated. fulfill ( )
406- }
383+ await fulfillments. next ( )
407384 }
408385 }
409386
@@ -508,7 +485,17 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
508485 )
509486 remoteInterface. rootItem? . children = [ serverItem]
510487
511- let notificationInterface = MockChangeNotificationInterface ( )
488+ let change1 = XCTestExpectation ( description: " First change notification " )
489+ let change2 = XCTestExpectation ( description: " Second change notification " )
490+
491+ let fulfillments = ExpectationFulfillmentCounter ( change1, change2)
492+
493+ let notificationInterface = MockChangeNotificationInterface {
494+ Task {
495+ await fulfillments. next ( )
496+ }
497+ }
498+
512499 let remoteChangeObserver = RemoteChangeObserver (
513500 account: Self . account,
514501 remoteInterface: remoteInterface,
@@ -520,19 +507,12 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
520507 self . remoteChangeObserver = remoteChangeObserver
521508
522509 // --- Phase 1: Test connection and change notification ---
523- let authExpectation =
524- XCTNSNotificationExpectation ( name: NotifyPushAuthenticatedNotificationName)
510+ let authExpectation = XCTNSNotificationExpectation ( name: NotifyPushAuthenticatedNotificationName)
525511 remoteChangeObserver. networkReachabilityObserver ( . reachableEthernetOrWiFi)
526512 await wait ( for: authExpectation, description: " initial authentication " )
527513
528- let changeExpectation1 = XCTestExpectation ( description: " First change notification " )
529-
530- await notificationInterface. replaceChangeHandler {
531- changeExpectation1. fulfill ( )
532- }
533-
534514 Self . notifyPushServer. send ( message: " notify_file " )
535- await wait ( for: changeExpectation1 , description: " first change " )
515+ await wait ( for: change1 , description: " first change " )
536516
537517 // --- Phase 2: Test connection loss ---
538518 remoteChangeObserver. networkReachabilityObserver ( . notReachable)
@@ -544,8 +524,7 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
544524 Self . notifyPushServer. reset ( )
545525
546526 // --- Phase 3: Test reconnection and change notification ---
547- let reauthExpectation =
548- XCTNSNotificationExpectation ( name: NotifyPushAuthenticatedNotificationName)
527+ let reauthExpectation = XCTNSNotificationExpectation ( name: NotifyPushAuthenticatedNotificationName)
549528
550529 // Trigger the reconnection logic.
551530 remoteChangeObserver. networkReachabilityObserver ( . reachableEthernetOrWiFi)
@@ -556,13 +535,7 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase {
556535
557536 XCTAssertTrue ( webSocketTaskActiveAfterReconnect, " Websocket should be active again after reconnection. " )
558537
559- let changeExpectation2 = XCTestExpectation ( description: " Second change notification " )
560-
561- await notificationInterface. replaceChangeHandler {
562- changeExpectation2. fulfill ( )
563- }
564-
565538 Self . notifyPushServer. send ( message: " notify_file " )
566- await wait ( for: changeExpectation2 , description: " second change " )
539+ await wait ( for: change2 , description: " second change " )
567540 }
568541}
0 commit comments