Skip to content

Commit 9c84f38

Browse files
committed
Add new tests for paginated working set enumeration
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
1 parent 9e445e0 commit 9c84f38

1 file changed

Lines changed: 198 additions & 0 deletions

File tree

Tests/NextcloudFileProviderKitTests/EnumeratorTests.swift

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,204 @@ final class EnumeratorTests: XCTestCase {
213213
XCTAssertEqual(dbFolder.etag, remoteFolder.versionIdentifier)
214214
}
215215

216+
func testWorkingSetPaginatedEnumeration() async throws {
217+
// 1. Setup a flat file structure with more items than the page size.
218+
rootItem.children = [] // Clear existing children
219+
for i in 0..<15 {
220+
let childItem = MockRemoteItem(
221+
identifier: "item\(i)",
222+
name: "item\(i).txt",
223+
remotePath: Self.account.davFilesUrl + "/item\(i).txt",
224+
account: Self.account.ncKitAccount,
225+
username: Self.account.username,
226+
userId: Self.account.id,
227+
serverUrl: Self.account.serverUrl
228+
)
229+
childItem.parent = rootItem
230+
rootItem.children.append(childItem)
231+
}
232+
233+
let db = Self.dbManager.ncDatabase() // Strong ref for in-memory test db
234+
debugPrint(db)
235+
let remoteInterface = MockRemoteInterface(rootItem: rootItem, pagination: true)
236+
237+
// 2. Create the enumerator with a specific page size.
238+
let enumerator = Enumerator(
239+
enumeratedItemIdentifier: .workingSet,
240+
account: Self.account,
241+
remoteInterface: remoteInterface,
242+
dbManager: Self.dbManager,
243+
pageSize: 5
244+
)
245+
let observer = MockEnumerationObserver(enumerator: enumerator)
246+
247+
// 3. Enumerate the items.
248+
try await observer.enumerateItems()
249+
250+
// 4. Assert the results.
251+
XCTAssertEqual(observer.items.count, 15)
252+
253+
for item in observer.items {
254+
XCTAssertNotNil(Self.dbManager.itemMetadata(ocId: item.itemIdentifier.rawValue))
255+
}
256+
257+
// The enumeration flow:
258+
// - Initial call enumerates the root.
259+
// - The enumerator then gets the first page of children.
260+
// - The observer requests the next pages until all items are fetched.
261+
// With 15 children and a page size of 5, we expect 3 pages of children.
262+
// Total pages observed: 1 (initial) + 3 (for children) = 4
263+
XCTAssertEqual(observer.observedPages.count, 4)
264+
XCTAssertEqual(
265+
observer.observedPages.first,
266+
NSFileProviderPage.initialPageSortedByName as NSFileProviderPage
267+
)
268+
}
269+
270+
func testWorkingSetPaginatedEnumerationWithMultipleDirectories() async throws {
271+
// 1. Setup a more complex, nested directory structure.
272+
// root
273+
// |- folder1 (7 items)
274+
// |- folder2
275+
// |- subfolder (3 items)
276+
// |- (8 items)
277+
278+
rootItem.children = [] // Clear existing children
279+
280+
let folder1 = MockRemoteItem(
281+
identifier: "folder1",
282+
name: "folder1",
283+
remotePath: Self.account.davFilesUrl + "/folder1",
284+
directory: true,
285+
account: Self.account.ncKitAccount,
286+
username: Self.account.username,
287+
userId: Self.account.id,
288+
serverUrl: Self.account.serverUrl
289+
)
290+
folder1.parent = rootItem
291+
rootItem.children.append(folder1)
292+
293+
for i in 0..<7 {
294+
let childItem = MockRemoteItem(
295+
identifier: "folder1-item\(i)",
296+
name: "item\(i).txt",
297+
remotePath: folder1.remotePath + "/item\(i).txt",
298+
account: Self.account.ncKitAccount,
299+
username: Self.account.username,
300+
userId: Self.account.id,
301+
serverUrl: Self.account.serverUrl
302+
)
303+
childItem.parent = folder1
304+
folder1.children.append(childItem)
305+
}
306+
307+
let folder2 = MockRemoteItem(
308+
identifier: "folder2",
309+
name: "folder2",
310+
remotePath: Self.account.davFilesUrl + "/folder2",
311+
directory: true,
312+
account: Self.account.ncKitAccount,
313+
username: Self.account.username,
314+
userId: Self.account.id,
315+
serverUrl: Self.account.serverUrl
316+
)
317+
folder2.parent = rootItem
318+
rootItem.children.append(folder2)
319+
320+
for i in 0..<8 {
321+
let childItem = MockRemoteItem(
322+
identifier: "folder2-item\(i)",
323+
name: "item\(i).txt",
324+
remotePath: folder2.remotePath + "/item\(i).txt",
325+
account: Self.account.ncKitAccount,
326+
username: Self.account.username,
327+
userId: Self.account.id,
328+
serverUrl: Self.account.serverUrl
329+
)
330+
childItem.parent = folder2
331+
folder2.children.append(childItem)
332+
}
333+
334+
let subfolder = MockRemoteItem(
335+
identifier: "subfolder",
336+
name: "subfolder",
337+
remotePath: folder2.remotePath + "/subfolder",
338+
directory: true,
339+
account: Self.account.ncKitAccount,
340+
username: Self.account.username,
341+
userId: Self.account.id,
342+
serverUrl: Self.account.serverUrl
343+
)
344+
subfolder.parent = folder2
345+
folder2.children.append(subfolder)
346+
347+
for i in 0..<3 {
348+
let childItem = MockRemoteItem(
349+
identifier: "subfolder-item\(i)",
350+
name: "item\(i).txt",
351+
remotePath: subfolder.remotePath + "/item\(i).txt",
352+
account: Self.account.ncKitAccount,
353+
username: Self.account.username,
354+
userId: Self.account.id,
355+
serverUrl: Self.account.serverUrl
356+
)
357+
childItem.parent = subfolder
358+
subfolder.children.append(childItem)
359+
}
360+
361+
let db = Self.dbManager.ncDatabase()
362+
debugPrint(db)
363+
let remoteInterface = MockRemoteInterface(rootItem: rootItem, pagination: true)
364+
365+
// 2. Create the enumerator.
366+
let enumerator = Enumerator(
367+
enumeratedItemIdentifier: .workingSet,
368+
account: Self.account,
369+
remoteInterface: remoteInterface,
370+
dbManager: Self.dbManager,
371+
pageSize: 5
372+
)
373+
let observer = MockEnumerationObserver(enumerator: enumerator)
374+
375+
// 3. Enumerate the items.
376+
try await observer.enumerateItems()
377+
378+
// 4. Assert the results.
379+
// Total items =
380+
// 0 (root) +
381+
// 1 (folder1) +
382+
// 7 (items in folder1) +
383+
// 1 (folder2) +
384+
// 8 (items in folder2) +
385+
// 1 (subfolder) +
386+
// 3 (items in subfolder)
387+
// = 22
388+
let expectedTotalItems = 0 + 1 + 7 + 1 + 8 + 1 + 3
389+
print(observer.items.map(\.itemIdentifier.rawValue))
390+
XCTAssertEqual(observer.items.count, expectedTotalItems)
391+
392+
for item in observer.items {
393+
XCTAssertNotNil(Self.dbManager.itemMetadata(ocId: item.itemIdentifier.rawValue))
394+
}
395+
396+
// The working set enumeration is recursive. The enumerator will first list the items
397+
// in the root directory, then it will be called again with the URLs of the subdirectories
398+
// as pages. This process continues until all directories have been enumerated.
399+
// We can verify that all items are discovered and stored in the database.
400+
let allItemIds = [
401+
rootItem.identifier,
402+
folder1.identifier,
403+
folder2.identifier,
404+
subfolder.identifier
405+
] + folder1.children.map(\.identifier)
406+
+ folder2.children.map(\.identifier)
407+
+ subfolder.children.map(\.identifier)
408+
409+
for itemId in allItemIds {
410+
XCTAssertNotNil(Self.dbManager.itemMetadata(ocId: itemId), "Item with id \(itemId) should be in the database")
411+
}
412+
}
413+
216414
func testWorkingSetChangeEnumeration() async throws {
217415
let db = Self.dbManager.ncDatabase() // Strong ref for in memory test db
218416
debugPrint(db)

0 commit comments

Comments
 (0)