mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Add 'submodules/SSignalKit/' from commit '359b2ee7c9f20f99f221f78e307369ef5ad0ece2'
git-subtree-dir: submodules/SSignalKit git-subtree-mainline:4459dc5b47git-subtree-split:359b2ee7c9
This commit is contained in:
@@ -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 ""
|
||||
}
|
||||
}
|
||||
}
|
||||
24
submodules/SSignalKit/SwiftSignalKitTests/Info.plist
Normal file
24
submodules/SSignalKit/SwiftSignalKitTests/Info.plist
Normal 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>
|
||||
166
submodules/SSignalKit/SwiftSignalKitTests/PerformanceTests.swift
Normal file
166
submodules/SSignalKit/SwiftSignalKitTests/PerformanceTests.swift
Normal 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)")
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user