diff --git a/Sources/NextcloudFileProviderKit/Enumeration/Enumerator+SyncEngine.swift b/Sources/NextcloudFileProviderKit/Enumeration/Enumerator+SyncEngine.swift index 8a9f6c88..b1dcc2a4 100644 --- a/Sources/NextcloudFileProviderKit/Enumeration/Enumerator+SyncEngine.swift +++ b/Sources/NextcloudFileProviderKit/Enumeration/Enumerator+SyncEngine.swift @@ -56,35 +56,35 @@ extension Enumerator { return (metadatas, nil, nil, nil, error) } - guard var (directoryMetadata, _, metadatas) = await files.toDirectoryReadMetadatas(account: account) else { - logger.error("Could not convert NKFiles to DirectoryReadMetadatas!") + guard var (directory, _, files) = await files.toSendableDirectoryMetadata(account: account, directoryToRead: serverUrl) else { + logger.error("Failed to convert array of NKFile to directory and files metadata objects!") return (nil, nil, nil, nil, .invalidData) } // STORE DATA FOR CURRENTLY SCANNED DIRECTORY - guard directoryMetadata.directory else { - logger.error("Expected directory metadata but received file metadata for serverUrl: \(serverUrl)") + guard directory.directory else { + logger.error("Expected directory metadata but received file metadata!", [.url: serverUrl]) return (nil, nil, nil, nil, .invalidData) } - if let existingMetadata = dbManager.itemMetadata(ocId: directoryMetadata.ocId) { - directoryMetadata.downloaded = existingMetadata.downloaded - directoryMetadata.keepDownloaded = existingMetadata.keepDownloaded + if let existingMetadata = dbManager.itemMetadata(ocId: directory.ocId) { + directory.downloaded = existingMetadata.downloaded + directory.keepDownloaded = existingMetadata.keepDownloaded } - directoryMetadata.visitedDirectory = true + directory.visitedDirectory = true - metadatas.insert(directoryMetadata, at: 0) + files.insert(directory, at: 0) let changedMetadatas = dbManager.depth1ReadUpdateItemMetadatas( account: account.ncKitAccount, serverUrl: serverUrl, - updatedMetadatas: metadatas, + updatedMetadatas: files, keepExistingDownloadState: true ) return ( - metadatas, + files, changedMetadatas.newMetadatas, changedMetadatas.updatedMetadatas, changedMetadatas.deletedMetadatas, @@ -214,9 +214,7 @@ extension Enumerator { return ([metadata], newMetadatas, updatedMetadatas, nil, nextPage, nil) } else if depth == .targetAndDirectChildren { - let ( - allMetadatas, newMetadatas, updatedMetadatas, deletedMetadatas, readError - ) = await handleDepth1ReadFileOrFolder( + let (allMetadatas, newMetadatas, updatedMetadatas, deletedMetadatas, readError) = await handleDepth1ReadFileOrFolder( serverUrl: serverUrl, account: account, dbManager: dbManager, diff --git a/Sources/NextcloudFileProviderKit/Extensions/NKFile+Extensions.swift b/Sources/NextcloudFileProviderKit/Extensions/NKFile+Extensions.swift index 5588fa68..8299cbd4 100644 --- a/Sources/NextcloudFileProviderKit/Extensions/NKFile+Extensions.swift +++ b/Sources/NextcloudFileProviderKit/Extensions/NKFile+Extensions.swift @@ -18,22 +18,21 @@ extension NKFile { func toItemMetadata(uploaded: Bool = true) -> SendableItemMetadata { let creationDate = creationDate ?? date let uploadDate = uploadDate ?? date - let classFile = (contentType == "text/markdown" || contentType == "text/x-markdown") - && classFile == NKTypeClassFile.unknow.rawValue + + let classFile = (contentType == "text/markdown" || contentType == "text/x-markdown") && classFile == NKTypeClassFile.unknow.rawValue ? NKTypeClassFile.document.rawValue : classFile + // Support for finding the correct filename for e2ee files should go here // Don't ask me why, NextcloudKit renames and moves the root folder details // Also don't ask me why, but, NextcloudKit marks the NKFile for this as not a directory let rootServerUrl = urlBase + Account.webDavFilesUrlSuffix + userId let rootRequiresFixup = serverUrl == rootServerUrl && fileName == NextcloudKit.shared.nkCommonInstance.rootFileName - let ocId = rootRequiresFixup - ? NSFileProviderItemIdentifier.rootContainer.rawValue - : self.ocId + let ocId = rootRequiresFixup ? NSFileProviderItemIdentifier.rootContainer.rawValue : self.ocId let directory = rootRequiresFixup ? true : self.directory let serverUrl = rootRequiresFixup ? rootServerUrl : self.serverUrl - let fileName = rootRequiresFixup ? "" : self.fileName + let fileName = rootRequiresFixup ? NextcloudKit.shared.nkCommonInstance.rootFileName : self.fileName return SendableItemMetadata( ocId: ocId, @@ -94,46 +93,79 @@ extension NKFile { } } +/// +/// Data container intended for use in combination with `concurrentChunkedForEach` to safely and concurrently convert a lot of metadata objects. +/// +private final actor DirectoryMetadataContainer: Sendable { + let root: SendableItemMetadata + var directories: [SendableItemMetadata] = [] + var files: [SendableItemMetadata] = [] + init(for root: SendableItemMetadata) { + self.root = root + } -extension Array { - private final actor DirectoryReadConversionActor: Sendable { - let directoryMetadata: SendableItemMetadata - var childDirectoriesMetadatas: [SendableItemMetadata] = [] - var metadatas: [SendableItemMetadata] = [] - - func convertedMetadatas() -> ( - SendableItemMetadata, [SendableItemMetadata], [SendableItemMetadata] - ) { - (directoryMetadata, childDirectoriesMetadatas, metadatas) + /// + /// Insert a new item into the container. + /// + func add(_ item: SendableItemMetadata) { + files.append(item) + + if item.directory { + directories.append(item) } + } + + /// + /// Return a tuple of the total current content. + /// + func content() -> (SendableItemMetadata, [SendableItemMetadata], [SendableItemMetadata]) { + (root, directories, files) + } +} - init(target: SendableItemMetadata) { - self.directoryMetadata = target +extension Array { + /// + /// Determine whether the given `NKFile` is the metadata object for the read remote directory. + /// + func isDirectoryToRead(_ file: NKFile, directoryToRead: String) -> Bool { + if file.serverUrl == directoryToRead && file.fileName == NextcloudKit.shared.nkCommonInstance.rootFileName { + return true } - func add(metadata: SendableItemMetadata) { - metadatas.append(metadata) - if metadata.directory { - childDirectoriesMetadatas.append(metadata) - } + if file.directory, "\(file.serverUrl)/\(file.fileName)" == directoryToRead { + return true } + + return false } - func toDirectoryReadMetadatas(account: Account) async -> ( - directoryMetadata: SendableItemMetadata, - childDirectoriesMetadatas: [SendableItemMetadata], - metadatas: [SendableItemMetadata] - )? { - guard var targetDirectoryMetadata = first?.toItemMetadata() else { + /// + /// Convert an array of `NKFile` to `SendableItemMetadata`. + /// + /// - Parameters: + /// - account: The account which the metadata belongs to. + /// - directoryToRead: The root path of the directory which this metadata comes from. This is required to distinguish the correct item for the metadata of the read directory itself from its children. + /// + /// - Returns: A tuple consisting of the metadata for the read directory itself (`root`), any child directories (`directories`) and separately any directly containted files (`files`). + /// + func toSendableDirectoryMetadata(account: Account, directoryToRead: String) async -> (root: SendableItemMetadata, directories: [SendableItemMetadata], files: [SendableItemMetadata])? { + guard let root = first(where: { isDirectoryToRead($0, directoryToRead: directoryToRead) })?.toItemMetadata() else { return nil } - let conversionActor = DirectoryReadConversionActor(target: targetDirectoryMetadata) + + let container = DirectoryMetadataContainer(for: root) + if self.count > 1 { - await self[1...].concurrentChunkedForEach { file in - await conversionActor.add(metadata: file.toItemMetadata()) + await concurrentChunkedForEach { file in + guard isDirectoryToRead(file, directoryToRead: directoryToRead) == false else { + return + } + + await container.add(file.toItemMetadata()) } } - return await conversionActor.convertedMetadatas() + + return await container.content() } } diff --git a/Sources/NextcloudFileProviderKit/Item/Item+Create.swift b/Sources/NextcloudFileProviderKit/Item/Item+Create.swift index dce15884..8971873e 100644 --- a/Sources/NextcloudFileProviderKit/Item/Item+Create.swift +++ b/Sources/NextcloudFileProviderKit/Item/Item+Create.swift @@ -87,16 +87,16 @@ public extension Item { )) } - guard var (directoryMetadata, _, _) = await files.toDirectoryReadMetadatas(account: account) - else { - logger.error("Received nil directory read metadatas during conversion") + guard var (directory, _, _) = await files.toSendableDirectoryMetadata(account: account, directoryToRead: remotePath) else { + logger.error("Failed to resolve directory metadata on item conversion!") return (nil, NSFileProviderError(.cannotSynchronize)) } - directoryMetadata.downloaded = true - dbManager.addItemMetadata(directoryMetadata) + + directory.downloaded = true + dbManager.addItemMetadata(directory) let fpItem = Item( - metadata: directoryMetadata, + metadata: directory, parentItemIdentifier: parentItemIdentifier, account: account, remoteInterface: remoteInterface, diff --git a/Tests/Interface/MockRemoteInterface.swift b/Tests/Interface/MockRemoteInterface.swift index 1a81a6ec..1d372ac7 100644 --- a/Tests/Interface/MockRemoteInterface.swift +++ b/Tests/Interface/MockRemoteInterface.swift @@ -614,6 +614,7 @@ public class MockRemoteInterface: RemoteInterface { } let sanitisedPath = sanitisedPath(remotePath, account: account) + guard sanitisedPath != "/" else { return remotePath.hasPrefix(account.trashUrl) ? rootTrashItem : rootItem } @@ -624,11 +625,15 @@ public class MockRemoteInterface: RemoteInterface { while pathComponents?.isEmpty == false { let component = pathComponents?.removeFirst() - guard component?.isEmpty == false, - let nextNode = currentNode?.children.first(where: { $0.name == component }) - else { return nil } - guard pathComponents?.isEmpty == false else { return nextNode } // This is the target + guard component?.isEmpty == false, let nextNode = currentNode?.children.first(where: { $0.name == component }) else { + return nil + } + + guard pathComponents?.isEmpty == false else { + return nextNode // This is the target + } + currentNode = nextNode } @@ -1031,12 +1036,15 @@ public class MockRemoteInterface: RemoteInterface { taskHandler: @escaping (URLSessionTask) -> Void = { _ in } ) async -> (account: String, files: [NKFile], data: AFDataResponse?, error: NKError) { var remotePath = remotePath + if remotePath.last == "." { remotePath.removeLast() } + if remotePath.last == "/" { remotePath.removeLast() } + print("Enumerating \(remotePath)") // Call the enumerate call handler if it exists diff --git a/Tests/Interface/MockRemoteItem.swift b/Tests/Interface/MockRemoteItem.swift index 9f3ba7d1..81ba5e7a 100644 --- a/Tests/Interface/MockRemoteItem.swift +++ b/Tests/Interface/MockRemoteItem.swift @@ -56,7 +56,7 @@ public class MockRemoteItem: Equatable { MockRemoteItem( identifier: NSFileProviderItemIdentifier.rootContainer.rawValue, versionIdentifier: "root", - name: "", + name: NextcloudKit.shared.nkCommonInstance.rootFileName, remotePath: account.davFilesUrl, directory: true, account: account.ncKitAccount, @@ -120,7 +120,7 @@ public class MockRemoteItem: Equatable { let isRoot = identifier == NSFileProviderItemIdentifier.rootContainer.rawValue var file = NKFile() file.fileName = isRoot - ? "__NC_ROOT__" + ? NextcloudKit.shared.nkCommonInstance.rootFileName : trashbinOriginalLocation?.split(separator: "/").last?.toString() ?? name file.size = size file.date = creationDate @@ -128,9 +128,7 @@ public class MockRemoteItem: Equatable { file.etag = versionIdentifier file.ocId = identifier file.fileId = identifier.replacingOccurrences(of: trashedItemIdSuffix, with: "") - file.serverUrl = isRoot - ? serverUrl + "/remote.php/dav/files/" + userId - : parent?.remotePath ?? remotePath + file.serverUrl = isRoot ? "\(serverUrl)/remote.php/dav/files/\(userId)" : parent?.remotePath ?? serverUrl file.account = account file.user = username file.userId = userId diff --git a/Tests/InterfaceTests/MockRemoteInterfaceTests.swift b/Tests/InterfaceTests/MockRemoteInterfaceTests.swift index f054d726..b7da7910 100644 --- a/Tests/InterfaceTests/MockRemoteInterfaceTests.swift +++ b/Tests/InterfaceTests/MockRemoteInterfaceTests.swift @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later import XCTest +import NextcloudKit @testable import NextcloudFileProviderKit @testable import NextcloudFileProviderKitMocks @testable import TestInterface @@ -503,8 +504,7 @@ final class MockRemoteInterfaceTests: XCTestCase { let targetRootFile = result.files.first let expectedRoot = remoteInterface.rootItem XCTAssertEqual(targetRootFile?.ocId, expectedRoot?.identifier) - XCTAssertEqual(targetRootFile?.fileName, "__NC_ROOT__") // NextcloudKit gives the root dir this name - XCTAssertNotEqual(targetRootFile?.fileName, expectedRoot?.name) + XCTAssertEqual(targetRootFile?.fileName, NextcloudKit.shared.nkCommonInstance.rootFileName) // NextcloudKit gives the root dir this name XCTAssertEqual(targetRootFile?.serverUrl, "https://mock.nc.com/remote.php/dav/files/testUserId") // NextcloudKit gives the root dir this url XCTAssertEqual(targetRootFile?.date, expectedRoot?.creationDate) XCTAssertEqual(targetRootFile?.etag, expectedRoot?.versionIdentifier) diff --git a/Tests/NextcloudFileProviderKitTests/NKFileExtensionTests.swift b/Tests/NextcloudFileProviderKitTests/NKFileExtensionTests.swift index ff676e51..a2299217 100644 --- a/Tests/NextcloudFileProviderKitTests/NKFileExtensionTests.swift +++ b/Tests/NextcloudFileProviderKitTests/NKFileExtensionTests.swift @@ -7,23 +7,12 @@ import NextcloudKit @testable import NextcloudFileProviderKit final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { + static let account = Account(user: "testUser", id: "testUserId", serverUrl: "https://mock.nc.com", password: "abcd") - static let account = Account( - user: "testUser", - id: "testUserId", - serverUrl: "https://mock.nc.com", - password: "abcd" - ) - - /// Creates a mock NKFile. - private func createNKFile( - ocId: String = "id1", - serverUrl: String? = nil, - fileName: String = "file.txt", - directory: Bool = false, - userId: String? = nil, - urlBase: String? = nil - ) -> NKFile { + /// + /// Mock an `NKFile` for the tests in here. + /// + private func createNKFile(ocId: String = "id1", serverUrl: String? = nil, fileName: String = "file.txt", directory: Bool = false, userId: String? = nil, urlBase: String? = nil) -> NKFile { var file = NKFile() file.ocId = ocId file.serverUrl = serverUrl ?? Self.account.davFilesUrl @@ -36,6 +25,7 @@ final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { file.date = Date() file.creationDate = Date() file.etag = "etag" + return file } @@ -47,7 +37,7 @@ final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { let rootNKFile = createNKFile( ocId: "rootId", serverUrl: "https://mock.nc.com/remote.php/dav/files/testUserId", // Special root value - fileName: "__NC_ROOT__", // Special root value + fileName: NextcloudKit.shared.nkCommonInstance.rootFileName, // Special root value directory: false // NextcloudKit sometimes marks the root as not a directory ) @@ -56,16 +46,8 @@ final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { // 3. Assert // The `rootRequiresFixup` logic should trigger. - XCTAssertEqual( - metadata.serverUrl, - Self.account.davFilesUrl, - "The serverUrl for the root should be corrected to the full WebDAV path." - ) - XCTAssertEqual( - metadata.fileName, - "", - "The fileName for the root should be corrected to an empty string." - ) + XCTAssertEqual(metadata.serverUrl, Self.account.davFilesUrl, "The serverUrl for the root should be corrected to the full WebDAV path.") + XCTAssertEqual(metadata.ocId, NSFileProviderItemIdentifier.rootContainer.rawValue, "The ocId for the root should be mapped to a file provider root container.") } func testToItemMetadataHandlesStandardFileCorrectly() { @@ -93,49 +75,73 @@ final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { ) } - // MARK: - toDirectoryReadMetadatas(account:) Tests + // MARK: - isDirectoryToRead(_:directoryToRead:) + + func testIsDirectoryToReadForRoot() { + let item = createNKFile(ocId: NextcloudKit.shared.nkCommonInstance.rootFileName, serverUrl: Self.account.davFilesUrl, fileName: NextcloudKit.shared.nkCommonInstance.rootFileName) + let items = [NKFile]() + let result = items.isDirectoryToRead(item, directoryToRead: Self.account.davFilesUrl) + XCTAssertTrue(result) + } + + func testIsDirectoryToReadForDirectoryInRoot() { + let item = createNKFile(ocId: "some", serverUrl: Self.account.davFilesUrl, fileName: "Subdirectory", directory: true) + let items = [NKFile]() + let result = items.isDirectoryToRead(item, directoryToRead: "\(Self.account.davFilesUrl)/Subdirectory") + XCTAssertTrue(result) + } + + func testIsDirectoryToReadForFileInRoot() { + let item = createNKFile(ocId: "some", serverUrl: Self.account.davFilesUrl, fileName: "File", directory: false) + let items = [NKFile]() + let result = items.isDirectoryToRead(item, directoryToRead: Self.account.davFilesUrl) + XCTAssertFalse(result) + } + + func testIsDirectoryToReadForFileInSubdirectory() { + let subdirectoryURL = "\(Self.account.davFilesUrl)/Subdirectory" + let item = createNKFile(ocId: "some", serverUrl: "\(subdirectoryURL)/File", fileName: "File", directory: false) + let items = [NKFile]() + let result = items.isDirectoryToRead(item, directoryToRead: subdirectoryURL) + XCTAssertFalse(result) + } - func testToDirectoryReadMetadatasHandlesRootAsTargetCorrectly() async { + // MARK: - toSendableDirectoryMetadata(account:directoryToRead:) Tests + + func testToSendableDirectoryMetadataHandlesRootAsTargetCorrectly() async throws { // 1. Arrange: Create an array of NKFiles where the first item is the special root. let rootNKFile = createNKFile( ocId: "rootId", // This will be overridden by the logic - serverUrl: "https://mock.nc.com/remote.php/dav/files/testUserId", - fileName: "__NC_ROOT__", + serverUrl: Self.account.davFilesUrl, + fileName: NextcloudKit.shared.nkCommonInstance.rootFileName, directory: false // Mimic NextcloudKit behavior ) + let childNKFile = createNKFile( ocId: "child1", - serverUrl: Self.account.davFilesUrl, + serverUrl: "\(Self.account.davFilesUrl)/document.txt", fileName: "document.txt" ) let files = [rootNKFile, childNKFile] // 2. Act - let result = await files.toDirectoryReadMetadatas(account: Self.account) + let result = await files.toSendableDirectoryMetadata(account: Self.account, directoryToRead: Self.account.davFilesUrl) // 3. Assert - XCTAssertNotNil(result, "The conversion should succeed.") - guard let result else { return } + let unwrappedResult = try XCTUnwrap(result) // The logic should identify the first item as the root and fix its properties. - XCTAssertEqual( - result.directoryMetadata.ocId, - NSFileProviderItemIdentifier.rootContainer.rawValue, - "The target directory's ocId should be corrected to the root container identifier." - ) - XCTAssertTrue( - result.directoryMetadata.directory, - "The target directory should be correctly marked as a directory, even if the NKFile was not." - ) + XCTAssertEqual(unwrappedResult.root.ocId, NSFileProviderItemIdentifier.rootContainer.rawValue, "The target directory's ocId should be corrected to the root container identifier.") + XCTAssertTrue(unwrappedResult.root.directory, "The target directory should be correctly marked as a directory, even if the NKFile was not.") // Ensure the child item is processed correctly. - XCTAssertEqual(result.metadatas.count, 1, "There should be one child metadata object.") - XCTAssertEqual(result.metadatas.first?.ocId, "child1") - XCTAssertTrue(result.childDirectoriesMetadatas.isEmpty, "The child is a file, so child directories should be empty.") + XCTAssertEqual(unwrappedResult.files.count, 1, "There should be one file metadata object.") + XCTAssertEqual(unwrappedResult.files.first?.ocId, "child1") + XCTAssertTrue(unwrappedResult.directories.isEmpty, "The child is a file, so child directories should be empty.") } - func testToDirectoryReadMetadatasHandlesNormalFolderAsTarget() async { + func testToSendableDirectoryMetadataHandlesNormalFolderAsTarget() async throws { // 1. Arrange: Create an array for a normal folder and its children. let parentFolderNKFile = createNKFile( ocId: "folder1", @@ -143,14 +149,16 @@ final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { fileName: "MyFolder", directory: true ) + let childFileNKFile = createNKFile( ocId: "file1", - serverUrl: Self.account.davFilesUrl + "/MyFolder", + serverUrl: "\(Self.account.davFilesUrl)/MyFolder", fileName: "report.docx" ) + let childDirNKFile = createNKFile( ocId: "dir2", - serverUrl: Self.account.davFilesUrl + "/MyFolder", + serverUrl: "\(Self.account.davFilesUrl)/MyFolder", fileName: "Subfolder", directory: true ) @@ -158,21 +166,20 @@ final class NKFileExtensionsTests: NextcloudFileProviderKitTestCase { let files = [parentFolderNKFile, childFileNKFile, childDirNKFile] // 2. Act - let result = await files.toDirectoryReadMetadatas(account: Self.account) + let result = await files.toSendableDirectoryMetadata(account: Self.account, directoryToRead: "\(Self.account.davFilesUrl)/MyFolder") // 3. Assert - XCTAssertNotNil(result) - guard let result else { return } + let unwrappedResult = try XCTUnwrap(result) // The root fixup logic should NOT trigger for a normal folder. - XCTAssertEqual(result.directoryMetadata.ocId, "folder1") - XCTAssertEqual(result.directoryMetadata.fileName, "MyFolder") - XCTAssertTrue(result.directoryMetadata.directory) + XCTAssertEqual(unwrappedResult.root.ocId, "folder1") + XCTAssertEqual(unwrappedResult.root.fileName, "MyFolder") + XCTAssertTrue(unwrappedResult.root.directory) // Check children processing - XCTAssertEqual(result.metadatas.count, 2, "Should have two child metadata objects.") - XCTAssertEqual(result.childDirectoriesMetadatas.count, 1, "Should identify one child directory.") - XCTAssertEqual(result.childDirectoriesMetadatas.first?.ocId, "dir2") + XCTAssertEqual(unwrappedResult.files.count, 2, "Should have two child metadata objects.") + XCTAssertEqual(unwrappedResult.directories.count, 1, "Should identify one child directory.") + XCTAssertEqual(unwrappedResult.directories.first?.ocId, "dir2") } } diff --git a/Tests/NextcloudFileProviderKitTests/RemoteChangeObserverTests.swift b/Tests/NextcloudFileProviderKitTests/RemoteChangeObserverTests.swift index c35b06d0..cd0fdab4 100644 --- a/Tests/NextcloudFileProviderKitTests/RemoteChangeObserverTests.swift +++ b/Tests/NextcloudFileProviderKitTests/RemoteChangeObserverTests.swift @@ -215,7 +215,7 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase { account: Self.account.ncKitAccount, username: Self.account.username, userId: Self.account.id, - serverUrl: Self.account.serverUrl + serverUrl: Self.account.davFilesUrl ) rootItem.children.append(serverRootFile) @@ -229,7 +229,7 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase { account: Self.account.ncKitAccount, username: Self.account.username, userId: Self.account.id, - serverUrl: Self.account.serverUrl + serverUrl: Self.account.davFilesUrl ) rootItem.children.append(serverFolderA) @@ -241,7 +241,7 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase { account: Self.account.ncKitAccount, username: Self.account.username, userId: Self.account.id, - serverUrl: Self.account.serverUrl + serverUrl: serverFolderA.remotePath ) serverFolderA.children.append(newFileInA) @@ -249,7 +249,10 @@ final class RemoteChangeObserverTests: NextcloudFileProviderKitTestCase { XCTNSNotificationExpectation(name: NotifyPushAuthenticatedNotificationName) let changeNotifiedExpectation = XCTestExpectation(description: "Change Notified") let notificationInterface = MockChangeNotificationInterface() - notificationInterface.changeHandler = { changeNotifiedExpectation.fulfill() } + + notificationInterface.changeHandler = { + changeNotifiedExpectation.fulfill() + } remoteChangeObserver = RemoteChangeObserver( account: Self.account,