SignalProducerLiftingSpec.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518
  1. //
  2. // SignalProducerLiftingSpec.swift
  3. // ReactiveCocoa
  4. //
  5. // Created by Neil Pankey on 6/14/15.
  6. // Copyright © 2015 GitHub. All rights reserved.
  7. //
  8. import Result
  9. import Nimble
  10. import Quick
  11. import ReactiveCocoa
  12. class SignalProducerLiftingSpec: QuickSpec {
  13. override func spec() {
  14. describe("map") {
  15. it("should transform the values of the signal") {
  16. let (producer, observer) = SignalProducer<Int, NoError>.pipe()
  17. let mappedProducer = producer.map { String($0 + 1) }
  18. var lastValue: String?
  19. mappedProducer.startWithNext {
  20. lastValue = $0
  21. return
  22. }
  23. expect(lastValue).to(beNil())
  24. observer.sendNext(0)
  25. expect(lastValue) == "1"
  26. observer.sendNext(1)
  27. expect(lastValue) == "2"
  28. }
  29. }
  30. describe("mapError") {
  31. it("should transform the errors of the signal") {
  32. let (producer, observer) = SignalProducer<Int, TestError>.pipe()
  33. let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 100, userInfo: nil)
  34. var error: NSError?
  35. producer
  36. .mapError { _ in producerError }
  37. .startWithFailed { error = $0 }
  38. expect(error).to(beNil())
  39. observer.sendFailed(TestError.Default)
  40. expect(error) == producerError
  41. }
  42. }
  43. describe("filter") {
  44. it("should omit values from the producer") {
  45. let (producer, observer) = SignalProducer<Int, NoError>.pipe()
  46. let mappedProducer = producer.filter { $0 % 2 == 0 }
  47. var lastValue: Int?
  48. mappedProducer.startWithNext { lastValue = $0 }
  49. expect(lastValue).to(beNil())
  50. observer.sendNext(0)
  51. expect(lastValue) == 0
  52. observer.sendNext(1)
  53. expect(lastValue) == 0
  54. observer.sendNext(2)
  55. expect(lastValue) == 2
  56. }
  57. }
  58. describe("ignoreNil") {
  59. it("should forward only non-nil values") {
  60. let (producer, observer) = SignalProducer<Int?, NoError>.pipe()
  61. let mappedProducer = producer.ignoreNil()
  62. var lastValue: Int?
  63. mappedProducer.startWithNext { lastValue = $0 }
  64. expect(lastValue).to(beNil())
  65. observer.sendNext(nil)
  66. expect(lastValue).to(beNil())
  67. observer.sendNext(1)
  68. expect(lastValue) == 1
  69. observer.sendNext(nil)
  70. expect(lastValue) == 1
  71. observer.sendNext(2)
  72. expect(lastValue) == 2
  73. }
  74. }
  75. describe("scan") {
  76. it("should incrementally accumulate a value") {
  77. let (baseProducer, observer) = SignalProducer<String, NoError>.pipe()
  78. let producer = baseProducer.scan("", +)
  79. var lastValue: String?
  80. producer.startWithNext { lastValue = $0 }
  81. expect(lastValue).to(beNil())
  82. observer.sendNext("a")
  83. expect(lastValue) == "a"
  84. observer.sendNext("bb")
  85. expect(lastValue) == "abb"
  86. }
  87. }
  88. describe("reduce") {
  89. it("should accumulate one value") {
  90. let (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
  91. let producer = baseProducer.reduce(1, +)
  92. var lastValue: Int?
  93. var completed = false
  94. producer.start { event in
  95. switch event {
  96. case let .Next(value):
  97. lastValue = value
  98. case .Completed:
  99. completed = true
  100. case .Failed, .Interrupted:
  101. break
  102. }
  103. }
  104. expect(lastValue).to(beNil())
  105. observer.sendNext(1)
  106. expect(lastValue).to(beNil())
  107. observer.sendNext(2)
  108. expect(lastValue).to(beNil())
  109. expect(completed) == false
  110. observer.sendCompleted()
  111. expect(completed) == true
  112. expect(lastValue) == 4
  113. }
  114. it("should send the initial value if none are received") {
  115. let (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
  116. let producer = baseProducer.reduce(1, +)
  117. var lastValue: Int?
  118. var completed = false
  119. producer.start { event in
  120. switch event {
  121. case let .Next(value):
  122. lastValue = value
  123. case .Completed:
  124. completed = true
  125. case .Failed, .Interrupted:
  126. break
  127. }
  128. }
  129. expect(lastValue).to(beNil())
  130. expect(completed) == false
  131. observer.sendCompleted()
  132. expect(lastValue) == 1
  133. expect(completed) == true
  134. }
  135. }
  136. describe("skip") {
  137. it("should skip initial values") {
  138. let (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
  139. let producer = baseProducer.skip(1)
  140. var lastValue: Int?
  141. producer.startWithNext { lastValue = $0 }
  142. expect(lastValue).to(beNil())
  143. observer.sendNext(1)
  144. expect(lastValue).to(beNil())
  145. observer.sendNext(2)
  146. expect(lastValue) == 2
  147. }
  148. it("should not skip any values when 0") {
  149. let (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
  150. let producer = baseProducer.skip(0)
  151. var lastValue: Int?
  152. producer.startWithNext { lastValue = $0 }
  153. expect(lastValue).to(beNil())
  154. observer.sendNext(1)
  155. expect(lastValue) == 1
  156. observer.sendNext(2)
  157. expect(lastValue) == 2
  158. }
  159. }
  160. describe("skipRepeats") {
  161. it("should skip duplicate Equatable values") {
  162. let (baseProducer, observer) = SignalProducer<Bool, NoError>.pipe()
  163. let producer = baseProducer.skipRepeats()
  164. var values: [Bool] = []
  165. producer.startWithNext { values.append($0) }
  166. expect(values) == []
  167. observer.sendNext(true)
  168. expect(values) == [ true ]
  169. observer.sendNext(true)
  170. expect(values) == [ true ]
  171. observer.sendNext(false)
  172. expect(values) == [ true, false ]
  173. observer.sendNext(true)
  174. expect(values) == [ true, false, true ]
  175. }
  176. it("should skip values according to a predicate") {
  177. let (baseProducer, observer) = SignalProducer<String, NoError>.pipe()
  178. let producer = baseProducer.skipRepeats { $0.characters.count == $1.characters.count }
  179. var values: [String] = []
  180. producer.startWithNext { values.append($0) }
  181. expect(values) == []
  182. observer.sendNext("a")
  183. expect(values) == [ "a" ]
  184. observer.sendNext("b")
  185. expect(values) == [ "a" ]
  186. observer.sendNext("cc")
  187. expect(values) == [ "a", "cc" ]
  188. observer.sendNext("d")
  189. expect(values) == [ "a", "cc", "d" ]
  190. }
  191. }
  192. describe("skipWhile") {
  193. var producer: SignalProducer<Int, NoError>!
  194. var observer: Signal<Int, NoError>.Observer!
  195. var lastValue: Int?
  196. beforeEach {
  197. let (baseProducer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
  198. producer = baseProducer.skipWhile { $0 < 2 }
  199. observer = incomingObserver
  200. lastValue = nil
  201. producer.startWithNext { lastValue = $0 }
  202. }
  203. it("should skip while the predicate is true") {
  204. expect(lastValue).to(beNil())
  205. observer.sendNext(1)
  206. expect(lastValue).to(beNil())
  207. observer.sendNext(2)
  208. expect(lastValue) == 2
  209. observer.sendNext(0)
  210. expect(lastValue) == 0
  211. }
  212. it("should not skip any values when the predicate starts false") {
  213. expect(lastValue).to(beNil())
  214. observer.sendNext(3)
  215. expect(lastValue) == 3
  216. observer.sendNext(1)
  217. expect(lastValue) == 1
  218. }
  219. }
  220. describe("skipUntil") {
  221. var producer: SignalProducer<Int, NoError>!
  222. var observer: Signal<Int, NoError>.Observer!
  223. var triggerObserver: Signal<(), NoError>.Observer!
  224. var lastValue: Int? = nil
  225. beforeEach {
  226. let (baseProducer, baseIncomingObserver) = SignalProducer<Int, NoError>.pipe()
  227. let (triggerProducer, incomingTriggerObserver) = SignalProducer<(), NoError>.pipe()
  228. producer = baseProducer.skipUntil(triggerProducer)
  229. observer = baseIncomingObserver
  230. triggerObserver = incomingTriggerObserver
  231. lastValue = nil
  232. producer.start { event in
  233. switch event {
  234. case let .Next(value):
  235. lastValue = value
  236. case .Failed, .Completed, .Interrupted:
  237. break
  238. }
  239. }
  240. }
  241. it("should skip values until the trigger fires") {
  242. expect(lastValue).to(beNil())
  243. observer.sendNext(1)
  244. expect(lastValue).to(beNil())
  245. observer.sendNext(2)
  246. expect(lastValue).to(beNil())
  247. triggerObserver.sendNext(())
  248. observer.sendNext(0)
  249. expect(lastValue) == 0
  250. }
  251. it("should skip values until the trigger completes") {
  252. expect(lastValue).to(beNil())
  253. observer.sendNext(1)
  254. expect(lastValue).to(beNil())
  255. observer.sendNext(2)
  256. expect(lastValue).to(beNil())
  257. triggerObserver.sendCompleted()
  258. observer.sendNext(0)
  259. expect(lastValue) == 0
  260. }
  261. }
  262. describe("take") {
  263. it("should take initial values") {
  264. let (baseProducer, observer) = SignalProducer<Int, NoError>.pipe()
  265. let producer = baseProducer.take(2)
  266. var lastValue: Int?
  267. var completed = false
  268. producer.start { event in
  269. switch event {
  270. case let .Next(value):
  271. lastValue = value
  272. case .Completed:
  273. completed = true
  274. case .Failed, .Interrupted:
  275. break
  276. }
  277. }
  278. expect(lastValue).to(beNil())
  279. expect(completed) == false
  280. observer.sendNext(1)
  281. expect(lastValue) == 1
  282. expect(completed) == false
  283. observer.sendNext(2)
  284. expect(lastValue) == 2
  285. expect(completed) == true
  286. }
  287. it("should complete immediately after taking given number of values") {
  288. let numbers = [ 1, 2, 4, 4, 5 ]
  289. let testScheduler = TestScheduler()
  290. let producer: SignalProducer<Int, NoError> = SignalProducer { observer, _ in
  291. // workaround `Class declaration cannot close over value 'observer' defined in outer scope`
  292. let observer = observer
  293. testScheduler.schedule {
  294. for number in numbers {
  295. observer.sendNext(number)
  296. }
  297. }
  298. }
  299. var completed = false
  300. producer
  301. .take(numbers.count)
  302. .startWithCompleted { completed = true }
  303. expect(completed) == false
  304. testScheduler.run()
  305. expect(completed) == true
  306. }
  307. it("should interrupt when 0") {
  308. let numbers = [ 1, 2, 4, 4, 5 ]
  309. let testScheduler = TestScheduler()
  310. let producer: SignalProducer<Int, NoError> = SignalProducer { observer, _ in
  311. // workaround `Class declaration cannot close over value 'observer' defined in outer scope`
  312. let observer = observer
  313. testScheduler.schedule {
  314. for number in numbers {
  315. observer.sendNext(number)
  316. }
  317. }
  318. }
  319. var result: [Int] = []
  320. var interrupted = false
  321. producer
  322. .take(0)
  323. .start { event in
  324. switch event {
  325. case let .Next(number):
  326. result.append(number)
  327. case .Interrupted:
  328. interrupted = true
  329. case .Failed, .Completed:
  330. break
  331. }
  332. }
  333. expect(interrupted) == true
  334. testScheduler.run()
  335. expect(result).to(beEmpty())
  336. }
  337. }
  338. describe("collect") {
  339. it("should collect all values") {
  340. let (original, observer) = SignalProducer<Int, NoError>.pipe()
  341. let producer = original.collect()
  342. let expectedResult = [ 1, 2, 3 ]
  343. var result: [Int]?
  344. producer.startWithNext { value in
  345. expect(result).to(beNil())
  346. result = value
  347. }
  348. for number in expectedResult {
  349. observer.sendNext(number)
  350. }
  351. expect(result).to(beNil())
  352. observer.sendCompleted()
  353. expect(result) == expectedResult
  354. }
  355. it("should complete with an empty array if there are no values") {
  356. let (original, observer) = SignalProducer<Int, NoError>.pipe()
  357. let producer = original.collect()
  358. var result: [Int]?
  359. producer.startWithNext { result = $0 }
  360. expect(result).to(beNil())
  361. observer.sendCompleted()
  362. expect(result) == []
  363. }
  364. it("should forward errors") {
  365. let (original, observer) = SignalProducer<Int, TestError>.pipe()
  366. let producer = original.collect()
  367. var error: TestError?
  368. producer.startWithFailed { error = $0 }
  369. expect(error).to(beNil())
  370. observer.sendFailed(.Default)
  371. expect(error) == TestError.Default
  372. }
  373. it("should collect an exact count of values") {
  374. let (original, observer) = SignalProducer<Int, NoError>.pipe()
  375. let producer = original.collect(count: 3)
  376. var observedValues: [[Int]] = []
  377. producer.startWithNext { value in
  378. observedValues.append(value)
  379. }
  380. var expectation: [[Int]] = []
  381. for i in 1...7 {
  382. observer.sendNext(i)
  383. if i % 3 == 0 {
  384. expectation.append([Int]((i - 2)...i))
  385. expect(observedValues) == expectation
  386. } else {
  387. expect(observedValues) == expectation
  388. }
  389. }
  390. observer.sendCompleted()
  391. expectation.append([7])
  392. expect(observedValues) == expectation
  393. }
  394. it("should collect values until it matches a certain value") {
  395. let (original, observer) = SignalProducer<Int, NoError>.pipe()
  396. let producer = original.collect { _, next in next != 5 }
  397. var expectedValues = [
  398. [5, 5],
  399. [42, 5]
  400. ]
  401. producer.startWithNext { value in
  402. expect(value) == expectedValues.removeFirst()
  403. }
  404. producer.startWithCompleted {
  405. expect(expectedValues) == []
  406. }
  407. expectedValues
  408. .flatMap { $0 }
  409. .forEach(observer.sendNext)
  410. observer.sendCompleted()
  411. }
  412. it("should collect values until it matches a certain condition on values") {
  413. let (original, observer) = SignalProducer<Int, NoError>.pipe()
  414. let producer = original.collect { values in values.reduce(0, combine: +) == 10 }
  415. var expectedValues = [
  416. [1, 2, 3, 4],
  417. [5, 6, 7, 8, 9]
  418. ]
  419. producer.startWithNext { value in
  420. expect(value) == expectedValues.removeFirst()
  421. }
  422. producer.startWithCompleted {
  423. expect(expectedValues) == []
  424. }
  425. expectedValues
  426. .flatMap { $0 }
  427. .forEach(observer.sendNext)
  428. observer.sendCompleted()
  429. }
  430. }
  431. describe("takeUntil") {
  432. var producer: SignalProducer<Int, NoError>!
  433. var observer: Signal<Int, NoError>.Observer!
  434. var triggerObserver: Signal<(), NoError>.Observer!
  435. var lastValue: Int? = nil
  436. var completed: Bool = false
  437. beforeEach {
  438. let (baseProducer, baseIncomingObserver) = SignalProducer<Int, NoError>.pipe()
  439. let (triggerProducer, incomingTriggerObserver) = SignalProducer<(), NoError>.pipe()
  440. producer = baseProducer.takeUntil(triggerProducer)
  441. observer = baseIncomingObserver
  442. triggerObserver = incomingTriggerObserver
  443. lastValue = nil
  444. completed = false
  445. producer.start { event in
  446. switch event {
  447. case let .Next(value):
  448. lastValue = value
  449. case .Completed:
  450. completed = true
  451. case .Failed, .Interrupted:
  452. break
  453. }
  454. }
  455. }
  456. it("should take values until the trigger fires") {
  457. expect(lastValue).to(beNil())
  458. observer.sendNext(1)
  459. expect(lastValue) == 1
  460. observer.sendNext(2)
  461. expect(lastValue) == 2
  462. expect(completed) == false
  463. triggerObserver.sendNext(())
  464. expect(completed) == true
  465. }
  466. it("should take values until the trigger completes") {
  467. expect(lastValue).to(beNil())
  468. observer.sendNext(1)
  469. expect(lastValue) == 1
  470. observer.sendNext(2)
  471. expect(lastValue) == 2
  472. expect(completed) == false
  473. triggerObserver.sendCompleted()
  474. expect(completed) == true
  475. }
  476. it("should complete if the trigger fires immediately") {
  477. expect(lastValue).to(beNil())
  478. expect(completed) == false
  479. triggerObserver.sendNext(())
  480. expect(completed) == true
  481. expect(lastValue).to(beNil())
  482. }
  483. }
  484. describe("takeUntilReplacement") {
  485. var producer: SignalProducer<Int, NoError>!
  486. var observer: Signal<Int, NoError>.Observer!
  487. var replacementObserver: Signal<Int, NoError>.Observer!
  488. var lastValue: Int? = nil
  489. var completed: Bool = false
  490. beforeEach {
  491. let (baseProducer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
  492. let (replacementProducer, incomingReplacementObserver) = SignalProducer<Int, NoError>.pipe()
  493. producer = baseProducer.takeUntilReplacement(replacementProducer)
  494. observer = incomingObserver
  495. replacementObserver = incomingReplacementObserver
  496. lastValue = nil
  497. completed = false
  498. producer.start { event in
  499. switch event {
  500. case let .Next(value):
  501. lastValue = value
  502. case .Completed:
  503. completed = true
  504. case .Failed, .Interrupted:
  505. break
  506. }
  507. }
  508. }
  509. it("should take values from the original then the replacement") {
  510. expect(lastValue).to(beNil())
  511. expect(completed) == false
  512. observer.sendNext(1)
  513. expect(lastValue) == 1
  514. observer.sendNext(2)
  515. expect(lastValue) == 2
  516. replacementObserver.sendNext(3)
  517. expect(lastValue) == 3
  518. expect(completed) == false
  519. observer.sendNext(4)
  520. expect(lastValue) == 3
  521. expect(completed) == false
  522. replacementObserver.sendNext(5)
  523. expect(lastValue) == 5
  524. expect(completed) == false
  525. replacementObserver.sendCompleted()
  526. expect(completed) == true
  527. }
  528. }
  529. describe("takeWhile") {
  530. var producer: SignalProducer<Int, NoError>!
  531. var observer: Signal<Int, NoError>.Observer!
  532. beforeEach {
  533. let (baseProducer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
  534. producer = baseProducer.takeWhile { $0 <= 4 }
  535. observer = incomingObserver
  536. }
  537. it("should take while the predicate is true") {
  538. var latestValue: Int!
  539. var completed = false
  540. producer.start { event in
  541. switch event {
  542. case let .Next(value):
  543. latestValue = value
  544. case .Completed:
  545. completed = true
  546. case .Failed, .Interrupted:
  547. break
  548. }
  549. }
  550. for value in -1...4 {
  551. observer.sendNext(value)
  552. expect(latestValue) == value
  553. expect(completed) == false
  554. }
  555. observer.sendNext(5)
  556. expect(latestValue) == 4
  557. expect(completed) == true
  558. }
  559. it("should complete if the predicate starts false") {
  560. var latestValue: Int?
  561. var completed = false
  562. producer.start { event in
  563. switch event {
  564. case let .Next(value):
  565. latestValue = value
  566. case .Completed:
  567. completed = true
  568. case .Failed, .Interrupted:
  569. break
  570. }
  571. }
  572. observer.sendNext(5)
  573. expect(latestValue).to(beNil())
  574. expect(completed) == true
  575. }
  576. }
  577. describe("observeOn") {
  578. it("should send events on the given scheduler") {
  579. let testScheduler = TestScheduler()
  580. let (producer, observer) = SignalProducer<Int, NoError>.pipe()
  581. var result: [Int] = []
  582. producer
  583. .observeOn(testScheduler)
  584. .startWithNext { result.append($0) }
  585. observer.sendNext(1)
  586. observer.sendNext(2)
  587. expect(result).to(beEmpty())
  588. testScheduler.run()
  589. expect(result) == [ 1, 2 ]
  590. }
  591. }
  592. describe("delay") {
  593. it("should send events on the given scheduler after the interval") {
  594. let testScheduler = TestScheduler()
  595. let producer: SignalProducer<Int, NoError> = SignalProducer { observer, _ in
  596. testScheduler.schedule {
  597. observer.sendNext(1)
  598. }
  599. testScheduler.scheduleAfter(5, action: {
  600. observer.sendNext(2)
  601. observer.sendCompleted()
  602. })
  603. }
  604. var result: [Int] = []
  605. var completed = false
  606. producer
  607. .delay(10, onScheduler: testScheduler)
  608. .start { event in
  609. switch event {
  610. case let .Next(number):
  611. result.append(number)
  612. case .Completed:
  613. completed = true
  614. case .Failed, .Interrupted:
  615. break
  616. }
  617. }
  618. testScheduler.advanceByInterval(4) // send initial value
  619. expect(result).to(beEmpty())
  620. testScheduler.advanceByInterval(10) // send second value and receive first
  621. expect(result) == [ 1 ]
  622. expect(completed) == false
  623. testScheduler.advanceByInterval(10) // send second value and receive first
  624. expect(result) == [ 1, 2 ]
  625. expect(completed) == true
  626. }
  627. it("should schedule errors immediately") {
  628. let testScheduler = TestScheduler()
  629. let producer: SignalProducer<Int, TestError> = SignalProducer { observer, _ in
  630. // workaround `Class declaration cannot close over value 'observer' defined in outer scope`
  631. let observer = observer
  632. testScheduler.schedule {
  633. observer.sendFailed(TestError.Default)
  634. }
  635. }
  636. var errored = false
  637. producer
  638. .delay(10, onScheduler: testScheduler)
  639. .startWithFailed { _ in errored = true }
  640. testScheduler.advance()
  641. expect(errored) == true
  642. }
  643. }
  644. describe("throttle") {
  645. var scheduler: TestScheduler!
  646. var observer: Signal<Int, NoError>.Observer!
  647. var producer: SignalProducer<Int, NoError>!
  648. beforeEach {
  649. scheduler = TestScheduler()
  650. let (baseProducer, baseObserver) = SignalProducer<Int, NoError>.pipe()
  651. observer = baseObserver
  652. producer = baseProducer.throttle(1, onScheduler: scheduler)
  653. }
  654. it("should send values on the given scheduler at no less than the interval") {
  655. var values: [Int] = []
  656. producer.startWithNext { value in
  657. values.append(value)
  658. }
  659. expect(values) == []
  660. observer.sendNext(0)
  661. expect(values) == []
  662. scheduler.advance()
  663. expect(values) == [ 0 ]
  664. observer.sendNext(1)
  665. observer.sendNext(2)
  666. expect(values) == [ 0 ]
  667. scheduler.advanceByInterval(1.5)
  668. expect(values) == [ 0, 2 ]
  669. scheduler.advanceByInterval(3)
  670. expect(values) == [ 0, 2 ]
  671. observer.sendNext(3)
  672. expect(values) == [ 0, 2 ]
  673. scheduler.advance()
  674. expect(values) == [ 0, 2, 3 ]
  675. observer.sendNext(4)
  676. observer.sendNext(5)
  677. scheduler.advance()
  678. expect(values) == [ 0, 2, 3 ]
  679. scheduler.run()
  680. expect(values) == [ 0, 2, 3, 5 ]
  681. }
  682. it("should schedule completion immediately") {
  683. var values: [Int] = []
  684. var completed = false
  685. producer.start { event in
  686. switch event {
  687. case let .Next(value):
  688. values.append(value)
  689. case .Completed:
  690. completed = true
  691. case .Failed, .Interrupted:
  692. break
  693. }
  694. }
  695. observer.sendNext(0)
  696. scheduler.advance()
  697. expect(values) == [ 0 ]
  698. observer.sendNext(1)
  699. observer.sendCompleted()
  700. expect(completed) == false
  701. scheduler.run()
  702. expect(values) == [ 0 ]
  703. expect(completed) == true
  704. }
  705. }
  706. describe("sampleWith") {
  707. var sampledProducer: SignalProducer<(Int, String), NoError>!
  708. var observer: Signal<Int, NoError>.Observer!
  709. var samplerObserver: Signal<String, NoError>.Observer!
  710. beforeEach {
  711. let (producer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
  712. let (sampler, incomingSamplerObserver) = SignalProducer<String, NoError>.pipe()
  713. sampledProducer = producer.sampleWith(sampler)
  714. observer = incomingObserver
  715. samplerObserver = incomingSamplerObserver
  716. }
  717. it("should forward the latest value when the sampler fires") {
  718. var result: [String] = []
  719. sampledProducer.startWithNext { (left, right) in result.append("\(left)\(right)") }
  720. observer.sendNext(1)
  721. observer.sendNext(2)
  722. samplerObserver.sendNext("a")
  723. expect(result) == [ "2a" ]
  724. }
  725. it("should do nothing if sampler fires before signal receives value") {
  726. var result: [String] = []
  727. sampledProducer.startWithNext { (left, right) in result.append("\(left)\(right)") }
  728. samplerObserver.sendNext("a")
  729. expect(result).to(beEmpty())
  730. }
  731. it("should send lates value multiple times when sampler fires multiple times") {
  732. var result: [String] = []
  733. sampledProducer.startWithNext { (left, right) in result.append("\(left)\(right)") }
  734. observer.sendNext(1)
  735. samplerObserver.sendNext("a")
  736. samplerObserver.sendNext("b")
  737. expect(result) == [ "1a", "1b" ]
  738. }
  739. it("should complete when both inputs have completed") {
  740. var completed = false
  741. sampledProducer.startWithCompleted { completed = true }
  742. observer.sendCompleted()
  743. expect(completed) == false
  744. samplerObserver.sendCompleted()
  745. expect(completed) == true
  746. }
  747. it("should emit an initial value if the sampler is a synchronous SignalProducer") {
  748. let producer = SignalProducer<Int, NoError>(values: [1])
  749. let sampler = SignalProducer<String, NoError>(value: "a")
  750. let result = producer.sampleWith(sampler)
  751. var valueReceived: String?
  752. result.startWithNext { (left, right) in valueReceived = "\(left)\(right)" }
  753. expect(valueReceived) == "1a"
  754. }
  755. }
  756. describe("sampleOn") {
  757. var sampledProducer: SignalProducer<Int, NoError>!
  758. var observer: Signal<Int, NoError>.Observer!
  759. var samplerObserver: Signal<(), NoError>.Observer!
  760. beforeEach {
  761. let (producer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
  762. let (sampler, incomingSamplerObserver) = SignalProducer<(), NoError>.pipe()
  763. sampledProducer = producer.sampleOn(sampler)
  764. observer = incomingObserver
  765. samplerObserver = incomingSamplerObserver
  766. }
  767. it("should forward the latest value when the sampler fires") {
  768. var result: [Int] = []
  769. sampledProducer.startWithNext { result.append($0) }
  770. observer.sendNext(1)
  771. observer.sendNext(2)
  772. samplerObserver.sendNext(())
  773. expect(result) == [ 2 ]
  774. }
  775. it("should do nothing if sampler fires before signal receives value") {
  776. var result: [Int] = []
  777. sampledProducer.startWithNext { result.append($0) }
  778. samplerObserver.sendNext(())
  779. expect(result).to(beEmpty())
  780. }
  781. it("should send lates value multiple times when sampler fires multiple times") {
  782. var result: [Int] = []
  783. sampledProducer.startWithNext { result.append($0) }
  784. observer.sendNext(1)
  785. samplerObserver.sendNext(())
  786. samplerObserver.sendNext(())
  787. expect(result) == [ 1, 1 ]
  788. }
  789. it("should complete when both inputs have completed") {
  790. var completed = false
  791. sampledProducer.startWithCompleted { completed = true }
  792. observer.sendCompleted()
  793. expect(completed) == false
  794. samplerObserver.sendCompleted()
  795. expect(completed) == true
  796. }
  797. it("should emit an initial value if the sampler is a synchronous SignalProducer") {
  798. let producer = SignalProducer<Int, NoError>(values: [1])
  799. let sampler = SignalProducer<(), NoError>(value: ())
  800. let result = producer.sampleOn(sampler)
  801. var valueReceived: Int?
  802. result.startWithNext { valueReceived = $0 }
  803. expect(valueReceived) == 1
  804. }
  805. describe("memory") {
  806. class Payload {
  807. let action: () -> Void
  808. init(onDeinit action: () -> Void) {
  809. self.action = action
  810. }
  811. deinit {
  812. action()
  813. }
  814. }
  815. var sampledProducer: SignalProducer<Payload, NoError>!
  816. var observer: Signal<Payload, NoError>.Observer!
  817. beforeEach {
  818. let (producer, incomingObserver) = SignalProducer<Payload, NoError>.pipe()
  819. let (sampler, _) = Signal<(), NoError>.pipe()
  820. sampledProducer = producer.sampleOn(sampler)
  821. observer = incomingObserver
  822. }
  823. it("should free payload when interrupted after complete of incoming producer") {
  824. var payloadFreed = false
  825. let disposable = sampledProducer.start()
  826. observer.sendNext(Payload { payloadFreed = true })
  827. observer.sendCompleted()
  828. expect(payloadFreed) == false
  829. disposable.dispose()
  830. expect(payloadFreed) == true
  831. }
  832. }
  833. }
  834. describe("combineLatestWith") {
  835. var combinedProducer: SignalProducer<(Int, Double), NoError>!
  836. var observer: Signal<Int, NoError>.Observer!
  837. var otherObserver: Signal<Double, NoError>.Observer!
  838. beforeEach {
  839. let (producer, incomingObserver) = SignalProducer<Int, NoError>.pipe()
  840. let (otherSignal, incomingOtherObserver) = SignalProducer<Double, NoError>.pipe()
  841. combinedProducer = producer.combineLatestWith(otherSignal)
  842. observer = incomingObserver
  843. otherObserver = incomingOtherObserver
  844. }
  845. it("should forward the latest values from both inputs") {
  846. var latest: (Int, Double)?
  847. combinedProducer.startWithNext { latest = $0 }
  848. observer.sendNext(1)
  849. expect(latest).to(beNil())
  850. // is there a better way to test tuples?
  851. otherObserver.sendNext(1.5)
  852. expect(latest?.0) == 1
  853. expect(latest?.1) == 1.5
  854. observer.sendNext(2)
  855. expect(latest?.0) == 2
  856. expect(latest?.1) == 1.5
  857. }
  858. it("should complete when both inputs have completed") {
  859. var completed = false
  860. combinedProducer.startWithCompleted { completed = true }
  861. observer.sendCompleted()
  862. expect(completed) == false
  863. otherObserver.sendCompleted()
  864. expect(completed) == true
  865. }
  866. }
  867. describe("zipWith") {
  868. var leftObserver: Signal<Int, NoError>.Observer!
  869. var rightObserver: Signal<String, NoError>.Observer!
  870. var zipped: SignalProducer<(Int, String), NoError>!
  871. beforeEach {
  872. let (leftProducer, incomingLeftObserver) = SignalProducer<Int, NoError>.pipe()
  873. let (rightProducer, incomingRightObserver) = SignalProducer<String, NoError>.pipe()
  874. leftObserver = incomingLeftObserver
  875. rightObserver = incomingRightObserver
  876. zipped = leftProducer.zipWith(rightProducer)
  877. }
  878. it("should combine pairs") {
  879. var result: [String] = []
  880. zipped.startWithNext { (left, right) in result.append("\(left)\(right)") }
  881. leftObserver.sendNext(1)
  882. leftObserver.sendNext(2)
  883. expect(result) == []
  884. rightObserver.sendNext("foo")
  885. expect(result) == [ "1foo" ]
  886. leftObserver.sendNext(3)
  887. rightObserver.sendNext("bar")
  888. expect(result) == [ "1foo", "2bar" ]
  889. rightObserver.sendNext("buzz")
  890. expect(result) == [ "1foo", "2bar", "3buzz" ]
  891. rightObserver.sendNext("fuzz")
  892. expect(result) == [ "1foo", "2bar", "3buzz" ]
  893. leftObserver.sendNext(4)
  894. expect(result) == [ "1foo", "2bar", "3buzz", "4fuzz" ]
  895. }
  896. it("should complete when the shorter signal has completed") {
  897. var result: [String] = []
  898. var completed = false
  899. zipped.start { event in
  900. switch event {
  901. case let .Next(left, right):
  902. result.append("\(left)\(right)")
  903. case .Completed:
  904. completed = true
  905. case .Failed, .Interrupted:
  906. break
  907. }
  908. }
  909. expect(completed) == false
  910. leftObserver.sendNext(0)
  911. leftObserver.sendCompleted()
  912. expect(completed) == false
  913. expect(result) == []
  914. rightObserver.sendNext("foo")
  915. expect(completed) == true
  916. expect(result) == [ "0foo" ]
  917. }
  918. }
  919. describe("materialize") {
  920. it("should reify events from the signal") {
  921. let (producer, observer) = SignalProducer<Int, TestError>.pipe()
  922. var latestEvent: Event<Int, TestError>?
  923. producer
  924. .materialize()
  925. .startWithNext { latestEvent = $0 }
  926. observer.sendNext(2)
  927. expect(latestEvent).toNot(beNil())
  928. if let latestEvent = latestEvent {
  929. switch latestEvent {
  930. case let .Next(value):
  931. expect(value) == 2
  932. case .Failed, .Completed, .Interrupted:
  933. fail()
  934. }
  935. }
  936. observer.sendFailed(TestError.Default)
  937. if let latestEvent = latestEvent {
  938. switch latestEvent {
  939. case .Failed:
  940. break
  941. case .Next, .Completed, .Interrupted:
  942. fail()
  943. }
  944. }
  945. }
  946. }
  947. describe("dematerialize") {
  948. typealias IntEvent = Event<Int, TestError>
  949. var observer: Signal<IntEvent, NoError>.Observer!
  950. var dematerialized: SignalProducer<Int, TestError>!
  951. beforeEach {
  952. let (producer, incomingObserver) = SignalProducer<IntEvent, NoError>.pipe()
  953. observer = incomingObserver
  954. dematerialized = producer.dematerialize()
  955. }
  956. it("should send values for Next events") {
  957. var result: [Int] = []
  958. dematerialized
  959. .assumeNoErrors()
  960. .startWithNext { result.append($0) }
  961. expect(result).to(beEmpty())
  962. observer.sendNext(.Next(2))
  963. expect(result) == [ 2 ]
  964. observer.sendNext(.Next(4))
  965. expect(result) == [ 2, 4 ]
  966. }
  967. it("should error out for Error events") {
  968. var errored = false
  969. dematerialized.startWithFailed { _ in errored = true }
  970. expect(errored) == false
  971. observer.sendNext(.Failed(TestError.Default))
  972. expect(errored) == true
  973. }
  974. it("should complete early for Completed events") {
  975. var completed = false
  976. dematerialized.startWithCompleted { completed = true }
  977. expect(completed) == false
  978. observer.sendNext(IntEvent.Completed)
  979. expect(completed) == true
  980. }
  981. }
  982. describe("takeLast") {
  983. var observer: Signal<Int, TestError>.Observer!
  984. var lastThree: SignalProducer<Int, TestError>!
  985. beforeEach {
  986. let (producer, incomingObserver) = SignalProducer<Int, TestError>.pipe()
  987. observer = incomingObserver
  988. lastThree = producer.takeLast(3)
  989. }
  990. it("should send the last N values upon completion") {
  991. var result: [Int] = []
  992. lastThree
  993. .assumeNoErrors()
  994. .startWithNext { result.append($0) }
  995. observer.sendNext(1)
  996. observer.sendNext(2)
  997. observer.sendNext(3)
  998. observer.sendNext(4)
  999. expect(result).to(beEmpty())
  1000. observer.sendCompleted()
  1001. expect(result) == [ 2, 3, 4 ]
  1002. }
  1003. it("should send less than N values if not enough were received") {
  1004. var result: [Int] = []
  1005. lastThree
  1006. .assumeNoErrors()
  1007. .startWithNext { result.append($0) }
  1008. observer.sendNext(1)
  1009. observer.sendNext(2)
  1010. observer.sendCompleted()
  1011. expect(result) == [ 1, 2 ]
  1012. }
  1013. it("should send nothing when errors") {
  1014. var result: [Int] = []
  1015. var errored = false
  1016. lastThree.start { event in
  1017. switch event {
  1018. case let .Next(value):
  1019. result.append(value)
  1020. case .Failed:
  1021. errored = true
  1022. case .Completed, .Interrupted:
  1023. break
  1024. }
  1025. }
  1026. observer.sendNext(1)
  1027. observer.sendNext(2)
  1028. observer.sendNext(3)
  1029. expect(errored) == false
  1030. observer.sendFailed(TestError.Default)
  1031. expect(errored) == true
  1032. expect(result).to(beEmpty())
  1033. }
  1034. }
  1035. describe("timeoutWithError") {
  1036. var testScheduler: TestScheduler!
  1037. var producer: SignalProducer<Int, TestError>!
  1038. var observer: Signal<Int, TestError>.Observer!
  1039. beforeEach {
  1040. testScheduler = TestScheduler()
  1041. let (baseProducer, incomingObserver) = SignalProducer<Int, TestError>.pipe()
  1042. producer = baseProducer.timeoutWithError(TestError.Default, afterInterval: 2, onScheduler: testScheduler)
  1043. observer = incomingObserver
  1044. }
  1045. it("should complete if within the interval") {
  1046. var completed = false
  1047. var errored = false
  1048. producer.start { event in
  1049. switch event {
  1050. case .Completed:
  1051. completed = true
  1052. case .Failed:
  1053. errored = true
  1054. case .Next, .Interrupted:
  1055. break
  1056. }
  1057. }
  1058. testScheduler.scheduleAfter(1) {
  1059. observer.sendCompleted()
  1060. }
  1061. expect(completed) == false
  1062. expect(errored) == false
  1063. testScheduler.run()
  1064. expect(completed) == true
  1065. expect(errored) == false
  1066. }
  1067. it("should error if not completed before the interval has elapsed") {
  1068. var completed = false
  1069. var errored = false
  1070. producer.start { event in
  1071. switch event {
  1072. case .Completed:
  1073. completed = true
  1074. case .Failed:
  1075. errored = true
  1076. case .Next, .Interrupted:
  1077. break
  1078. }
  1079. }
  1080. testScheduler.scheduleAfter(3) {
  1081. observer.sendCompleted()
  1082. }
  1083. expect(completed) == false
  1084. expect(errored) == false
  1085. testScheduler.run()
  1086. expect(completed) == false
  1087. expect(errored) == true
  1088. }
  1089. }
  1090. describe("attempt") {
  1091. it("should forward original values upon success") {
  1092. let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
  1093. let producer = baseProducer.attempt { _ in
  1094. return .Success()
  1095. }
  1096. var current: Int?
  1097. producer
  1098. .assumeNoErrors()
  1099. .startWithNext { value in
  1100. current = value
  1101. }
  1102. for value in 1...5 {
  1103. observer.sendNext(value)
  1104. expect(current) == value
  1105. }
  1106. }
  1107. it("should error if an attempt fails") {
  1108. let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
  1109. let producer = baseProducer.attempt { _ in
  1110. return .Failure(.Default)
  1111. }
  1112. var error: TestError?
  1113. producer.startWithFailed { err in
  1114. error = err
  1115. }
  1116. observer.sendNext(42)
  1117. expect(error) == TestError.Default
  1118. }
  1119. }
  1120. describe("attemptMap") {
  1121. it("should forward mapped values upon success") {
  1122. let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
  1123. let producer = baseProducer.attemptMap { num -> Result<Bool, TestError> in
  1124. return .Success(num % 2 == 0)
  1125. }
  1126. var even: Bool?
  1127. producer
  1128. .assumeNoErrors()
  1129. .startWithNext { value in
  1130. even = value
  1131. }
  1132. observer.sendNext(1)
  1133. expect(even) == false
  1134. observer.sendNext(2)
  1135. expect(even) == true
  1136. }
  1137. it("should error if a mapping fails") {
  1138. let (baseProducer, observer) = SignalProducer<Int, TestError>.pipe()
  1139. let producer = baseProducer.attemptMap { _ -> Result<Bool, TestError> in
  1140. return .Failure(.Default)
  1141. }
  1142. var error: TestError?
  1143. producer.startWithFailed { err in
  1144. error = err
  1145. }
  1146. observer.sendNext(42)
  1147. expect(error) == TestError.Default
  1148. }
  1149. }
  1150. describe("combinePrevious") {
  1151. var observer: Signal<Int, NoError>.Observer!
  1152. let initialValue: Int = 0
  1153. var latestValues: (Int, Int)?
  1154. beforeEach {
  1155. latestValues = nil
  1156. let (signal, baseObserver) = SignalProducer<Int, NoError>.pipe()
  1157. observer = baseObserver
  1158. signal.combinePrevious(initialValue).startWithNext { latestValues = $0 }
  1159. }
  1160. it("should forward the latest value with previous value") {
  1161. expect(latestValues).to(beNil())
  1162. observer.sendNext(1)
  1163. expect(latestValues?.0) == initialValue
  1164. expect(latestValues?.1) == 1
  1165. observer.sendNext(2)
  1166. expect(latestValues?.0) == 1
  1167. expect(latestValues?.1) == 2
  1168. }
  1169. }
  1170. }
  1171. }