FromEventTest.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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.Concurrency;
  8. using System.Reactive.Linq;
  9. using System.Threading;
  10. using Microsoft.Reactive.Testing;
  11. using Microsoft.VisualStudio.TestTools.UnitTesting;
  12. using Assert = Xunit.Assert;
  13. namespace ReactiveTests.Tests
  14. {
  15. [TestClass]
  16. public class FromEventTest : ReactiveTest
  17. {
  18. [TestMethod]
  19. public void FromEvent_ArgumentChecking()
  20. {
  21. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }, h => { }));
  22. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, default, h => { }));
  23. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, h => { }, default));
  24. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }));
  25. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => { }, default));
  26. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(default, h => { }));
  27. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(h => { }, default));
  28. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(default, h => { }));
  29. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(h => { }, default));
  30. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }, h => { }, Scheduler.Default));
  31. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, default, h => { }, Scheduler.Default));
  32. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, h => { }, default, Scheduler.Default));
  33. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, h => { }, h => { }, default));
  34. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }, Scheduler.Default));
  35. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => { }, default, Scheduler.Default));
  36. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => { }, h => { }, default));
  37. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(default, h => { }, Scheduler.Default));
  38. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(h => { }, default, Scheduler.Default));
  39. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(h => { }, h => { }, default));
  40. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(default, h => { }, Scheduler.Default));
  41. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(h => { }, default, Scheduler.Default));
  42. ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(h => { }, h => { }, default));
  43. }
  44. [TestMethod]
  45. public void FromEvent_Action()
  46. {
  47. var fe = new FromEvent();
  48. var xs = Observable.FromEvent(h => fe.A += h, h => fe.A -= h);
  49. fe.OnA();
  50. var n = 0;
  51. var d = xs.Subscribe(_ => n++);
  52. fe.OnA();
  53. fe.OnA();
  54. d.Dispose();
  55. fe.OnA();
  56. Assert.Equal(2, n);
  57. }
  58. [TestMethod]
  59. public void FromEvent_ActionOfInt()
  60. {
  61. var fe = new FromEvent();
  62. var xs = Observable.FromEvent<int>(h => fe.B += h, h => fe.B -= h);
  63. fe.OnB(1);
  64. var n = 0;
  65. var d = xs.Subscribe(x => n += x);
  66. fe.OnB(2);
  67. fe.OnB(3);
  68. d.Dispose();
  69. fe.OnB(4);
  70. Assert.Equal(2 + 3, n);
  71. }
  72. [TestMethod]
  73. public void FromEvent_ActionOfInt_SpecifiedExplicitly()
  74. {
  75. var fe = new FromEvent();
  76. var xs = Observable.FromEvent<Action<int>, int>(h => fe.B += h, h => fe.B -= h);
  77. fe.OnB(1);
  78. var n = 0;
  79. var d = xs.Subscribe(x => n += x);
  80. fe.OnB(2);
  81. fe.OnB(3);
  82. d.Dispose();
  83. fe.OnB(4);
  84. Assert.Equal(2 + 3, n);
  85. }
  86. [TestMethod]
  87. public void FromEvent_ActionOfInt_SpecifiedExplicitly_TrivialConversion()
  88. {
  89. var fe = new FromEvent();
  90. var xs = Observable.FromEvent<Action<int>, int>(h => h, h => fe.B += h, h => fe.B -= h);
  91. fe.OnB(1);
  92. var n = 0;
  93. var d = xs.Subscribe(x => n += x);
  94. fe.OnB(2);
  95. fe.OnB(3);
  96. d.Dispose();
  97. fe.OnB(4);
  98. Assert.Equal(2 + 3, n);
  99. }
  100. [TestMethod]
  101. public void FromEvent_MyAction()
  102. {
  103. var fe = new FromEvent();
  104. var xs = Observable.FromEvent<MyAction, int>(h => new MyAction(h), h => fe.C += h, h => fe.C -= h);
  105. fe.OnC(1);
  106. var n = 0;
  107. var d = xs.Subscribe(x => n += x);
  108. fe.OnC(2);
  109. fe.OnC(3);
  110. d.Dispose();
  111. fe.OnC(4);
  112. Assert.Equal(2 + 3, n);
  113. }
  114. #region Rx v2.0 behavior
  115. [TestMethod]
  116. public void FromEvent_ImplicitPublish()
  117. {
  118. var src = new MyEventSource();
  119. var addCount = 0;
  120. var remCount = 0;
  121. var xs = Observable.FromEventPattern<MyEventArgs>(h => { addCount++; src.Bar += h; }, h => { src.Bar -= h; remCount++; }, Scheduler.Immediate);
  122. Assert.Equal(0, addCount);
  123. Assert.Equal(0, remCount);
  124. src.OnBar(41);
  125. var fst = new List<int>();
  126. var d1 = xs.Subscribe(e => fst.Add(e.EventArgs.Value));
  127. Assert.Equal(1, addCount);
  128. Assert.Equal(0, remCount);
  129. src.OnBar(42);
  130. Assert.True(fst.SequenceEqual(new[] { 42 }));
  131. d1.Dispose();
  132. Assert.Equal(1, addCount);
  133. Assert.Equal(1, remCount);
  134. var snd = new List<int>();
  135. var d2 = xs.Subscribe(e => snd.Add(e.EventArgs.Value));
  136. Assert.Equal(2, addCount);
  137. Assert.Equal(1, remCount);
  138. src.OnBar(43);
  139. Assert.True(fst.SequenceEqual(new[] { 42 }));
  140. Assert.True(snd.SequenceEqual(new[] { 43 }));
  141. var thd = new List<int>();
  142. var d3 = xs.Subscribe(e => thd.Add(e.EventArgs.Value));
  143. Assert.Equal(2, addCount);
  144. Assert.Equal(1, remCount);
  145. src.OnBar(44);
  146. Assert.True(fst.SequenceEqual(new[] { 42 }));
  147. Assert.True(snd.SequenceEqual(new[] { 43, 44 }));
  148. Assert.True(thd.SequenceEqual(new[] { 44 }));
  149. d2.Dispose();
  150. Assert.Equal(2, addCount);
  151. Assert.Equal(1, remCount);
  152. src.OnBar(45);
  153. Assert.True(fst.SequenceEqual(new[] { 42 }));
  154. Assert.True(snd.SequenceEqual(new[] { 43, 44 }));
  155. Assert.True(thd.SequenceEqual(new[] { 44, 45 }));
  156. d3.Dispose();
  157. Assert.Equal(2, addCount);
  158. Assert.Equal(2, remCount);
  159. src.OnBar(46);
  160. Assert.True(fst.SequenceEqual(new[] { 42 }));
  161. Assert.True(snd.SequenceEqual(new[] { 43, 44 }));
  162. Assert.True(thd.SequenceEqual(new[] { 44, 45 }));
  163. }
  164. #if !NO_THREAD
  165. [TestMethod]
  166. public void FromEvent_SynchronizationContext()
  167. {
  168. var beforeSubscribeNull = false;
  169. var afterSubscribeNull = false;
  170. var subscribeOnCtx = false;
  171. var fstNext = false;
  172. var sndNext = false;
  173. var thdNext = false;
  174. var beforeDisposeNull = false;
  175. var afterDisposeNull = false;
  176. var disposeOnCtx = false;
  177. RunWithContext(new MyEventSyncCtx(), ctx =>
  178. {
  179. var src = new MyEventSource();
  180. var addCtx = default(SynchronizationContext);
  181. var remCtx = default(SynchronizationContext);
  182. var addEvt = new ManualResetEvent(false);
  183. var remEvt = new ManualResetEvent(false);
  184. var xs = Observable.FromEventPattern<MyEventArgs>(h => { addCtx = SynchronizationContext.Current; src.Bar += h; addEvt.Set(); }, h => { remCtx = SynchronizationContext.Current; src.Bar -= h; remEvt.Set(); });
  185. Assert.Null(addCtx);
  186. Assert.Null(remCtx);
  187. var d = default(IDisposable);
  188. var res = new List<int>();
  189. var s = new Thread(() =>
  190. {
  191. beforeSubscribeNull = SynchronizationContext.Current is null;
  192. d = xs.Subscribe(e => res.Add(e.EventArgs.Value));
  193. afterSubscribeNull = SynchronizationContext.Current is null;
  194. });
  195. s.Start();
  196. s.Join();
  197. addEvt.WaitOne();
  198. subscribeOnCtx = ReferenceEquals(addCtx, ctx);
  199. src.OnBar(42);
  200. fstNext = res.SequenceEqual(new[] { 42 });
  201. src.OnBar(43);
  202. sndNext = res.SequenceEqual(new[] { 42, 43 });
  203. var u = new Thread(() =>
  204. {
  205. beforeDisposeNull = SynchronizationContext.Current is null;
  206. d.Dispose();
  207. afterDisposeNull = SynchronizationContext.Current is null;
  208. });
  209. u.Start();
  210. u.Join();
  211. remEvt.WaitOne();
  212. disposeOnCtx = ReferenceEquals(remCtx, ctx);
  213. src.OnBar(44);
  214. thdNext = res.SequenceEqual(new[] { 42, 43 });
  215. });
  216. Assert.True(beforeSubscribeNull);
  217. Assert.True(subscribeOnCtx);
  218. Assert.True(afterSubscribeNull);
  219. Assert.True(fstNext);
  220. Assert.True(sndNext);
  221. Assert.True(thdNext);
  222. Assert.True(beforeDisposeNull);
  223. Assert.True(disposeOnCtx);
  224. Assert.True(afterDisposeNull);
  225. }
  226. private void RunWithContext<T>(T ctx, Action<T> run)
  227. where T : SynchronizationContext
  228. {
  229. var t = new Thread(() =>
  230. {
  231. SynchronizationContext.SetSynchronizationContext(ctx);
  232. run(ctx);
  233. });
  234. t.Start();
  235. t.Join();
  236. }
  237. #endif
  238. [TestMethod]
  239. public void FromEvent_Scheduler1()
  240. {
  241. RunWithScheduler((s, add, remove) => Observable.FromEvent<MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  242. }
  243. [TestMethod]
  244. public void FromEvent_Scheduler2()
  245. {
  246. RunWithScheduler((s, add, remove) => Observable.FromEvent(h => { add(); }, h => { remove(); }, s));
  247. }
  248. [TestMethod]
  249. public void FromEvent_Scheduler3()
  250. {
  251. RunWithScheduler((s, add, remove) => Observable.FromEvent<Action<MyEventArgs>, MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  252. }
  253. [TestMethod]
  254. public void FromEvent_Scheduler4()
  255. {
  256. RunWithScheduler((s, add, remove) => Observable.FromEvent<Action, MyEventArgs>(h => () => { }, h => { add(); }, h => { remove(); }, s));
  257. }
  258. private void RunWithScheduler<T>(Func<IScheduler, Action, Action, IObservable<T>> run)
  259. {
  260. var n = 0;
  261. var a = 0;
  262. var r = 0;
  263. var s = new MyEventScheduler(() => n++);
  264. var add = new Action(() => a++);
  265. var rem = new Action(() => r++);
  266. var xs = run(s, add, rem);
  267. Assert.Equal(0, n);
  268. Assert.Equal(0, a);
  269. Assert.Equal(0, r);
  270. var d1 = xs.Subscribe();
  271. Assert.Equal(1, n);
  272. Assert.Equal(1, a);
  273. Assert.Equal(0, r);
  274. var d2 = xs.Subscribe();
  275. Assert.Equal(1, n);
  276. Assert.Equal(1, a);
  277. Assert.Equal(0, r);
  278. d1.Dispose();
  279. Assert.Equal(1, n);
  280. Assert.Equal(1, a);
  281. Assert.Equal(0, r);
  282. d2.Dispose();
  283. Assert.Equal(2, n);
  284. Assert.Equal(1, a);
  285. Assert.Equal(1, r);
  286. }
  287. #endregion
  288. }
  289. }