CatchTest.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Reactive;
  8. using System.Reactive.Concurrency;
  9. using System.Reactive.Linq;
  10. using System.Threading;
  11. using Microsoft.Reactive.Testing;
  12. using ReactiveTests.Dummies;
  13. using Xunit;
  14. namespace ReactiveTests.Tests
  15. {
  16. public class CatchTest : ReactiveTest
  17. {
  18. [Fact]
  19. public void Catch_ArgumentChecking()
  20. {
  21. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Catch<int>(null));
  22. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Catch((IEnumerable<IObservable<int>>)null));
  23. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Catch(DummyObservable<int>.Instance, null));
  24. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Catch(null, DummyObservable<int>.Instance));
  25. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Catch<int, Exception>(null, _ => DummyObservable<int>.Instance));
  26. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.Catch<int, Exception>(DummyObservable<int>.Instance, null));
  27. }
  28. [Fact]
  29. public void Catch_IEofIO_GetEnumeratorThrows()
  30. {
  31. var ex = new Exception();
  32. var scheduler = new TestScheduler();
  33. var xss = new RogueEnumerable<IObservable<int>>(ex);
  34. var res = scheduler.Start(() =>
  35. Observable.Catch(xss)
  36. );
  37. res.Messages.AssertEqual(
  38. OnError<int>(200, ex)
  39. );
  40. }
  41. [Fact]
  42. public void Catch_IEofIO()
  43. {
  44. var scheduler = new TestScheduler();
  45. var xs1 = scheduler.CreateColdObservable(
  46. OnNext(10, 1),
  47. OnNext(20, 2),
  48. OnNext(30, 3),
  49. OnError<int>(40, new Exception())
  50. );
  51. var xs2 = scheduler.CreateColdObservable(
  52. OnNext(10, 4),
  53. OnNext(20, 5),
  54. OnError<int>(30, new Exception())
  55. );
  56. var xs3 = scheduler.CreateColdObservable(
  57. OnNext(10, 6),
  58. OnNext(20, 7),
  59. OnNext(30, 8),
  60. OnNext(40, 9),
  61. OnCompleted<int>(50)
  62. );
  63. var res = scheduler.Start(() =>
  64. Observable.Catch(new[] { xs1, xs2, xs3 })
  65. );
  66. res.Messages.AssertEqual(
  67. OnNext(210, 1),
  68. OnNext(220, 2),
  69. OnNext(230, 3),
  70. OnNext(250, 4),
  71. OnNext(260, 5),
  72. OnNext(280, 6),
  73. OnNext(290, 7),
  74. OnNext(300, 8),
  75. OnNext(310, 9),
  76. OnCompleted<int>(320)
  77. );
  78. xs1.Subscriptions.AssertEqual(
  79. Subscribe(200, 240)
  80. );
  81. xs2.Subscriptions.AssertEqual(
  82. Subscribe(240, 270)
  83. );
  84. xs3.Subscriptions.AssertEqual(
  85. Subscribe(270, 320)
  86. );
  87. }
  88. [Fact]
  89. public void Catch_NoErrors()
  90. {
  91. var scheduler = new TestScheduler();
  92. var o1 = scheduler.CreateHotObservable(
  93. OnNext(150, 1),
  94. OnNext(210, 2),
  95. OnNext(220, 3),
  96. OnCompleted<int>(230)
  97. );
  98. var o2 = scheduler.CreateHotObservable(
  99. OnNext(240, 4),
  100. OnCompleted<int>(250)
  101. );
  102. var res = scheduler.Start(() =>
  103. o1.Catch(o2)
  104. );
  105. res.Messages.AssertEqual(
  106. OnNext(210, 2),
  107. OnNext(220, 3),
  108. OnCompleted<int>(230)
  109. );
  110. o1.Subscriptions.AssertEqual(
  111. Subscribe(200, 230)
  112. );
  113. o2.Subscriptions.AssertEqual(
  114. );
  115. }
  116. [Fact]
  117. public void Catch_Never()
  118. {
  119. var scheduler = new TestScheduler();
  120. var o1 = scheduler.CreateHotObservable(
  121. OnNext(150, 1)
  122. );
  123. var o2 = scheduler.CreateHotObservable(
  124. OnNext(240, 4),
  125. OnCompleted<int>(250)
  126. );
  127. var res = scheduler.Start(() =>
  128. o1.Catch(o2)
  129. );
  130. res.Messages.AssertEqual(
  131. );
  132. o1.Subscriptions.AssertEqual(
  133. Subscribe(200, 1000)
  134. );
  135. o2.Subscriptions.AssertEqual(
  136. );
  137. }
  138. [Fact]
  139. public void Catch_Empty()
  140. {
  141. var scheduler = new TestScheduler();
  142. var o1 = scheduler.CreateHotObservable(
  143. OnNext(150, 1),
  144. OnCompleted<int>(230)
  145. );
  146. var o2 = scheduler.CreateHotObservable(
  147. OnNext(240, 4),
  148. OnCompleted<int>(250)
  149. );
  150. var res = scheduler.Start(() =>
  151. o1.Catch(o2)
  152. );
  153. res.Messages.AssertEqual(
  154. OnCompleted<int>(230)
  155. );
  156. o1.Subscriptions.AssertEqual(
  157. Subscribe(200, 230)
  158. );
  159. o2.Subscriptions.AssertEqual(
  160. );
  161. }
  162. [Fact]
  163. public void Catch_Return()
  164. {
  165. var scheduler = new TestScheduler();
  166. var o1 = scheduler.CreateHotObservable(
  167. OnNext(150, 1),
  168. OnNext(210, 2),
  169. OnCompleted<int>(230)
  170. );
  171. var o2 = scheduler.CreateHotObservable(
  172. OnNext(240, 4),
  173. OnCompleted<int>(250)
  174. );
  175. var res = scheduler.Start(() =>
  176. o1.Catch(o2)
  177. );
  178. res.Messages.AssertEqual(
  179. OnNext(210, 2),
  180. OnCompleted<int>(230)
  181. );
  182. o1.Subscriptions.AssertEqual(
  183. Subscribe(200, 230)
  184. );
  185. o2.Subscriptions.AssertEqual(
  186. );
  187. }
  188. [Fact]
  189. public void Catch_Error()
  190. {
  191. var scheduler = new TestScheduler();
  192. var ex = new Exception();
  193. var o1 = scheduler.CreateHotObservable(
  194. OnNext(150, 1),
  195. OnNext(210, 2),
  196. OnNext(220, 3),
  197. OnError<int>(230, ex)
  198. );
  199. var o2 = scheduler.CreateHotObservable(
  200. OnNext(240, 4),
  201. OnCompleted<int>(250)
  202. );
  203. var res = scheduler.Start(() =>
  204. o1.Catch(o2)
  205. );
  206. res.Messages.AssertEqual(
  207. OnNext(210, 2),
  208. OnNext(220, 3),
  209. OnNext(240, 4),
  210. OnCompleted<int>(250)
  211. );
  212. o1.Subscriptions.AssertEqual(
  213. Subscribe(200, 230)
  214. );
  215. o2.Subscriptions.AssertEqual(
  216. Subscribe(230, 250)
  217. );
  218. }
  219. [Fact]
  220. public void Catch_Error_Never()
  221. {
  222. var scheduler = new TestScheduler();
  223. var ex = new Exception();
  224. var o1 = scheduler.CreateHotObservable(
  225. OnNext(150, 1),
  226. OnNext(210, 2),
  227. OnNext(220, 3),
  228. OnError<int>(230, ex)
  229. );
  230. var o2 = scheduler.CreateHotObservable(
  231. OnNext(150, 1)
  232. );
  233. var res = scheduler.Start(() =>
  234. o1.Catch(o2)
  235. );
  236. res.Messages.AssertEqual(
  237. OnNext(210, 2),
  238. OnNext(220, 3)
  239. );
  240. o1.Subscriptions.AssertEqual(
  241. Subscribe(200, 230)
  242. );
  243. o2.Subscriptions.AssertEqual(
  244. Subscribe(230, 1000)
  245. );
  246. }
  247. [Fact]
  248. public void Catch_Error_Error()
  249. {
  250. var scheduler = new TestScheduler();
  251. var ex = new Exception();
  252. var o1 = scheduler.CreateHotObservable(
  253. OnNext(150, 1),
  254. OnNext(210, 2),
  255. OnNext(220, 3),
  256. OnError<int>(230, new Exception())
  257. );
  258. var o2 = scheduler.CreateHotObservable(
  259. OnNext(240, 4),
  260. OnError<int>(250, ex)
  261. );
  262. var res = scheduler.Start(() =>
  263. o1.Catch(o2)
  264. );
  265. res.Messages.AssertEqual(
  266. OnNext(210, 2),
  267. OnNext(220, 3),
  268. OnNext(240, 4),
  269. OnError<int>(250, ex)
  270. );
  271. o1.Subscriptions.AssertEqual(
  272. Subscribe(200, 230)
  273. );
  274. o2.Subscriptions.AssertEqual(
  275. Subscribe(230, 250)
  276. );
  277. }
  278. [Fact]
  279. public void Catch_Multiple()
  280. {
  281. var scheduler = new TestScheduler();
  282. var ex = new Exception();
  283. var o1 = scheduler.CreateHotObservable(
  284. OnNext(150, 1),
  285. OnNext(210, 2),
  286. OnError<int>(215, ex)
  287. );
  288. var o2 = scheduler.CreateHotObservable(
  289. OnNext(220, 3),
  290. OnError<int>(225, ex)
  291. );
  292. var o3 = scheduler.CreateHotObservable(
  293. OnNext(230, 4),
  294. OnCompleted<int>(235)
  295. );
  296. var res = scheduler.Start(() =>
  297. Observable.Catch(o1, o2, o3)
  298. );
  299. res.Messages.AssertEqual(
  300. OnNext(210, 2),
  301. OnNext(220, 3),
  302. OnNext(230, 4),
  303. OnCompleted<int>(235)
  304. );
  305. o1.Subscriptions.AssertEqual(
  306. Subscribe(200, 215)
  307. );
  308. o2.Subscriptions.AssertEqual(
  309. Subscribe(215, 225)
  310. );
  311. o3.Subscriptions.AssertEqual(
  312. Subscribe(225, 235)
  313. );
  314. }
  315. [Fact]
  316. public void Catch_ErrorSpecific_Caught()
  317. {
  318. var scheduler = new TestScheduler();
  319. var ex = new ArgumentException("x");
  320. var o1 = scheduler.CreateHotObservable(
  321. OnNext(150, 1),
  322. OnNext(210, 2),
  323. OnNext(220, 3),
  324. OnError<int>(230, ex)
  325. );
  326. var o2 = scheduler.CreateHotObservable(
  327. OnNext(240, 4),
  328. OnCompleted<int>(250)
  329. );
  330. var handlerCalled = default(long?);
  331. var res = scheduler.Start(() =>
  332. o1.Catch((ArgumentException ex_) => { handlerCalled = scheduler.Clock; return o2; })
  333. );
  334. Assert.Equal(230, handlerCalled);
  335. res.Messages.AssertEqual(
  336. OnNext(210, 2),
  337. OnNext(220, 3),
  338. OnNext(240, 4),
  339. OnCompleted<int>(250)
  340. );
  341. o1.Subscriptions.AssertEqual(
  342. Subscribe(200, 230)
  343. );
  344. o2.Subscriptions.AssertEqual(
  345. Subscribe(230, 250)
  346. );
  347. }
  348. [Fact]
  349. public void Catch_ErrorSpecific_Uncaught()
  350. {
  351. var scheduler = new TestScheduler();
  352. var ex = new InvalidOperationException("x");
  353. var o1 = scheduler.CreateHotObservable(
  354. OnNext(150, 1),
  355. OnNext(210, 2),
  356. OnNext(220, 3),
  357. OnError<int>(230, ex)
  358. );
  359. var o2 = scheduler.CreateHotObservable(
  360. OnNext(240, 4),
  361. OnCompleted<int>(250)
  362. );
  363. var handlerCalled = default(long?);
  364. var res = scheduler.Start(() =>
  365. o1.Catch((ArgumentException ex_) => { handlerCalled = scheduler.Clock; return o2; })
  366. );
  367. Assert.Equal(null, handlerCalled);
  368. res.Messages.AssertEqual(
  369. OnNext(210, 2),
  370. OnNext(220, 3),
  371. OnError<int>(230, ex)
  372. );
  373. o1.Subscriptions.AssertEqual(
  374. Subscribe(200, 230)
  375. );
  376. o2.Subscriptions.AssertEqual(
  377. );
  378. }
  379. [Fact]
  380. public void Catch_HandlerThrows()
  381. {
  382. var scheduler = new TestScheduler();
  383. var ex1 = new ArgumentException("x");
  384. var ex2 = new Exception();
  385. var o1 = scheduler.CreateHotObservable(
  386. OnNext(150, 1),
  387. OnNext(210, 2),
  388. OnNext(220, 3),
  389. OnError<int>(230, ex1)
  390. );
  391. var handlerCalled = default(long?);
  392. var res = scheduler.Start(() =>
  393. o1.Catch((ArgumentException ex_) => { handlerCalled = scheduler.Clock; throw ex2; })
  394. );
  395. Assert.Equal(230, handlerCalled);
  396. res.Messages.AssertEqual(
  397. OnNext(210, 2),
  398. OnNext(220, 3),
  399. OnError<int>(230, ex2)
  400. );
  401. o1.Subscriptions.AssertEqual(
  402. Subscribe(200, 230)
  403. );
  404. }
  405. [Fact]
  406. public void Catch_Nested_OuterCatches()
  407. {
  408. var scheduler = new TestScheduler();
  409. var ex = new ArgumentException("x");
  410. var o1 = scheduler.CreateHotObservable(
  411. OnNext(150, 1),
  412. OnNext(210, 2),
  413. OnError<int>(215, ex)
  414. );
  415. var o2 = scheduler.CreateHotObservable(
  416. OnNext(220, 3),
  417. OnCompleted<int>(225)
  418. );
  419. var o3 = scheduler.CreateHotObservable(
  420. OnNext(220, 4), //!
  421. OnCompleted<int>(225)
  422. );
  423. var firstHandlerCalled = default(long?);
  424. var secondHandlerCalled = default(long?);
  425. var res = scheduler.Start(() =>
  426. o1
  427. .Catch((InvalidOperationException ex_) => { firstHandlerCalled = scheduler.Clock; return o2; })
  428. .Catch((ArgumentException ex_) => { secondHandlerCalled = scheduler.Clock; return o3; })
  429. );
  430. Assert.Equal(null, firstHandlerCalled);
  431. Assert.Equal(215, secondHandlerCalled);
  432. res.Messages.AssertEqual(
  433. OnNext(210, 2),
  434. OnNext(220, 4),
  435. OnCompleted<int>(225)
  436. );
  437. o1.Subscriptions.AssertEqual(
  438. Subscribe(200, 215)
  439. );
  440. o2.Subscriptions.AssertEqual(
  441. );
  442. o3.Subscriptions.AssertEqual(
  443. Subscribe(215, 225)
  444. );
  445. }
  446. [Fact]
  447. public void Catch_Nested_InnerCatches()
  448. {
  449. var scheduler = new TestScheduler();
  450. var ex = new ArgumentException("x");
  451. var o1 = scheduler.CreateHotObservable(
  452. OnNext(150, 1),
  453. OnNext(210, 2),
  454. OnError<int>(215, ex)
  455. );
  456. var o2 = scheduler.CreateHotObservable(
  457. OnNext(220, 3), //!
  458. OnCompleted<int>(225)
  459. );
  460. var o3 = scheduler.CreateHotObservable(
  461. OnNext(220, 4),
  462. OnCompleted<int>(225)
  463. );
  464. var firstHandlerCalled = default(long?);
  465. var secondHandlerCalled = default(long?);
  466. var res = scheduler.Start(() =>
  467. o1
  468. .Catch((ArgumentException ex_) => { firstHandlerCalled = scheduler.Clock; return o2; })
  469. .Catch((InvalidOperationException ex_) => { secondHandlerCalled = scheduler.Clock; return o3; })
  470. );
  471. Assert.Equal(215, firstHandlerCalled);
  472. Assert.Equal(null, secondHandlerCalled);
  473. res.Messages.AssertEqual(
  474. OnNext(210, 2),
  475. OnNext(220, 3),
  476. OnCompleted<int>(225)
  477. );
  478. o1.Subscriptions.AssertEqual(
  479. Subscribe(200, 215)
  480. );
  481. o2.Subscriptions.AssertEqual(
  482. Subscribe(215, 225)
  483. );
  484. o3.Subscriptions.AssertEqual(
  485. );
  486. }
  487. [Fact]
  488. public void Catch_ThrowFromNestedCatch()
  489. {
  490. var scheduler = new TestScheduler();
  491. var ex1 = new ArgumentException("x1");
  492. var ex2 = new ArgumentException("x2");
  493. var o1 = scheduler.CreateHotObservable(
  494. OnNext(150, 1),
  495. OnNext(210, 2),
  496. OnError<int>(215, ex1)
  497. );
  498. var o2 = scheduler.CreateHotObservable(
  499. OnNext(220, 3), //!
  500. OnError<int>(225, ex2)
  501. );
  502. var o3 = scheduler.CreateHotObservable(
  503. OnNext(230, 4),
  504. OnCompleted<int>(235)
  505. );
  506. var firstHandlerCalled = default(long?);
  507. var secondHandlerCalled = default(long?);
  508. var res = scheduler.Start(() =>
  509. o1
  510. .Catch((ArgumentException ex_) => { firstHandlerCalled = scheduler.Clock; Assert.True(ex1 == ex_, "Expected ex1"); return o2; })
  511. .Catch((ArgumentException ex_) => { secondHandlerCalled = scheduler.Clock; Assert.True(ex2 == ex_, "Expected ex2"); return o3; })
  512. );
  513. Assert.Equal(215, firstHandlerCalled);
  514. Assert.Equal(225, secondHandlerCalled);
  515. res.Messages.AssertEqual(
  516. OnNext(210, 2),
  517. OnNext(220, 3),
  518. OnNext(230, 4),
  519. OnCompleted<int>(235)
  520. );
  521. o1.Subscriptions.AssertEqual(
  522. Subscribe(200, 215)
  523. );
  524. o2.Subscriptions.AssertEqual(
  525. Subscribe(215, 225)
  526. );
  527. o3.Subscriptions.AssertEqual(
  528. Subscribe(225, 235)
  529. );
  530. }
  531. [Fact]
  532. public void Catch_DefaultScheduler_Binary()
  533. {
  534. var evt = new ManualResetEvent(false);
  535. var res = 0;
  536. Observable.Return(1).Catch(Observable.Return(2)).Subscribe(x =>
  537. {
  538. res = x;
  539. evt.Set();
  540. });
  541. evt.WaitOne();
  542. Assert.Equal(1, res);
  543. }
  544. [Fact]
  545. public void Catch_DefaultScheduler_Nary()
  546. {
  547. var evt = new ManualResetEvent(false);
  548. var res = 0;
  549. Observable.Catch(Observable.Return(1), Observable.Return(2), Observable.Return(3)).Subscribe(x =>
  550. {
  551. res = x;
  552. evt.Set();
  553. });
  554. evt.WaitOne();
  555. Assert.Equal(1, res);
  556. }
  557. [Fact]
  558. public void Catch_DefaultScheduler_NaryEnumerable()
  559. {
  560. var evt = new ManualResetEvent(false);
  561. IEnumerable<IObservable<int>> sources = new[] { Observable.Return(1), Observable.Return(2), Observable.Return(3) };
  562. var res = 0;
  563. Observable.Catch(sources).Subscribe(x =>
  564. {
  565. res = x;
  566. evt.Set();
  567. });
  568. evt.WaitOne();
  569. Assert.Equal(1, res);
  570. }
  571. [Fact]
  572. public void Catch_EmptyIterator()
  573. {
  574. var scheduler = new TestScheduler();
  575. var res = scheduler.Start(() =>
  576. Observable.Catch((IEnumerable<IObservable<int>>)new IObservable<int>[0])
  577. );
  578. res.Messages.AssertEqual(
  579. OnCompleted<int>(200)
  580. );
  581. }
  582. [Fact]
  583. public void Catch_IteratorThrows()
  584. {
  585. var scheduler = new TestScheduler();
  586. var ex = new Exception();
  587. var res = scheduler.Start(() =>
  588. Observable.Catch(Catch_IteratorThrows_Source(ex, true))
  589. );
  590. res.Messages.AssertEqual(
  591. OnError<int>(200, ex)
  592. );
  593. }
  594. private IEnumerable<IObservable<int>> Catch_IteratorThrows_Source(Exception ex, bool b)
  595. {
  596. if (b)
  597. {
  598. throw ex;
  599. }
  600. else
  601. {
  602. yield break;
  603. }
  604. }
  605. [Fact]
  606. public void Catch_EnumerableThrows()
  607. {
  608. var scheduler = new TestScheduler();
  609. var o = scheduler.CreateHotObservable(
  610. OnNext(150, 1),
  611. OnNext(210, 2),
  612. OnNext(220, 3),
  613. OnCompleted<int>(225)
  614. );
  615. var ex = new Exception();
  616. var xss = new MockEnumerable<IObservable<int>>(scheduler, GetObservablesForCatchThrow(o, ex));
  617. var res = scheduler.Start(() =>
  618. xss.Catch()
  619. );
  620. res.Messages.AssertEqual(
  621. OnNext(210, 2),
  622. OnNext(220, 3),
  623. OnCompleted<int>(225)
  624. );
  625. o.Subscriptions.AssertEqual(
  626. Subscribe(200, 225)
  627. );
  628. xss.Subscriptions.AssertEqual(
  629. Subscribe(200, 225)
  630. );
  631. }
  632. private IEnumerable<IObservable<int>> GetObservablesForCatchThrow(IObservable<int> first, Exception ex)
  633. {
  634. yield return first;
  635. throw ex;
  636. }
  637. [Fact]
  638. public void Catch_EnumerableTiming()
  639. {
  640. var scheduler = new TestScheduler();
  641. var o1 = scheduler.CreateHotObservable(
  642. OnNext(150, 1),
  643. OnNext(210, 2), // !
  644. OnNext(220, 3), // !
  645. OnError<int>(230, new Exception())
  646. );
  647. var o2 = scheduler.CreateColdObservable(
  648. OnNext(50, 4), // !
  649. OnNext(60, 5), // !
  650. OnNext(70, 6), // !
  651. OnError<int>(80, new Exception())
  652. );
  653. var o3 = scheduler.CreateHotObservable(
  654. OnNext(150, 1),
  655. OnNext(200, 2),
  656. OnNext(210, 3),
  657. OnNext(220, 4),
  658. OnNext(230, 5),
  659. OnNext(270, 6),
  660. OnNext(320, 7), // !
  661. OnNext(330, 8), // !
  662. OnCompleted<int>(340)
  663. );
  664. var xss = new MockEnumerable<ITestableObservable<int>>(scheduler, new[] { o1, o2, o3, o2 });
  665. var res = scheduler.Start(() =>
  666. xss.Select(xs => (IObservable<int>)xs).Catch()
  667. );
  668. res.Messages.AssertEqual(
  669. OnNext(210, 2),
  670. OnNext(220, 3),
  671. OnNext(280, 4),
  672. OnNext(290, 5),
  673. OnNext(300, 6),
  674. OnNext(320, 7),
  675. OnNext(330, 8),
  676. OnCompleted<int>(340)
  677. );
  678. o1.Subscriptions.AssertEqual(
  679. Subscribe(200, 230)
  680. );
  681. o2.Subscriptions.AssertEqual(
  682. Subscribe(230, 310)
  683. );
  684. o3.Subscriptions.AssertEqual(
  685. Subscribe(310, 340)
  686. );
  687. xss.Subscriptions.AssertEqual(
  688. Subscribe(200, 340)
  689. );
  690. }
  691. [Fact]
  692. public void Catch_Enumerable_Dispose()
  693. {
  694. var scheduler = new TestScheduler();
  695. var o1 = scheduler.CreateHotObservable(
  696. OnNext(150, 1),
  697. OnNext(210, 2),
  698. OnNext(220, 3),
  699. OnError<int>(230, new Exception())
  700. );
  701. var o2 = scheduler.CreateHotObservable(
  702. OnNext(150, 1),
  703. OnNext(200, 2),
  704. OnNext(210, 3),
  705. OnNext(240, 4),
  706. OnNext(270, 5),
  707. OnNext(320, 6),
  708. OnNext(330, 7),
  709. OnCompleted<int>(340)
  710. );
  711. var xss = new MockEnumerable<ITestableObservable<int>>(scheduler, new[] { o1, o2 });
  712. var res = scheduler.Start(() =>
  713. xss.Select(xs => (IObservable<int>)xs).Catch(),
  714. 300
  715. );
  716. res.Messages.AssertEqual(
  717. OnNext(210, 2),
  718. OnNext(220, 3),
  719. OnNext(240, 4),
  720. OnNext(270, 5)
  721. );
  722. o1.Subscriptions.AssertEqual(
  723. Subscribe(200, 230)
  724. );
  725. o2.Subscriptions.AssertEqual(
  726. Subscribe(230, 300)
  727. );
  728. xss.Subscriptions.AssertEqual(
  729. Subscribe(200, 300)
  730. );
  731. }
  732. #if !NO_PERF
  733. [Fact]
  734. public void Catch_TailRecursive1()
  735. {
  736. var create = 0L;
  737. var start = 200L;
  738. var end = 1000L;
  739. var scheduler = new TestScheduler();
  740. var o = scheduler.CreateColdObservable(
  741. OnNext(10, 1),
  742. OnNext(20, 2),
  743. OnNext(30, 3),
  744. OnError<int>(40, new Exception())
  745. );
  746. IObservable<int> f() => Observable.Defer(() => o.Catch(f()));
  747. var res = scheduler.Start(() => f(), create, start, end);
  748. var expected = new List<Recorded<Notification<int>>>();
  749. var t = start;
  750. while (t <= end)
  751. {
  752. var n = (t - start) / 10;
  753. if (n % 4 != 0)
  754. {
  755. expected.Add(OnNext(t, (int)(n % 4)));
  756. }
  757. t += 10;
  758. }
  759. res.Messages.AssertEqual(expected);
  760. }
  761. #if HAS_STACKTRACE && !NO_THREAD
  762. [Fact]
  763. public void Catch_TailRecursive2()
  764. {
  765. var f = default(Func<int, IObservable<int>>);
  766. f = x => Observable.Defer(() => Observable.Throw<int>(new Exception(), ThreadPoolScheduler.Instance).StartWith(x).Catch(f(x + 1)));
  767. var lst = new List<int>();
  768. f(0).Select(x => new StackTrace().FrameCount).Take(10).ForEach(lst.Add);
  769. Assert.True(lst.Last() - lst.First() < 10);
  770. }
  771. #endif
  772. [Fact]
  773. public void Catch_TailRecursive3()
  774. {
  775. var ex = new Exception();
  776. var res =
  777. Observable.Catch(
  778. Observable.Defer(() =>
  779. {
  780. if (ex != null)
  781. {
  782. throw ex;
  783. }
  784. return Observable.Return(-2);
  785. }),
  786. Observable.Defer(() =>
  787. {
  788. if (ex != null)
  789. {
  790. throw ex;
  791. }
  792. return Observable.Return(-1);
  793. }),
  794. Observable.Return(42)
  795. );
  796. Assert.Equal(42, res.Wait());
  797. }
  798. #endif
  799. }
  800. }