Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions Sources/CoreDataRepository/CoreDataRepository+CRUD.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ extension CoreDataRepository {
_ item: Model,
transactionAuthor: String? = nil
) async -> Result<Model, CoreDataRepositoryError> {
await context.performInScratchPad(schedule: .enqueued) { scratchPad in
await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
scratchPad.transactionAuthor = transactionAuthor
let object = Model.RepoManaged(context: scratchPad)
object.create(from: item)
try scratchPad.save()
try context.performAndWait {
try context.save()
}
try scratchPad.obtainPermanentIDs(for: [object])
return object.asUnmanaged
}
}
Expand Down Expand Up @@ -68,12 +72,15 @@ extension CoreDataRepository {
with item: Model,
transactionAuthor _: String? = nil
) async -> Result<Model, CoreDataRepositoryError> {
await context.performInScratchPad(schedule: .enqueued) { scratchPad in
await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
let id = try scratchPad.tryObjectId(from: url)
let object = try scratchPad.notDeletedObject(for: id)
let repoManaged: Model.RepoManaged = try object.asRepoManaged()
repoManaged.update(from: item)
try scratchPad.save()
try context.performAndWait {
try context.save()
}
return repoManaged.asUnmanaged
}
}
Expand All @@ -92,12 +99,15 @@ extension CoreDataRepository {
_ url: URL,
transactionAuthor _: String? = nil
) async -> Result<Void, CoreDataRepositoryError> {
await context.performInScratchPad(schedule: .enqueued) { scratchPad in
await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
let id = try scratchPad.tryObjectId(from: url)
let object = try scratchPad.notDeletedObject(for: id)
object.prepareForDeletion()
scratchPad.delete(object)
try scratchPad.save()
try context.performAndWait {
try context.save()
}
return ()
}
}
Expand Down
4 changes: 4 additions & 0 deletions Tests/CoreDataRepositoryTests/BatchRepositoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ final class BatchRepositoryTests: CoreDataXCTestCase {
XCTAssertEqual(result.success.count, newMovies.count)
XCTAssertEqual(result.failed.count, 0)

for movie in result.success {
try await verify(movie)
}

try await repositoryContext().perform {
let data = try self.repositoryContext().fetch(fetchRequest)
XCTAssertEqual(
Expand Down
37 changes: 22 additions & 15 deletions Tests/CoreDataRepositoryTests/CRUDRepositoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ final class CRUDRepositoryTests: CoreDataXCTestCase {
func testCreateSuccess() async throws {
let movie = Movie(id: UUID(), title: "Create Success", releaseDate: Date(), boxOffice: 100)
let result: Result<Movie, CoreDataRepositoryError> = try await repository().create(movie)
guard case var .success(resultMovie) = result else {
guard case let .success(resultMovie) = result else {
XCTFail("Not expecting a failed result")
return
}
var tempResultMovie = resultMovie
XCTAssertNotNil(tempResultMovie.url)
tempResultMovie.url = nil
XCTAssertNoDifference(tempResultMovie, movie)

XCTAssertNotNil(resultMovie.url)
resultMovie.url = nil
let diff = CustomDump.diff(resultMovie, movie)
XCTAssertNil(diff)
try await verify(resultMovie)
}

func testReadSuccess() async throws {
Expand All @@ -39,15 +40,18 @@ final class CRUDRepositoryTests: CoreDataXCTestCase {
let result: Result<Movie, CoreDataRepositoryError> = try await repository()
.read(try XCTUnwrap(createdMovie.url))

guard case var .success(resultMovie) = result else {
guard case let .success(resultMovie) = result else {
XCTFail("Not expecting a failed result")
return
}

XCTAssertNotNil(resultMovie.url)
resultMovie.url = nil
let diff = CustomDump.diff(resultMovie, movie)
XCTAssertNil(diff)
var tempResultMovie = resultMovie

XCTAssertNotNil(tempResultMovie.url)
tempResultMovie.url = nil
XCTAssertNoDifference(tempResultMovie, movie)

try await verify(resultMovie)
}

func testReadFailure() async throws {
Expand Down Expand Up @@ -91,15 +95,18 @@ final class CRUDRepositoryTests: CoreDataXCTestCase {
let result: Result<Movie, CoreDataRepositoryError> = try await repository()
.update(try XCTUnwrap(createdMovie.url), with: movie)

guard case var .success(resultMovie) = result else {
guard case let .success(resultMovie) = result else {
XCTFail("Not expecting a failed result")
return
}

XCTAssertNotNil(resultMovie.url)
resultMovie.url = nil
let diff = CustomDump.diff(resultMovie, movie)
XCTAssertNil(diff)
var tempResultMovie = resultMovie

XCTAssertNotNil(tempResultMovie.url)
tempResultMovie.url = nil
XCTAssertNoDifference(tempResultMovie, movie)

try await verify(resultMovie)
}

func testUpdateFailure() async throws {
Expand Down
37 changes: 37 additions & 0 deletions Tests/CoreDataRepositoryTests/CoreDataXCTestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import Combine
import CoreData
import CoreDataRepository
import CustomDump
import XCTest

class CoreDataXCTestCase: XCTestCase {
Expand Down Expand Up @@ -49,4 +50,40 @@ class CoreDataXCTestCase: XCTestCase {
_repository = nil
cancellables.forEach { $0.cancel() }
}

func verify<T>(_ item: T) async throws where T: UnmanagedModel {
guard let url = item.managedRepoUrl else {
XCTFail("Failed to verify item in store because it has no URL")
return
}

let context = try repositoryContext()
let coordinator = try container().persistentStoreCoordinator
context.performAndWait {
guard let objectID = coordinator.managedObjectID(forURIRepresentation: url) else {
XCTFail("Failed to verify item in store because no NSManagedObjectID found in viewContext from URL.")
return
}
var _object: NSManagedObject?
do {
_object = try context.existingObject(with: objectID)
} catch {
XCTFail(
"Failed to verify item in store because it was not found by its NSManagedObjectID. Error: \(error.localizedDescription)"
)
return
}

guard let object = _object else {
XCTFail("Failed to verify item in store because it was not found by its NSManagedObjectID")
return
}

guard let managedItem = object as? T.RepoManaged else {
XCTFail("Failed to verify item in store because it failed to cast to RepoManaged type.")
return
}
XCTAssertNoDifference(item, managedItem.asUnmanaged)
}
}
}