Skip to content
This repository has been archived by the owner on Aug 29, 2022. It is now read-only.

Commit

Permalink
Split out and improve testing for the basics of progress composition
Browse files Browse the repository at this point in the history
  • Loading branch information
zwaldowski committed Oct 11, 2018
1 parent a2b587a commit 306782a
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 114 deletions.
8 changes: 8 additions & 0 deletions Deferred.xcodeproj/project.pbxproj
Expand Up @@ -214,6 +214,9 @@
DBABD0BC203F2E3E00C50896 /* Atomics.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBABD0BA203F2E3E00C50896 /* Atomics.swift */; };
DBABD0BD203F2E3E00C50896 /* Atomics.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBABD0BA203F2E3E00C50896 /* Atomics.swift */; };
DBABD0BE203F2E3E00C50896 /* Atomics.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBABD0BA203F2E3E00C50896 /* Atomics.swift */; };
DBEC962B216FF229004CF0FC /* TaskProgressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEC962A216FF229004CF0FC /* TaskProgressTests.swift */; };
DBEC962C216FF229004CF0FC /* TaskProgressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEC962A216FF229004CF0FC /* TaskProgressTests.swift */; };
DBEC962D216FF229004CF0FC /* TaskProgressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEC962A216FF229004CF0FC /* TaskProgressTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -311,6 +314,7 @@
DBA01B0C2071E6FF00083CD0 /* FuturePeek.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FuturePeek.swift; sourceTree = "<group>"; };
DBABD0BA203F2E3E00C50896 /* Atomics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomics.swift; sourceTree = "<group>"; };
DBC742631DC2F6D4002FB30D /* FutureEveryMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FutureEveryMap.swift; sourceTree = "<group>"; };
DBEC962A216FF229004CF0FC /* TaskProgressTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskProgressTests.swift; sourceTree = "<group>"; };
EBEB828C1DC4A79A00B7E089 /* TaskComprehensiveTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskComprehensiveTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -483,6 +487,7 @@
DB55F1F71D96968E00FC1439 /* ResultRecoveryTests.swift */,
DB55F1FD1D96968E00FC1439 /* TaskAsyncTests.swift */,
EBEB828C1DC4A79A00B7E089 /* TaskComprehensiveTests.swift */,
DBEC962A216FF229004CF0FC /* TaskProgressTests.swift */,
DB78F5EB215C4C5700D07CC6 /* TaskProtocolTests.swift */,
DB55F1F81D96968E00FC1439 /* TaskResultTests.swift */,
DB55F1FC1D96968E00FC1439 /* TaskTests.swift */,
Expand Down Expand Up @@ -804,6 +809,7 @@
DB126D641E5368B900054E95 /* FutureTests.swift in Sources */,
DB126D661E5368B900054E95 /* ProtectedTests.swift in Sources */,
DB126D6E1E5368B900054E95 /* TaskAsyncTests.swift in Sources */,
DBEC962B216FF229004CF0FC /* TaskProgressTests.swift in Sources */,
DB34FC942096DCE1005D5B82 /* FilledDeferredTests.swift in Sources */,
DB126D6D1E5368B900054E95 /* TaskTests.swift in Sources */,
DB126D621E5368B900054E95 /* FutureCustomExecutorTests.swift in Sources */,
Expand Down Expand Up @@ -872,6 +878,7 @@
DB126D741E5368B900054E95 /* FutureTests.swift in Sources */,
DB126D761E5368B900054E95 /* ProtectedTests.swift in Sources */,
DB126D7E1E5368B900054E95 /* TaskAsyncTests.swift in Sources */,
DBEC962C216FF229004CF0FC /* TaskProgressTests.swift in Sources */,
DB34FC952096DCE1005D5B82 /* FilledDeferredTests.swift in Sources */,
DB126D7D1E5368B900054E95 /* TaskTests.swift in Sources */,
DB126D721E5368B900054E95 /* FutureCustomExecutorTests.swift in Sources */,
Expand Down Expand Up @@ -940,6 +947,7 @@
DB126D841E5368BA00054E95 /* FutureTests.swift in Sources */,
DB126D861E5368BA00054E95 /* ProtectedTests.swift in Sources */,
DB126D8E1E5368BA00054E95 /* TaskAsyncTests.swift in Sources */,
DBEC962D216FF229004CF0FC /* TaskProgressTests.swift in Sources */,
DB34FC962096DCE1005D5B82 /* FilledDeferredTests.swift in Sources */,
DB126D8D1E5368BA00054E95 /* TaskTests.swift in Sources */,
DB126D821E5368BA00054E95 /* FutureCustomExecutorTests.swift in Sources */,
Expand Down
164 changes: 164 additions & 0 deletions Tests/TaskTests/TaskProgressTests.swift
@@ -0,0 +1,164 @@
//
// TaskProgressTests.swift
// DeferredTests
//
// Created by Zachary Waldowski on 10/11/18.
// Copyright © 2018 Big Nerd Ranch. Licensed under MIT.
//

