@@ -29,7 +29,7 @@ import XCTest
2929import CoreData
3030@testable import Sourcing
3131
32- // swiftlint:disable force_cast force_try force_unwrapping
32+ // swiftlint:disable force_cast force_try force_unwrapping xctfail_message
3333class FetchedResultsDataProviderTests : XCTestCase {
3434 func managedObjectContextForTesting( ) -> NSManagedObjectContext {
3535 let context = NSManagedObjectContext ( concurrencyType: . mainQueueConcurrencyType)
@@ -42,46 +42,61 @@ class FetchedResultsDataProviderTests: XCTestCase {
4242 }
4343
4444 var managedObjectContext : NSManagedObjectContext !
45- var train : CDTrain !
45+ var train1 : CDTrain !
46+ var train2 : CDTrain !
4647 var fetchedResultsController : NSFetchedResultsController < CDTrain > !
4748 var dataProvider : FetchedResultsDataProvider < CDTrain > !
4849
4950 override func setUp( ) {
5051 managedObjectContext = managedObjectContextForTesting ( )
5152
52- train = NSEntityDescription . insertNewObject ( forEntityName: " CDTrain " , into: managedObjectContext) as! CDTrain
53- train. id = " 1 "
54- train. name = " ICE "
55- managedObjectContext. insert ( train)
53+ train1 = self . train ( id: " 1 " , name: " ICE " )
54+ managedObjectContext. insert ( train1)
5655
57- let fetchReuqest = NSFetchRequest < CDTrain > ( entityName: " CDTrain " )
58- let sortDescriptor = NSSortDescriptor ( key: " name " , ascending: true )
56+ train2 = self . train ( id: " 2 " , name: " ICE " )
57+ managedObjectContext. insert ( train2)
58+
59+ let fetchReuqest : NSFetchRequest < CDTrain > = CDTrain . fetchRequest ( )
60+ let sortDescriptor = NSSortDescriptor ( key: #keyPath( CDTrain . id) , ascending: true )
5961 fetchReuqest. sortDescriptors = [ sortDescriptor]
6062 fetchedResultsController = NSFetchedResultsController ( fetchRequest: fetchReuqest, managedObjectContext: managedObjectContext,
61- sectionNameKeyPath: " name " , cacheName: nil )
63+ sectionNameKeyPath: #keyPath ( CDTrain . name) , cacheName: nil )
6264 dataProvider = try ! FetchedResultsDataProvider ( fetchedResultsController: fetchedResultsController, dataProviderDidUpdate: { _ in } )
6365 }
6466
67+ private func train( id: String , name: String ) -> CDTrain {
68+ let train = CDTrain . newObject ( in: managedObjectContext)
69+ train. id = id
70+ train. name = name
71+ return train
72+ }
73+
6574 func testNumberOfSections( ) {
6675 //Then
6776 XCTAssertEqual ( dataProvider. numberOfSections ( ) , 1 )
6877 }
6978
7079 func testNumberOfItems( ) {
7180 //Then
72- XCTAssertEqual ( dataProvider. numberOfItems ( inSection: 0 ) , 1 )
81+ XCTAssertEqual ( dataProvider. numberOfItems ( inSection: 0 ) , 2 )
7382 }
7483
7584 func testObjectAtIndexPath( ) {
7685 //Then
77- let indexPath = IndexPath ( item: 0 , section: 0 )
78- XCTAssertEqual ( dataProvider. object ( at: indexPath) , train)
86+ var indexPath = IndexPath ( item: 0 , section: 0 )
87+ XCTAssertEqual ( dataProvider. object ( at: indexPath) , train1)
88+
89+ indexPath = IndexPath ( item: 1 , section: 0 )
90+ XCTAssertEqual ( dataProvider. object ( at: indexPath) , train2)
7991 }
8092
8193 func testIndexPathForObject( ) {
8294 //Then
83- let indexPath = IndexPath ( item: 0 , section: 0 )
84- XCTAssertEqual ( dataProvider. indexPath ( for: train) , indexPath)
95+ var indexPath = IndexPath ( item: 0 , section: 0 )
96+ XCTAssertEqual ( dataProvider. indexPath ( for: train1) , indexPath)
97+
98+ indexPath = IndexPath ( item: 1 , section: 0 )
99+ XCTAssertEqual ( dataProvider. indexPath ( for: train2) , indexPath)
85100 }
86101
87102 func testReconfigureFetchRequest( ) {
@@ -201,6 +216,106 @@ class FetchedResultsDataProviderTests: XCTestCase {
201216 XCTAssert ( didUpdateDataSource)
202217 }
203218
219+ func testProcessUpdatesForMoveChange( ) {
220+ //Given
221+ var updateIndexPath = IndexPath ( )
222+ var moveIndexPaths = [ IndexPath] ( )
223+
224+ dataProvider = try ! FetchedResultsDataProvider ( fetchedResultsController: fetchedResultsController, dataProviderDidUpdate: { _ in } )
225+ dataProvider. whenDataProviderChanged = { updates in
226+ guard let updates = updates, !updates. isEmpty else {
227+ return
228+ }
229+
230+ for update in updates {
231+ switch update {
232+ case . update( let indexPath, _) :
233+ updateIndexPath = indexPath
234+ case . move( let indexPath, let newIndexPath) :
235+ moveIndexPaths = [ indexPath, newIndexPath]
236+ default : break
237+ }
238+ }
239+ }
240+
241+ let oldIndexPath = IndexPath ( row: 0 , section: 0 )
242+ let newIndexPath = IndexPath ( row: 1 , section: 0 )
243+ dataProvider. controller ( fetchedResultsController as! NSFetchedResultsController < NSFetchRequestResult > ,
244+ didChange: 1 , at: oldIndexPath, for: . move, newIndexPath: newIndexPath)
245+
246+ //When
247+ dataProvider. controllerDidChangeContent ( fetchedResultsController as! NSFetchedResultsController < NSFetchRequestResult > )
248+
249+ //Then
250+ XCTAssertEqual ( updateIndexPath, newIndexPath)
251+ XCTAssertEqual ( moveIndexPaths, [ oldIndexPath, newIndexPath] )
252+ }
253+
254+ func testProcessUpdatesOrderForMoveChange( ) {
255+ var updatesNumber = 0
256+ var isFirstMoveCall = false
257+ var isSecondUpdateCall = false
258+
259+ dataProvider = try ! FetchedResultsDataProvider ( fetchedResultsController: fetchedResultsController, dataProviderDidUpdate: { _ in } )
260+ dataProvider. whenDataProviderChanged = { updates in
261+ guard let updates = updates, !updates. isEmpty else {
262+ return
263+ }
264+
265+ updatesNumber += 1
266+
267+ if case . move( _, _) = updates. first! {
268+ isFirstMoveCall = true
269+ }
270+
271+ if case . update( _, _) = updates. first! {
272+ if isFirstMoveCall {
273+ isSecondUpdateCall = true
274+ }
275+ }
276+
277+ }
278+
279+ let oldIndexPath = IndexPath ( row: 0 , section: 0 )
280+ let newIndexPath = IndexPath ( row: 1 , section: 0 )
281+ dataProvider. controller ( fetchedResultsController as! NSFetchedResultsController < NSFetchRequestResult > ,
282+ didChange: 1 , at: oldIndexPath, for: . move, newIndexPath: newIndexPath)
283+
284+ //When
285+ dataProvider. controllerDidChangeContent ( fetchedResultsController as! NSFetchedResultsController < NSFetchRequestResult > )
286+
287+ //Then
288+ XCTAssertEqual ( updatesNumber, 2 )
289+ XCTAssert ( isFirstMoveCall)
290+ XCTAssert ( isSecondUpdateCall)
291+ }
292+
293+ func testProcessUpdatesForUpdateChange( ) {
294+ //Given
295+ var updateIndexPath = IndexPath ( )
296+
297+ dataProvider = try ! FetchedResultsDataProvider ( fetchedResultsController: fetchedResultsController, dataProviderDidUpdate: { _ in } )
298+ dataProvider. whenDataProviderChanged = { updates in
299+ guard let updates = updates, !updates. isEmpty else {
300+ return
301+ }
302+
303+ if case . update( let indexPath, _) = updates. first! {
304+ updateIndexPath = indexPath
305+ }
306+ }
307+
308+ let indexPath = IndexPath ( row: 1 , section: 0 )
309+ dataProvider. controller ( fetchedResultsController as! NSFetchedResultsController < NSFetchRequestResult > ,
310+ didChange: 1 , at: indexPath, for: . update, newIndexPath: indexPath)
311+
312+ //When
313+ dataProvider. controllerDidChangeContent ( fetchedResultsController as! NSFetchedResultsController < NSFetchRequestResult > )
314+
315+ //Then
316+ XCTAssertEqual ( updateIndexPath, indexPath)
317+ }
318+
204319 func testWillChangeContent( ) {
205320 //Given
206321 let oldIndexPath = IndexPath ( row: 0 , section: 0 )
0 commit comments