| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264 |
- //
- // SignalSpec.swift
- // ReactiveCocoa
- //
- // Created by Justin Spahr-Summers on 2015-01-23.
- // Copyright (c) 2015 GitHub. All rights reserved.
- //
- import Result
- import Nimble
- import Quick
- import ReactiveCocoa
- class SignalSpec: QuickSpec {
- override func spec() {
- describe("init") {
- var testScheduler: TestScheduler!
-
- beforeEach {
- testScheduler = TestScheduler()
- }
-
- it("should run the generator immediately") {
- var didRunGenerator = false
- _ = Signal<AnyObject, NoError> { observer in
- didRunGenerator = true
- return nil
- }
-
- expect(didRunGenerator) == true
- }
- it("should forward events to observers") {
- let numbers = [ 1, 2, 5 ]
-
- let signal: Signal<Int, NoError> = Signal { observer in
- testScheduler.schedule {
- for number in numbers {
- observer.sendNext(number)
- }
- observer.sendCompleted()
- }
- return nil
- }
-
- var fromSignal: [Int] = []
- var completed = false
-
- signal.observe { event in
- switch event {
- case let .Next(number):
- fromSignal.append(number)
- case .Completed:
- completed = true
- default:
- break
- }
- }
-
- expect(completed) == false
- expect(fromSignal).to(beEmpty())
-
- testScheduler.run()
-
- expect(completed) == true
- expect(fromSignal) == numbers
- }
- it("should dispose of returned disposable upon error") {
- let disposable = SimpleDisposable()
-
- let signal: Signal<AnyObject, TestError> = Signal { observer in
- testScheduler.schedule {
- observer.sendFailed(TestError.Default)
- }
- return disposable
- }
-
- var errored = false
-
- signal.observeFailed { _ in errored = true }
-
- expect(errored) == false
- expect(disposable.disposed) == false
-
- testScheduler.run()
-
- expect(errored) == true
- expect(disposable.disposed) == true
- }
- it("should dispose of returned disposable upon completion") {
- let disposable = SimpleDisposable()
-
- let signal: Signal<AnyObject, NoError> = Signal { observer in
- testScheduler.schedule {
- observer.sendCompleted()
- }
- return disposable
- }
-
- var completed = false
-
- signal.observeCompleted { completed = true }
-
- expect(completed) == false
- expect(disposable.disposed) == false
-
- testScheduler.run()
-
- expect(completed) == true
- expect(disposable.disposed) == true
- }
- it("should dispose of returned disposable upon interrupted") {
- let disposable = SimpleDisposable()
- let signal: Signal<AnyObject, NoError> = Signal { observer in
- testScheduler.schedule {
- observer.sendInterrupted()
- }
- return disposable
- }
- var interrupted = false
- signal.observeInterrupted {
- interrupted = true
- }
- expect(interrupted) == false
- expect(disposable.disposed) == false
- testScheduler.run()
- expect(interrupted) == true
- expect(disposable.disposed) == true
- }
- }
- describe("Signal.empty") {
- it("should interrupt its observers without emitting any value") {
- let signal = Signal<(), NoError>.empty
- var hasUnexpectedEventsEmitted = false
- var signalInterrupted = false
- signal.observe { event in
- switch event {
- case .Next, .Failed, .Completed:
- hasUnexpectedEventsEmitted = true
- case .Interrupted:
- signalInterrupted = true
- }
- }
- expect(hasUnexpectedEventsEmitted) == false
- expect(signalInterrupted) == true
- }
- }
- describe("Signal.pipe") {
- it("should forward events to observers") {
- let (signal, observer) = Signal<Int, NoError>.pipe()
-
- var fromSignal: [Int] = []
- var completed = false
-
- signal.observe { event in
- switch event {
- case let .Next(number):
- fromSignal.append(number)
- case .Completed:
- completed = true
- default:
- break
- }
- }
-
- expect(fromSignal).to(beEmpty())
- expect(completed) == false
-
- observer.sendNext(1)
- expect(fromSignal) == [ 1 ]
-
- observer.sendNext(2)
- expect(fromSignal) == [ 1, 2 ]
-
- expect(completed) == false
- observer.sendCompleted()
- expect(completed) == true
- }
- context("memory") {
- it("should not crash allocating memory with a few observers") {
- let (signal, _) = Signal<Int, NoError>.pipe()
- for _ in 0..<50 {
- autoreleasepool {
- let disposable = signal.observe { _ in }
- disposable!.dispose()
- }
- }
- }
- }
- }
- describe("observe") {
- var testScheduler: TestScheduler!
-
- beforeEach {
- testScheduler = TestScheduler()
- }
-
- it("should stop forwarding events when disposed") {
- let disposable = SimpleDisposable()
-
- let signal: Signal<Int, NoError> = Signal { observer in
- testScheduler.schedule {
- for number in [ 1, 2 ] {
- observer.sendNext(number)
- }
- observer.sendCompleted()
- observer.sendNext(4)
- }
- return disposable
- }
-
- var fromSignal: [Int] = []
- signal.observeNext { number in
- fromSignal.append(number)
- }
-
- expect(disposable.disposed) == false
- expect(fromSignal).to(beEmpty())
-
- testScheduler.run()
-
- expect(disposable.disposed) == true
- expect(fromSignal) == [ 1, 2 ]
- }
- it("should not trigger side effects") {
- var runCount = 0
- let signal: Signal<(), NoError> = Signal { observer in
- runCount += 1
- return nil
- }
-
- expect(runCount) == 1
-
- signal.observe(Observer<(), NoError>())
- expect(runCount) == 1
- }
- it("should release observer after termination") {
- weak var testStr: NSMutableString?
- let (signal, observer) = Signal<Int, NoError>.pipe()
- let test = {
- let innerStr: NSMutableString = NSMutableString()
- signal.observeNext { value in
- innerStr.appendString("\(value)")
- }
- testStr = innerStr
- }
- test()
- observer.sendNext(1)
- expect(testStr) == "1"
- observer.sendNext(2)
- expect(testStr) == "12"
- observer.sendCompleted()
- expect(testStr).to(beNil())
- }
- it("should release observer after interruption") {
- weak var testStr: NSMutableString?
- let (signal, observer) = Signal<Int, NoError>.pipe()
- let test = {
- let innerStr: NSMutableString = NSMutableString()
- signal.observeNext { value in
- innerStr.appendString("\(value)")
- }
- testStr = innerStr
- }
- test()
- observer.sendNext(1)
- expect(testStr) == "1"
- observer.sendNext(2)
- expect(testStr) == "12"
- observer.sendInterrupted()
- expect(testStr).to(beNil())
- }
- }
- describe("trailing closure") {
- it("receives next values") {
- var values = [Int]()
- let (signal, observer) = Signal<Int, NoError>.pipe()
- signal.observeNext { next in
- values.append(next)
- }
- observer.sendNext(1)
- expect(values) == [1]
- }
- // TODO: remove when the method is marked unavailable
- it("receives next values with erroring signal") {
- var values = [Int]()
- let (signal, observer) = Signal<Int, TestError>.pipe()
- signal.observeNext { next in
- values.append(next)
- }
- observer.sendNext(1)
- expect(values) == [1]
- }
- it("receives results") {
- let (signal, observer) = Signal<Int, TestError>.pipe()
- var results: [Result<Int, TestError>] = []
- signal.observeResult { results.append($0) }
- observer.sendNext(1)
- observer.sendNext(2)
- observer.sendNext(3)
- observer.sendFailed(.Default)
- observer.sendCompleted()
- expect(results).to(haveCount(4))
- expect(results[0].value) == 1
- expect(results[1].value) == 2
- expect(results[2].value) == 3
- expect(results[3].error) == .Default
- }
- }
- describe("map") {
- it("should transform the values of the signal") {
- let (signal, observer) = Signal<Int, NoError>.pipe()
- let mappedSignal = signal.map { String($0 + 1) }
- var lastValue: String?
- mappedSignal.observeNext {
- lastValue = $0
- return
- }
- expect(lastValue).to(beNil())
- observer.sendNext(0)
- expect(lastValue) == "1"
- observer.sendNext(1)
- expect(lastValue) == "2"
- }
- }
-
-
- describe("mapError") {
- it("should transform the errors of the signal") {
- let (signal, observer) = Signal<Int, TestError>.pipe()
- let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 100, userInfo: nil)
- var error: NSError?
- signal
- .mapError { _ in producerError }
- .observeFailed { err in error = err }
- expect(error).to(beNil())
- observer.sendFailed(TestError.Default)
- expect(error) == producerError
- }
- }
- describe("filter") {
- it("should omit values from the signal") {
- let (signal, observer) = Signal<Int, NoError>.pipe()
- let mappedSignal = signal.filter { $0 % 2 == 0 }
- var lastValue: Int?
- mappedSignal.observeNext { lastValue = $0 }
- expect(lastValue).to(beNil())
- observer.sendNext(0)
- expect(lastValue) == 0
- observer.sendNext(1)
- expect(lastValue) == 0
- observer.sendNext(2)
- expect(lastValue) == 2
- }
- }
- describe("ignoreNil") {
- it("should forward only non-nil values") {
- let (signal, observer) = Signal<Int?, NoError>.pipe()
- let mappedSignal = signal.ignoreNil()
- var lastValue: Int?
- mappedSignal.observeNext { lastValue = $0 }
- expect(lastValue).to(beNil())
- observer.sendNext(nil)
- expect(lastValue).to(beNil())
- observer.sendNext(1)
- expect(lastValue) == 1
- observer.sendNext(nil)
- expect(lastValue) == 1
- observer.sendNext(2)
- expect(lastValue) == 2
- }
- }
- describe("scan") {
- it("should incrementally accumulate a value") {
- let (baseSignal, observer) = Signal<String, NoError>.pipe()
- let signal = baseSignal.scan("", +)
- var lastValue: String?
- signal.observeNext { lastValue = $0 }
- expect(lastValue).to(beNil())
- observer.sendNext("a")
- expect(lastValue) == "a"
- observer.sendNext("bb")
- expect(lastValue) == "abb"
- }
- }
- describe("reduce") {
- it("should accumulate one value") {
- let (baseSignal, observer) = Signal<Int, NoError>.pipe()
- let signal = baseSignal.reduce(1, +)
- var lastValue: Int?
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- expect(lastValue).to(beNil())
- observer.sendNext(1)
- expect(lastValue).to(beNil())
- observer.sendNext(2)
- expect(lastValue).to(beNil())
- expect(completed) == false
- observer.sendCompleted()
- expect(completed) == true
- expect(lastValue) == 4
- }
- it("should send the initial value if none are received") {
- let (baseSignal, observer) = Signal<Int, NoError>.pipe()
- let signal = baseSignal.reduce(1, +)
- var lastValue: Int?
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- expect(lastValue).to(beNil())
- expect(completed) == false
- observer.sendCompleted()
- expect(lastValue) == 1
- expect(completed) == true
- }
- }
- describe("skip") {
- it("should skip initial values") {
- let (baseSignal, observer) = Signal<Int, NoError>.pipe()
- let signal = baseSignal.skip(1)
- var lastValue: Int?
- signal.observeNext { lastValue = $0 }
- expect(lastValue).to(beNil())
- observer.sendNext(1)
- expect(lastValue).to(beNil())
- observer.sendNext(2)
- expect(lastValue) == 2
- }
- it("should not skip any values when 0") {
- let (baseSignal, observer) = Signal<Int, NoError>.pipe()
- let signal = baseSignal.skip(0)
- var lastValue: Int?
- signal.observeNext { lastValue = $0 }
- expect(lastValue).to(beNil())
- observer.sendNext(1)
- expect(lastValue) == 1
- observer.sendNext(2)
- expect(lastValue) == 2
- }
- }
- describe("skipRepeats") {
- it("should skip duplicate Equatable values") {
- let (baseSignal, observer) = Signal<Bool, NoError>.pipe()
- let signal = baseSignal.skipRepeats()
- var values: [Bool] = []
- signal.observeNext { values.append($0) }
- expect(values) == []
- observer.sendNext(true)
- expect(values) == [ true ]
- observer.sendNext(true)
- expect(values) == [ true ]
- observer.sendNext(false)
- expect(values) == [ true, false ]
- observer.sendNext(true)
- expect(values) == [ true, false, true ]
- }
- it("should skip values according to a predicate") {
- let (baseSignal, observer) = Signal<String, NoError>.pipe()
- let signal = baseSignal.skipRepeats { $0.characters.count == $1.characters.count }
- var values: [String] = []
- signal.observeNext { values.append($0) }
- expect(values) == []
- observer.sendNext("a")
- expect(values) == [ "a" ]
- observer.sendNext("b")
- expect(values) == [ "a" ]
- observer.sendNext("cc")
- expect(values) == [ "a", "cc" ]
- observer.sendNext("d")
- expect(values) == [ "a", "cc", "d" ]
- }
- it("should not store strong reference to previously passed items") {
- var disposedItems: [Bool] = []
- struct Item {
- let payload: Bool
- let disposable: ScopedDisposable
- }
- func item(payload: Bool) -> Item {
- return Item(
- payload: payload,
- disposable: ScopedDisposable(ActionDisposable { disposedItems.append(payload) })
- )
- }
- let (baseSignal, observer) = Signal<Item, NoError>.pipe()
- baseSignal.skipRepeats { $0.payload == $1.payload }.observeNext { _ in }
- observer.sendNext(item(true))
- expect(disposedItems) == []
- observer.sendNext(item(false))
- expect(disposedItems) == [ true ]
- observer.sendNext(item(false))
- expect(disposedItems) == [ true, false ]
- observer.sendNext(item(true))
- expect(disposedItems) == [ true, false, false ]
- observer.sendCompleted()
- expect(disposedItems) == [ true, false, false, true ]
- }
- }
-
- describe("uniqueValues") {
- it("should skip values that have been already seen") {
- let (baseSignal, observer) = Signal<String, NoError>.pipe()
- let signal = baseSignal.uniqueValues()
-
- var values: [String] = []
- signal.observeNext { values.append($0) }
-
- expect(values) == []
- observer.sendNext("a")
- expect(values) == [ "a" ]
-
- observer.sendNext("b")
- expect(values) == [ "a", "b" ]
-
- observer.sendNext("a")
- expect(values) == [ "a", "b" ]
-
- observer.sendNext("b")
- expect(values) == [ "a", "b" ]
-
- observer.sendNext("c")
- expect(values) == [ "a", "b", "c" ]
-
- observer.sendCompleted()
- expect(values) == [ "a", "b", "c" ]
- }
- }
-
- describe("skipWhile") {
- var signal: Signal<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var lastValue: Int?
- beforeEach {
- let (baseSignal, incomingObserver) = Signal<Int, NoError>.pipe()
- signal = baseSignal.skipWhile { $0 < 2 }
- observer = incomingObserver
- lastValue = nil
- signal.observeNext { lastValue = $0 }
- }
- it("should skip while the predicate is true") {
- expect(lastValue).to(beNil())
- observer.sendNext(1)
- expect(lastValue).to(beNil())
- observer.sendNext(2)
- expect(lastValue) == 2
- observer.sendNext(0)
- expect(lastValue) == 0
- }
- it("should not skip any values when the predicate starts false") {
- expect(lastValue).to(beNil())
- observer.sendNext(3)
- expect(lastValue) == 3
- observer.sendNext(1)
- expect(lastValue) == 1
- }
- }
-
- describe("skipUntil") {
- var signal: Signal<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var triggerObserver: Signal<(), NoError>.Observer!
-
- var lastValue: Int? = nil
-
- beforeEach {
- let (baseSignal, incomingObserver) = Signal<Int, NoError>.pipe()
- let (triggerSignal, incomingTriggerObserver) = Signal<(), NoError>.pipe()
-
- signal = baseSignal.skipUntil(triggerSignal)
- observer = incomingObserver
- triggerObserver = incomingTriggerObserver
-
- lastValue = nil
-
- signal.observe { event in
- switch event {
- case let .Next(value):
- lastValue = value
- default:
- break
- }
- }
- }
-
- it("should skip values until the trigger fires") {
- expect(lastValue).to(beNil())
-
- observer.sendNext(1)
- expect(lastValue).to(beNil())
- observer.sendNext(2)
- expect(lastValue).to(beNil())
- triggerObserver.sendNext(())
- observer.sendNext(0)
- expect(lastValue) == 0
- }
-
- it("should skip values until the trigger completes") {
- expect(lastValue).to(beNil())
-
- observer.sendNext(1)
- expect(lastValue).to(beNil())
-
- observer.sendNext(2)
- expect(lastValue).to(beNil())
-
- triggerObserver.sendCompleted()
- observer.sendNext(0)
- expect(lastValue) == 0
- }
- }
- describe("take") {
- it("should take initial values") {
- let (baseSignal, observer) = Signal<Int, NoError>.pipe()
- let signal = baseSignal.take(2)
- var lastValue: Int?
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- expect(lastValue).to(beNil())
- expect(completed) == false
- observer.sendNext(1)
- expect(lastValue) == 1
- expect(completed) == false
- observer.sendNext(2)
- expect(lastValue) == 2
- expect(completed) == true
- }
-
- it("should complete immediately after taking given number of values") {
- let numbers = [ 1, 2, 4, 4, 5 ]
- let testScheduler = TestScheduler()
-
- var signal: Signal<Int, NoError> = Signal { observer in
- testScheduler.schedule {
- for number in numbers {
- observer.sendNext(number)
- }
- }
- return nil
- }
-
- var completed = false
-
- signal = signal.take(numbers.count)
- signal.observeCompleted { completed = true }
-
- expect(completed) == false
- testScheduler.run()
- expect(completed) == true
- }
- it("should interrupt when 0") {
- let numbers = [ 1, 2, 4, 4, 5 ]
- let testScheduler = TestScheduler()
- let signal: Signal<Int, NoError> = Signal { observer in
- testScheduler.schedule {
- for number in numbers {
- observer.sendNext(number)
- }
- }
- return nil
- }
- var result: [Int] = []
- var interrupted = false
- signal
- .take(0)
- .observe { event in
- switch event {
- case let .Next(number):
- result.append(number)
- case .Interrupted:
- interrupted = true
- default:
- break
- }
- }
- expect(interrupted) == true
- testScheduler.run()
- expect(result).to(beEmpty())
- }
- }
- describe("collect") {
- it("should collect all values") {
- let (original, observer) = Signal<Int, NoError>.pipe()
- let signal = original.collect()
- let expectedResult = [ 1, 2, 3 ]
- var result: [Int]?
- signal.observeNext { value in
- expect(result).to(beNil())
- result = value
- }
- for number in expectedResult {
- observer.sendNext(number)
- }
- expect(result).to(beNil())
- observer.sendCompleted()
- expect(result) == expectedResult
- }
- it("should complete with an empty array if there are no values") {
- let (original, observer) = Signal<Int, NoError>.pipe()
- let signal = original.collect()
- var result: [Int]?
- signal.observeNext { result = $0 }
- expect(result).to(beNil())
- observer.sendCompleted()
- expect(result) == []
- }
- it("should forward errors") {
- let (original, observer) = Signal<Int, TestError>.pipe()
- let signal = original.collect()
- var error: TestError?
- signal.observeFailed { error = $0 }
- expect(error).to(beNil())
- observer.sendFailed(.Default)
- expect(error) == TestError.Default
- }
- it("should collect an exact count of values") {
- let (original, observer) = Signal<Int, NoError>.pipe()
- let signal = original.collect(count: 3)
- var observedValues: [[Int]] = []
- signal.observeNext { value in
- observedValues.append(value)
- }
- var expectation: [[Int]] = []
- for i in 1...7 {
- observer.sendNext(i)
- if i % 3 == 0 {
- expectation.append([Int]((i - 2)...i))
- expect(observedValues) == expectation
- } else {
- expect(observedValues) == expectation
- }
- }
- observer.sendCompleted()
- expectation.append([7])
- expect(observedValues) == expectation
- }
- it("should collect values until it matches a certain value") {
- let (original, observer) = Signal<Int, NoError>.pipe()
- let signal = original.collect { _, next in next != 5 }
- var expectedValues = [
- [5, 5],
- [42, 5]
- ]
- signal.observeNext { value in
- expect(value) == expectedValues.removeFirst()
- }
- signal.observeCompleted {
- expect(expectedValues) == []
- }
- expectedValues
- .flatMap { $0 }
- .forEach(observer.sendNext)
- observer.sendCompleted()
- }
- it("should collect values until it matches a certain condition on values") {
- let (original, observer) = Signal<Int, NoError>.pipe()
- let signal = original.collect { values in values.reduce(0, combine: +) == 10 }
- var expectedValues = [
- [1, 2, 3, 4],
- [5, 6, 7, 8, 9]
- ]
- signal.observeNext { value in
- expect(value) == expectedValues.removeFirst()
- }
- signal.observeCompleted {
- expect(expectedValues) == []
- }
- expectedValues
- .flatMap { $0 }
- .forEach(observer.sendNext)
- observer.sendCompleted()
- }
- }
- describe("takeUntil") {
- var signal: Signal<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var triggerObserver: Signal<(), NoError>.Observer!
- var lastValue: Int? = nil
- var completed: Bool = false
- beforeEach {
- let (baseSignal, incomingObserver) = Signal<Int, NoError>.pipe()
- let (triggerSignal, incomingTriggerObserver) = Signal<(), NoError>.pipe()
- signal = baseSignal.takeUntil(triggerSignal)
- observer = incomingObserver
- triggerObserver = incomingTriggerObserver
- lastValue = nil
- completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- }
- it("should take values until the trigger fires") {
- expect(lastValue).to(beNil())
- observer.sendNext(1)
- expect(lastValue) == 1
- observer.sendNext(2)
- expect(lastValue) == 2
- expect(completed) == false
- triggerObserver.sendNext(())
- expect(completed) == true
- }
-
- it("should take values until the trigger completes") {
- expect(lastValue).to(beNil())
-
- observer.sendNext(1)
- expect(lastValue) == 1
-
- observer.sendNext(2)
- expect(lastValue) == 2
-
- expect(completed) == false
- triggerObserver.sendCompleted()
- expect(completed) == true
- }
- it("should complete if the trigger fires immediately") {
- expect(lastValue).to(beNil())
- expect(completed) == false
- triggerObserver.sendNext(())
- expect(completed) == true
- expect(lastValue).to(beNil())
- }
- }
- describe("takeUntilReplacement") {
- var signal: Signal<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var replacementObserver: Signal<Int, NoError>.Observer!
- var lastValue: Int? = nil
- var completed: Bool = false
- beforeEach {
- let (baseSignal, incomingObserver) = Signal<Int, NoError>.pipe()
- let (replacementSignal, incomingReplacementObserver) = Signal<Int, NoError>.pipe()
- signal = baseSignal.takeUntilReplacement(replacementSignal)
- observer = incomingObserver
- replacementObserver = incomingReplacementObserver
- lastValue = nil
- completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- }
- it("should take values from the original then the replacement") {
- expect(lastValue).to(beNil())
- expect(completed) == false
- observer.sendNext(1)
- expect(lastValue) == 1
- observer.sendNext(2)
- expect(lastValue) == 2
- replacementObserver.sendNext(3)
- expect(lastValue) == 3
- expect(completed) == false
- observer.sendNext(4)
- expect(lastValue) == 3
- expect(completed) == false
- replacementObserver.sendNext(5)
- expect(lastValue) == 5
- expect(completed) == false
- replacementObserver.sendCompleted()
- expect(completed) == true
- }
- }
- describe("takeWhile") {
- var signal: Signal<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- beforeEach {
- let (baseSignal, incomingObserver) = Signal<Int, NoError>.pipe()
- signal = baseSignal.takeWhile { $0 <= 4 }
- observer = incomingObserver
- }
- it("should take while the predicate is true") {
- var latestValue: Int!
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- latestValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- for value in -1...4 {
- observer.sendNext(value)
- expect(latestValue) == value
- expect(completed) == false
- }
- observer.sendNext(5)
- expect(latestValue) == 4
- expect(completed) == true
- }
- it("should complete if the predicate starts false") {
- var latestValue: Int?
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- latestValue = value
- case .Completed:
- completed = true
- default:
- break
- }
- }
- observer.sendNext(5)
- expect(latestValue).to(beNil())
- expect(completed) == true
- }
- }
- describe("observeOn") {
- it("should send events on the given scheduler") {
- let testScheduler = TestScheduler()
- let (signal, observer) = Signal<Int, NoError>.pipe()
-
- var result: [Int] = []
-
- signal
- .observeOn(testScheduler)
- .observeNext { result.append($0) }
-
- observer.sendNext(1)
- observer.sendNext(2)
- expect(result).to(beEmpty())
-
- testScheduler.run()
- expect(result) == [ 1, 2 ]
- }
- }
- describe("delay") {
- it("should send events on the given scheduler after the interval") {
- let testScheduler = TestScheduler()
- let signal: Signal<Int, NoError> = Signal { observer in
- testScheduler.schedule {
- observer.sendNext(1)
- }
- testScheduler.scheduleAfter(5, action: {
- observer.sendNext(2)
- observer.sendCompleted()
- })
- return nil
- }
-
- var result: [Int] = []
- var completed = false
-
- signal
- .delay(10, onScheduler: testScheduler)
- .observe { event in
- switch event {
- case let .Next(number):
- result.append(number)
- case .Completed:
- completed = true
- default:
- break
- }
- }
-
- testScheduler.advanceByInterval(4) // send initial value
- expect(result).to(beEmpty())
-
- testScheduler.advanceByInterval(10) // send second value and receive first
- expect(result) == [ 1 ]
- expect(completed) == false
-
- testScheduler.advanceByInterval(10) // send second value and receive first
- expect(result) == [ 1, 2 ]
- expect(completed) == true
- }
- it("should schedule errors immediately") {
- let testScheduler = TestScheduler()
- let signal: Signal<Int, TestError> = Signal { observer in
- testScheduler.schedule {
- observer.sendFailed(TestError.Default)
- }
- return nil
- }
-
- var errored = false
-
- signal
- .delay(10, onScheduler: testScheduler)
- .observeFailed { _ in errored = true }
-
- testScheduler.advance()
- expect(errored) == true
- }
- }
- describe("throttle") {
- var scheduler: TestScheduler!
- var observer: Signal<Int, NoError>.Observer!
- var signal: Signal<Int, NoError>!
- beforeEach {
- scheduler = TestScheduler()
- let (baseSignal, baseObserver) = Signal<Int, NoError>.pipe()
- observer = baseObserver
- signal = baseSignal.throttle(1, onScheduler: scheduler)
- expect(signal).notTo(beNil())
- }
- it("should send values on the given scheduler at no less than the interval") {
- var values: [Int] = []
- signal.observeNext { value in
- values.append(value)
- }
- expect(values) == []
- observer.sendNext(0)
- expect(values) == []
- scheduler.advance()
- expect(values) == [ 0 ]
- observer.sendNext(1)
- observer.sendNext(2)
- expect(values) == [ 0 ]
- scheduler.advanceByInterval(1.5)
- expect(values) == [ 0, 2 ]
- scheduler.advanceByInterval(3)
- expect(values) == [ 0, 2 ]
- observer.sendNext(3)
- expect(values) == [ 0, 2 ]
- scheduler.advance()
- expect(values) == [ 0, 2, 3 ]
- observer.sendNext(4)
- observer.sendNext(5)
- scheduler.advance()
- expect(values) == [ 0, 2, 3 ]
- scheduler.run()
- expect(values) == [ 0, 2, 3, 5 ]
- }
- it("should schedule completion immediately") {
- var values: [Int] = []
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- values.append(value)
- case .Completed:
- completed = true
- default:
- break
- }
- }
- observer.sendNext(0)
- scheduler.advance()
- expect(values) == [ 0 ]
- observer.sendNext(1)
- observer.sendCompleted()
- expect(completed) == false
- scheduler.advance()
- expect(values) == [ 0 ]
- expect(completed) == true
- scheduler.run()
- expect(values) == [ 0 ]
- expect(completed) == true
- }
- }
- describe("debounce") {
- var scheduler: TestScheduler!
- var observer: Signal<Int, NoError>.Observer!
- var signal: Signal<Int, NoError>!
- beforeEach {
- scheduler = TestScheduler()
- let (baseSignal, baseObserver) = Signal<Int, NoError>.pipe()
- observer = baseObserver
- signal = baseSignal.debounce(1, onScheduler: scheduler)
- expect(signal).notTo(beNil())
- }
- it("should send values on the given scheduler once the interval has passed since the last value was sent") {
- var values: [Int] = []
- signal.observeNext { value in
- values.append(value)
- }
- expect(values) == []
- observer.sendNext(0)
- expect(values) == []
- scheduler.advance()
- expect(values) == []
- observer.sendNext(1)
- observer.sendNext(2)
- expect(values) == []
- scheduler.advanceByInterval(1.5)
- expect(values) == [ 2 ]
- scheduler.advanceByInterval(3)
- expect(values) == [ 2 ]
- observer.sendNext(3)
- expect(values) == [ 2 ]
- scheduler.advance()
- expect(values) == [ 2 ]
- observer.sendNext(4)
- observer.sendNext(5)
- scheduler.advance()
- expect(values) == [ 2 ]
- scheduler.run()
- expect(values) == [ 2, 5 ]
- }
- it("should schedule completion immediately") {
- var values: [Int] = []
- var completed = false
- signal.observe { event in
- switch event {
- case let .Next(value):
- values.append(value)
- case .Completed:
- completed = true
- default:
- break
- }
- }
- observer.sendNext(0)
- scheduler.advance()
- expect(values) == []
- observer.sendNext(1)
- observer.sendCompleted()
- expect(completed) == false
- scheduler.advance()
- expect(values) == []
- expect(completed) == true
- scheduler.run()
- expect(values) == []
- expect(completed) == true
- }
- }
- describe("sampleWith") {
- var sampledSignal: Signal<(Int, String), NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var samplerObserver: Signal<String, NoError>.Observer!
-
- beforeEach {
- let (signal, incomingObserver) = Signal<Int, NoError>.pipe()
- let (sampler, incomingSamplerObserver) = Signal<String, NoError>.pipe()
- sampledSignal = signal.sampleWith(sampler)
- observer = incomingObserver
- samplerObserver = incomingSamplerObserver
- }
- it("should forward the latest value when the sampler fires") {
- var result: [String] = []
- sampledSignal.observeNext { (left, right) in result.append("\(left)\(right)") }
-
- observer.sendNext(1)
- observer.sendNext(2)
- samplerObserver.sendNext("a")
- expect(result) == [ "2a" ]
- }
- it("should do nothing if sampler fires before signal receives value") {
- var result: [String] = []
- sampledSignal.observeNext { (left, right) in result.append("\(left)\(right)") }
-
- samplerObserver.sendNext("a")
- expect(result).to(beEmpty())
- }
- it("should send lates value with sampler value multiple times when sampler fires multiple times") {
- var result: [String] = []
- sampledSignal.observeNext { (left, right) in result.append("\(left)\(right)") }
-
- observer.sendNext(1)
- samplerObserver.sendNext("a")
- samplerObserver.sendNext("b")
- expect(result) == [ "1a", "1b" ]
- }
- it("should complete when both inputs have completed") {
- var completed = false
- sampledSignal.observeCompleted { completed = true }
-
- observer.sendCompleted()
- expect(completed) == false
-
- samplerObserver.sendCompleted()
- expect(completed) == true
- }
- }
- describe("sampleOn") {
- var sampledSignal: Signal<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var samplerObserver: Signal<(), NoError>.Observer!
-
- beforeEach {
- let (signal, incomingObserver) = Signal<Int, NoError>.pipe()
- let (sampler, incomingSamplerObserver) = Signal<(), NoError>.pipe()
- sampledSignal = signal.sampleOn(sampler)
- observer = incomingObserver
- samplerObserver = incomingSamplerObserver
- }
-
- it("should forward the latest value when the sampler fires") {
- var result: [Int] = []
- sampledSignal.observeNext { result.append($0) }
-
- observer.sendNext(1)
- observer.sendNext(2)
- samplerObserver.sendNext(())
- expect(result) == [ 2 ]
- }
-
- it("should do nothing if sampler fires before signal receives value") {
- var result: [Int] = []
- sampledSignal.observeNext { result.append($0) }
-
- samplerObserver.sendNext(())
- expect(result).to(beEmpty())
- }
-
- it("should send lates value multiple times when sampler fires multiple times") {
- var result: [Int] = []
- sampledSignal.observeNext { result.append($0) }
-
- observer.sendNext(1)
- samplerObserver.sendNext(())
- samplerObserver.sendNext(())
- expect(result) == [ 1, 1 ]
- }
- it("should complete when both inputs have completed") {
- var completed = false
- sampledSignal.observeCompleted { completed = true }
-
- observer.sendCompleted()
- expect(completed) == false
-
- samplerObserver.sendCompleted()
- expect(completed) == true
- }
- }
- describe("combineLatestWith") {
- var combinedSignal: Signal<(Int, Double), NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var otherObserver: Signal<Double, NoError>.Observer!
-
- beforeEach {
- let (signal, incomingObserver) = Signal<Int, NoError>.pipe()
- let (otherSignal, incomingOtherObserver) = Signal<Double, NoError>.pipe()
- combinedSignal = signal.combineLatestWith(otherSignal)
- observer = incomingObserver
- otherObserver = incomingOtherObserver
- }
-
- it("should forward the latest values from both inputs") {
- var latest: (Int, Double)?
- combinedSignal.observeNext { latest = $0 }
-
- observer.sendNext(1)
- expect(latest).to(beNil())
-
- // is there a better way to test tuples?
- otherObserver.sendNext(1.5)
- expect(latest?.0) == 1
- expect(latest?.1) == 1.5
-
- observer.sendNext(2)
- expect(latest?.0) == 2
- expect(latest?.1) == 1.5
- }
- it("should complete when both inputs have completed") {
- var completed = false
- combinedSignal.observeCompleted { completed = true }
-
- observer.sendCompleted()
- expect(completed) == false
-
- otherObserver.sendCompleted()
- expect(completed) == true
- }
- }
- describe("zipWith") {
- var leftObserver: Signal<Int, NoError>.Observer!
- var rightObserver: Signal<String, NoError>.Observer!
- var zipped: Signal<(Int, String), NoError>!
- beforeEach {
- let (leftSignal, incomingLeftObserver) = Signal<Int, NoError>.pipe()
- let (rightSignal, incomingRightObserver) = Signal<String, NoError>.pipe()
- leftObserver = incomingLeftObserver
- rightObserver = incomingRightObserver
- zipped = leftSignal.zipWith(rightSignal)
- }
- it("should combine pairs") {
- var result: [String] = []
- zipped.observeNext { (left, right) in result.append("\(left)\(right)") }
- leftObserver.sendNext(1)
- leftObserver.sendNext(2)
- expect(result) == []
- rightObserver.sendNext("foo")
- expect(result) == [ "1foo" ]
- leftObserver.sendNext(3)
- rightObserver.sendNext("bar")
- expect(result) == [ "1foo", "2bar" ]
- rightObserver.sendNext("buzz")
- expect(result) == [ "1foo", "2bar", "3buzz" ]
- rightObserver.sendNext("fuzz")
- expect(result) == [ "1foo", "2bar", "3buzz" ]
- leftObserver.sendNext(4)
- expect(result) == [ "1foo", "2bar", "3buzz", "4fuzz" ]
- }
- it("should complete when the shorter signal has completed") {
- var result: [String] = []
- var completed = false
- zipped.observe { event in
- switch event {
- case let .Next(left, right):
- result.append("\(left)\(right)")
- case .Completed:
- completed = true
- default:
- break
- }
- }
- expect(completed) == false
- leftObserver.sendNext(0)
- leftObserver.sendCompleted()
- expect(completed) == false
- expect(result) == []
- rightObserver.sendNext("foo")
- expect(completed) == true
- expect(result) == [ "0foo" ]
- }
- it("should complete when both signal have completed") {
- var result: [String] = []
- var completed = false
- zipped.observe { event in
- switch event {
- case let .Next(left, right):
- result.append("\(left)\(right)")
- case .Completed:
- completed = true
- default:
- break
- }
- }
- expect(completed) == false
- leftObserver.sendNext(0)
- leftObserver.sendCompleted()
- expect(completed) == false
- expect(result) == []
- rightObserver.sendCompleted()
- expect(result) == [ ]
- }
- it("should complete and drop unpaired pending values when both signal have completed") {
- var result: [String] = []
- var completed = false
- zipped.observe { event in
- switch event {
- case let .Next(left, right):
- result.append("\(left)\(right)")
- case .Completed:
- completed = true
- default:
- break
- }
- }
- expect(completed) == false
- leftObserver.sendNext(0)
- leftObserver.sendNext(1)
- leftObserver.sendNext(2)
- leftObserver.sendNext(3)
- leftObserver.sendCompleted()
- expect(completed) == false
- expect(result) == []
- rightObserver.sendNext("foo")
- rightObserver.sendNext("bar")
- rightObserver.sendCompleted()
- expect(result) == ["0foo", "1bar"]
- }
- }
- describe("materialize") {
- it("should reify events from the signal") {
- let (signal, observer) = Signal<Int, TestError>.pipe()
- var latestEvent: Event<Int, TestError>?
- signal
- .materialize()
- .observeNext { latestEvent = $0 }
-
- observer.sendNext(2)
-
- expect(latestEvent).toNot(beNil())
- if let latestEvent = latestEvent {
- switch latestEvent {
- case let .Next(value):
- expect(value) == 2
- default:
- fail()
- }
- }
-
- observer.sendFailed(TestError.Default)
- if let latestEvent = latestEvent {
- switch latestEvent {
- case .Failed:
- ()
- default:
- fail()
- }
- }
- }
- }
- describe("dematerialize") {
- typealias IntEvent = Event<Int, TestError>
- var observer: Signal<IntEvent, NoError>.Observer!
- var dematerialized: Signal<Int, TestError>!
-
- beforeEach {
- let (signal, incomingObserver) = Signal<IntEvent, NoError>.pipe()
- observer = incomingObserver
- dematerialized = signal.dematerialize()
- }
-
- it("should send values for Next events") {
- var result: [Int] = []
- dematerialized
- .assumeNoErrors()
- .observeNext { result.append($0) }
-
- expect(result).to(beEmpty())
-
- observer.sendNext(.Next(2))
- expect(result) == [ 2 ]
-
- observer.sendNext(.Next(4))
- expect(result) == [ 2, 4 ]
- }
- it("should error out for Error events") {
- var errored = false
- dematerialized.observeFailed { _ in errored = true }
-
- expect(errored) == false
-
- observer.sendNext(.Failed(TestError.Default))
- expect(errored) == true
- }
- it("should complete early for Completed events") {
- var completed = false
- dematerialized.observeCompleted { completed = true }
-
- expect(completed) == false
- observer.sendNext(IntEvent.Completed)
- expect(completed) == true
- }
- }
- describe("takeLast") {
- var observer: Signal<Int, TestError>.Observer!
- var lastThree: Signal<Int, TestError>!
-
- beforeEach {
- let (signal, incomingObserver) = Signal<Int, TestError>.pipe()
- observer = incomingObserver
- lastThree = signal.takeLast(3)
- }
- it("should send the last N values upon completion") {
- var result: [Int] = []
- lastThree
- .assumeNoErrors()
- .observeNext { result.append($0) }
-
- observer.sendNext(1)
- observer.sendNext(2)
- observer.sendNext(3)
- observer.sendNext(4)
- expect(result).to(beEmpty())
-
- observer.sendCompleted()
- expect(result) == [ 2, 3, 4 ]
- }
- it("should send less than N values if not enough were received") {
- var result: [Int] = []
- lastThree
- .assumeNoErrors()
- .observeNext { result.append($0) }
-
- observer.sendNext(1)
- observer.sendNext(2)
- observer.sendCompleted()
- expect(result) == [ 1, 2 ]
- }
-
- it("should send nothing when errors") {
- var result: [Int] = []
- var errored = false
- lastThree.observe { event in
- switch event {
- case let .Next(value):
- result.append(value)
- case .Failed:
- errored = true
- default:
- break
- }
- }
-
- observer.sendNext(1)
- observer.sendNext(2)
- observer.sendNext(3)
- expect(errored) == false
-
- observer.sendFailed(TestError.Default)
- expect(errored) == true
- expect(result).to(beEmpty())
- }
- }
- describe("timeoutWithError") {
- var testScheduler: TestScheduler!
- var signal: Signal<Int, TestError>!
- var observer: Signal<Int, TestError>.Observer!
- beforeEach {
- testScheduler = TestScheduler()
- let (baseSignal, incomingObserver) = Signal<Int, TestError>.pipe()
- signal = baseSignal.timeoutWithError(TestError.Default, afterInterval: 2, onScheduler: testScheduler)
- observer = incomingObserver
- }
- it("should complete if within the interval") {
- var completed = false
- var errored = false
- signal.observe { event in
- switch event {
- case .Completed:
- completed = true
- case .Failed:
- errored = true
- default:
- break
- }
- }
- testScheduler.scheduleAfter(1) {
- observer.sendCompleted()
- }
- expect(completed) == false
- expect(errored) == false
- testScheduler.run()
- expect(completed) == true
- expect(errored) == false
- }
- it("should error if not completed before the interval has elapsed") {
- var completed = false
- var errored = false
- signal.observe { event in
- switch event {
- case .Completed:
- completed = true
- case .Failed:
- errored = true
- default:
- break
- }
- }
- testScheduler.scheduleAfter(3) {
- observer.sendCompleted()
- }
- expect(completed) == false
- expect(errored) == false
- testScheduler.run()
- expect(completed) == false
- expect(errored) == true
- }
- }
- describe("attempt") {
- it("should forward original values upon success") {
- let (baseSignal, observer) = Signal<Int, TestError>.pipe()
- let signal = baseSignal.attempt { _ in
- return .Success()
- }
-
- var current: Int?
- signal
- .assumeNoErrors()
- .observeNext { value in
- current = value
- }
-
- for value in 1...5 {
- observer.sendNext(value)
- expect(current) == value
- }
- }
-
- it("should error if an attempt fails") {
- let (baseSignal, observer) = Signal<Int, TestError>.pipe()
- let signal = baseSignal.attempt { _ in
- return .Failure(.Default)
- }
-
- var error: TestError?
- signal.observeFailed { err in
- error = err
- }
-
- observer.sendNext(42)
- expect(error) == TestError.Default
- }
- }
-
- describe("attemptMap") {
- it("should forward mapped values upon success") {
- let (baseSignal, observer) = Signal<Int, TestError>.pipe()
- let signal = baseSignal.attemptMap { num -> Result<Bool, TestError> in
- return .Success(num % 2 == 0)
- }
-
- var even: Bool?
- signal
- .assumeNoErrors()
- .observeNext { value in
- even = value
- }
-
- observer.sendNext(1)
- expect(even) == false
-
- observer.sendNext(2)
- expect(even) == true
- }
-
- it("should error if a mapping fails") {
- let (baseSignal, observer) = Signal<Int, TestError>.pipe()
- let signal = baseSignal.attemptMap { _ -> Result<Bool, TestError> in
- return .Failure(.Default)
- }
-
- var error: TestError?
- signal.observeFailed { err in
- error = err
- }
-
- observer.sendNext(42)
- expect(error) == TestError.Default
- }
- }
-
- describe("combinePrevious") {
- var observer: Signal<Int, NoError>.Observer!
- let initialValue: Int = 0
- var latestValues: (Int, Int)?
-
- beforeEach {
- latestValues = nil
-
- let (signal, baseObserver) = Signal<Int, NoError>.pipe()
- observer = baseObserver
- signal.combinePrevious(initialValue).observeNext { latestValues = $0 }
- }
-
- it("should forward the latest value with previous value") {
- expect(latestValues).to(beNil())
-
- observer.sendNext(1)
- expect(latestValues?.0) == initialValue
- expect(latestValues?.1) == 1
-
- observer.sendNext(2)
- expect(latestValues?.0) == 1
- expect(latestValues?.1) == 2
- }
- }
- describe("combineLatest") {
- var signalA: Signal<Int, NoError>!
- var signalB: Signal<Int, NoError>!
- var signalC: Signal<Int, NoError>!
- var observerA: Signal<Int, NoError>.Observer!
- var observerB: Signal<Int, NoError>.Observer!
- var observerC: Signal<Int, NoError>.Observer!
-
- var combinedValues: [Int]?
- var completed: Bool!
-
- beforeEach {
- combinedValues = nil
- completed = false
-
- let (baseSignalA, baseObserverA) = Signal<Int, NoError>.pipe()
- let (baseSignalB, baseObserverB) = Signal<Int, NoError>.pipe()
- let (baseSignalC, baseObserverC) = Signal<Int, NoError>.pipe()
-
- signalA = baseSignalA
- signalB = baseSignalB
- signalC = baseSignalC
-
- observerA = baseObserverA
- observerB = baseObserverB
- observerC = baseObserverC
- }
-
- let combineLatestExampleName = "combineLatest examples"
- sharedExamples(combineLatestExampleName) {
- it("should forward the latest values from all inputs"){
- expect(combinedValues).to(beNil())
-
- observerA.sendNext(0)
- observerB.sendNext(1)
- observerC.sendNext(2)
- expect(combinedValues) == [0, 1, 2]
-
- observerA.sendNext(10)
- expect(combinedValues) == [10, 1, 2]
- }
-
- it("should not forward the latest values before all inputs"){
- expect(combinedValues).to(beNil())
-
- observerA.sendNext(0)
- expect(combinedValues).to(beNil())
-
- observerB.sendNext(1)
- expect(combinedValues).to(beNil())
-
- observerC.sendNext(2)
- expect(combinedValues) == [0, 1, 2]
- }
-
- it("should complete when all inputs have completed"){
- expect(completed) == false
-
- observerA.sendCompleted()
- observerB.sendCompleted()
- expect(completed) == false
-
- observerC.sendCompleted()
- expect(completed) == true
- }
- }
-
- describe("tuple") {
- beforeEach {
- combineLatest(signalA, signalB, signalC)
- .observe { event in
- switch event {
- case let .Next(value):
- combinedValues = [value.0, value.1, value.2]
- case .Completed:
- completed = true
- default:
- break
- }
- }
- }
-
- itBehavesLike(combineLatestExampleName)
- }
-
- describe("sequence") {
- beforeEach {
- combineLatest([signalA, signalB, signalC])
- .observe { event in
- switch event {
- case let .Next(values):
- combinedValues = values
- case .Completed:
- completed = true
- default:
- break
- }
- }
- }
-
- itBehavesLike(combineLatestExampleName)
- }
- }
-
- describe("zip") {
- var signalA: Signal<Int, NoError>!
- var signalB: Signal<Int, NoError>!
- var signalC: Signal<Int, NoError>!
- var observerA: Signal<Int, NoError>.Observer!
- var observerB: Signal<Int, NoError>.Observer!
- var observerC: Signal<Int, NoError>.Observer!
- var zippedValues: [Int]?
- var completed: Bool!
-
- beforeEach {
- zippedValues = nil
- completed = false
-
- let (baseSignalA, baseObserverA) = Signal<Int, NoError>.pipe()
- let (baseSignalB, baseObserverB) = Signal<Int, NoError>.pipe()
- let (baseSignalC, baseObserverC) = Signal<Int, NoError>.pipe()
-
- signalA = baseSignalA
- signalB = baseSignalB
- signalC = baseSignalC
-
- observerA = baseObserverA
- observerB = baseObserverB
- observerC = baseObserverC
- }
-
- let zipExampleName = "zip examples"
- sharedExamples(zipExampleName) {
- it("should combine all set"){
- expect(zippedValues).to(beNil())
-
- observerA.sendNext(0)
- expect(zippedValues).to(beNil())
-
- observerB.sendNext(1)
- expect(zippedValues).to(beNil())
-
- observerC.sendNext(2)
- expect(zippedValues) == [0, 1, 2]
-
- observerA.sendNext(10)
- expect(zippedValues) == [0, 1, 2]
-
- observerA.sendNext(20)
- expect(zippedValues) == [0, 1, 2]
-
- observerB.sendNext(11)
- expect(zippedValues) == [0, 1, 2]
-
- observerC.sendNext(12)
- expect(zippedValues) == [10, 11, 12]
- }
-
- it("should complete when the shorter signal has completed"){
- expect(completed) == false
-
- observerB.sendNext(1)
- observerC.sendNext(2)
- observerB.sendCompleted()
- observerC.sendCompleted()
- expect(completed) == false
-
- observerA.sendNext(0)
- expect(completed) == true
- }
- }
-
- describe("tuple") {
- beforeEach {
- zip(signalA, signalB, signalC)
- .observe { event in
- switch event {
- case let .Next(value):
- zippedValues = [value.0, value.1, value.2]
- case .Completed:
- completed = true
- default:
- break
- }
- }
- }
-
- itBehavesLike(zipExampleName)
- }
-
- describe("sequence") {
- beforeEach {
- zip([signalA, signalB, signalC])
- .observe { event in
- switch event {
- case let .Next(values):
- zippedValues = values
- case .Completed:
- completed = true
- default:
- break
- }
- }
- }
-
- itBehavesLike(zipExampleName)
- }
-
- describe("log events") {
- it("should output the correct event without identifier") {
- let expectations: [String -> Void] = [
- { event in expect(event) == "[] Next 1" },
- { event in expect(event) == "[] Completed" },
- { event in expect(event) == "[] Terminated" },
- { event in expect(event) == "[] Disposed" },
- ]
- let logger = TestLogger(expectations: expectations)
-
- let (signal, observer) = Signal<Int, NoError>.pipe()
- signal
- .logEvents(logger: logger.logEvent)
- .observe { _ in }
-
- observer.sendNext(1)
- observer.sendCompleted()
- }
-
- it("should output the correct event with identifier") {
- let expectations: [String -> Void] = [
- { event in expect(event) == "[test.rac] Next 1" },
- { event in expect(event) == "[test.rac] Failed Error1" },
- { event in expect(event) == "[test.rac] Terminated" },
- { event in expect(event) == "[test.rac] Disposed" },
- ]
- let logger = TestLogger(expectations: expectations)
- let (signal, observer) = Signal<Int, TestError>.pipe()
- signal
- .logEvents(identifier: "test.rac", logger: logger.logEvent)
- .observe { _ in }
-
- observer.sendNext(1)
- observer.sendFailed(.Error1)
- }
-
- it("should only output the events specified in the `events` parameter") {
- let expectations: [String -> Void] = [
- { event in expect(event) == "[test.rac] Failed Error1" },
- ]
-
- let logger = TestLogger(expectations: expectations)
-
- let (signal, observer) = Signal<Int, TestError>.pipe()
- signal
- .logEvents(identifier: "test.rac", events: [.Failed], logger: logger.logEvent)
- .observe { _ in }
-
- observer.sendNext(1)
- observer.sendFailed(.Error1)
- }
- }
- }
- }
- }
|