summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2023-04-26 18:07:58 +0200
committerAndrej Mihajlov <and@mullvad.net>2023-05-03 16:41:55 +0200
commitf3760caf18da794e3aaa95a2f40a492d04a3f5f8 (patch)
tree5db7476a37518bd1bfc99208098d4fbd3409980d
parent3d4e85a949c2d92a9484e354072df221c477bd63 (diff)
downloadmullvadvpn-f3760caf18da794e3aaa95a2f40a492d04a3f5f8.tar.xz
mullvadvpn-f3760caf18da794e3aaa95a2f40a492d04a3f5f8.zip
Operations: add new tests
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj16
-rw-r--r--ios/Operations/AsyncOperation.swift5
-rw-r--r--ios/OperationsTests/AsyncBlockOperationTests.swift100
-rw-r--r--ios/OperationsTests/AsyncResultBlockOperationTests.swift75
-rw-r--r--ios/OperationsTests/OperationCancellationTests.swift35
-rw-r--r--ios/OperationsTests/OperationObserverTests.swift4
-rw-r--r--ios/OperationsTests/TransformOperationTests.swift93
7 files changed, 287 insertions, 41 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 08a215b1c9..9e3cabb024 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -116,7 +116,6 @@
585E820327F3285E00939F0E /* SendStoreReceiptOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */; };
58607A4D2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58607A4C2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift */; };
586168692976F6BD00EF8598 /* DisplayError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586168682976F6BD00EF8598 /* DisplayError.swift */; };
- 586250BB29E6F8F300F4B521 /* OperationCancellationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586250BA29E6F8F300F4B521 /* OperationCancellationTests.swift */; };
5862805422428EF100F5A6E1 /* TranslucentButtonBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */; };
5864211F29F04CED00822139 /* UIBarButtonItem+Blocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864211E29F04CED00822139 /* UIBarButtonItem+Blocks.swift */; };
5864859929A0D028006C5743 /* FormsheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5864859829A0D028006C5743 /* FormsheetPresentationController.swift */; };
@@ -221,6 +220,9 @@
58ACF64B26553C3F00ACE4B7 /* SettingsSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ACF64A26553C3F00ACE4B7 /* SettingsSwitchCell.swift */; };
58ACF64D26567A5000ACE4B7 /* CustomSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ACF64C26567A4F00ACE4B7 /* CustomSwitch.swift */; };
58ACF64F26567A7100ACE4B7 /* CustomSwitchContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58ACF64E26567A7100ACE4B7 /* CustomSwitchContainer.swift */; };
+ 58AFC99529F96F7B000829DE /* AsyncBlockOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AFC99429F96F7B000829DE /* AsyncBlockOperationTests.swift */; };
+ 58AFC99729F9753D000829DE /* AsyncResultBlockOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AFC99629F9753D000829DE /* AsyncResultBlockOperationTests.swift */; };
+ 58AFC99929F97856000829DE /* TransformOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58AFC99829F97856000829DE /* TransformOperationTests.swift */; };
58B0A2A8238EE68200BC001D /* RelaySelectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584B26F3237434D00073B10E /* RelaySelectorTests.swift */; };
58B26E1E2943514300D5980C /* InAppNotificationDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B26E1D2943514300D5980C /* InAppNotificationDescriptor.swift */; };
58B26E22294351EA00D5980C /* InAppNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B26E21294351EA00D5980C /* InAppNotificationProvider.swift */; };
@@ -748,7 +750,6 @@
585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendStoreReceiptOperation.swift; sourceTree = "<group>"; };
58607A4C2947287800BC467D /* AccountExpiryInAppNotificationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountExpiryInAppNotificationProvider.swift; sourceTree = "<group>"; };
586168682976F6BD00EF8598 /* DisplayError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayError.swift; sourceTree = "<group>"; };
- 586250BA29E6F8F300F4B521 /* OperationCancellationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationCancellationTests.swift; sourceTree = "<group>"; };
5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslucentButtonBlurView.swift; sourceTree = "<group>"; };
5864211E29F04CED00822139 /* UIBarButtonItem+Blocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+Blocks.swift"; sourceTree = "<group>"; };
5864859829A0D028006C5743 /* FormsheetPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormsheetPresentationController.swift; sourceTree = "<group>"; };
@@ -851,6 +852,9 @@
58ACF64C26567A4F00ACE4B7 /* CustomSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSwitch.swift; sourceTree = "<group>"; };
58ACF64E26567A7100ACE4B7 /* CustomSwitchContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSwitchContainer.swift; sourceTree = "<group>"; };
58AEEF642344A36000C9BBD5 /* KeychainError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainError.swift; sourceTree = "<group>"; };
+ 58AFC99429F96F7B000829DE /* AsyncBlockOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncBlockOperationTests.swift; sourceTree = "<group>"; };
+ 58AFC99629F9753D000829DE /* AsyncResultBlockOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncResultBlockOperationTests.swift; sourceTree = "<group>"; };
+ 58AFC99829F97856000829DE /* TransformOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransformOperationTests.swift; sourceTree = "<group>"; };
58B0A2A0238EE67E00BC001D /* MullvadVPNTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadVPNTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
58B0A2A4238EE67E00BC001D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
58B26E1D2943514300D5980C /* InAppNotificationDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppNotificationDescriptor.swift; sourceTree = "<group>"; };
@@ -1646,7 +1650,9 @@
58DF5B772852178600E92647 /* OperationInputInjectionTests.swift */,
583E1E292848DF67004838B3 /* OperationObserverTests.swift */,
580CBFB72848D503007878F0 /* OperationConditionTests.swift */,
- 586250BA29E6F8F300F4B521 /* OperationCancellationTests.swift */,
+ 58AFC99429F96F7B000829DE /* AsyncBlockOperationTests.swift */,
+ 58AFC99629F9753D000829DE /* AsyncResultBlockOperationTests.swift */,
+ 58AFC99829F97856000829DE /* TransformOperationTests.swift */,
);
path = OperationsTests;
sourceTree = "<group>";
@@ -2567,9 +2573,11 @@
files = (
589A455F28E094BF00565204 /* OperationConditionTests.swift in Sources */,
589A455E28E094BF00565204 /* OperationInputInjectionTests.swift in Sources */,
- 586250BB29E6F8F300F4B521 /* OperationCancellationTests.swift in Sources */,
+ 58AFC99529F96F7B000829DE /* AsyncBlockOperationTests.swift in Sources */,
+ 58AFC99729F9753D000829DE /* AsyncResultBlockOperationTests.swift in Sources */,
589A455C28E094BF00565204 /* OperationSmokeTests.swift in Sources */,
589A455D28E094BF00565204 /* OperationObserverTests.swift in Sources */,
+ 58AFC99929F97856000829DE /* TransformOperationTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/ios/Operations/AsyncOperation.swift b/ios/Operations/AsyncOperation.swift
index 2ca049030c..ca11e86d7e 100644
--- a/ios/Operations/AsyncOperation.swift
+++ b/ios/Operations/AsyncOperation.swift
@@ -436,6 +436,11 @@ extension OperationBlockObserverSupport where Self: AsyncOperation {
addBlockObserver(OperationBlockObserver(didFinish: fn))
}
+ /// Add observer responding to start event.
+ public func onStart(_ fn: @escaping (Self) -> Void) {
+ addBlockObserver(OperationBlockObserver(didStart: fn))
+ }
+
/// Add block-based observer.
public func addBlockObserver(_ observer: OperationBlockObserver<Self>) {
addObserver(observer)
diff --git a/ios/OperationsTests/AsyncBlockOperationTests.swift b/ios/OperationsTests/AsyncBlockOperationTests.swift
new file mode 100644
index 0000000000..03373a57bf
--- /dev/null
+++ b/ios/OperationsTests/AsyncBlockOperationTests.swift
@@ -0,0 +1,100 @@
+//
+// AsyncBlockOperationTests.swift
+// OperationsTests
+//
+// Created by pronebird on 26/04/2023.
+// Copyright © 2023 Mullvad VPN AB. All rights reserved.
+//
+
+import MullvadTypes
+import Operations
+import XCTest
+
+final class AsyncBlockOperationTests: XCTestCase {
+ let operationQueue = AsyncOperationQueue()
+
+ func testBlockOperation() {
+ let executionExpectation = expectation(description: "Should execute")
+ let finishExpectation = expectation(description: "Should finish")
+
+ let operation = AsyncBlockOperation(block: { op in
+ executionExpectation.fulfill()
+ op.finish()
+ })
+
+ operation.completionBlock = {
+ finishExpectation.fulfill()
+ }
+
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testSynchronousBlockOperation() {
+ let executionExpectation = expectation(description: "Should execute")
+ let finishExpectation = expectation(description: "Should finish")
+
+ let operation = AsyncBlockOperation {
+ executionExpectation.fulfill()
+ }
+
+ operation.completionBlock = {
+ finishExpectation.fulfill()
+ }
+
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testCancellableTaskBlockOperation() {
+ let executionExpectation = expectation(description: "Should execute")
+ let cancelExpectation = expectation(description: "Should cancel")
+ let finishExpectation = expectation(description: "Should finish")
+
+ let operation = AsyncBlockOperation(cancellableTask: { op in
+ executionExpectation.fulfill()
+
+ return AnyCancellable {
+ cancelExpectation.fulfill()
+
+ op.finish()
+ }
+ })
+
+ operation.completionBlock = {
+ finishExpectation.fulfill()
+ }
+
+ operation.onStart { op in
+ op.cancel()
+ }
+
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 100)
+ }
+
+ func testCancellationShouldNotFireBeforeOperationIsEnqueued() throws {
+ let expect = expectation(description: "Cancellation should not fire.")
+ expect.isInverted = true
+
+ let operation = AsyncBlockOperation {}
+ operation.onCancel { _ in expect.fulfill() }
+ operation.cancel()
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testCancellationShouldFireAfterCancelledOperationIsEnqueued() throws {
+ let expect = expectation(description: "Cancellation should fire.")
+
+ let operation = AsyncBlockOperation {}
+ operation.onCancel { _ in expect.fulfill() }
+ operation.cancel()
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+}
diff --git a/ios/OperationsTests/AsyncResultBlockOperationTests.swift b/ios/OperationsTests/AsyncResultBlockOperationTests.swift
new file mode 100644
index 0000000000..160e7b2580
--- /dev/null
+++ b/ios/OperationsTests/AsyncResultBlockOperationTests.swift
@@ -0,0 +1,75 @@
+//
+// AsyncResultBlockOperationTests.swift
+// OperationsTests
+//
+// Created by pronebird on 26/04/2023.
+// Copyright © 2023 Mullvad VPN AB. All rights reserved.
+//
+
+import MullvadTypes
+import Operations
+import XCTest
+
+final class AsyncResultBlockOperationTests: XCTestCase {
+ let operationQueue = AsyncOperationQueue()
+
+ func testBlockOperation() {
+ let expectation = expectation(description: "Should finish")
+
+ let operation = ResultBlockOperation<Bool> { op in
+ op.finish(result: .success(true))
+ }
+
+ operation.onFinish { op, error in
+ XCTAssertEqual(op.result?.value, true)
+ expectation.fulfill()
+ }
+
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testThrowingBlockOperation() {
+ let expectation = expectation(description: "Should finish")
+
+ let operation = ResultBlockOperation {
+ throw URLError(.badURL)
+ }
+
+ operation.onFinish { op, error in
+ XCTAssertEqual(op.result?.error as? URLError, URLError(.badURL))
+ XCTAssertEqual(error as? URLError, URLError(.badURL))
+
+ expectation.fulfill()
+ }
+
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testCancellableTaskOperation() {
+ let expectation = expectation(description: "Should finish")
+
+ let operation = ResultBlockOperation<Bool>(cancellableTask: { op in
+ return AnyCancellable {
+ op.finish(result: .failure(URLError(.cancelled)))
+ }
+ })
+
+ operation.onStart { op in
+ op.cancel()
+ }
+
+ operation.onFinish { op, error in
+ XCTAssertEqual(op.result?.error as? URLError, URLError(.cancelled))
+ XCTAssertEqual(error as? URLError, URLError(.cancelled))
+ expectation.fulfill()
+ }
+
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+}
diff --git a/ios/OperationsTests/OperationCancellationTests.swift b/ios/OperationsTests/OperationCancellationTests.swift
deleted file mode 100644
index 7313bc83b2..0000000000
--- a/ios/OperationsTests/OperationCancellationTests.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// OperationCancellationTests.swift
-// OperationsTests
-//
-// Created by pronebird on 12/04/2023.
-// Copyright © 2023 Mullvad VPN AB. All rights reserved.
-//
-
-import Operations
-import XCTest
-
-final class OperationCancellationTests: XCTestCase {
- func testCancellationShouldNotFireBeforeOperationIsEnqueued() throws {
- let expect = expectation(description: "Cancellation should not fire.")
- expect.isInverted = true
-
- let operation = AsyncBlockOperation {}
- operation.onCancel { _ in expect.fulfill() }
- operation.cancel()
-
- waitForExpectations(timeout: 1)
- }
-
- func testCancellationShouldFireAfterCancelledOperationIsEnqueued() throws {
- let expect = expectation(description: "Cancellation should fire.")
-
- let operationQueue = AsyncOperationQueue()
- let operation = AsyncBlockOperation {}
- operation.onCancel { _ in expect.fulfill() }
- operation.cancel()
- operationQueue.addOperation(operation)
-
- waitForExpectations(timeout: 1)
- }
-}
diff --git a/ios/OperationsTests/OperationObserverTests.swift b/ios/OperationsTests/OperationObserverTests.swift
index c246cdc526..de334be21a 100644
--- a/ios/OperationsTests/OperationObserverTests.swift
+++ b/ios/OperationsTests/OperationObserverTests.swift
@@ -17,7 +17,7 @@ class OperationObserverTests: XCTestCase {
expectDidCancel.isInverted = true
let expectDidFinish = expectation(description: "didAttach handler")
- let operation = AsyncBlockOperation()
+ let operation = AsyncBlockOperation {}
operation.addBlockObserver(OperationBlockObserver(
didAttach: { op in
expectDidAttach.fulfill()
@@ -44,7 +44,7 @@ class OperationObserverTests: XCTestCase {
let expectDidCancel = expectation(description: "didCancel handler")
let expectDidFinish = expectation(description: "didAttach handler")
- let operation = AsyncBlockOperation()
+ let operation = AsyncBlockOperation {}
operation.addBlockObserver(OperationBlockObserver(
didAttach: { op in
expectDidAttach.fulfill()
diff --git a/ios/OperationsTests/TransformOperationTests.swift b/ios/OperationsTests/TransformOperationTests.swift
new file mode 100644
index 0000000000..20eabc77e6
--- /dev/null
+++ b/ios/OperationsTests/TransformOperationTests.swift
@@ -0,0 +1,93 @@
+//
+// TransformOperationTests.swift
+// OperationsTests
+//
+// Created by pronebird on 26/04/2023.
+// Copyright © 2023 Mullvad VPN AB. All rights reserved.
+//
+
+import MullvadTypes
+import Operations
+import XCTest
+
+final class TransformOperationTests: XCTestCase {
+ let operationQueue = AsyncOperationQueue()
+
+ func testBlockTransformOperation() {
+ let finishExpectation = expectation(description: "Should finish")
+
+ let transform = TransformOperation(input: Int.zero) { input, op in
+ op.finish(result: .success(input + 1))
+ }
+
+ transform.onFinish { op, error in
+ XCTAssertEqual(op.result?.value, 1)
+
+ finishExpectation.fulfill()
+ }
+
+ operationQueue.addOperation(transform)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testThrowingBlockTransformOperation() {
+ let finishExpectation = expectation(description: "Should finish")
+
+ let transform = TransformOperation(input: Int.zero) { value in
+ throw URLError(.badURL)
+ }
+
+ transform.onFinish { op, error in
+ XCTAssertEqual(error as? URLError, URLError(.badURL))
+
+ finishExpectation.fulfill()
+ }
+
+ operationQueue.addOperation(transform)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testCancellableTaskBlockTranasformOperation() {
+ let finishExpectation = expectation(description: "Should finish")
+
+ let transform = TransformOperation<Int, Int>(input: Int.zero, cancellableTask: { _, op in
+ return AnyCancellable {
+ op.finish(result: .failure(URLError(.cancelled)))
+ }
+ })
+
+ transform.onStart { op in
+ op.cancel()
+ }
+
+ transform.onFinish { op, error in
+ XCTAssertEqual(error as? URLError, URLError(.cancelled))
+
+ finishExpectation.fulfill()
+ }
+
+ operationQueue.addOperation(transform)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testShouldFailWithUnsatisfiedRequirement() {
+ let finishExpectation = expectation(description: "Should finish")
+
+ let transform = TransformOperation<Int, Int> { input, op in
+ op.finish(result: .success(input))
+ }
+
+ transform.onFinish { _, error in
+ XCTAssertEqual(error as? OperationError, .unsatisfiedRequirement)
+
+ finishExpectation.fulfill()
+ }
+
+ operationQueue.addOperation(transform)
+
+ waitForExpectations(timeout: 1)
+ }
+}