| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518 |
- //
- // SignalProducerLiftingSpec.swift
- // ReactiveCocoa
- //
- // Created by Neil Pankey on 6/14/15.
- // Copyright © 2015 GitHub. All rights reserved.
- //
- import Result
- import Nimble
- import Quick
- import ReactiveCocoa
- class SignalProducerLiftingSpec: QuickSpec {
- override func spec() {
- describe("map") {
- it("should transform the values of the signal") {
- let (producer, observer) = SignalProducer<Int, NoError>.pipe()
- let mappedProducer = producer.map { String($0 + 1) }
- var lastValue: String?
- mappedProducer.startWithNext {
- 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 (producer, observer) = SignalProducer<Int, TestError>.pipe()
- let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 100, userInfo: nil)
- var error: NSError?
- producer
- .mapError { _ in producerError }
- .startWithFailed { error = $0 }
- expect(error).to(beNil())
- observer.sendFailed(TestError.Default)
- expect(error) == producerError
- }
- }
- describe("filter") {
- it("should omit values from the producer") {
- let (producer, observer) = SignalProducer<Int, NoError>.pipe()
- let mappedProducer = producer.filter { $0 % 2 == 0 }
- var lastValue: Int?
- mappedProducer.startWithNext { 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 (producer, observer) = SignalProducer<Int?, NoError>.pipe()
- let mappedProducer = producer.ignoreNil()
- var lastValue: Int?
- mappedProducer.startWithNext { 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 (baseProducer, observer) = SignalProducer<String, NoError>.pipe()
- let producer = baseProducer.scan("", +)
- var lastValue: String?
- producer.startWithNext { 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 (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = baseProducer.reduce(1, +)
- var lastValue: Int?
- var completed = false
- producer.start { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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 (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = baseProducer.reduce(1, +)
- var lastValue: Int?
- var completed = false
- producer.start { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- break
- }
- }
- expect(lastValue).to(beNil())
- expect(completed) == false
- observer.sendCompleted()
- expect(lastValue) == 1
- expect(completed) == true
- }
- }
- describe("skip") {
- it("should skip initial values") {
- let (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = baseProducer.skip(1)
- var lastValue: Int?
- producer.startWithNext { 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 (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = baseProducer.skip(0)
- var lastValue: Int?
- producer.startWithNext { 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 (baseProducer, observer) = SignalProducer<Bool, NoError>.pipe()
- let producer = baseProducer.skipRepeats()
- var values: [Bool] = []
- producer.startWithNext { 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 (baseProducer, observer) = SignalProducer<String, NoError>.pipe()
- let producer = baseProducer.skipRepeats { $0.characters.count == $1.characters.count }
- var values: [String] = []
- producer.startWithNext { 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" ]
- }
- }
- describe("skipWhile") {
- var producer: SignalProducer<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var lastValue: Int?
- beforeEach {
- let (baseProducer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
- producer = baseProducer.skipWhile { $0 < 2 }
- observer = incomingObserver
- lastValue = nil
- producer.startWithNext { 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 producer: SignalProducer<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var triggerObserver: Signal<(), NoError>.Observer!
-
- var lastValue: Int? = nil
-
- beforeEach {
- let (baseProducer, baseIncomingObserver) = SignalProducer<Int, NoError>.pipe()
- let (triggerProducer, incomingTriggerObserver) = SignalProducer<(), NoError>.pipe()
- producer = baseProducer.skipUntil(triggerProducer)
- observer = baseIncomingObserver
- triggerObserver = incomingTriggerObserver
-
- lastValue = nil
-
- producer.start { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Failed, .Completed, .Interrupted:
- 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 (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = baseProducer.take(2)
- var lastValue: Int?
- var completed = false
- producer.start { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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()
-
- let producer: SignalProducer<Int, NoError> = SignalProducer { observer, _ in
- // workaround `Class declaration cannot close over value 'observer' defined in outer scope`
- let observer = observer
- testScheduler.schedule {
- for number in numbers {
- observer.sendNext(number)
- }
- }
- }
-
- var completed = false
-
- producer
- .take(numbers.count)
- .startWithCompleted { 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 producer: SignalProducer<Int, NoError> = SignalProducer { observer, _ in
- // workaround `Class declaration cannot close over value 'observer' defined in outer scope`
- let observer = observer
- testScheduler.schedule {
- for number in numbers {
- observer.sendNext(number)
- }
- }
- }
- var result: [Int] = []
- var interrupted = false
- producer
- .take(0)
- .start { event in
- switch event {
- case let .Next(number):
- result.append(number)
- case .Interrupted:
- interrupted = true
- case .Failed, .Completed:
- break
- }
- }
- expect(interrupted) == true
- testScheduler.run()
- expect(result).to(beEmpty())
- }
- }
- describe("collect") {
- it("should collect all values") {
- let (original, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = original.collect()
- let expectedResult = [ 1, 2, 3 ]
- var result: [Int]?
- producer.startWithNext { 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) = SignalProducer<Int, NoError>.pipe()
- let producer = original.collect()
- var result: [Int]?
- producer.startWithNext { result = $0 }
- expect(result).to(beNil())
- observer.sendCompleted()
- expect(result) == []
- }
- it("should forward errors") {
- let (original, observer) = SignalProducer<Int, TestError>.pipe()
- let producer = original.collect()
- var error: TestError?
- producer.startWithFailed { error = $0 }
- expect(error).to(beNil())
- observer.sendFailed(.Default)
- expect(error) == TestError.Default
- }
- it("should collect an exact count of values") {
- let (original, observer) = SignalProducer<Int, NoError>.pipe()
- let producer = original.collect(count: 3)
- var observedValues: [[Int]] = []
- producer.startWithNext { 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) = SignalProducer<Int, NoError>.pipe()
- let producer = original.collect { _, next in next != 5 }
- var expectedValues = [
- [5, 5],
- [42, 5]
- ]
- producer.startWithNext { value in
- expect(value) == expectedValues.removeFirst()
- }
- producer.startWithCompleted {
- 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) = SignalProducer<Int, NoError>.pipe()
- let producer = original.collect { values in values.reduce(0, combine: +) == 10 }
- var expectedValues = [
- [1, 2, 3, 4],
- [5, 6, 7, 8, 9]
- ]
- producer.startWithNext { value in
- expect(value) == expectedValues.removeFirst()
- }
- producer.startWithCompleted {
- expect(expectedValues) == []
- }
- expectedValues
- .flatMap { $0 }
- .forEach(observer.sendNext)
-
- observer.sendCompleted()
- }
-
- }
- describe("takeUntil") {
- var producer: SignalProducer<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var triggerObserver: Signal<(), NoError>.Observer!
- var lastValue: Int? = nil
- var completed: Bool = false
- beforeEach {
- let (baseProducer, baseIncomingObserver) = SignalProducer<Int, NoError>.pipe()
- let (triggerProducer, incomingTriggerObserver) = SignalProducer<(), NoError>.pipe()
- producer = baseProducer.takeUntil(triggerProducer)
- observer = baseIncomingObserver
- triggerObserver = incomingTriggerObserver
- lastValue = nil
- completed = false
- producer.start { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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 producer: SignalProducer<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var replacementObserver: Signal<Int, NoError>.Observer!
- var lastValue: Int? = nil
- var completed: Bool = false
- beforeEach {
- let (baseProducer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
- let (replacementProducer, incomingReplacementObserver) = SignalProducer<Int, NoError>.pipe()
- producer = baseProducer.takeUntilReplacement(replacementProducer)
- observer = incomingObserver
- replacementObserver = incomingReplacementObserver
- lastValue = nil
- completed = false
- producer.start { event in
- switch event {
- case let .Next(value):
- lastValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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 producer: SignalProducer<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- beforeEach {
- let (baseProducer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
- producer = baseProducer.takeWhile { $0 <= 4 }
- observer = incomingObserver
- }
- it("should take while the predicate is true") {
- var latestValue: Int!
- var completed = false
- producer.start { event in
- switch event {
- case let .Next(value):
- latestValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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
- producer.start { event in
- switch event {
- case let .Next(value):
- latestValue = value
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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 (producer, observer) = SignalProducer<Int, NoError>.pipe()
- var result: [Int] = []
- producer
- .observeOn(testScheduler)
- .startWithNext { 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 producer: SignalProducer<Int, NoError> = SignalProducer { observer, _ in
- testScheduler.schedule {
- observer.sendNext(1)
- }
- testScheduler.scheduleAfter(5, action: {
- observer.sendNext(2)
- observer.sendCompleted()
- })
- }
-
- var result: [Int] = []
- var completed = false
-
- producer
- .delay(10, onScheduler: testScheduler)
- .start { event in
- switch event {
- case let .Next(number):
- result.append(number)
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- 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 producer: SignalProducer<Int, TestError> = SignalProducer { observer, _ in
- // workaround `Class declaration cannot close over value 'observer' defined in outer scope`
- let observer = observer
- testScheduler.schedule {
- observer.sendFailed(TestError.Default)
- }
- }
-
- var errored = false
-
- producer
- .delay(10, onScheduler: testScheduler)
- .startWithFailed { _ in errored = true }
-
- testScheduler.advance()
- expect(errored) == true
- }
- }
- describe("throttle") {
- var scheduler: TestScheduler!
- var observer: Signal<Int, NoError>.Observer!
- var producer: SignalProducer<Int, NoError>!
- beforeEach {
- scheduler = TestScheduler()
- let (baseProducer, baseObserver) = SignalProducer<Int, NoError>.pipe()
- observer = baseObserver
- producer = baseProducer.throttle(1, onScheduler: scheduler)
- }
- it("should send values on the given scheduler at no less than the interval") {
- var values: [Int] = []
- producer.startWithNext { 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
- producer.start { event in
- switch event {
- case let .Next(value):
- values.append(value)
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- break
- }
- }
- observer.sendNext(0)
- scheduler.advance()
- expect(values) == [ 0 ]
- observer.sendNext(1)
- observer.sendCompleted()
- expect(completed) == false
- scheduler.run()
- expect(values) == [ 0 ]
- expect(completed) == true
- }
- }
- describe("sampleWith") {
- var sampledProducer: SignalProducer<(Int, String), NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var samplerObserver: Signal<String, NoError>.Observer!
-
- beforeEach {
- let (producer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
- let (sampler, incomingSamplerObserver) = SignalProducer<String, NoError>.pipe()
- sampledProducer = producer.sampleWith(sampler)
- observer = incomingObserver
- samplerObserver = incomingSamplerObserver
- }
-
- it("should forward the latest value when the sampler fires") {
- var result: [String] = []
- sampledProducer.startWithNext { (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] = []
- sampledProducer.startWithNext { (left, right) in result.append("\(left)\(right)") }
-
- samplerObserver.sendNext("a")
- expect(result).to(beEmpty())
- }
-
- it("should send lates value multiple times when sampler fires multiple times") {
- var result: [String] = []
- sampledProducer.startWithNext { (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
- sampledProducer.startWithCompleted { completed = true }
-
- observer.sendCompleted()
- expect(completed) == false
-
- samplerObserver.sendCompleted()
- expect(completed) == true
- }
-
- it("should emit an initial value if the sampler is a synchronous SignalProducer") {
- let producer = SignalProducer<Int, NoError>(values: [1])
- let sampler = SignalProducer<String, NoError>(value: "a")
-
- let result = producer.sampleWith(sampler)
-
- var valueReceived: String?
- result.startWithNext { (left, right) in valueReceived = "\(left)\(right)" }
-
- expect(valueReceived) == "1a"
- }
- }
- describe("sampleOn") {
- var sampledProducer: SignalProducer<Int, NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var samplerObserver: Signal<(), NoError>.Observer!
-
- beforeEach {
- let (producer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
- let (sampler, incomingSamplerObserver) = SignalProducer<(), NoError>.pipe()
- sampledProducer = producer.sampleOn(sampler)
- observer = incomingObserver
- samplerObserver = incomingSamplerObserver
- }
-
- it("should forward the latest value when the sampler fires") {
- var result: [Int] = []
- sampledProducer.startWithNext { 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] = []
- sampledProducer.startWithNext { result.append($0) }
-
- samplerObserver.sendNext(())
- expect(result).to(beEmpty())
- }
-
- it("should send lates value multiple times when sampler fires multiple times") {
- var result: [Int] = []
- sampledProducer.startWithNext { 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
- sampledProducer.startWithCompleted { completed = true }
-
- observer.sendCompleted()
- expect(completed) == false
-
- samplerObserver.sendCompleted()
- expect(completed) == true
- }
- it("should emit an initial value if the sampler is a synchronous SignalProducer") {
- let producer = SignalProducer<Int, NoError>(values: [1])
- let sampler = SignalProducer<(), NoError>(value: ())
-
- let result = producer.sampleOn(sampler)
-
- var valueReceived: Int?
- result.startWithNext { valueReceived = $0 }
-
- expect(valueReceived) == 1
- }
- describe("memory") {
- class Payload {
- let action: () -> Void
- init(onDeinit action: () -> Void) {
- self.action = action
- }
- deinit {
- action()
- }
- }
- var sampledProducer: SignalProducer<Payload, NoError>!
- var observer: Signal<Payload, NoError>.Observer!
- beforeEach {
- let (producer, incomingObserver) = SignalProducer<Payload, NoError>.pipe()
- let (sampler, _) = Signal<(), NoError>.pipe()
- sampledProducer = producer.sampleOn(sampler)
- observer = incomingObserver
- }
- it("should free payload when interrupted after complete of incoming producer") {
- var payloadFreed = false
- let disposable = sampledProducer.start()
- observer.sendNext(Payload { payloadFreed = true })
- observer.sendCompleted()
- expect(payloadFreed) == false
- disposable.dispose()
- expect(payloadFreed) == true
- }
- }
- }
- describe("combineLatestWith") {
- var combinedProducer: SignalProducer<(Int, Double), NoError>!
- var observer: Signal<Int, NoError>.Observer!
- var otherObserver: Signal<Double, NoError>.Observer!
-
- beforeEach {
- let (producer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
- let (otherSignal, incomingOtherObserver) = SignalProducer<Double, NoError>.pipe()
- combinedProducer = producer.combineLatestWith(otherSignal)
- observer = incomingObserver
- otherObserver = incomingOtherObserver
- }
-
- it("should forward the latest values from both inputs") {
- var latest: (Int, Double)?
- combinedProducer.startWithNext { 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
- combinedProducer.startWithCompleted { 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: SignalProducer<(Int, String), NoError>!
- beforeEach {
- let (leftProducer, incomingLeftObserver) = SignalProducer<Int, NoError>.pipe()
- let (rightProducer, incomingRightObserver) = SignalProducer<String, NoError>.pipe()
- leftObserver = incomingLeftObserver
- rightObserver = incomingRightObserver
- zipped = leftProducer.zipWith(rightProducer)
- }
- it("should combine pairs") {
- var result: [String] = []
- zipped.startWithNext { (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.start { event in
- switch event {
- case let .Next(left, right):
- result.append("\(left)\(right)")
- case .Completed:
- completed = true
- case .Failed, .Interrupted:
- break
- }
- }
- expect(completed) == false
- leftObserver.sendNext(0)
- leftObserver.sendCompleted()
- expect(completed) == false
- expect(result) == []
- rightObserver.sendNext("foo")
- expect(completed) == true
- expect(result) == [ "0foo" ]
- }
- }
- describe("materialize") {
- it("should reify events from the signal") {
- let (producer, observer) = SignalProducer<Int, TestError>.pipe()
- var latestEvent: Event<Int, TestError>?
- producer
- .materialize()
- .startWithNext { latestEvent = $0 }
-
- observer.sendNext(2)
-
- expect(latestEvent).toNot(beNil())
- if let latestEvent = latestEvent {
- switch latestEvent {
- case let .Next(value):
- expect(value) == 2
- case .Failed, .Completed, .Interrupted:
- fail()
- }
- }
-
- observer.sendFailed(TestError.Default)
- if let latestEvent = latestEvent {
- switch latestEvent {
- case .Failed:
- break
- case .Next, .Completed, .Interrupted:
- fail()
- }
- }
- }
- }
- describe("dematerialize") {
- typealias IntEvent = Event<Int, TestError>
- var observer: Signal<IntEvent, NoError>.Observer!
- var dematerialized: SignalProducer<Int, TestError>!
-
- beforeEach {
- let (producer, incomingObserver) = SignalProducer<IntEvent, NoError>.pipe()
- observer = incomingObserver
- dematerialized = producer.dematerialize()
- }
-
- it("should send values for Next events") {
- var result: [Int] = []
- dematerialized
- .assumeNoErrors()
- .startWithNext { 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.startWithFailed { _ 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.startWithCompleted { completed = true }
-
- expect(completed) == false
- observer.sendNext(IntEvent.Completed)
- expect(completed) == true
- }
- }
- describe("takeLast") {
- var observer: Signal<Int, TestError>.Observer!
- var lastThree: SignalProducer<Int, TestError>!
-
- beforeEach {
- let (producer, incomingObserver) = SignalProducer<Int, TestError>.pipe()
- observer = incomingObserver
- lastThree = producer.takeLast(3)
- }
-
- it("should send the last N values upon completion") {
- var result: [Int] = []
- lastThree
- .assumeNoErrors()
- .startWithNext { 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()
- .startWithNext { 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.start { event in
- switch event {
- case let .Next(value):
- result.append(value)
- case .Failed:
- errored = true
- case .Completed, .Interrupted:
- 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 producer: SignalProducer<Int, TestError>!
- var observer: Signal<Int, TestError>.Observer!
- beforeEach {
- testScheduler = TestScheduler()
- let (baseProducer, incomingObserver) = SignalProducer<Int, TestError>.pipe()
- producer = baseProducer.timeoutWithError(TestError.Default, afterInterval: 2, onScheduler: testScheduler)
- observer = incomingObserver
- }
- it("should complete if within the interval") {
- var completed = false
- var errored = false
- producer.start { event in
- switch event {
- case .Completed:
- completed = true
- case .Failed:
- errored = true
- case .Next, .Interrupted:
- 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
- producer.start { event in
- switch event {
- case .Completed:
- completed = true
- case .Failed:
- errored = true
- case .Next, .Interrupted:
- 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 (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
- let producer = baseProducer.attempt { _ in
- return .Success()
- }
-
- var current: Int?
- producer
- .assumeNoErrors()
- .startWithNext { value in
- current = value
- }
-
- for value in 1...5 {
- observer.sendNext(value)
- expect(current) == value
- }
- }
-
- it("should error if an attempt fails") {
- let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
- let producer = baseProducer.attempt { _ in
- return .Failure(.Default)
- }
-
- var error: TestError?
- producer.startWithFailed { err in
- error = err
- }
-
- observer.sendNext(42)
- expect(error) == TestError.Default
- }
- }
-
- describe("attemptMap") {
- it("should forward mapped values upon success") {
- let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
- let producer = baseProducer.attemptMap { num -> Result<Bool, TestError> in
- return .Success(num % 2 == 0)
- }
-
- var even: Bool?
- producer
- .assumeNoErrors()
- .startWithNext { value in
- even = value
- }
-
- observer.sendNext(1)
- expect(even) == false
-
- observer.sendNext(2)
- expect(even) == true
- }
-
- it("should error if a mapping fails") {
- let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
- let producer = baseProducer.attemptMap { _ -> Result<Bool, TestError> in
- return .Failure(.Default)
- }
-
- var error: TestError?
- producer.startWithFailed { 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) = SignalProducer<Int, NoError>.pipe()
- observer = baseObserver
- signal.combinePrevious(initialValue).startWithNext { 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
- }
- }
- }
- }
|