import XCTest

#if SWIFT_PACKAGE
import Atomics
import Task
#else
import Deferred
import Deferred.Atomics
#endif

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
class TaskProgressTests: CustomExecutorTestCase {
static let allTests: [(String, (TaskProgressTests) -> () throws -> Void)] = [
("testThatCancellationIsAppliedImmediatelyWhenMapping", testThatCancellationIsAppliedImmediatelyWhenMapping),
("testThatTaskCreatedWithProgressReflectsThatProgress", testThatTaskCreatedWithProgressReflectsThatProgress),
("testTaskCreatedUnfilledIs0PercentCompleted", testTaskCreatedUnfilledIs0PercentCompleted),
("testTaskCreatedFilledIs100PercentCompleted", testTaskCreatedFilledIs100PercentCompleted),
("testThatTaskCreatedUnfilledIsIndeterminate", testThatTaskCreatedUnfilledIsIndeterminate),
("testThatTaskWrappingUnfilledIsIndeterminate", testThatTaskWrappingUnfilledIsIndeterminate),
("testThatTaskCreatedFilledIsDeterminate", testThatTaskCreatedFilledIsDeterminate),
("testThatMapProgressFinishesAlongsideBaseProgress", testThatMapProgressFinishesAlongsideBaseProgress),
("testThatAndThenProgressFinishesAlongsideBaseProgress", testThatAndThenProgressFinishesAlongsideBaseProgress),
("testThanMappedProgressTakesUpMajorityOfDerivedProgress", testThanMappedProgressTakesUpMajorityOfDerivedProgress)
]

func testThatCancellationIsAppliedImmediatelyWhenMapping() {
let beforeExpect = expectation(description: "original task cancelled")
let beforeTask = Task<Int>(.never) {
beforeExpect.fulfill()
}

beforeTask.cancel()
XCTAssert(beforeTask.progress.isCancelled)

let afterExpect = expectation(description: "filled with same error")
afterExpect.isInverted = true

let afterTask = beforeTask.map(upon: executor) { (value) -> String in
afterExpect.fulfill()
return String(describing: value)
}

XCTAssert(afterTask.progress.isCancelled)

shortWait(for: [ beforeExpect, afterExpect ])
assertExecutorNeverCalled()
}

func testThatTaskCreatedWithProgressReflectsThatProgress() {
let key = ProgressUserInfoKey(rawValue: "Test")

let progress = Progress(parent: nil, userInfo: nil)
progress.totalUnitCount = 10
progress.setUserInfoObject(true, forKey: key)
progress.isCancellable = false

let task = Task<Int>(.never, progress: progress)

XCTAssertEqual(task.progress.fractionCompleted, 0, accuracy: 0.001)
XCTAssertEqual(progress.userInfo[key] as? Bool, true)
XCTAssert(task.progress.isCancellable)

progress.completedUnitCount = 5
XCTAssertEqual(task.progress.fractionCompleted, 0.5, accuracy: 0.001)
}

func testTaskCreatedUnfilledIs0PercentCompleted() {
let incompleteTask = Task<Int>.never
XCTAssertEqual(incompleteTask.progress.fractionCompleted, 0)
}

func testTaskCreatedFilledIs100PercentCompleted() {
let completedTask = Task(success: 42)
XCTAssertEqual(completedTask.progress.fractionCompleted, 1)
}

func testThatTaskCreatedUnfilledIsIndeterminate() {
let task = Task<Int>.never
XCTAssert(task.progress.isIndeterminate)
}

func testThatTaskWrappingUnfilledIsIndeterminate() {
let deferred = Task<Int>.Promise()
let wrappedTask = Task(deferred)
XCTAssertFalse(wrappedTask.progress.isIndeterminate)
}

func testThatTaskCreatedFilledIsDeterminate() {
let completedTask = Task(success: 42)
XCTAssertFalse(completedTask.progress.isIndeterminate)
}

func testThatMapProgressFinishesAlongsideBaseProgress() {
let deferred = Task<Int>.Promise()
let task1 = Task(deferred)
let task2 = task1.map(upon: queue) { $0 * 2 }

XCTAssertNotEqual(task1.progress.fractionCompleted, 1)
XCTAssertNotEqual(task2.progress.fractionCompleted, 1)

deferred.succeed(with: 9000)

shortWait(for: [
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task1.progress),
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task2.progress),
expectQueueToBeEmpty()
])
}

