CatchTest.cs 27 KB

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