Skip to content

Commit

Permalink
Move CancelableProcedure to CommonInternal
Browse files Browse the repository at this point in the history
  • Loading branch information
ra1028 committed Mar 8, 2018
1 parent a67113b commit 4d795f4
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// Encapsulate the function and make it cancelable.
/// A function will not be executed after canceling, except already in progress execution.
public final class CancelableProcedure<Value> {
final class CancelableProcedure<Value> {
/// A Bool value indicating whether canceled.
public var isCanceled: Bool {
var isCanceled: Bool {
return _isCanceled.value
}

Expand All @@ -13,31 +13,31 @@ public final class CancelableProcedure<Value> {
///
/// - Parameters:
/// - execute: A function to be executed by calling `execute(with:)` until canceled.
public init(_ execute: @escaping (Value) -> Void) {
init(_ execute: @escaping (Value) -> Void) {
_execute = execute
}

/// Synchronously execute the specified function.
///
/// - Parameters:
/// - value: A value to be pass to specified function.
public func execute(with value: @autoclosure () -> Value) {
func execute(with value: @autoclosure () -> Value) {
guard !isCanceled, let execute = _execute else { return }
execute(value())
}

/// Cancel the specified function.
/// Cancellation does not affect already in progress execution.
public func cancel() {
func cancel() {
guard _isCanceled.compareAndSwapBarrier(old: false, new: true) else { return }
_execute = nil
}
}

public extension CancelableProcedure where Value == Void {
extension CancelableProcedure where Value == Void {
/// Synchronously execute the specified function.
@inline(__always)
public func execute() {
func execute() {
self.execute(with: ())
}
}
168 changes: 107 additions & 61 deletions Tests/CancelableProcedureTests.swift
Original file line number Diff line number Diff line change
@@ -1,85 +1,131 @@
import XCTest
@testable import VueFlux
@testable import VueFluxReactive

private protocol CancelableProcedureProtocol {
associatedtype Value

var isCanceled: Bool { get }

init(_ execute: @escaping (Value) -> Void)
func execute(with value: @autoclosure () -> Value)
func cancel()
}

extension VueFlux.CancelableProcedure: CancelableProcedureProtocol {}
extension VueFluxReactive.CancelableProcedure: CancelableProcedureProtocol {}

final class CancelableProcedureTests: XCTestCase {
func testVoidProcedure() {
var value = 0

let procedure = CancelableProcedure<Void> {
value += 1
func runTest<CancelableProcedure: CancelableProcedureProtocol>(for type: CancelableProcedure.Type) where CancelableProcedure.Value == Void {

var value = 0

let procedure = CancelableProcedure {
value += 1
}

XCTAssertEqual(value, 0)

procedure.execute(with: ())

XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute(with: ())

XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute(with: ())

XCTAssertEqual(value, 1)
}

XCTAssertEqual(value, 0)

procedure.execute()

XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute()

XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute()

XCTAssertEqual(value, 1)
runTest(for: VueFlux.CancelableProcedure<Void>.self)
runTest(for: VueFluxReactive.CancelableProcedure<Void>.self)
}

func testValueWorkItem() {
var value = 0

let procedure = CancelableProcedure<Int> { int in
value = int
func runTest<CancelableProcedure: CancelableProcedureProtocol>(for type: CancelableProcedure.Type) where CancelableProcedure.Value == Int {
var value = 0

let procedure = CancelableProcedure { int in
value = int
}

XCTAssertEqual(value, 0)

procedure.execute(with: 1)

XCTAssertFalse(procedure.isCanceled)
XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute(with: 2)

XCTAssertTrue(procedure.isCanceled)
XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute(with: 3)

XCTAssertTrue(procedure.isCanceled)
XCTAssertEqual(value, 1)
}

XCTAssertEqual(value, 0)

procedure.execute(with: 1)

XCTAssertFalse(procedure.isCanceled)
XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute(with: 2)

XCTAssertTrue(procedure.isCanceled)
XCTAssertEqual(value, 1)

procedure.cancel()
procedure.execute(with: 3)

XCTAssertTrue(procedure.isCanceled)
XCTAssertEqual(value, 1)
runTest(for: VueFlux.CancelableProcedure<Int>.self)
runTest(for: VueFluxReactive.CancelableProcedure<Int>.self)
}

func testCancelProcedureAsync() {
let queue = DispatchQueue(label: "testCancelProcedureAsync")
func runTest<CancelableProcedure: CancelableProcedureProtocol>(for type: CancelableProcedure.Type) where CancelableProcedure.Value == Int {
let queue = DispatchQueue(label: "testCancelProcedureAsync")

var value = 0

let expectation = self.expectation(description: "testCancelProcedureAsync")

let procedure = CancelableProcedure { int in
value = int
}

XCTAssertFalse(procedure.isCanceled)

queue.suspend()

queue.async {
procedure.execute(with: 1)
}

procedure.cancel()
queue.resume()

queue.async(execute: expectation.fulfill)

waitForExpectations(timeout: 1) { _ in
XCTAssertTrue(procedure.isCanceled)
XCTAssertEqual(value, 0)
}
}

runTest(for: VueFlux.CancelableProcedure<Int>.self)
runTest(for: VueFluxReactive.CancelableProcedure<Int>.self)
}

func testExecuteVoidProcedure() {
var value = 0

let expectation = self.expectation(description: "testCancelProcedureAsync")

let procedure = CancelableProcedure<Int> { int in
value = int
let vueFluxProcedure = VueFlux.CancelableProcedure<Void> {
value = 1
}

XCTAssertFalse(procedure.isCanceled)

queue.suspend()

queue.async {
procedure.execute(with: 1)
let vueFluxReactiveProcedure = VueFluxReactive.CancelableProcedure<Void> {
value = 2
}

procedure.cancel()
queue.resume()

queue.async(execute: expectation.fulfill)
vueFluxProcedure.execute()
vueFluxReactiveProcedure.execute()

waitForExpectations(timeout: 1) { _ in
XCTAssertTrue(procedure.isCanceled)
XCTAssertEqual(value, 0)
}
XCTAssertEqual(value, 2)
}
}
16 changes: 9 additions & 7 deletions VueFlux.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
6B41947A2045B72300C40218 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B4194792045B72300C40218 /* Lock.swift */; };
6B41947B2045B72800C40218 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B4194792045B72300C40218 /* Lock.swift */; };
6B41947D2045B7A500C40218 /* LockTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B41947C2045B7A500C40218 /* LockTests.swift */; };
6B665528200AE8A000883C12 /* CancelableProcedure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B665527200AE8A000883C12 /* CancelableProcedure.swift */; };
6B730BC82045E9280059D851 /* AtomicBool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B730BC72045E9280059D851 /* AtomicBool.swift */; };
6B730BC92045E9480059D851 /* AtomicBool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B730BC72045E9280059D851 /* AtomicBool.swift */; };
6B730BCB2045E9620059D851 /* AtomicBoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B730BCA2045E9620059D851 /* AtomicBoolTests.swift */; };
Expand All @@ -41,6 +40,8 @@
6BB30C512018E3E700C52C76 /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BB30C502018E3E700C52C76 /* Variable.swift */; };
6BB30C532018E41600C52C76 /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BB30C522018E41600C52C76 /* Constant.swift */; };
6BB9F56B20514317008C6C77 /* CancelableProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BB9F56A20514317008C6C77 /* CancelableProcedureTests.swift */; };
6BB9F56D20514DCA008C6C77 /* CancelableProcedure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BB9F56C20514DCA008C6C77 /* CancelableProcedure.swift */; };
6BB9F56E20514DCA008C6C77 /* CancelableProcedure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BB9F56C20514DCA008C6C77 /* CancelableProcedure.swift */; };
6BC664F51FEC5ABF00BD74C8 /* AnyDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC664F41FEC5ABF00BD74C8 /* AnyDisposable.swift */; };
6BC664F71FEC627E00BD74C8 /* SignalOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC664F61FEC627E00BD74C8 /* SignalOperators.swift */; };
6BC665331FF032C500BD74C8 /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC665321FF032C500BD74C8 /* Executor.swift */; };
Expand Down Expand Up @@ -78,7 +79,6 @@
6B14405820453C3D00E0B3FF /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
6B4194792045B72300C40218 /* Lock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = "<group>"; };
6B41947C2045B7A500C40218 /* LockTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockTests.swift; sourceTree = "<group>"; };
6B665527200AE8A000883C12 /* CancelableProcedure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelableProcedure.swift; sourceTree = "<group>"; };
6B730BC72045E9280059D851 /* AtomicBool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicBool.swift; sourceTree = "<group>"; };
6B730BCA2045E9620059D851 /* AtomicBoolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicBoolTests.swift; sourceTree = "<group>"; };
6B9E32811FA639DF000B24D4 /* VueFlux.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = VueFlux.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -104,6 +104,7 @@
6BB30C522018E41600C52C76 /* Constant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constant.swift; sourceTree = "<group>"; };
6BB5BAF92044353A0009F779 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = "<group>"; };
6BB9F56A20514317008C6C77 /* CancelableProcedureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelableProcedureTests.swift; sourceTree = "<group>"; };
6BB9F56C20514DCA008C6C77 /* CancelableProcedure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelableProcedure.swift; sourceTree = "<group>"; };
6BC664F41FEC5ABF00BD74C8 /* AnyDisposable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyDisposable.swift; sourceTree = "<group>"; };
6BC664F61FEC627E00BD74C8 /* SignalOperators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalOperators.swift; sourceTree = "<group>"; };
6BC665321FF032C500BD74C8 /* Executor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Executor.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -155,8 +156,9 @@
isa = PBXGroup;
children = (
6B14405820453C3D00E0B3FF /* Storage.swift */,
6B4194792045B72300C40218 /* Lock.swift */,
6BB9F56C20514DCA008C6C77 /* CancelableProcedure.swift */,
6B730BC72045E9280059D851 /* AtomicBool.swift */,
6B4194792045B72300C40218 /* Lock.swift */,
);
path = CommonInternal;
sourceTree = "<group>";
Expand Down Expand Up @@ -189,7 +191,6 @@
children = (
6BE63FFE1FB3A6D8007F8B5D /* VueFluxTests.swift */,
6BE63FF91FB39EA6007F8B5D /* ExecutorTests.swift */,
6BB9F56A20514317008C6C77 /* CancelableProcedureTests.swift */,
6BE63FF61FB39CDD007F8B5D /* DispatcherTests.swift */,
6BE63FF31FB39A3C007F8B5D /* DispatcherContextTests.swift */,
6BE63FF01FB39446007F8B5D /* AtomicReferenceTests.swift */,
Expand All @@ -200,8 +201,9 @@
6BA27BCB1FB8CD3100809472 /* DisposableTests.swift */,
6BA27BCE1FB8CE1A00809472 /* DisposableScopeTests.swift */,
6BA27BD31FB8CFE600809472 /* StorageTests.swift */,
6B41947C2045B7A500C40218 /* LockTests.swift */,
6BB9F56A20514317008C6C77 /* CancelableProcedureTests.swift */,
6B730BCA2045E9620059D851 /* AtomicBoolTests.swift */,
6B41947C2045B7A500C40218 /* LockTests.swift */,
6B9E329F1FA63B07000B24D4 /* Info.plist */,
);
path = Tests;
Expand All @@ -212,7 +214,6 @@
children = (
6B9EB21C1FCB14BF009F0659 /* VueFlux.swift */,
6BC665321FF032C500BD74C8 /* Executor.swift */,
6B665527200AE8A000883C12 /* CancelableProcedure.swift */,
6B9EB23D1FCB1CFB009F0659 /* AtomicReference.swift */,
6B9EB2141FCB14BF009F0659 /* Internal */,
6B9EB2131FCB14BF009F0659 /* Info.plist */,
Expand Down Expand Up @@ -444,10 +445,10 @@
buildActionMask = 2147483647;
files = (
6B730BC82045E9280059D851 /* AtomicBool.swift in Sources */,
6BB9F56E20514DCA008C6C77 /* CancelableProcedure.swift in Sources */,
6B9EB21D1FCB14ED009F0659 /* Dispatcher.swift in Sources */,
6B14405920453C4300E0B3FF /* Storage.swift in Sources */,
6B9EB21E1FCB14ED009F0659 /* DispatcherContext.swift in Sources */,
6B665528200AE8A000883C12 /* CancelableProcedure.swift in Sources */,
6B9EB2241FCB14ED009F0659 /* VueFlux.swift in Sources */,
6B9EB23F1FCB1CFB009F0659 /* AtomicReference.swift in Sources */,
6B41947A2045B72300C40218 /* Lock.swift in Sources */,
Expand Down Expand Up @@ -486,6 +487,7 @@
6BB30C4F2018E3CA00C52C76 /* Signal.swift in Sources */,
6BC664F71FEC627E00BD74C8 /* SignalOperators.swift in Sources */,
6BB30C4D2018E3AC00C52C76 /* Sink.swift in Sources */,
6BB9F56D20514DCA008C6C77 /* CancelableProcedure.swift in Sources */,
6BB30C512018E3E700C52C76 /* Variable.swift in Sources */,
6BC664F51FEC5ABF00BD74C8 /* AnyDisposable.swift in Sources */,
6B730BC92045E9480059D851 /* AtomicBool.swift in Sources */,
Expand Down

0 comments on commit 4d795f4

Please sign in to comment.