func testThatAndThenProgressFinishesAlongsideBaseProgress() {
let deferred = Task<Int>.Promise()
let task1 = Task(deferred)
let task2 = task1.andThen(upon: executor) { (result) -> Task<Int>.Promise in
let deferred2 = Task<Int>.Promise()
self.afterShortDelay {
deferred2.succeed(with: result * 2)
}
return deferred2
}

XCTAssertNotEqual(task1.progress.fractionCompleted, 1)
XCTAssertNotEqual(task2.progress.fractionCompleted, 1)

deferred.succeed(with: 9000)

shortWait(for: [
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task1.progress),
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task2.progress)
])

assertExecutorCalled(atLeast: 1)
}

func testThanMappedProgressTakesUpMajorityOfDerivedProgress() {
let customProgress = Progress(totalUnitCount: 5)
let deferred = Task<Int>.Promise()
let task = Task(deferred, progress: customProgress)
.map(upon: .any(), transform: { $0 * 2 })
.map(upon: .any(), transform: { "\($0)" })
.map(upon: .any(), transform: { "\($0)\($0)" })

XCTAssertNotEqual(customProgress.fractionCompleted, 1)
XCTAssertNotEqual(task.progress.fractionCompleted, 1)

customProgress.completedUnitCount = 5

XCTAssertGreaterThanOrEqual(task.progress.fractionCompleted, 0.75)

deferred.succeed(with: 9000)

shortWait(for: [
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task.progress)
])
}
}
#endif
115 changes: 1 addition & 114 deletions Tests/TaskTests/TaskTests.swift
Expand Up @@ -17,11 +17,8 @@ import Deferred
import Deferred.Atomics
#endif

// swiftlint:disable file_length
// swiftlint:disable type_body_length

