Add 'submodules/SSignalKit/' from commit '359b2ee7c9f20f99f221f78e307369ef5ad0ece2'

git-subtree-dir: submodules/SSignalKit
git-subtree-mainline: 4459dc5b47
git-subtree-split: 359b2ee7c9
This commit is contained in:
Peter
2019-06-11 18:57:57 +01:00
101 changed files with 11173 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
import Foundation
internal class DeallocatingObject : CustomStringConvertible {
private var deallocated: UnsafeMutablePointer<Bool>
init(deallocated: UnsafeMutablePointer<Bool>) {
self.deallocated = deallocated
}
deinit {
self.deallocated.pointee = true
}
var description: String {
get {
return ""
}
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@@ -0,0 +1,166 @@
import UIKit
import XCTest
import SwiftSignalKit
import Foundation
final class DisposableLock {
private var action: (() -> Void)?
private var lock = pthread_mutex_t()
init(action: @escaping () -> Void) {
self.action = action
pthread_mutex_init(&self.lock, nil)
}
func dispose() {
var action: (() -> Void)?
pthread_mutex_lock(&self.lock)
action = self.action
self.action = nil
pthread_mutex_unlock(&self.lock)
if let action = action {
action()
}
}
}
final class DisposableSpinLock {
private var action: (() -> Void)?
private var lock = OSSpinLock()
init(action: @escaping () -> Void) {
self.action = action
}
func dispose() {
var action: (() -> Void)?
OSSpinLockLock(&self.lock)
action = self.action
self.action = nil
OSSpinLockUnlock(&self.lock)
if let action = action {
action()
}
}
}
final class DisposableNoLock {
private var action: (() -> Void)?
init(action: @escaping () -> Void) {
self.action = action
}
func dispose() {
var action: (() -> Void)?
action = self.action
self.action = nil
if let action = action {
action()
}
}
}
final class DisposableAtomic {
private var action: () -> Void
private var disposed: Int32 = 0
init(action: @escaping () -> Void) {
self.action = action
}
func dispose() {
if OSAtomicCompareAndSwap32(0, 1, &self.disposed) {
self.action()
}
}
}
class PerformanceTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testMeasureLock() {
measure {
for _ in 0 ..< 1000000 {
let disposable = DisposableLock(action: {})
disposable.dispose()
}
}
}
func testMeasureSpinlock() {
measure {
for _ in 0 ..< 1000000 {
let disposable = DisposableSpinLock(action: {})
disposable.dispose()
}
}
}
func testMeasureAtomic() {
measure {
for _ in 0 ..< 1000000 {
let disposable = DisposableAtomic(action: {})
disposable.dispose()
}
}
}
func read(_ idxin: Int, _ size: Int, _ tree: inout [Int: Int], _ reads: inout Set<Int>) -> Int {
var idx = idxin
var sum = 0
while idx <= size {
print("read at \(idx)")
if let value = tree[idx] {
sum += value
}
reads.insert(idx)
idx += (idx & -idx)
}
return sum
}
func update(_ idxin: Int, _ val: Int, _ tree: inout [Int: Int], _ updates: inout Set<Int>) {
var idx = idxin
while (idx > 0) {
if let value = tree[idx] {
tree[idx] = value + val
} else {
tree[idx] = val
}
//print("write at \(idx)")
updates.insert(idx)
idx -= (idx & -idx)
}
}
func testTree() {
let size = 2_000_000
var dict: [Int: Int] = [:]
var updates = Set<Int>()
var index = 0
for _ in 1 ..< 100_000 {
//update(Int(1 + arc4random_uniform(UInt32(size))), 1, &dict, &updates)
update(index, 1, &dict, &updates)
index += Int(1 + arc4random_uniform(100))
}
update(size - 1, 1, &dict, &updates)
print("update ops = \(updates.count), tree = \(dict.count) items")
var reads = Set<Int>()
let sum = read(1, size, &dict, &reads)
print("read = \(sum) ops = \(reads.count)")
update(99, -2, &dict, &updates)
reads.removeAll()
let sum2 = read(1, size, &dict, &reads)
print("read2 = \(sum2) ops = \(reads.count)")
}
}

View File

@@ -0,0 +1,281 @@
import UIKit
import XCTest
import SwiftSignalKit
class SwiftSignalKitTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testActionDisposableDisposed() {
var deallocated = false
var disposed = false
if true {
var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let disposable = ActionDisposable(action: { [object] () -> Void in
let _ = object.debugDescription
disposed = true
})
object = nil
XCTAssertFalse(deallocated, "deallocated != false")
disposable.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
}
func testActionDisposableNotDisposed() {
var deallocated = false
var disposed = false
if true {
let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let _ = ActionDisposable(action: { [object] () -> Void in
let _ = object.debugDescription
disposed = true
})
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertFalse(disposed, "disposed != false")
}
func testMetaDisposableDisposed() {
var deallocated = false
var disposed = false
if true {
let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let disposable = ActionDisposable(action: { [object] () -> Void in
let _ = object.debugDescription
disposed = true
})
let metaDisposable = MetaDisposable()
metaDisposable.set(disposable)
metaDisposable.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
}
func testMetaDisposableDisposedMultipleTimes() {
var deallocated1 = false
var disposed1 = false
var deallocated2 = false
var disposed2 = false
if true {
let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1)
let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in
let _ = object1.debugDescription
disposed1 = true
})
let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2)
let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in
let _ = object2.debugDescription
disposed2 = true
})
let metaDisposable = MetaDisposable()
metaDisposable.set(actionDisposable1)
metaDisposable.set(actionDisposable2)
metaDisposable.dispose()
}
XCTAssertTrue(deallocated1, "deallocated1 != true")
XCTAssertTrue(disposed1, "disposed1 != true")
XCTAssertTrue(deallocated2, "deallocated2 != true")
XCTAssertTrue(disposed2, "disposed2 != true")
}
func testMetaDisposableNotDisposed() {
var deallocated = false
var disposed = false
if true {
let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let disposable = ActionDisposable(action: { [object] () -> Void in
let _ = object.debugDescription
disposed = true
})
let metaDisposable = MetaDisposable()
metaDisposable.set(disposable)
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertFalse(disposed, "disposed != false")
}
func testDisposableSetSingleDisposed() {
var deallocated = false
var disposed = false
if true {
let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let disposable = ActionDisposable(action: { [object] () -> Void in
let _ = object.debugDescription
disposed = true
})
let disposableSet = DisposableSet()
disposableSet.add(disposable)
disposableSet.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
}
func testDisposableSetMultipleDisposed() {
var deallocated1 = false
var disposed1 = false
var deallocated2 = false
var disposed2 = false
if true {
let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1)
let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in
let _ = object1.debugDescription
disposed1 = true
})
let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2)
let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in
let _ = object2.debugDescription
disposed2 = true
})
let disposableSet = DisposableSet()
disposableSet.add(actionDisposable1)
disposableSet.add(actionDisposable2)
disposableSet.dispose()
}
XCTAssertTrue(deallocated1, "deallocated1 != true")
XCTAssertTrue(disposed1, "disposed1 != true")
XCTAssertTrue(deallocated2, "deallocated2 != true")
XCTAssertTrue(disposed2, "disposed2 != true")
}
func testDisposableSetSingleNotDisposed() {
var deallocated = false
var disposed = false
if true {
let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let disposable = ActionDisposable(action: { [object] () -> Void in
let _ = object.debugDescription
disposed = true
})
let disposableSet = DisposableSet()
disposableSet.add(disposable)
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertFalse(disposed, "disposed != false")
}
func testDisposableSetMultipleNotDisposed() {
var deallocated1 = false
var disposed1 = false
var deallocated2 = false
var disposed2 = false
if true {
let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1)
let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in
let _ = object1.debugDescription
disposed1 = true
})
let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2)
let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in
let _ = object2.debugDescription
disposed2 = true
})
let disposableSet = DisposableSet()
disposableSet.add(actionDisposable1)
disposableSet.add(actionDisposable2)
}
XCTAssertTrue(deallocated1, "deallocated1 != true")
XCTAssertFalse(disposed1, "disposed1 != false")
XCTAssertTrue(deallocated2, "deallocated2 != true")
XCTAssertFalse(disposed2, "disposed2 != false")
}
func testMetaDisposableAlreadyDisposed() {
var deallocated1 = false
var disposed1 = false
var deallocated2 = false
var disposed2 = false
if true {
let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1)
let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in
let _ = object1.debugDescription
disposed1 = true
})
let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2)
let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in
let _ = object2.debugDescription
disposed2 = true
})
let metaDisposable = MetaDisposable()
metaDisposable.set(actionDisposable1)
metaDisposable.dispose()
metaDisposable.set(actionDisposable2)
}
XCTAssertTrue(deallocated1, "deallocated1 != true")
XCTAssertTrue(disposed1, "disposed1 != true")
XCTAssertTrue(deallocated2, "deallocated2 != true")
XCTAssertTrue(disposed2, "disposed2 != true")
}
func testDisposableSetAlreadyDisposed() {
var deallocated1 = false
var disposed1 = false
var deallocated2 = false
var disposed2 = false
if true {
let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1)
let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in
let _ = object1.debugDescription
disposed1 = true
})
let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2)
let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in
let _ = object2.debugDescription
disposed2 = true
})
let disposableSet = DisposableSet()
disposableSet.add(actionDisposable1)
disposableSet.dispose()
disposableSet.add(actionDisposable2)
}
XCTAssertTrue(deallocated1, "deallocated1 != true")
XCTAssertTrue(disposed1, "disposed1 != true")
XCTAssertTrue(deallocated2, "deallocated2 != true")
XCTAssertTrue(disposed2, "disposed2 != true")
}
func testDelayed1() {
var flag = false
let signal = Signal<Signal<Void, NoError>, NoError> { subscriber in
Queue.concurrentDefaultQueue().after(0.1, {
subscriber.putNext(Signal { susbcriber2 in
return ActionDisposable {
flag = true
}
})
})
return EmptyDisposable
} |> switchToLatest
let disposable = signal.start()
disposable.dispose()
usleep(1000000 * 20)
XCTAssert(flag == true)
}
}

