CatchTest.cs 27 KB

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