@@ -1165,4 +1165,130 @@ final class EnumeratorTests: XCTestCase {
11651165 XCTAssertEqual ( observer. observedPages. first, NSFileProviderPage . initialPageSortedByName as NSFileProviderPage )
11661166 XCTAssertEqual ( observer. observedPages. count, 5 )
11671167 }
1168+
1169+ func testEmptyFolderPaginatedEnumeration( ) async throws {
1170+ // 1. Setup: remoteFolder exists in the DB but has no children.
1171+ // Ensure the folder itself is in the database, as the enumerator for a specific item
1172+ // will try to fetch its metadata.
1173+ remoteFolder. children = [ ] // Ensure it's empty for this test
1174+ Self . dbManager. addItemMetadata ( remoteFolder. toItemMetadata ( account: Self . account) )
1175+ XCTAssertNotNil ( Self . dbManager. itemMetadata ( ocId: remoteFolder. identifier) , " Folder metadata should be in DB for enumeration. " )
1176+
1177+ let db = Self . dbManager. ncDatabase ( ) // Strong ref for in-memory test db
1178+ debugPrint ( db)
1179+ // Enable pagination in MockRemoteInterface to ensure the pagination path is taken
1180+ let remoteInterface = MockRemoteInterface ( rootItem: rootItem, pagination: true )
1181+
1182+ // 2. Create enumerator for the empty folder with a specific pageSize.
1183+ let enumerator = Enumerator (
1184+ enumeratedItemIdentifier: NSFileProviderItemIdentifier ( remoteFolder. identifier) ,
1185+ account: Self . account,
1186+ remoteInterface: remoteInterface,
1187+ dbManager: Self . dbManager,
1188+ pageSize: 5 // Page size can be anything, as the folder is empty
1189+ )
1190+ let observer = MockEnumerationObserver ( enumerator: enumerator)
1191+
1192+ // 3. Enumerate items.
1193+ try await observer. enumerateItems ( )
1194+
1195+ // 4. Assertions.
1196+ // When enumerating a folder (even an empty one) with depth .targetAndDirectChildren,
1197+ // the folder item itself should not be returned.
1198+ XCTAssertEqual ( observer. items. count, 0 , " Should enumerate nothing. " )
1199+
1200+ // For an empty folder, there's only one "page" of results (the folder itself).
1201+ XCTAssertEqual ( observer. observedPages. count, 1 , " Should be one page call for an empty folder. " )
1202+
1203+ // Verify the folder's metadata in the database is up-to-date.
1204+ // This ensures the enumeration process also updates the target item's metadata if necessary
1205+ let dbFolderMetadata =
1206+ try XCTUnwrap ( Self . dbManager. itemMetadata ( ocId: remoteFolder. identifier) )
1207+ XCTAssertEqual (
1208+ dbFolderMetadata. etag,
1209+ remoteFolder. versionIdentifier,
1210+ " Folder ETag should be updated in DB if changed by enumeration. "
1211+ )
1212+ let storedFolderItem = Item (
1213+ metadata: dbFolderMetadata,
1214+ parentItemIdentifier: . init( rootItem. identifier) ,
1215+ account: Self . account,
1216+ remoteInterface: remoteInterface,
1217+ dbManager: Self . dbManager
1218+ )
1219+ let childItemCount = storedFolderItem. childItemCount as? Int
1220+ let expectedChildItemCount = remoteFolder. children. count
1221+ XCTAssertEqual ( childItemCount, expectedChildItemCount)
1222+ }
1223+
1224+ func testFolderWithFewItemsPaginatedEnumeration( ) async throws {
1225+ // 1. Setup: remoteFolder with 3 children (fewer than pageSize 5).
1226+ // Add folder metadata to DB.
1227+ remoteFolder. children = [ ]
1228+ for i in 0 ..< 3 {
1229+ let childItem = MockRemoteItem (
1230+ identifier: " fewItems-child \( i) " ,
1231+ name: " child \( i) .txt " ,
1232+ remotePath: remoteFolder. remotePath + " /child \( i) .txt " ,
1233+ account: Self . account. ncKitAccount,
1234+ username: Self . account. username,
1235+ userId: Self . account. id,
1236+ serverUrl: Self . account. serverUrl
1237+ )
1238+ childItem. parent = remoteFolder
1239+ remoteFolder. children. append ( childItem)
1240+ }
1241+ Self . dbManager. addItemMetadata ( remoteFolder. toItemMetadata ( account: Self . account) )
1242+ XCTAssertNotNil ( Self . dbManager. itemMetadata ( ocId: remoteFolder. identifier) )
1243+
1244+ let db = Self . dbManager. ncDatabase ( )
1245+ debugPrint ( db)
1246+ let remoteInterface = MockRemoteInterface ( rootItem: rootItem, pagination: true )
1247+
1248+ // 2. Create enumerator with pageSize > number of children.
1249+ let enumerator = Enumerator (
1250+ enumeratedItemIdentifier: NSFileProviderItemIdentifier ( remoteFolder. identifier) ,
1251+ account: Self . account,
1252+ remoteInterface: remoteInterface,
1253+ dbManager: Self . dbManager,
1254+ pageSize: 5
1255+ )
1256+ let observer = MockEnumerationObserver ( enumerator: enumerator)
1257+
1258+ // 3. Enumerate items.
1259+ try await observer. enumerateItems ( )
1260+
1261+ // 4. Assertions.
1262+ // Expected items: 0 (folder itself) + 3 children = 3 items.
1263+ XCTAssertEqual ( observer. items. count, 3 , " Should enumerate the 3 children. " )
1264+ XCTAssertFalse (
1265+ observer. items. contains ( where: { $0. itemIdentifier. rawValue == remoteFolder. identifier } ) ,
1266+ " Folder itself should be enumerated. "
1267+ )
1268+ for i in 0 ..< 3 {
1269+ XCTAssertTrue (
1270+ observer. items. contains ( where: { $0. itemIdentifier. rawValue == " fewItems-child \( i) " } ) ,
1271+ " Child item fewItems-child \( i) should be enumerated. "
1272+ )
1273+ }
1274+
1275+ // All items fit on one page.
1276+ XCTAssertEqual (
1277+ observer. observedPages. count,
1278+ 1 ,
1279+ " Should be one page call as all items fit in the first page. "
1280+ )
1281+
1282+ // Verify folder metadata in DB.
1283+ let dbFolderMetadata =
1284+ try XCTUnwrap ( Self . dbManager. itemMetadata ( ocId: remoteFolder. identifier) )
1285+ XCTAssertEqual ( dbFolderMetadata. etag, remoteFolder. versionIdentifier)
1286+ // Ensure all children are also in the DB after enumeration
1287+ for i in 0 ..< 3 {
1288+ XCTAssertNotNil (
1289+ Self . dbManager. itemMetadata ( ocId: " fewItems-child \( i) " ) ,
1290+ " Child item fewItems-child \( i) metadata should be in DB. "
1291+ )
1292+ }
1293+ }
11681294}
0 commit comments