From a6d75d30826e14947ef7e81c2dbdcea04ac7ca7f Mon Sep 17 00:00:00 2001 From: Iva Horn Date: Tue, 14 Oct 2025 13:30:22 +0200 Subject: [PATCH] fix: Directory enumeration. - Our corporate instance was a real world use case in which the retrieved metadata of a directory and its content is no longer fulfilling the previous assumption that the first item is related to the queried directory itself. Instead, it can be anywhere in the array. Hence the implementation had to be changed to detect it by other means while taking the special `__NC_ROOT__` case into consideration. - While reading, I also applied code style changes based on conventional Swift code style. - Further, I hope to improve clarity by renaming some symbols like `DirectoryReadConversionActor` to `DirectoryMetadataContainer` which hints its purpose a lot better in my opinion. - Also replaced some occurrences of empty strings or `__NC_ROOT__` literals with the symbol reference to NextcloudKit. Signed-off-by: Iva Horn <142165879+i2h3@users.noreply.github.com> --- .../Enumeration/Enumerator+SyncEngine.swift | 26 ++-- .../Extensions/NKFile+Extensions.swift | 98 +++++++++----- .../Item/Item+Create.swift | 12 +- Tests/Interface/MockRemoteInterface.swift | 16 ++- Tests/Interface/MockRemoteItem.swift | 8 +- .../MockRemoteInterfaceTests.swift | 4 +- .../NKFileExtensionTests.swift | 125 +++++++++--------- .../RemoteChangeObserverTests.swift | 11 +- 8 files changed, 173 insertions(+), 127 deletions(-) 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,