class TaskTests: CustomExecutorTestCase {
static let universalTests: [(String, (TaskTests) -> () throws -> Void)] = [
static let allTests: [(String, (TaskTests) -> () throws -> Void)] = [
("testUponSuccess", testUponSuccess),
("testUponFailure", testUponFailure),
("testThatThrowingMapSubstitutesWithError", testThatThrowingMapSubstitutesWithError),
Expand All @@ -39,24 +36,6 @@ class TaskTests: CustomExecutorTestCase {
("testSimpleFutureCanBeUpgradedToTask", testSimpleFutureCanBeUpgradedToTask)
]

static var allTests: [(String, (TaskTests) -> () throws -> Void)] {
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
return universalTests + [
("testThatCancellationIsAppliedImmediatelyWhenMapping", testThatCancellationIsAppliedImmediatelyWhenMapping),
("testThatTaskCreatedWithProgressReflectsThatProgress", testThatTaskCreatedWithProgressReflectsThatProgress),
("testTaskCreatedUnfilledIs100PercentCompleted", testTaskCreatedUnfilledIs100PercentCompleted),
("testTaskCreatedFilledIs100PercentCompleted", testTaskCreatedFilledIs100PercentCompleted),
("testThatTaskCreatedUnfilledIsIndeterminate", testThatTaskCreatedUnfilledIsIndeterminate),
("testThatTaskWrappingUnfilledIsIndeterminate", testThatTaskWrappingUnfilledIsIndeterminate),
("testThatTaskWrappingFilledIsDeterminate", testThatTaskWrappingFilledIsDeterminate),
("testThatMapIncrementsParentProgressFraction", testThatMapIncrementsParentProgressFraction),
("testThatAndThenIncrementsParentProgressFraction", testThatAndThenIncrementsParentProgressFraction)
]
#else
return universalTests
#endif
}

private func expectation<T: Equatable>(that task: Task<T>, succeedsWith makeExpected: @autoclosure @escaping() -> T, description: String? = nil) -> XCTestExpectation {
let expect = expectation(description: description ?? "uponSuccess is called")
task.uponSuccess(on: executor) { (value) in
Expand Down Expand Up @@ -187,98 +166,6 @@ class TaskTests: CustomExecutorTestCase {
assertExecutorCalled(atLeast: 1)
}

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
func testThatCancellationIsAppliedImmediatelyWhenMapping() {
let beforeExpect = expectation(description: "original task cancelled")
let beforeTask = Task<Int>(Deferred<Task<Int>.Result>()) {
beforeExpect.fulfill()
}

beforeTask.cancel()
XCTAssert(beforeTask.progress.isCancelled)

let afterExpect = expectation(description: "filled with same error")
afterExpect.isInverted = true

let afterTask = beforeTask.map(upon: executor) { (value) -> String in
afterExpect.fulfill()
return String(describing: value)
}

XCTAssert(afterTask.progress.isCancelled)

shortWait(for: [ beforeExpect, afterExpect ])
assertExecutorNeverCalled()
}

func testThatTaskCreatedWithProgressReflectsThatProgress() {
let key = ProgressUserInfoKey(rawValue: "Test")

let progress = Progress(parent: nil, userInfo: nil)
progress.totalUnitCount = 10
progress.setUserInfoObject(true, forKey: key)
progress.isCancellable = false

let task = Task<Int>(Deferred<Task<Int>.Result>(), progress: progress)

XCTAssertEqual(task.progress.fractionCompleted, 0, accuracy: 0.001)
XCTAssertEqual(progress.userInfo[key] as? Bool, true)
XCTAssert(task.progress.isCancellable)

progress.completedUnitCount = 5
XCTAssertEqual(task.progress.fractionCompleted, 0.5, accuracy: 0.001)
}

func testTaskCreatedUnfilledIs100PercentCompleted() {
XCTAssertEqual(makeAnyUnfinishedTask().1.progress.fractionCompleted, 0)
}

func testTaskCreatedFilledIs100PercentCompleted() {
XCTAssertEqual(makeAnyFinishedTask().progress.fractionCompleted, 1)
}

func testThatTaskCreatedUnfilledIsIndeterminate() {
let task = Task<Int>.never

XCTAssert(task.progress.isIndeterminate)
}

func testThatTaskWrappingUnfilledIsIndeterminate() {
let deferred = Deferred<Task<Int>.Result>()
let wrappedTask = Task(deferred)

XCTAssertFalse(wrappedTask.progress.isIndeterminate)
}

func testThatTaskWrappingFilledIsDeterminate() {
let deferred = Deferred<Task<Int>.Result>(filledWith: .success(42))
let wrappedTask = Task(deferred)

XCTAssertFalse(wrappedTask.progress.isIndeterminate)
}

func testThatMapIncrementsParentProgressFraction() {
let task = makeAnyFinishedTask().map(upon: executor) { $0 * 2 }

shortWait(for: [
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task.progress)
])

assertExecutorCalled(atLeast: 1)
}

func testThatAndThenIncrementsParentProgressFraction() {
let task = makeAnyFinishedTask().andThen(upon: executor, start: makeContrivedNextTask)
XCTAssertNotEqual(task.progress.fractionCompleted, 1)

shortWait(for: [
expectation(for: NSPredicate(format: "fractionCompleted == 1"), evaluatedWith: task.progress)
])

assertExecutorCalled(atLeast: 1)
}
#endif

func testThatFallbackProducesANewTask() {
let task = makeAnyFailedTask().fallback(upon: queue) { _ -> Task<Int> in
return self.makeAnyFinishedTask()
Expand Down

0 comments on commit 306782a

Please sign in to comment.