View File

@@ -0,0 +1,733 @@
import UIKit
import XCTest
import SwiftSignalKit
func singleSignalInt(_ value: Signal<Int, Void>) -> Signal<Signal<Int, Void>, Void> {
return Signal { subscriber in
subscriber.putNext(value)
subscriber.putCompletion()
return EmptyDisposable
}
}
class SwiftSignalKitFunctionsTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testSignalGenerated() {
var deallocated = false
var disposed = false
var generated = false
if true {
var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let signal = Signal<Int, Void> { [object] subscriber in
subscriber.putNext(1)
return ActionDisposable {
let _ = object?.description
disposed = true
}
}
let disposable = signal.start(next: { [object] next in
generated = true
let _ = object?.description
})
object = nil
XCTAssertFalse(deallocated, "deallocated != false")
disposable.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
XCTAssertTrue(generated, "generated != true")
}
func testSignalGeneratedCompleted() {
var deallocated = false
var disposed = false
var generated = false
var completed = false
if true {
var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let signal = Signal<Int, Void> { [object] subscriber in
subscriber.putNext(1)
subscriber.putCompletion()
return ActionDisposable {
let _ = object?.description
disposed = true
}
}
let disposable = signal.start(next: { [object] next in
generated = true
let _ = object?.description
}, completed: { [object]
completed = true
let _ = object?.description
})
object = nil
XCTAssertFalse(deallocated, "deallocated != false")
disposable.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
XCTAssertTrue(generated, "generated != true")
XCTAssertTrue(completed, "completed != true")
}
func testSignalGeneratedError() {
var deallocated = false
var disposed = false
var generated = false
var completed = false
var error = false
if true {
var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
let signal = Signal<Int, Void> { [object] subscriber in
subscriber.putError()
subscriber.putNext(1)
return ActionDisposable {
let _ = object?.description
disposed = true
}
}
let disposable = signal.start(next: { [object] next in
generated = true
let _ = object?.description
}, error: { [object] _ in
error = true
let _ = object?.description
},
completed: { [object]
completed = true
let _ = object?.description
})
object = nil
XCTAssertFalse(deallocated, "deallocated != false")
disposable.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
XCTAssertFalse(generated, "generated != false")
XCTAssertFalse(completed, "completed != false")
XCTAssertTrue(error, "error != true")
}
func testMap() {
var deallocated = false
var disposed = false
var generated = false
if true {
var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated)
var signal = Signal<Int, Void> { [object] subscriber in
subscriber.putNext(1)
return ActionDisposable {
let _ = object?.description
disposed = true
}
}
signal = signal |> map { $0 * 2}
let disposable = signal.start(next: { [object] next in
generated = next == 2
let _ = object?.description
})
object = nil
XCTAssertFalse(deallocated, "deallocated != false")
disposable.dispose()
}
XCTAssertTrue(deallocated, "deallocated != true")
XCTAssertTrue(disposed, "disposed != true")
XCTAssertTrue(generated, "generated != true")
}
func testCatch() {
let failingSignal = Signal<Int, Int> { subscriber in
subscriber.putNext(1)
subscriber.putError(1)
return EmptyDisposable
}
let catchSignal = failingSignal |> `catch` { error in
return Signal<Int, Int> { subscriber in
subscriber.putNext(error * 2)
return EmptyDisposable
}
}
var result = 0
let _ = catchSignal.start(next: { next in
result += next
})
XCTAssertTrue(result == 3, "result != 2")
}
func testSubscriberDisposal() {
var disposed = false
var generated = false
let queue = DispatchQueue(label: "")
if true {
let signal = Signal<Int, Void> { subscriber in
queue.async {
usleep(200)
subscriber.putNext(1)
}
return ActionDisposable {
disposed = true
}
}
let disposable = signal.start(next: { next in
generated = true
})
disposable.dispose()
queue.sync(flags: [.barrier], execute: {})
XCTAssertTrue(disposed, "disposed != true")
XCTAssertFalse(generated, "generated != false")
}
}
func testThen() {
var generatedFirst = false
var disposedFirst = false
var generatedSecond = false
var disposedSecond = false
var result = 0
var signal = Signal<Int, Void> { subscriber in
generatedFirst = true
subscriber.putNext(1)
subscriber.putCompletion()
return ActionDisposable {
disposedFirst = true
}
}
signal = signal |> then (Signal<Int, Void> { subscriber in
generatedSecond = true
subscriber.putNext(2)
subscriber.putCompletion()
return ActionDisposable {
disposedSecond = true
}
})
let _ = signal.start(next: { next in
result += next
})
XCTAssertTrue(generatedFirst, "generatedFirst != true");
XCTAssertTrue(disposedFirst, "disposedFirst != true");
XCTAssertTrue(generatedSecond, "generatedSecond !+ true");
XCTAssertTrue(disposedSecond, "disposedSecond != true");
XCTAssertTrue(result == 3, "result != 3");
}
func testCombineLatest2() {
let s1 = Signal<Int, Void> { subscriber in
subscriber.putNext(1)
subscriber.putCompletion()
return EmptyDisposable
}
let s2 = Signal<Int, Void> { subscriber in
subscriber.putNext(2)
subscriber.putCompletion()
return EmptyDisposable
}
let signal = combineLatest(s1, s2)
var completed = false
let _ = signal.start(next: { next in
XCTAssert(next.0 == 1 && next.1 == 2, "next != (1, 2)")
return
}, completed: {
completed = true
})
XCTAssert(completed == true, "completed != true")
}
func testCombineLatest3() {
let s1 = Signal<Int, Void> { subscriber in
subscriber.putNext(1)
subscriber.putCompletion()
return EmptyDisposable
}
let s2 = Signal<Int, Void> { subscriber in
subscriber.putNext(2)
subscriber.putCompletion()
return EmptyDisposable
}
let s3 = Signal<Int, Void> { subscriber in
subscriber.putNext(3)
subscriber.putCompletion()
return EmptyDisposable
}
let signal = combineLatest(s1, s2, s3)
var completed = false
let _ = signal.start(next: { next in
XCTAssert(next.0 == 1 && next.1 == 2 && next.2 == 3, "next != (1, 2, 3)")
return
}, completed: {
completed = true
})
XCTAssert(completed == true, "completed != true")
}
func testSingle() {
let s1 = single(1, Void.self)
let s2 = fail(Int.self, Void())
let s3 = complete(Int.self, Void.self)
var singleEmitted = false
let _ = s1.start(next: { next in
singleEmitted = next == 1
})
XCTAssert(singleEmitted == true, "singleEmitted != true")
var errorEmitted = false
let _ = s2.start(error: { error in
errorEmitted = true
})
XCTAssert(errorEmitted == true, "errorEmitted != true")
var completedEmitted = false
let _ = s3.start(completed: {
completedEmitted = true
})
XCTAssert(completedEmitted == true, "errorEmitted != true")
}
func testSwitchToLatest() {
var result: [Int] = []
var disposedOne = false
var disposedTwo = false
var disposedThree = false
var completedAll = false
var deallocatedOne = false
var deallocatedTwo = false
var deallocatedThree = false
if true {
let objectOne: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedOne)
let objectTwo: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedTwo)
let objectThree: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedThree)
let one = Signal<Int, Void> { subscriber in
subscriber.putNext(1)
subscriber.putCompletion()
return ActionDisposable { [objectOne] in
let _ = objectOne?.description
disposedOne = true
}
}
let two = Signal<Int, Void> { subscriber in
subscriber.putNext(2)
subscriber.putCompletion()
return ActionDisposable { [objectTwo] in
let _ = objectTwo?.description
disposedTwo = true
}
}
let three = Signal<Int, Void> { subscriber in
subscriber.putNext(3)
subscriber.putCompletion()
return ActionDisposable { [objectThree] in
let _ = objectThree?.description
disposedThree = true
}
}
let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> switchToLatest
let _ = signal.start(next: { next in
result.append(next)
}, completed: {
completedAll = true
})
}
XCTAssert(result.count == 3 && result[0] == 1 && result[1] == 2 && result[2] == 3, "result != [1, 2, 3]");
XCTAssert(disposedOne == true, "disposedOne != true");
XCTAssert(disposedTwo == true, "disposedTwo != true");
XCTAssert(disposedThree == true, "disposedThree != true");
XCTAssert(deallocatedOne == true, "deallocatedOne != true");
XCTAssert(deallocatedTwo == true, "deallocatedTwo != true");
XCTAssert(deallocatedThree == true, "deallocatedThree != true");
XCTAssert(completedAll == true, "completedAll != true");
}
func testSwitchToLatestError() {
var errorGenerated = false
let one = Signal<Int, Void> { subscriber in
subscriber.putError(Void())
return EmptyDisposable
}
let signal = singleSignalInt(one) |> switchToLatest
let _ = signal.start(error: { error in
errorGenerated = true
})
XCTAssert(errorGenerated == true, "errorGenerated != true")
}
func testQueue() {
let q = DispatchQueue(label: "")
var disposedOne = false
var disposedTwo = false
var disposedThree = false
var completedAll = false
var result: [Int] = []
let one = Signal<Int, Void> { subscriber in
q.async {
subscriber.putNext(1)
subscriber.putCompletion()
}
return ActionDisposable {
disposedOne = true
}
}
let two = Signal<Int, Void> { subscriber in
q.async {
subscriber.putNext(2)
subscriber.putCompletion()
}
return ActionDisposable {
disposedTwo = true
}
}
let three = Signal<Int, Void> { subscriber in
q.async {
subscriber.putNext(3)
subscriber.putCompletion()
}
return ActionDisposable {
disposedThree = true
}
}
let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue
let _ = signal.start(next: { next in
print("next: \(next)")
result.append(next)
}, completed: {
completedAll = true
})
usleep(1000 * 200)
XCTAssert(result.count == 3 && result[0] == 1 && result[1] == 2 && result[2] == 3, "result != [1, 2, 3]");
XCTAssert(disposedOne == true, "disposedOne != true");
XCTAssert(disposedTwo == true, "disposedTwo != true");
XCTAssert(disposedThree == true, "disposedThree != true");
XCTAssert(completedAll == true, "completedAll != true");
}
func testQueueInterrupted() {
let q = DispatchQueue(label: "")
var disposedOne = false
var disposedTwo = false
var disposedThree = false
var startedThird = false
var completedAll = false
var result: [Int] = []
let one = Signal<Int, Void> { subscriber in
q.async {
subscriber.putNext(1)
subscriber.putCompletion()
}
return ActionDisposable {
disposedOne = true
}
}
let two = Signal<Int, Void> { subscriber in
q.async {
subscriber.putNext(2)
subscriber.putError(Void())
}
return ActionDisposable {
disposedTwo = true
}
}
let three = Signal<Int, Void> { subscriber in
startedThird = true
q.async {
subscriber.putNext(3)
subscriber.putCompletion()
}
return ActionDisposable {
disposedThree = true
}
}
let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue
let _ = signal.start(next: { next in
result.append(next)
}, completed: {
completedAll = true
})
usleep(1000 * 200)
XCTAssert(result.count == 2 && result[0] == 1 && result[1] == 2, "result != [1, 2]");
XCTAssert(disposedOne == true, "disposedOne != true");
XCTAssert(disposedTwo == true, "disposedTwo != true");
XCTAssert(disposedThree == false, "disposedThree != false");
XCTAssert(startedThird == false, "startedThird != false");
XCTAssert(completedAll == false, "completedAll != false");
}
func testQueueDisposed() {
let q = DispatchQueue(label: "")
var disposedOne = false
var disposedTwo = false
var disposedThree = false
var startedFirst = false
var startedSecond = false
var startedThird = false
var result: [Int] = []
let one = Signal<Int, Void> { subscriber in
startedFirst = true
var cancelled = false
q.async {
if !cancelled {
usleep(100 * 1000)
subscriber.putNext(1)
subscriber.putCompletion()
}
}
return ActionDisposable {
cancelled = true
disposedOne = true
}
}
let two = Signal<Int, Void> { subscriber in
startedSecond = true
var cancelled = false
q.async {
if !cancelled {
usleep(100 * 1000)
subscriber.putNext(2)
subscriber.putError(Void())
}
}
return ActionDisposable {
cancelled = true
disposedTwo = true
}
}
let three = Signal<Int, Void> { subscriber in
startedThird = true
var cancelled = false
q.async {
if !cancelled {
usleep(100 * 1000)
subscriber.putNext(3)
subscriber.putCompletion()
}
}
return ActionDisposable {
cancelled = true
disposedThree = true
}
}
let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue
signal.start(next: { next in
result.append(next)
}).dispose()
usleep(1000 * 200)
XCTAssert(result.count == 0, "result != []");
XCTAssert(disposedOne == true, "disposedOne != true");
XCTAssert(disposedTwo == false, "disposedTwo != false");
XCTAssert(disposedThree == false, "disposedThree != false");
XCTAssert(startedFirst == true, "startedFirst != false");
XCTAssert(startedSecond == false, "startedSecond != false");
XCTAssert(startedThird == false, "startedThird != false");
}
func testRestart() {
let q = DispatchQueue(label: "", attributes: [.concurrent])
let signal = Signal<Int, Void> { subscriber in
q.async {
subscriber.putNext(1)
subscriber.putCompletion()
}
return EmptyDisposable
}
var result = 0
let _ = (signal |> restart |> take(3)).start(next: { next in
result += next
})
usleep(100 * 1000)
XCTAssert(result == 3, "result != 3")
}
func testPipe() {
let pipe = ValuePipe<Int>()
var result1 = 0
let disposable1 = pipe.signal().start(next: { next in
result1 += next
})
var result2 = 0
let disposable2 = pipe.signal().start(next: { next in
result2 += next
})
pipe.putNext(1)
XCTAssert(result1 == 1, "result1 != 1")
XCTAssert(result2 == 1, "result2 != 1")
disposable1.dispose()
pipe.putNext(1)
XCTAssert(result1 == 1, "result1 != 1")
XCTAssert(result2 == 2, "result2 != 2")
disposable2.dispose()
pipe.putNext(1)
XCTAssert(result1 == 1, "result1 != 1")
XCTAssert(result2 == 2, "result2 != 2")
}
func testQueueRecursive() {
let q = Queue()
let signal = Signal<Int, NoError> { subscriber in
for _ in 0 ..< 1000 {
subscriber.putNext(1)
}
subscriber.putCompletion()
return EmptyDisposable
}
let queued = signal
|> mapToQueue { _ -> Signal<Void, NoError> in
return complete(Void.self, NoError.self) |> deliverOn(q)
}
let _ = queued.start()
}
func testReduceSignal() {
let q = Queue()
let signal = Signal<Int, NoError> { subscriber in
for i in 0 ..< 1000 {
subscriber.putNext(i)
}
subscriber.putCompletion()
return EmptyDisposable
}
let reduced = signal
|> reduceLeft(0, generator: { current, next -> Signal<(Int, Passthrough<Int>), NoError> in
return Signal { subscriber in
subscriber.putNext((current + next, Passthrough.Some(current + next)))
subscriber.putCompletion()
return EmptyDisposable
} |> deliverOn(q)
})
var values: [Int] = []
let _ = reduced.start(next: { next in
values.append(next)
})
q.sync { }
XCTAssert(values.count == 1001, "count \(values.count) != 1001")
var previous = 0
for i in 0 ..< 1001 {
let value: Int
if i >= 1000 {
value = previous
} else {
value = previous + i
previous = value
}
previous = value
XCTAssert(values[i] == value, "at \(i): \(values[i]) != \(value)")
}
}
func testMainQueueReentrant() {
let q = Queue.mainQueue()
var a = 1
q.async {
usleep(150 * 1000)
a = 2
}
XCTAssert(a == 2)
}
}