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
7 changes: 7 additions & 0 deletions WordPress/Classes/Utility/ContainerContextFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ class ContainerContextFactory: NSObject, ManagedObjectContextFactory {
completionBlock?()
}
}

/// Ensure that the `context`'s concurrency type is not `confinementConcurrencyType`, since it will crash if `perform` or `performAndWait` is called.
guard context.concurrencyType == .mainQueueConcurrencyType || context.concurrencyType == .privateQueueConcurrencyType else {
Copy link
Contributor Author

@dvdchr dvdchr Dec 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do if context.concurrencyType == .confinementConcurrencyType {, but Xcode will throw out a warning if we type a deprecated enum value. 🙃

block()
return
}

if wait {
context.performAndWait(block)
} else {
Expand Down
16 changes: 10 additions & 6 deletions WordPress/WordPress.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -5209,6 +5209,7 @@
FE25C235271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */; };
FE25C236271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */; };
FE2E3729281C839C00A1E82A /* BloggingPromptsServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2E3728281C839C00A1E82A /* BloggingPromptsServiceTests.swift */; };
FE320CC5294705990046899B /* ContainerContextFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE320CC4294705990046899B /* ContainerContextFactoryTests.swift */; };
FE32E7F12844971000744D80 /* ReminderScheduleCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32E7F02844971000744D80 /* ReminderScheduleCoordinatorTests.swift */; };
FE32EFFF275914390040BE67 /* MenuSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32EFFE275914390040BE67 /* MenuSheetViewController.swift */; };
FE32F000275914390040BE67 /* MenuSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32EFFE275914390040BE67 /* MenuSheetViewController.swift */; };
Expand Down Expand Up @@ -8810,6 +8811,7 @@
FE23EB4826E7C91F005A1698 /* richCommentStyle.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = richCommentStyle.css; path = Resources/HTML/richCommentStyle.css; sourceTree = "<group>"; };
FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderCommentsNotificationSheetViewController.swift; sourceTree = "<group>"; };
FE2E3728281C839C00A1E82A /* BloggingPromptsServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsServiceTests.swift; sourceTree = "<group>"; };
FE320CC4294705990046899B /* ContainerContextFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerContextFactoryTests.swift; sourceTree = "<group>"; };
FE32E7F02844971000744D80 /* ReminderScheduleCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderScheduleCoordinatorTests.swift; sourceTree = "<group>"; };
FE32E7F32846A68800744D80 /* WordPress 142.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 142.xcdatamodel"; sourceTree = "<group>"; };
FE32EFFE275914390040BE67 /* MenuSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuSheetViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -9877,7 +9879,7 @@
path = Classes;
sourceTree = "<group>";
};
29B97314FDCFA39411CA2CEA = {
29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
isa = PBXGroup;
children = (
3F20FDF3276BF21000DA3CAD /* Packages */,
Expand Down Expand Up @@ -14564,6 +14566,7 @@
93E9050319E6F242005513C9 /* ContextManagerTests.swift */,
B5ECA6CC1DBAAD510062D7E0 /* CoreDataHelperTests.swift */,
931D26FF19EDAE8600114F17 /* CoreDataMigrationTests.m */,
FE320CC4294705990046899B /* ContainerContextFactoryTests.swift */,
);
name = "Core Data";
sourceTree = "<group>";
Expand Down Expand Up @@ -17869,14 +17872,14 @@
bg,
sk,
);
mainGroup = 29B97314FDCFA39411CA2CEA;
mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
packageReferences = (
3FF1442E266F3C2400138163 /* XCRemoteSwiftPackageReference "ScreenObject" */,
3FC2C33B26C4CF0A00C6D98F /* XCRemoteSwiftPackageReference "XCUITestHelpers" */,
17A8858B2757B97F0071FCA3 /* XCRemoteSwiftPackageReference "AutomatticAbout-swift" */,
3F2B62DA284F4E0B0008CD59 /* XCRemoteSwiftPackageReference "Charts" */,
3F3B23C02858A1B300CACE60 /* XCRemoteSwiftPackageReference "test-collector-swift" */,
3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios.git" */,
3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios" */,
3F338B6F289BD3040014ADC5 /* XCRemoteSwiftPackageReference "Nimble" */,
);
productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */;
Expand Down Expand Up @@ -22318,6 +22321,7 @@
C738CB1128626606001BE107 /* QRLoginVerifyCoordinatorTests.swift in Sources */,
FF0B2567237A023C004E255F /* GutenbergVideoUploadProcessorTests.swift in Sources */,
FF1B11E7238FE27A0038B93E /* GutenbergGalleryUploadProcessorTests.swift in Sources */,
FE320CC5294705990046899B /* ContainerContextFactoryTests.swift in Sources */,
F4D9AF51288AE23500803D40 /* SuggestionTableViewTests.swift in Sources */,
8BC12F72231FEBA1004DDA72 /* PostCoordinatorTests.swift in Sources */,
C3C2F84628AC8BC700937E45 /* JetpackBannerScrollVisibilityTests.swift in Sources */,
Expand Down Expand Up @@ -29112,7 +29116,7 @@
minimumVersion = 0.3.0;
};
};
3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios.git" */ = {
3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/airbnb/lottie-ios.git";
requirement = {
Expand Down Expand Up @@ -29185,12 +29189,12 @@
};
3F411B6E28987E3F002513AE /* Lottie */ = {
isa = XCSwiftPackageProductDependency;
package = 3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios.git" */;
package = 3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios" */;
productName = Lottie;
};
3F44DD57289C379C006334CD /* Lottie */ = {
isa = XCSwiftPackageProductDependency;
package = 3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios.git" */;
package = 3F411B6D28987E3F002513AE /* XCRemoteSwiftPackageReference "lottie-ios" */;
productName = Lottie;
};
3FC2C33C26C4CF0A00C6D98F /* XCUITestHelpers */ = {
Expand Down
112 changes: 112 additions & 0 deletions WordPress/WordPressTest/ContainerContextFactoryTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import XCTest

@testable import WordPress

final class ContainerContextFactoryTests: XCTestCase {

private var persistentContainer: NSPersistentContainer!
private var factory: ContainerContextFactory!

override func setUp() {
super.setUp()

persistentContainer = makeInMemoryContainer()
factory = ContainerContextFactory(persistentContainer: persistentContainer)
}

override func tearDown() {
persistentContainer = nil
factory = nil

super.tearDown()
}

// MARK: - `save` Tests

func test_save_givenMainQueueConcurrencyType_shouldCallPerform() {
let context = makeMockContext(concurrencyType: .mainQueueConcurrencyType)

factory.save(context, andWait: false, withCompletionBlock: nil)

XCTAssertTrue(context.performCalled)
XCTAssertFalse(context.performAndWaitCalled)
}

func test_save_givenMainQueueConcurrencyType_andWaitIsSetToTrue_shouldCallPerformAndWait() {
let context = makeMockContext(concurrencyType: .mainQueueConcurrencyType)

factory.save(context, andWait: true, withCompletionBlock: nil)

XCTAssertFalse(context.performCalled)
XCTAssertTrue(context.performAndWaitCalled)
}

func test_save_givenPrivateQueueConcurrencyType_shouldCallPerform() {
let context = makeMockContext(concurrencyType: .privateQueueConcurrencyType)

factory.save(context, andWait: false, withCompletionBlock: nil)

XCTAssertTrue(context.performCalled)
XCTAssertFalse(context.performAndWaitCalled)
}

func test_save_givenPrivateQueueConcurrencyType_andWaitIsSetToTrue_shouldCallPerformAndWait() {
let context = makeMockContext(concurrencyType: .privateQueueConcurrencyType)

factory.save(context, andWait: true, withCompletionBlock: nil)

XCTAssertFalse(context.performCalled)
XCTAssertTrue(context.performAndWaitCalled)
}

func test_save_givenDeprecatedConcurrencyType_shouldNotCallPerform() {
/// creates a context with `.confinementConcurrencyType`. The enum is created from its raw value
/// to prevent Xcode from complaining since the enum value is deprecated.
let context = makeMockContext(concurrencyType: NSManagedObjectContextConcurrencyType(rawValue: 0)!)

factory.save(context, andWait: false, withCompletionBlock: nil)

XCTAssertFalse(context.performCalled)
XCTAssertFalse(context.performAndWaitCalled)
}
}

// MARK: - Private Helpers

private extension ContainerContextFactoryTests {

class MockManagedObjectContext: NSManagedObjectContext {

var performCalled = false
var performAndWaitCalled = false

override func perform(_ block: @escaping () -> Void) {
performCalled = true
}

override func performAndWait(_ block: () -> Void) {
performAndWaitCalled = true
}

override func save() throws {
// do nothing. let's make sure nothing gets saved.
}
}

/// Creates an "in-memory" NSPersistentContainer.
/// This follows the approach used in WWDC'18: https://developer.apple.com/videos/play/wwdc2018/224/
///
/// - Returns: An instance of NSPersistentContainer that stores data in memory.
func makeInMemoryContainer() -> NSPersistentContainer {
let container = NSPersistentContainer(name: "WordPress")
let description = NSPersistentStoreDescription(url: .init(fileURLWithPath: "/dev/null"))
container.persistentStoreDescriptions = [description]

return container
}

func makeMockContext(concurrencyType: NSManagedObjectContextConcurrencyType) -> MockManagedObjectContext {
return MockManagedObjectContext(concurrencyType: concurrencyType)
}

}