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