Implemented some more tests to the FetcherTests test cases.
This commit is contained in:
parent
a96c762b85
commit
62a07ff873
@ -24,7 +24,7 @@ public class Fetcher<Model: NSManagedObject>: NSObject, NSFetchedResultsControll
|
|||||||
fetchedResultsController.sections?.count ?? 0
|
fetchedResultsController.sections?.count ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private var inProgressChanges: [Change] = []
|
private var changesToNotify: [Change] = []
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
|
|
||||||
@ -87,11 +87,11 @@ public class Fetcher<Model: NSManagedObject>: NSObject, NSFetchedResultsControll
|
|||||||
// MARK: NSFetchedResultsControllerDelegate
|
// MARK: NSFetchedResultsControllerDelegate
|
||||||
|
|
||||||
public func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
public func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||||
inProgressChanges.removeAll()
|
changesToNotify.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||||
didChangePublisher.send(inProgressChanges)
|
didChangePublisher.send(changesToNotify)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func controller(
|
public func controller(
|
||||||
@ -101,9 +101,9 @@ public class Fetcher<Model: NSManagedObject>: NSObject, NSFetchedResultsControll
|
|||||||
for type: NSFetchedResultsChangeType
|
for type: NSFetchedResultsChangeType
|
||||||
) {
|
) {
|
||||||
if type == .insert {
|
if type == .insert {
|
||||||
inProgressChanges.append(.section(.inserted(sectionIndex)))
|
changesToNotify.append(.section(.inserted(sectionIndex)))
|
||||||
} else if type == .delete {
|
} else if type == .delete {
|
||||||
inProgressChanges.append(.section(.deleted(sectionIndex)))
|
changesToNotify.append(.section(.deleted(sectionIndex)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,19 +118,19 @@ public class Fetcher<Model: NSManagedObject>: NSObject, NSFetchedResultsControll
|
|||||||
case .insert:
|
case .insert:
|
||||||
guard let newIndexPath else { return }
|
guard let newIndexPath else { return }
|
||||||
|
|
||||||
inProgressChanges.append(.object(.inserted(at: newIndexPath)))
|
changesToNotify.append(.object(.inserted(at: newIndexPath)))
|
||||||
case .delete:
|
case .delete:
|
||||||
guard let indexPath else { return }
|
guard let indexPath else { return }
|
||||||
|
|
||||||
inProgressChanges.append(.object(.deleted(from: indexPath)))
|
changesToNotify.append(.object(.deleted(from: indexPath)))
|
||||||
case .move:
|
case .move:
|
||||||
guard let indexPath, let newIndexPath else { return }
|
guard let indexPath, let newIndexPath else { return }
|
||||||
|
|
||||||
inProgressChanges.append(.object(.moved(from: indexPath, to: newIndexPath)))
|
changesToNotify.append(.object(.moved(from: indexPath, to: newIndexPath)))
|
||||||
case .update:
|
case .update:
|
||||||
guard let indexPath else { return }
|
guard let indexPath else { return }
|
||||||
|
|
||||||
inProgressChanges.append(.object(.updated(at: indexPath)))
|
changesToNotify.append(.object(.updated(at: indexPath)))
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
// Copyright © 2023 Röck+Cöde. All rights reserved.
|
// Copyright © 2023 Röck+Cöde. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
import Persistence
|
import Persistence
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
@ -13,21 +14,16 @@ final class FetcherTests: XCTestCase {
|
|||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
private let persistence = TestPersistenceService.shared
|
private lazy var persistence: TestPersistenceService = .shared
|
||||||
|
private lazy var fetcher: Fetcher<TestEntity> = .init(
|
||||||
private var fetcher: Fetcher<TestEntity>!
|
|
||||||
|
|
||||||
// MARK: Setup
|
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
|
||||||
fetcher = .init(
|
|
||||||
fetchRequest: .allTestEntities(),
|
fetchRequest: .allTestEntities(),
|
||||||
managedObjectContext: persistence.viewContext
|
managedObjectContext: persistence.viewContext
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
// MARK: Setup
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
fetcher = nil
|
try persistence.clean()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Number of sections tests
|
// MARK: Number of sections tests
|
||||||
@ -132,7 +128,7 @@ final class FetcherTests: XCTestCase {
|
|||||||
try fetcher.fetch()
|
try fetcher.fetch()
|
||||||
|
|
||||||
// WHEN & THEN
|
// WHEN & THEN
|
||||||
let indexPath = IndexPath(
|
let _ = IndexPath(
|
||||||
item: 0,
|
item: 0,
|
||||||
section: fetcher.numberOfSections - 1
|
section: fetcher.numberOfSections - 1
|
||||||
)
|
)
|
||||||
@ -169,7 +165,7 @@ final class FetcherTests: XCTestCase {
|
|||||||
try fetcher.fetch()
|
try fetcher.fetch()
|
||||||
|
|
||||||
// WHEN & THEN
|
// WHEN & THEN
|
||||||
let indexPath = IndexPath(
|
let _ = IndexPath(
|
||||||
item: entities.count,
|
item: entities.count,
|
||||||
section: fetcher.numberOfSections
|
section: fetcher.numberOfSections
|
||||||
)
|
)
|
||||||
@ -191,4 +187,133 @@ final class FetcherTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Did change publisher tests
|
||||||
|
|
||||||
|
func test_didChangePublisher_whenModelIsEmpty() throws {
|
||||||
|
let expectation = self.expectation(description: "didChangePublisher when model is filled.")
|
||||||
|
|
||||||
|
var result: [Change]?
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
let cancellable = fetcher
|
||||||
|
.didChangePublisher
|
||||||
|
.sink(receiveValue: { value in
|
||||||
|
result = value
|
||||||
|
|
||||||
|
expectation.fulfill()
|
||||||
|
})
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
try fetcher.fetch()
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
let waiter = XCTWaiter.wait(for: [expectation], timeout: 1.0)
|
||||||
|
|
||||||
|
guard waiter == .timedOut else {
|
||||||
|
XCTFail("Waiter expected to time out.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellable.cancel()
|
||||||
|
|
||||||
|
XCTAssertNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_didChangePublisher_whenModelIsFilled() throws {
|
||||||
|
let expectation = self.expectation(description: "didChangePublisher when model is filled.")
|
||||||
|
|
||||||
|
var result: [Change]?
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
let context = persistence.makeChildContext()
|
||||||
|
let _ = [
|
||||||
|
TestEntity(context: context),
|
||||||
|
TestEntity(context: context),
|
||||||
|
TestEntity(context: context)
|
||||||
|
]
|
||||||
|
|
||||||
|
let cancellable = fetcher
|
||||||
|
.didChangePublisher
|
||||||
|
.sink(receiveValue: { value in
|
||||||
|
result = value
|
||||||
|
|
||||||
|
expectation.fulfill()
|
||||||
|
})
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
try persistence.save(childContext: context)
|
||||||
|
try fetcher.fetch()
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
let waiter = XCTWaiter.wait(for: [expectation], timeout: 1.0)
|
||||||
|
|
||||||
|
guard waiter == .timedOut else {
|
||||||
|
XCTFail("Waiter expected to time out.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellable.cancel()
|
||||||
|
|
||||||
|
XCTAssertNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_didChangePublisher_whenModelIsUpdated() throws {
|
||||||
|
let expectation = self.expectation(description: "didChangePublisher when model is updated.")
|
||||||
|
|
||||||
|
var result: [Change]?
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
let context = persistence.makeChildContext()
|
||||||
|
let entities = [
|
||||||
|
TestEntity(context: context),
|
||||||
|
TestEntity(context: context),
|
||||||
|
TestEntity(context: context)
|
||||||
|
]
|
||||||
|
|
||||||
|
let cancellable = fetcher
|
||||||
|
.didChangePublisher
|
||||||
|
.sink(receiveValue: { value in
|
||||||
|
result = value
|
||||||
|
|
||||||
|
expectation.fulfill()
|
||||||
|
})
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
try fetcher.fetch()
|
||||||
|
try persistence.save(childContext: context)
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
waitForExpectations(timeout: 1.0)
|
||||||
|
|
||||||
|
cancellable.cancel()
|
||||||
|
|
||||||
|
XCTAssertNotNil(result)
|
||||||
|
XCTAssertEqual(result?.count, entities.count)
|
||||||
|
XCTAssertEqual(result, [
|
||||||
|
.object(.inserted(at: .init(item: 2, section: 0))),
|
||||||
|
.object(.inserted(at: .init(item: 1, section: 0))),
|
||||||
|
.object(.inserted(at: .init(item: 0, section: 0))),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - TestPersistenceService+Functions
|
||||||
|
|
||||||
|
private extension TestPersistenceService {
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
|
||||||
|
func clean() throws {
|
||||||
|
let context = makeChildContext()
|
||||||
|
|
||||||
|
try context.performAndWait {
|
||||||
|
try context
|
||||||
|
.fetch(.allTestEntities())
|
||||||
|
.forEach(context.delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
try save(childContext: context)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user