PageRenderTime 60ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/System.Reactive.Tests/System.Reactive.Linq/ObservableTest.cs

https://github.com/gshackles/mono-reactive
C# | 1129 lines | 1007 code | 99 blank | 23 comment | 22 complexity | a37f4a28d63be36953ad7e0dd77c202c MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reactive;
  6. using System.Reactive.Concurrency;
  7. using System.Reactive.Disposables;
  8. using System.Reactive.Linq;
  9. using System.Threading;
  10. using NUnit.Framework;
  11. namespace System.Reactive.Linq.Tests
  12. {
  13. [TestFixture]
  14. public class ObservableTest
  15. {
  16. // first, test some basic functionality used by every other tests.
  17. [Test]
  18. public void ToEnumerable ()
  19. {
  20. var e = Observable.Range (0, 3).ToEnumerable ();
  21. var ee = e.GetEnumerator ();
  22. Assert.IsTrue (ee.MoveNext (), "#1");
  23. Assert.AreEqual (0, ee.Current, "#2");
  24. Assert.IsTrue (ee.MoveNext (), "#3");
  25. Assert.AreEqual (1, ee.Current, "#4");
  26. Assert.IsTrue (ee.MoveNext (), "#5");
  27. Assert.AreEqual (2, ee.Current, "#6");
  28. Assert.IsFalse (ee.MoveNext (), "#7");
  29. }
  30. [Test]
  31. public void ToEnumerableWithInterval ()
  32. {
  33. var obs = Observable.Interval (TimeSpan.FromMilliseconds (100)).Take (5);
  34. obs.Subscribe (v => {}); // should not affect ToEnumerable() startup.
  35. int i = 0;
  36. Thread.Sleep (200);
  37. DateTime start = DateTime.Now;
  38. var e = obs.ToEnumerable ();
  39. foreach (var v in e)
  40. i ++;
  41. Assert.AreEqual (5, i, "#1");
  42. Assert.IsTrue (DateTime.Now - start > TimeSpan.FromMilliseconds (500), "#2"); // if it enumerates in incorrect time, it will result in false.
  43. }
  44. [Test]
  45. public void Materialize ()
  46. {
  47. var expected = new NotificationKind [] {
  48. NotificationKind.OnNext,
  49. NotificationKind.OnNext,
  50. NotificationKind.OnError };
  51. var source = Observable.Range (0, 2).Concat (Observable.Throw<int> (new Exception ("failure")));
  52. var l = new List<NotificationKind> ();
  53. bool done = false;
  54. var dis = source.Materialize ().Subscribe (v => l.Add (v.Kind), () => done = true); // test that Materialize() yields OnCompleted event after yielding OnError.
  55. Assert.IsTrue (SpinWait.SpinUntil (() => done, TimeSpan.FromSeconds (1)), "#1");
  56. Assert.AreEqual (expected, l.ToArray (), "#3");
  57. dis.Dispose ();
  58. }
  59. public class MyObservable<T> : IObservable<T>
  60. {
  61. public IDisposable Subscribe (IObserver<T> observer)
  62. {
  63. throw new MyException ();
  64. }
  65. }
  66. [Test]
  67. [ExpectedException (typeof (MyException))]
  68. public void ErrorFlow ()
  69. {
  70. // throw error on main
  71. new MyObservable<int> ().Timestamp ().Subscribe (v => {});
  72. Assert.Fail ("should not reach here");
  73. }
  74. [Test]
  75. public void ErrorSubscription ()
  76. {
  77. bool done = false;
  78. bool shouldNotPass = false;
  79. var o = Observable.Create<int> (observer => { try { throw new Exception (); return Disposable.Empty; } finally { done = true; } });
  80. var dis = new SingleAssignmentDisposable ();
  81. try {
  82. dis.Disposable = o.SubscribeOn (Scheduler.ThreadPool).Subscribe (v => {}, ex => shouldNotPass = true);
  83. } finally {
  84. dis.Dispose ();
  85. }
  86. SpinWait.SpinUntil (() => done, 1000);
  87. Assert.IsTrue (done, "#1");
  88. Assert.IsFalse (shouldNotPass, "#2");
  89. // the exception does not occur in *this* thread, so it passes here.
  90. }
  91. // tests for individual method follow...
  92. [Test]
  93. public void Aggregate ()
  94. {
  95. int i = 0, j = 0, k = 0;
  96. var source = Observable.Range (1, 4).Aggregate ((v1, v2) => v1 + v2);
  97. source.Subscribe (v => { i += v; k++; }, () => j++);
  98. Assert.IsTrue (SpinWait.SpinUntil (() => j != 0, 1000), "#1");
  99. Assert.AreEqual (10, i, "#2");
  100. Assert.AreEqual (1, k, "#3");
  101. }
  102. [Test]
  103. [ExpectedException (typeof (InvalidOperationException))]
  104. public void AggregateEmpty ()
  105. {
  106. Observable.Empty<int> ().Aggregate ((v1, v2) => v1 + v2).Subscribe (TextWriter.Null.WriteLine);
  107. }
  108. [Test]
  109. public void AggregateWithSeed ()
  110. {
  111. int i = 0, j = 0, k = 0;
  112. var source = Observable.Range (1, 4).Aggregate (5, (v1, v2) => v1 + v2);
  113. source.Subscribe (v => { i += v; k++; }, () => j++);
  114. Assert.IsTrue (SpinWait.SpinUntil (() => j != 0, 1000), "#1");
  115. Assert.AreEqual (15, i, "#2");
  116. Assert.AreEqual (1, k, "#3");
  117. }
  118. [Test]
  119. // Note that this overload does not result in error.
  120. public void AggregateEmptyWithSeed ()
  121. {
  122. int i = 0, j = 0, k = 0;
  123. var source = Observable.Empty<int> ().Aggregate (5, (v1, v2) => v1 + v2).Do (v => k++);
  124. source.Subscribe (v => i += v, () => j++);
  125. Assert.IsTrue (SpinWait.SpinUntil (() => j != 0, 1000), "#1");
  126. Assert.AreEqual (5, i, "#2");
  127. Assert.AreEqual (1, k, "#3");
  128. }
  129. [Test]
  130. public void All ()
  131. {
  132. Assert.IsFalse (Observable.Empty<int> ().All (v => true).ToEnumerable ().First (), "#1");
  133. Assert.IsTrue (Observable.Return<int> (1).All (v => true).ToEnumerable ().First (), "#2");
  134. Assert.IsFalse (Observable.Range (1, 3).All (v => v % 2 == 1).ToEnumerable ().First (), "#3");
  135. }
  136. [Test]
  137. [ExpectedException (typeof (MyException))]
  138. public void AllPredicateError ()
  139. {
  140. var source = Observable.Range (0, 20).All (i => { throw new MyException (); });
  141. source.Subscribe (v => {} , ex => Assert.Fail ("Should not reach OnError"), () => Assert.Fail ("Should not reach OnCompleted"));
  142. }
  143. [Test]
  144. public void Amb ()
  145. {
  146. var scheduler = new HistoricalScheduler ();
  147. var s1 = Observable.Range (1, 3).Delay (TimeSpan.FromMilliseconds (500), scheduler);
  148. var s2 = Observable.Range (4, 3);
  149. var e = s1.Amb (s2).ToEnumerable ().ToArray ();
  150. scheduler.AdvanceBy (TimeSpan.FromSeconds (1));
  151. Assert.AreEqual (new int [] {4, 5, 6}, e, "#1");
  152. }
  153. [Test]
  154. public void AndThenWhen ()
  155. {
  156. var s1 = Observable.Range (1, 3);
  157. var s2 = Observable.Range (4, 4); // extra element is ignored.
  158. var e = Observable.When<int> (s1.And (s2).Then ((v1, v2) => v1 + v2)).ToEnumerable ().ToArray ();
  159. Assert.AreEqual (new int [] {5, 7, 9}, e, "#1");
  160. }
  161. [Test]
  162. public void Any ()
  163. {
  164. Assert.IsFalse (Observable.Empty<int> ().Any (v => true).ToEnumerable ().First (), "#1");
  165. Assert.IsTrue (Observable.Return<int> (1).Any (v => true).ToEnumerable ().First (), "#2");
  166. Assert.IsTrue (Observable.Range (1, 3).Any (v => v % 2 == 0).ToEnumerable ().First (), "#3");
  167. }
  168. [Test]
  169. [ExpectedException (typeof (MyException))]
  170. public void AnyPredicateError ()
  171. {
  172. var source = Observable.Range (0, 20).Any (i => { throw new MyException (); });
  173. source.Subscribe (v => {} , ex => Assert.Fail ("Should not reach OnError"), () => Assert.Fail ("Should not reach OnCompleted"));
  174. }
  175. [Test]
  176. public void BufferCountAndSkip ()
  177. {
  178. var sw = new StringWriter () { NewLine = "\n" };
  179. var source = Observable.Range (0, 20).Buffer (3, 5);
  180. source.Subscribe (v => sw.WriteLine (String.Concat (v)), () => sw.Write ("done"));
  181. string expected = "012\n567\n101112\n151617\ndone".Replace ("\r", "");
  182. Assert.AreEqual (expected, sw.ToString (), "#1");
  183. }
  184. [Test]
  185. public void BufferCountAndSkip2 ()
  186. {
  187. // It has to work for overlapped range
  188. var sw = new StringWriter () { NewLine = "\n" };
  189. var source = Observable.Range (0, 10).Buffer (5, 3);
  190. source.Subscribe (v => sw.WriteLine (String.Concat (v)), () => sw.Write ("done"));
  191. var expected = "01234\n34567\n6789\n9\ndone".Replace ("\r", "");
  192. Assert.AreEqual (expected, sw.ToString (), "#1");
  193. }
  194. [Test]
  195. public void BufferTimeSpans ()
  196. {
  197. var scheduler = new HistoricalScheduler ();
  198. var interval = TimeSpan.FromMilliseconds (100);
  199. var span = TimeSpan.FromMilliseconds (300);
  200. var shift = TimeSpan.FromMilliseconds (500);
  201. // This makes notable corner case ... FromMilliseconds (3100) passes the test, while FromSeconds (3) does not. It is because the source is cut at that state.
  202. var total = TimeSpan.FromSeconds (3);
  203. var sw = new StringWriter () { NewLine = "\n" };
  204. var source = Observable.Interval (interval, scheduler).Take (30).Buffer (span, shift, scheduler);
  205. source.Subscribe (v => sw.WriteLine (String.Concat (v)), () => sw.Write ("done"));
  206. scheduler.AdvanceBy (total);
  207. var expected = "01\n456\n91011\n141516\n192021\n242526\n29\ndone".Replace ("\r", "");
  208. Assert.AreEqual (expected, sw.ToString (), "#1");
  209. }
  210. [Test]
  211. public void BufferTimeSpans2 ()
  212. {
  213. var scheduler = new HistoricalScheduler ();
  214. var interval = TimeSpan.FromMilliseconds (100);
  215. var span = TimeSpan.FromMilliseconds (500);
  216. var shift = TimeSpan.FromMilliseconds (300);
  217. var total = TimeSpan.FromSeconds (2);
  218. var sw = new StringWriter () { NewLine = "\n" };
  219. var source = Observable.Interval (interval, scheduler).Take (10).Buffer (span, shift, scheduler);
  220. source.Subscribe (v => sw.WriteLine (String.Concat (v)), () => sw.Write ("done"));
  221. scheduler.AdvanceBy (total);
  222. // this overlaps the list
  223. var expected = "0123\n23456\n56789\n89\ndone".Replace ("\r", "");
  224. Assert.AreEqual (expected, sw.ToString (), "#1");
  225. }
  226. [Test]
  227. public void BufferTimeAndCount ()
  228. {
  229. // This emites events as: 0 <0ms> 1 <100ms> 2 ... 5 <500ms>
  230. var o1 = Observable.Generate<int, int> (0, i => i < 6, i => { Thread.Sleep (i * 50); return i + 1; }, i => i);
  231. var source = o1.Buffer (TimeSpan.FromMilliseconds (500), 3);
  232. bool done = false;
  233. DateTime start = DateTime.Now;
  234. int iter = 0;
  235. var dis = source.Subscribe (l => {
  236. if (iter == 0) {
  237. Assert.IsTrue (DateTime.Now - start <= TimeSpan.FromMilliseconds (500), "#1");
  238. Assert.AreEqual (3, l.Count, "#2");
  239. } else if (iter == 1) {
  240. Assert.IsTrue (l.Count < 3, "#3");
  241. Assert.IsTrue (DateTime.Now - start >= TimeSpan.FromMilliseconds (500), "#4");
  242. }
  243. else
  244. Assert.Fail ("Unexpected Generate() iteration");
  245. iter++;
  246. }, () => done = true);
  247. Assert.IsTrue (SpinWait.SpinUntil (() => done == true, 2000), "#5");
  248. dis.Dispose ();
  249. }
  250. [Test]
  251. public void Concat ()
  252. {
  253. int i = 0, j = 0;
  254. var source = Observable.Range (0, 5).Concat (Observable.Range (11, 3));
  255. source.Subscribe (v => i += v, () => j++);
  256. Assert.IsTrue (SpinWait.SpinUntil (() => j != 0, 1000), "#1");
  257. Assert.AreEqual (46, i, "#2");
  258. source = Observable.Range (0, 4).Concat (Observable.Throw<int> (new MyException ()));
  259. try {
  260. source.ToEnumerable ().All (v => true);
  261. Assert.Fail ("should not complete");
  262. } catch (MyException) {
  263. }
  264. }
  265. [Test]
  266. public void Concat2 ()
  267. {
  268. var expected = new NotificationKind [] {
  269. NotificationKind.OnNext,
  270. NotificationKind.OnNext,
  271. NotificationKind.OnError };
  272. var source = Observable.Range (0, 2).Concat (Observable.Throw<int> (new Exception ("failure")));
  273. var arr = from n in source.Materialize ().ToEnumerable () select n.Kind;
  274. Assert.AreEqual (expected, arr.ToArray (), "#1");
  275. }
  276. [Test]
  277. public void Concat3 ()
  278. {
  279. var expected = new NotificationKind [] {
  280. NotificationKind.OnNext,
  281. NotificationKind.OnNext,
  282. NotificationKind.OnNext,
  283. NotificationKind.OnNext,
  284. NotificationKind.OnCompleted };
  285. var scheduler = new HistoricalScheduler ();
  286. var source = Observable.Range (1, 3).Concat (Observable.Return (2).Delay (TimeSpan.FromMilliseconds (50), scheduler));
  287. bool done = false;
  288. var l = new List<NotificationKind> ();
  289. source.Materialize ().Subscribe (v => l.Add (v.Kind), () => done = true);
  290. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (50));
  291. Assert.AreEqual (expected, l.ToArray (), "#1");
  292. Assert.IsTrue (done, "#2");
  293. }
  294. IEnumerable<IObservable<long>> IntervalSelectTakeDoEnumerable (HistoricalScheduler scheduler, List<string> l, TextWriter sw)
  295. {
  296. DateTimeOffset start = scheduler.Now;
  297. for (int i = 0; i < 5; i++) {
  298. int x = i;
  299. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (150));
  300. yield return Observable.Interval (TimeSpan.FromMilliseconds (100), scheduler)
  301. #if false
  302. .Select (v => x * 10 + v).Take (5)
  303. #else
  304. // FIXME: this select should work, but it does not give expected "i" or "x" values, likely due to some mcs bug regarding local variable volatility...
  305. // ... So I used out-of-scope value comparison here.
  306. .Select (v => (long) ((scheduler.Now - start).TotalMilliseconds / 20) + v).Take (5)
  307. #endif
  308. .Do (v => l.Add (String.Format ("{0:ss.fff}: {1} {2}", scheduler.Now, i, v)), () => sw.WriteLine ());
  309. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (50));
  310. }
  311. }
  312. [Test]
  313. [ExpectedException (typeof (MyException))]
  314. public void FirstOrDefault ()
  315. {
  316. var source = Observable.Throw<int> (new MyException ());
  317. var ret = source.FirstOrDefault ();
  318. }
  319. [Test] // some practical test
  320. public void IntervalSelectTakeDo ()
  321. {
  322. var scheduler = new HistoricalScheduler ();
  323. var l = new List<string> ();
  324. var sw = new StringWriter () { NewLine = "\n" };
  325. foreach (var o in IntervalSelectTakeDoEnumerable (scheduler, l, TextWriter.Null))
  326. o.Subscribe (v => {}); // dummy
  327. scheduler.AdvanceBy (TimeSpan.FromSeconds (3));
  328. l.Sort ();
  329. foreach (var s in l)
  330. sw.WriteLine (s);
  331. string expected = @"00.250: 1 12
  332. 00.350: 1 18
  333. 00.450: 2 22
  334. 00.450: 2 24
  335. 00.550: 2 28
  336. 00.550: 2 30
  337. 00.650: 3 32
  338. 00.650: 3 34
  339. 00.650: 3 36
  340. 00.750: 3 38
  341. 00.750: 3 40
  342. 00.850: 4 42
  343. 00.850: 4 44
  344. 00.850: 4 46
  345. 00.950: 4 48
  346. 00.950: 4 50
  347. 01.050: 5 52
  348. 01.050: 5 54
  349. 01.050: 5 56
  350. 01.150: 5 58
  351. 01.150: 5 60
  352. 01.250: 5 64
  353. 01.250: 5 66
  354. 01.350: 5 70
  355. 01.450: 5 76
  356. ".Replace ("\r", "").Replace ("\t", "");
  357. Assert.AreEqual (expected, sw.ToString (), "#1");
  358. }
  359. [Test]
  360. public void Concat4 ()
  361. {
  362. var scheduler = new HistoricalScheduler ();
  363. var sw = new StringWriter () { NewLine = "\n" };
  364. var source = IntervalSelectTakeDoEnumerable (scheduler, new List<string> (), sw).ToObservable ().Concat ();
  365. source.Subscribe (v => sw.Write ("{0} ", v), () => sw.WriteLine ());
  366. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (3000));
  367. var expected = @"12 18 24 30 36
  368. 37 43 49 55 61
  369. 62 68 74 80 86
  370. 87 93 99 105 111
  371. 112 118 124 130 136
  372. ".Replace ("\r", "").Replace ("\t", "");
  373. Assert.AreEqual (expected, sw.ToString (), "#1");
  374. }
  375. [Test]
  376. public void Delay ()
  377. {
  378. var scheduler = new HistoricalScheduler ();
  379. var source = Observable.Return (2).Delay (TimeSpan.FromMilliseconds (50), scheduler).Materialize ();
  380. var l = new List<NotificationKind> ();
  381. bool done = false;
  382. source.Subscribe (v => l.Add (v.Kind), () => done = true);
  383. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (50));
  384. Assert.IsTrue (done, "#2");
  385. Assert.AreEqual (new NotificationKind [] {
  386. NotificationKind.OnNext,
  387. NotificationKind.OnCompleted }, l.ToArray (), "#3");
  388. }
  389. [Test]
  390. public void Delay2 ()
  391. {
  392. // github issue #12
  393. var scheduler = new HistoricalScheduler ();
  394. var source = Observable.Interval (TimeSpan.FromSeconds (1), scheduler).Take (5).Timestamp ();
  395. var delayed = source.Delay (TimeSpan.FromSeconds (4), scheduler).Timestamp ();
  396. bool done = false;
  397. delayed.Subscribe (item => Assert.IsTrue (item.Value.Timestamp < item.Timestamp, "not delayed"), () => done = true);
  398. scheduler.AdvanceBy (TimeSpan.FromSeconds (3));
  399. Assert.IsFalse (done, "#1");
  400. scheduler.AdvanceBy (TimeSpan.FromSeconds (10));
  401. Assert.IsTrue (done, "#2");
  402. }
  403. [Test]
  404. public void Distinct ()
  405. {
  406. var source = new int [] {0, 1, 1, 3, 3, 1}.ToObservable ().Distinct ();
  407. string s = null;
  408. source.Subscribe (i => s += i, ex => s += "error:" + ex.GetType (), () => s += "done");
  409. Assert.AreEqual ("013done", s, "#1");
  410. }
  411. [Test]
  412. public void DistinctError ()
  413. {
  414. var source = new int [] {0, 1, 1, 3, 3, 1}.ToObservable ().Concat (Observable.Throw<int> (new SystemException ())).Distinct ();
  415. string s = null;
  416. source.Subscribe (i => s += i, ex => s += "error:" + ex.GetType (), () => s += "done");
  417. Assert.AreEqual ("013error:System.SystemException", s, "#1");
  418. }
  419. [Test]
  420. public void DistinctUntilChanged ()
  421. {
  422. var l = new List<int> ();
  423. var source = new int [] {3, 3, 5, 5, 4, 3}.ToObservable ().DistinctUntilChanged<int,int> (i => i);
  424. bool done = false;
  425. source.Subscribe (v => l.Add (v), () => done = true);
  426. SpinWait.SpinUntil (() => done, 1000);
  427. Assert.IsTrue (done, "#1");
  428. Assert.AreEqual (new int [] {3, 5, 4, 3}, l.ToArray (), "#2");
  429. }
  430. [Test]
  431. public void DistinctUntilChangedErrorSequence ()
  432. {
  433. string s = null;
  434. var source = new int [] {3, 3, 5, 5, 4, 3}.ToObservable ().Concat (Observable.Throw<int> (new SystemException ())).DistinctUntilChanged<int,int> (i => i);
  435. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => Assert.Fail ("Should not reach OnCompleted"));
  436. Assert.AreEqual ("3543error:System.SystemException", s, "#1");
  437. }
  438. [Test]
  439. [ExpectedException (typeof (MyException))]
  440. public void DistinctUntilChangedErrorSelector ()
  441. {
  442. var source = new int [] {3, 3, 5, 5, 4, 3}.ToObservable ().DistinctUntilChanged<int,int> (i => { throw new MyException (); });
  443. source.Subscribe (v => {} , ex => Assert.Fail ("Should not reach OnError"), () => Assert.Fail ("Should not reach OnCompleted"));
  444. }
  445. [Test]
  446. public void Do ()
  447. {
  448. int i = 0, j = 0, k = 0;
  449. var source = Observable.Range (0, 5).Do (v => k += v);
  450. source.Subscribe (v => i += v, () => j++);
  451. Assert.IsTrue (SpinWait.SpinUntil (() => j != 0, 1000), "#1");
  452. Assert.AreEqual (10, i, "#2");
  453. Assert.AreEqual (10, k, "#3");
  454. }
  455. [Test]
  456. public void Generate ()
  457. {
  458. var source = Observable.Generate (-1, x => x < 5, x => x + 1, x => x);
  459. int i = 0;
  460. var dis = new CompositeDisposable ();
  461. int done = 0;
  462. // test multiple subscription
  463. foreach (var iter in Enumerable.Range (0, 5))
  464. dis.Add (source.Subscribe (v => i += v, () => done++));
  465. Assert.IsTrue (SpinWait.SpinUntil (() => done == 5, 1000), "#1");
  466. dis.Dispose ();
  467. Assert.AreEqual (45, i, "#2");
  468. }
  469. [Test]
  470. [ExpectedException (typeof (MyException))]
  471. public void GenerateErrorSelector ()
  472. {
  473. var source = Observable.Generate<int,int> (-1, x => x < 5, x => x + 1, x => { throw new MyException (); });
  474. source.Subscribe (v => {} , ex => Assert.Fail ("Should not reach OnError"), () => Assert.Fail ("Should not reach OnCompleted"));
  475. }
  476. [Test]
  477. public void GroupBy ()
  478. {
  479. var dic = new Dictionary<int, List<int>> ();
  480. var source = Observable.Range (0, 20).GroupBy (i => i / 5);
  481. bool done = false;
  482. var dis = new CompositeDisposable ();
  483. dis.Add (source.Subscribe (g => dis.Add (g.Subscribe (v => {
  484. List<int> l;
  485. if (!dic.TryGetValue (g.Key, out l)) {
  486. l = new List<int> ();
  487. dic [g.Key] = l;
  488. }
  489. l.Add (v);
  490. })), () => done = true));
  491. SpinWait.SpinUntil (() => done, 1000);
  492. Assert.IsTrue (done, "#1");
  493. Assert.AreEqual (new int [] {0, 1, 2, 3, 4}, dic [0].ToArray (), "#2");
  494. Assert.AreEqual (new int [] {15, 16, 17, 18, 19}, dic [3].ToArray (), "#3");
  495. Assert.AreEqual (4, dic.Count, "#4");
  496. }
  497. [Test]
  498. public void GroupBySequenceError ()
  499. {
  500. var source = new int[] { 0, 1, 1, 3, 3, 1 }.ToObservable ().Concat (Observable.Throw<int> (new SystemException ())).GroupBy (k => k);
  501. string s = null;
  502. source.Subscribe (i => i.ToEnumerable ().Select (j => s += j), ex=> s += "error:" + ex.GetType (), () => s += "done");
  503. Assert.AreEqual ("error:System.SystemException", s, "#1");
  504. }
  505. [Test]
  506. [ExpectedException (typeof (MyException))]
  507. public void GroupBySelectorError ()
  508. {
  509. var source = Observable.Range (0, 20).GroupBy<int,int> (i => { throw new MyException (); });
  510. source.Subscribe (v => {} , ex => Assert.Fail ("Should not reach OnError"), () => Assert.Fail ("Should not reach OnCompleted"));
  511. }
  512. [Test]
  513. public void GroupByUntilSequenceError ()
  514. {
  515. var scheduler = new HistoricalScheduler ();
  516. var source = new int[] { 0, 1, 1, 3, 3, 1 }.ToObservable ().Concat (Observable.Throw<int> (new SystemException ())).GroupByUntil (k => k, x => Observable.Interval (TimeSpan.FromSeconds (1), scheduler).Take (1));
  517. string s = null;
  518. source.Subscribe (i => i.ToEnumerable ().Select (j => s += j), ex=> s += "error:" + ex.GetType (), () => s += "done");
  519. Assert.AreEqual ("error:System.SystemException", s, "#1");
  520. }
  521. [Test]
  522. public void GroupByUntilDurationSequenceError ()
  523. {
  524. var scheduler = new HistoricalScheduler ();
  525. var source = new int[] { 0, 1, 1, 3, 3, 1 }.ToObservable ().GroupByUntil (k => k, x => Observable.Throw<int> (new SystemException ()));
  526. string s = null;
  527. source.Subscribe (i => i.ToEnumerable ().Select (j => s += j), ex=> s += "error:" + ex.GetType (), () => s += "done");
  528. Assert.AreEqual ("error:System.SystemException", s, "#1");
  529. }
  530. [Test]
  531. public void GroupJoin ()
  532. {
  533. var scheduler = new HistoricalScheduler ();
  534. var source = Observable.GroupJoin (
  535. Observable.Interval (TimeSpan.FromMilliseconds (500), scheduler).Take (10),
  536. Observable.Interval (TimeSpan.FromMilliseconds (800), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  537. l => Observable.Interval (TimeSpan.FromMilliseconds (1500), scheduler),
  538. r => Observable.Interval (TimeSpan.FromMilliseconds (1600), scheduler),
  539. (l, rob) => new { Left = l, Rights = rob }
  540. );
  541. bool done = false;
  542. bool [,] results = new bool [10, 10];
  543. bool [] groupDone = new bool [10];
  544. source.Subscribe (
  545. v => v.Rights.Subscribe (
  546. r => results [v.Left, r] = true,
  547. () => groupDone [v.Left] = true),
  548. () => done = true);
  549. scheduler.AdvanceBy (TimeSpan.FromSeconds (15));
  550. Assert.IsTrue (done, "#1");
  551. Assert.AreEqual (-1, Array.IndexOf (groupDone, false), "#2");
  552. int [] rstarts = new int [] {0, 0, 0, 0, 0, 0, 1, 1, 2, 3};
  553. int [] rends = new int [] {0, 0, 1, 2, 2, 3, 3, 4, 5, 5};
  554. for (int l = 0; l < 10; l++)
  555. for (int r = 0; r < 10; r++)
  556. Assert.AreEqual (rstarts [l] <= r && r <= rends [l], results [l, r], String.Format ("({0}, {1})", l, r));
  557. }
  558. [Test]
  559. public void GroupJoin2 ()
  560. {
  561. // almost identical to the previous one, but without delay. And I only test some corner case that could result in difference.
  562. var scheduler = new HistoricalScheduler ();
  563. var source = Observable.GroupJoin (
  564. Observable.Interval (TimeSpan.FromMilliseconds (500), scheduler).Take (10),
  565. Observable.Interval (TimeSpan.FromMilliseconds (800), scheduler),
  566. l => Observable.Interval (TimeSpan.FromMilliseconds (1500), scheduler),
  567. r => Observable.Interval (TimeSpan.FromMilliseconds (1600), scheduler),
  568. (l, rob) => new { Left = l, Rights = rob }
  569. );
  570. bool done = false;
  571. bool [,] results = new bool [10, 10];
  572. bool [] groupDone = new bool [10];
  573. source.Subscribe (
  574. v => v.Rights.Subscribe (
  575. r => results [v.Left, r] = true,
  576. () => groupDone [v.Left] = true),
  577. () => done = true);
  578. scheduler.AdvanceBy (TimeSpan.FromSeconds (15));
  579. Assert.IsTrue (done, "#1");
  580. // this value could be published *IF* unsubscription is
  581. // handled *after* 7 is published as a left value.
  582. // Rx does not publish this, likely means a right value
  583. // at the end moment of rightDuration is *not* published
  584. // ... so we do that too.
  585. Assert.IsFalse (results [7, 2], "#2");
  586. }
  587. [Test]
  588. public void GroupJoinLeftSequenceError ()
  589. {
  590. var scheduler = new HistoricalScheduler ();
  591. var source = Observable.GroupJoin (
  592. Observable.Throw<int> (new SystemException ()),
  593. Observable.Interval (TimeSpan.FromMilliseconds (800), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  594. l => Observable.Interval (TimeSpan.FromMilliseconds (1500), scheduler),
  595. r => Observable.Interval (TimeSpan.FromMilliseconds (1600), scheduler),
  596. (l, rob) => new { Left = l, Rights = rob }
  597. );
  598. string s = null;
  599. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  600. scheduler.AdvanceBy (TimeSpan.FromSeconds (15));
  601. Assert.AreEqual ("error:System.SystemException", s, "#1");
  602. }
  603. [Test]
  604. public void GroupJoinRightSequenceError ()
  605. {
  606. var scheduler = new HistoricalScheduler ();
  607. var source = Observable.GroupJoin (
  608. Observable.Interval (TimeSpan.FromMilliseconds (800), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  609. Observable.Throw<int> (new SystemException ()),
  610. l => Observable.Interval (TimeSpan.FromMilliseconds (1500), scheduler),
  611. r => Observable.Interval (TimeSpan.FromMilliseconds (1600), scheduler),
  612. (l, rob) => new { Left = l, Rights = rob }
  613. );
  614. string s = null;
  615. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  616. scheduler.AdvanceBy (TimeSpan.FromSeconds (15));
  617. Assert.AreEqual ("error:System.SystemException", s, "#1");
  618. }
  619. [Test]
  620. public void GroupJoinLeftDurationError ()
  621. {
  622. var scheduler = new HistoricalScheduler ();
  623. var source = Observable.GroupJoin (
  624. Observable.Interval (TimeSpan.FromMilliseconds (500), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  625. Observable.Interval (TimeSpan.FromMilliseconds (800), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  626. l => Observable.Throw<int> (new SystemException ()),
  627. r => Observable.Interval (TimeSpan.FromMilliseconds (1600), scheduler),
  628. (l, rob) => new { Left = l, Rights = rob }
  629. );
  630. string s = null;
  631. source.Subscribe (v => {}, ex => s += "error:" + ex.GetType (), () => s += "done");
  632. scheduler.AdvanceBy (TimeSpan.FromSeconds (15));
  633. // LAMESPEC: shouldn't this also raise OnError() ? GroupByUntil() does so.
  634. Assert.AreEqual ("error:System.SystemException", s, "#1");
  635. }
  636. [Test]
  637. public void GroupJoinRightDurationError ()
  638. {
  639. var scheduler = new HistoricalScheduler ();
  640. var source = Observable.GroupJoin (
  641. Observable.Interval (TimeSpan.FromMilliseconds (500), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  642. Observable.Interval (TimeSpan.FromMilliseconds (800), scheduler).Delay (TimeSpan.FromSeconds (1), scheduler),
  643. l => Observable.Interval (TimeSpan.FromMilliseconds (1600), scheduler),
  644. r => Observable.Throw<int> (new SystemException ()),
  645. (l, rob) => new { Left = l, Rights = rob }
  646. );
  647. string s = null;
  648. source.Subscribe (v => {}, ex => s += "error:" + ex.GetType (), () => s += "done");
  649. scheduler.AdvanceBy (TimeSpan.FromSeconds (15));
  650. // LAMESPEC: shouldn't this also raise OnError() ? GroupByUntil() does so.
  651. Assert.AreEqual ("error:System.SystemException", s, "#1");
  652. }
  653. [Test] // this test is processing-speed dependent, but (unlike other tests) I think testing this with default (ThreadPool) scheduler should make sense...
  654. public void Interval ()
  655. {
  656. var interval = Observable.Interval (TimeSpan.FromMilliseconds (100)).Take (6);
  657. long v1 = 0, v2 = 0;
  658. int done = 0;
  659. long diff = 0;
  660. var sub1 = interval.Subscribe (v => v1++, () => { done++; diff = v1 - v2; });
  661. Thread.Sleep (400);
  662. var sub2 = interval.Subscribe (v => v2++, () => done++);
  663. Assert.IsTrue (v1 != v2, "#1"); // at arbitrary time
  664. SpinWait.SpinUntil (() => done == 2, 1000);
  665. Assert.AreEqual (2, done, "#2");
  666. // test that two sequences runs in different time, same speed.
  667. Assert.IsTrue (diff > 2, "#3");
  668. sub1.Dispose ();
  669. sub2.Dispose ();
  670. }
  671. [Test]
  672. public void LongCountErrorSequence ()
  673. {
  674. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).LongCount ();
  675. string s = null;
  676. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  677. Assert.AreEqual ("error:System.SystemException", s, "#1");
  678. }
  679. [Test]
  680. public void MaxByErrorSequence ()
  681. {
  682. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).MaxBy (v => v);
  683. string s = null;
  684. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  685. Assert.AreEqual ("error:System.SystemException", s, "#1");
  686. }
  687. [Test]
  688. [ExpectedException (typeof (MyException))]
  689. public void MaxByErrorSelector ()
  690. {
  691. var source = Observable.Range (0, 3).MaxBy<int,int> (v => { throw new MyException (); });
  692. string s = null;
  693. source.Subscribe (v => s += v, ex => Assert.Fail ("should not reach OnError"), () => Assert.Fail ("should not reach OnCompleted"));
  694. }
  695. [Test]
  696. public void MinByErrorSequence ()
  697. {
  698. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).MinBy (v => v);
  699. string s = null;
  700. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  701. Assert.AreEqual ("error:System.SystemException", s, "#1");
  702. }
  703. [Test]
  704. [ExpectedException (typeof (MyException))]
  705. public void MinByErrorSelector ()
  706. {
  707. var source = Observable.Range (0, 3).MaxBy<int,int> (v => { throw new MyException (); });
  708. string s = null;
  709. source.Subscribe (v => s += v, ex => Assert.Fail ("should not reach OnError"), () => Assert.Fail ("should not reach OnCompleted"));
  710. }
  711. [Test]
  712. [ExpectedException (typeof (MyException))]
  713. public void RangeErrorScheduler ()
  714. {
  715. var source = Observable.Range (0, 3, new ErrorScheduler ());
  716. source.Subscribe (v => {} , ex => Assert.Fail ("Should not reach OnError"), () => Assert.Fail ("Should not reach OnCompleted"));
  717. }
  718. [Test]
  719. public void Retry ()
  720. {
  721. var source = Observable.Range (0, 4).Concat (Observable.Throw<int> (new Exception ("failure"))).Retry (2);
  722. var i = 0;
  723. bool done = false, error = false;
  724. var dis = source.Subscribe (
  725. v => i += v,
  726. ex => { error = true; done = true; Assert.AreEqual ("failure", ex.Message, "#1"); },
  727. () => Assert.Fail ("should not complete"));
  728. Assert.IsTrue (SpinWait.SpinUntil (() => done, 500), "#2");
  729. dis.Dispose ();
  730. Assert.IsTrue (error, "#3");
  731. Assert.AreEqual (12, i, "#4");
  732. }
  733. [Test]
  734. public void RetryZero ()
  735. {
  736. var source = Observable.Range (0, 4).Concat (Observable.Throw<int> (new Exception ("failure"))).Retry (0);
  737. bool done = false;
  738. var dis = source.Subscribe (
  739. v => Assert.Fail ("should not increment", "#1"),
  740. ex => Assert.Fail ("should not fail", "#2"),
  741. () => done = true
  742. );
  743. Assert.IsTrue (SpinWait.SpinUntil (() => done, 500), "#3");
  744. Assert.IsTrue (done, "#4");
  745. dis.Dispose ();
  746. }
  747. [Test]
  748. public void Sample ()
  749. {
  750. var l = new List<long> ();
  751. var l2 = new List<long> ();
  752. var scheduler = new HistoricalScheduler ();
  753. var source = Observable.Interval (TimeSpan.FromMilliseconds (300), scheduler).Delay (TimeSpan.FromSeconds (2), scheduler);
  754. source.Subscribe (v => l.Add (v));
  755. var sampler = Observable.Interval (TimeSpan.FromMilliseconds (1000), scheduler).Take (10);
  756. var o = source.Sample (sampler);
  757. bool done = false;
  758. o.Subscribe (v => l2.Add (v), () => done = true);
  759. for (int i = 0; i < 50; i++)
  760. scheduler.AdvanceBy (TimeSpan.FromMilliseconds (300));
  761. //scheduler.AdvanceBy (TimeSpan.FromMilliseconds (15000));
  762. Assert.AreEqual (43, l.Count, "#1");
  763. Assert.AreEqual (new long [] {2, 5, 8, 12, 15, 18, 22, 25}, l2.ToArray (), "#2");
  764. Assert.IsFalse (done, "#3"); // while sampler finishes, sample observable never does.
  765. }
  766. [Test]
  767. public void SelectErrorSequence ()
  768. {
  769. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).Select (v => v);
  770. string s = null;
  771. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  772. Assert.AreEqual ("012error:System.SystemException", s, "#1");
  773. }
  774. [Test]
  775. [ExpectedException (typeof (MyException))]
  776. public void SelectErrorSelector ()
  777. {
  778. var source = Observable.Range (0, 3).Select<int,int> (v => { throw new MyException (); });
  779. string s = null;
  780. source.Subscribe (v => s += v, ex => Assert.Fail ("should not reach OnError"), () => Assert.Fail ("should not reach OnCompleted"));
  781. }
  782. [Test]
  783. public void SelectManyObservable ()
  784. {
  785. var scheduler = new HistoricalScheduler ();
  786. Func<int,IObservable<int>> f = x => Observable.Return (x).Delay (TimeSpan.FromSeconds (1), scheduler);
  787. var source = Observable.Range (0, 5).SelectMany (n => f (n));
  788. var l = new List<int> ();
  789. bool done = false;
  790. var dis = source.Subscribe (v => l.Add (v), () => done = true);
  791. Assert.IsFalse (done ,"#1");
  792. scheduler.AdvanceBy (TimeSpan.FromSeconds (1));
  793. Assert.AreEqual (new int [] {0, 1, 2, 3, 4}, l.ToArray (), "#2");
  794. Assert.IsTrue (done, "#3");
  795. }
  796. [Test]
  797. public void SkipLastErrorSequence ()
  798. {
  799. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).SkipLast (3); // note that this could still result in OnError
  800. string s = null;
  801. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  802. Assert.AreEqual ("error:System.SystemException", s, "#1");
  803. }
  804. [Test]
  805. public void Start ()
  806. {
  807. bool next = false;
  808. try {
  809. Observable.Start (() => { Thread.Sleep (200); throw new MyException (); }); // run it in another thread.
  810. next = true;
  811. } catch (MyException) {
  812. Assert.IsTrue (next, "#1");
  813. }
  814. }
  815. [Test]
  816. public void TakeLastErrorSequence ()
  817. {
  818. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).TakeLast (3);
  819. string s = null;
  820. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  821. Assert.AreEqual ("error:System.SystemException", s, "#1");
  822. }
  823. [Test]
  824. public void TakeWhile ()
  825. {
  826. var source = Observable.Range (0, 5).TakeWhile (i => i < 3);
  827. string s = null;
  828. source.Subscribe (i => s += i, () => s += "done");
  829. Assert.AreEqual ("012done", s, "#1");
  830. }
  831. [Test]
  832. public void TakeWhileErrorSequence ()
  833. {
  834. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).TakeWhile (i => i < 3);
  835. string s = null;
  836. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  837. Assert.AreEqual ("012error:System.SystemException", s, "#1");
  838. }
  839. [Test]
  840. [ExpectedException (typeof (MyException))]
  841. public void TakeWhileErrorSelector ()
  842. {
  843. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).TakeWhile (i => { throw new MyException (); });
  844. string s = null;
  845. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  846. }
  847. [Test]
  848. public void Throttle ()
  849. {
  850. var scheduler = new HistoricalScheduler ();
  851. var source = Observable.Range (1, 3).Concat (Observable.Return (2).Delay (TimeSpan.FromMilliseconds (100), scheduler)).Throttle (TimeSpan.FromMilliseconds (50), scheduler);
  852. bool done = false;
  853. var l = new List<int> ();
  854. var dis = source.Subscribe (v => l.Add (v), () => done = true);
  855. scheduler.AdvanceBy (TimeSpan.FromSeconds (1));
  856. Assert.IsTrue (done, "#1");
  857. Assert.AreEqual (new int [] {3, 2}, l.ToArray (), "#2");
  858. dis.Dispose ();
  859. }
  860. [Test]
  861. public void TimeoutInTime ()
  862. {
  863. var scheduler = new HistoricalScheduler ();
  864. var source = Observable.Range (0, 3).Timeout (TimeSpan.FromSeconds (1), scheduler);
  865. string s = null;
  866. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  867. Assert.AreEqual ("012done", s, "#1");
  868. }
  869. [Test]
  870. public void TimeoutOutOfTime ()
  871. {
  872. var scheduler = new HistoricalScheduler ();
  873. var source = Observable.Interval (TimeSpan.FromSeconds (1), scheduler).Take (2).Timeout (TimeSpan.FromSeconds (1), scheduler);
  874. string s = null;
  875. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  876. scheduler.AdvanceBy (TimeSpan.FromSeconds (5));
  877. Assert.AreEqual ("error:System.TimeoutException", s, "#1");
  878. }
  879. [Test]
  880. public void TimeoutErrorSelector ()
  881. {
  882. var scheduler = new HistoricalScheduler ();
  883. var source = Observable.Range (0, 3).Concat (Observable.Throw<int> (new SystemException ())).Timeout (TimeSpan.FromSeconds (1), scheduler);
  884. string s = null;
  885. source.Subscribe (v => s += v, ex => s += "error:" + ex.GetType (), () => s += "done");
  886. Assert.AreEqual ("012error:System.SystemException", s, "#1");
  887. }
  888. class Resource : IDisposable
  889. {
  890. public bool Disposed;
  891. public Resource ()
  892. {
  893. }
  894. public void Dispose ()
  895. {
  896. Disposed = true;
  897. }
  898. public IObservable<int> GetObservable ()
  899. {
  900. return Observable.Range (0, 3);
  901. }
  902. }
  903. [Test]
  904. public void Using ()
  905. {
  906. var res = new Resource ();
  907. var ro = Observable.Using<int,Resource> (() => res, r => r.GetObservable ());
  908. Assert.IsFalse (res.Disposed, "#1");
  909. int i = 0;
  910. bool done = false;
  911. var dis = ro.Subscribe (v => i += v, () => done = true);
  912. Assert.IsTrue (SpinWait.SpinUntil (() => done, TimeSpan.FromSeconds (1)), "#2");
  913. Assert.IsFalse (res.Disposed, "#2");
  914. dis.Dispose ();
  915. Assert.IsTrue (res.Disposed, "#3");
  916. }
  917. [Test]
  918. public void Where ()
  919. {
  920. var source = Observable.Range (0, 5).Where (i => i < 3);
  921. string s = null;
  922. source.Subscribe (i => s += i, () => s += "done");
  923. Assert.AreEqual ("012done", s, "#1");
  924. }
  925. [Test]
  926. public void WindowCounts ()
  927. {
  928. string expected = "(0,0)(1,0)(2,0)(3,0)(3,1)(4,0)(4,1)(5,1)(6,1)(6,2)(7,1)(7,2)(8,2)(9,2)(9,3)(10,2)(10,3)(11,3)(12,3)(12,4)(13,3)(13,4)(14,4)(15,4)(15,5)(16,4)(16,5)(17,5)(18,5)(18,6)(19,5)(19,6)done";
  929. WindowCounts (5, 3, 7, expected);
  930. }
  931. [Test]
  932. public void WindowCounts2 ()
  933. {
  934. string expected = "(0,0)(1,0)(2,0)(5,1)(6,1)(7,1)(10,2)(11,2)(12,2)(15,3)(16,3)(17,3)done";
  935. WindowCounts (3, 5, 4, expected);
  936. }
  937. void WindowCounts (int count, int skip, int windowCount, string expected)
  938. {
  939. var scheduler = new HistoricalScheduler ();
  940. var sources = Observable.Range (0, 20).Window (count, skip);
  941. int windows = 0;
  942. var sw = new StringWriter () { NewLine = "\n" };
  943. bool [] windowDone = new bool [windowCount];
  944. sources.Subscribe (source => {
  945. int w = windows++;
  946. source.Subscribe (v => sw.Write ("({0},{1})", v, w), () => windowDone [w] = true);
  947. }, () => sw.Write ("done"));
  948. Assert.AreEqual (expected, sw.ToString (), "#1");
  949. Assert.AreEqual (-1, Array.IndexOf (windowDone, false), "#2");
  950. }
  951. [Test]
  952. public void WindowTimeSpans ()
  953. {
  954. var scheduler = new HistoricalScheduler ();
  955. var interval = TimeSpan.FromMilliseconds (100);
  956. var span = TimeSpan.FromMilliseconds (300);
  957. var shift = TimeSpan.FromMilliseconds (500);
  958. var total = TimeSpan.FromMilliseconds (1500);
  959. var sw = new StringWriter () { NewLine = "\n" };
  960. var sources = Observable.Interval (interval, scheduler).Take (15).Window (span, shift, scheduler);
  961. int windows = 0;
  962. bool [] windowDone = new bool [4];
  963. sources.Subscribe (source => {
  964. int w = windows++;
  965. source.Subscribe (v => sw.WriteLine("{0:ss.fff} {1} [{2}]", scheduler.Now, v, w), () => windowDone [w] = true);
  966. }, () => sw.WriteLine ("done"));
  967. scheduler.AdvanceBy (total);
  968. string expected = @"00.100 0 [0]
  969. 00.200 1 [0]
  970. 00.500 4 [1]
  971. 00.600 5 [1]
  972. 00.700 6 [1]
  973. 01.000 9 [2]
  974. 01.100 10 [2]
  975. 01.200 11 [2]
  976. 01.500 14 [3]
  977. done
  978. ".Replace ("\t", "").Replace ("\r", "");
  979. Assert.AreEqual (expected, sw.ToString (), "#1");
  980. Assert.AreEqual (-1, Array.IndexOf (windowDone, false), "#2");
  981. }
  982. [Test]
  983. public void WindowTimeSpans2 ()
  984. {
  985. var scheduler = new HistoricalScheduler ();
  986. var interval = TimeSpan.FromMilliseconds (100);
  987. var span = TimeSpan.FromMilliseconds (500);
  988. var shift = TimeSpan.FromMilliseconds (300);
  989. var total = TimeSpan.FromMilliseconds (1500);
  990. var sw = new StringWriter () { NewLine = "\n" };
  991. var sources = Observable.Interval (interval, scheduler).Take (15).Window (span, shift, scheduler);
  992. int windows = 0;
  993. bool [] windowDone = new bool [6];
  994. sources.Subscribe (source => {
  995. int w = windows++;
  996. source.Subscribe (v => sw.WriteLine("{0:ss.fff} {1} [{2}]", scheduler.Now, v, w), () => windowDone [w] = true);
  997. }, () => sw.WriteLine ("done"));
  998. scheduler.AdvanceBy (total);
  999. string expected = @"00.100 0 [0]
  1000. 00.200 1 [0]
  1001. 00.300 2 [0]
  1002. 00.300 2 [1]
  1003. 00.400 3 [0]
  1004. 00.400 3 [1]
  1005. 00.500 4 [1]
  1006. 00.600 5 [1]
  1007. 00.600 5 [2]
  1008. 00.700 6 [1]
  1009. 00.700 6 [2]
  1010. 00.800 7 [2]
  1011. 00.900 8 [2]
  1012. 00.900 8 [3]
  1013. 01.000 9 [2]
  1014. 01.000 9 [3]
  1015. 01.100 10 [3]
  1016. 01.200 11 [3]
  1017. 01.200 11 [4]
  1018. 01.300 12 [3]
  1019. 01.300 12 [4]
  1020. 01.400 13 [4]
  1021. 01.500 14 [4]
  1022. 01.500 14 [5]
  1023. done
  1024. ".Replace ("\t", "").Replace ("\r", "");
  1025. Assert.AreEqual (expected, sw.ToString (), "#1");
  1026. Assert.AreEqual (-1, Array.IndexOf (windowDone, false), "#2");
  1027. }
  1028. }
  1029. }