Swiftgram/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift
Peter 971273e8f8 Add 'submodules/SSignalKit/' from commit '359b2ee7c9f20f99f221f78e307369ef5ad0ece2'
git-subtree-dir: submodules/SSignalKit
git-subtree-mainline: 4459dc5b47e7db4ea1adb3a43a4324d1c2f9feab
git-subtree-split: 359b2ee7c9f20f99f221f78e307369ef5ad0ece2
2019-06-11 18:57:57 +01:00

734 lines
22 KiB
Swift

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)
}
}