FromEventTest.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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([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([42]));
  140. Assert.True(snd.SequenceEqual([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([42]));
  147. Assert.True(snd.SequenceEqual([43, 44]));
  148. Assert.True(thd.SequenceEqual([44]));
  149. d2.Dispose();
  150. Assert.Equal(2, addCount);
  151. Assert.Equal(1, remCount);
  152. src.OnBar(45);
  153. Assert.True(fst.SequenceEqual([42]));
  154. Assert.True(snd.SequenceEqual([43, 44]));
  155. Assert.True(thd.SequenceEqual([44, 45]));
  156. d3.Dispose();
  157. Assert.Equal(2, addCount);
  158. Assert.Equal(2, remCount);
  159. src.OnBar(46);
  160. Assert.True(fst.SequenceEqual([42]));
  161. Assert.True(snd.SequenceEqual([43, 44]));
  162. Assert.True(thd.SequenceEqual([44, 45]));
  163. }
  164. [TestMethod]
  165. public void FromEvent_SynchronizationContext()
  166. {
  167. var beforeSubscribeNull = false;
  168. var afterSubscribeNull = false;
  169. var subscribeOnCtx = false;
  170. var fstNext = false;
  171. var sndNext = false;
  172. var thdNext = false;
  173. var beforeDisposeNull = false;
  174. var afterDisposeNull = false;
  175. var disposeOnCtx = false;
  176. RunWithContext(new MyEventSyncCtx(), ctx =>
  177. {
  178. var src = new MyEventSource();
  179. var addCtx = default(SynchronizationContext);
  180. var remCtx = default(SynchronizationContext);
  181. var addEvt = new ManualResetEvent(false);
  182. var remEvt = new ManualResetEvent(false);
  183. var xs = Observable.FromEventPattern<MyEventArgs>(h => { addCtx = SynchronizationContext.Current; src.Bar += h; addEvt.Set(); }, h => { remCtx = SynchronizationContext.Current; src.Bar -= h; remEvt.Set(); });
  184. Assert.Null(addCtx);
  185. Assert.Null(remCtx);
  186. var d = default(IDisposable);
  187. var res = new List<int>();
  188. var s = new Thread(() =>
  189. {
  190. beforeSubscribeNull = SynchronizationContext.Current is null;
  191. d = xs.Subscribe(e => res.Add(e.EventArgs.Value));
  192. afterSubscribeNull = SynchronizationContext.Current is null;
  193. });
  194. s.Start();
  195. s.Join();
  196. addEvt.WaitOne();
  197. subscribeOnCtx = ReferenceEquals(addCtx, ctx);
  198. src.OnBar(42);
  199. fstNext = res.SequenceEqual([42]);
  200. src.OnBar(43);
  201. sndNext = res.SequenceEqual([42, 43]);
  202. var u = new Thread(() =>
  203. {
  204. beforeDisposeNull = SynchronizationContext.Current is null;
  205. d.Dispose();
  206. afterDisposeNull = SynchronizationContext.Current is null;
  207. });
  208. u.Start();
  209. u.Join();
  210. remEvt.WaitOne();
  211. disposeOnCtx = ReferenceEquals(remCtx, ctx);
  212. src.OnBar(44);
  213. thdNext = res.SequenceEqual([42, 43]);
  214. });
  215. Assert.True(beforeSubscribeNull);
  216. Assert.True(subscribeOnCtx);
  217. Assert.True(afterSubscribeNull);
  218. Assert.True(fstNext);
  219. Assert.True(sndNext);
  220. Assert.True(thdNext);
  221. Assert.True(beforeDisposeNull);
  222. Assert.True(disposeOnCtx);
  223. Assert.True(afterDisposeNull);
  224. }
  225. private void RunWithContext<T>(T ctx, Action<T> run)
  226. where T : SynchronizationContext
  227. {
  228. var t = new Thread(() =>
  229. {
  230. SynchronizationContext.SetSynchronizationContext(ctx);
  231. run(ctx);
  232. });
  233. t.Start();
  234. t.Join();
  235. }
  236. [TestMethod]
  237. public void FromEvent_Scheduler1()
  238. {
  239. RunWithScheduler((s, add, remove) => Observable.FromEvent<MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  240. }
  241. [TestMethod]
  242. public void FromEvent_Scheduler2()
  243. {
  244. RunWithScheduler((s, add, remove) => Observable.FromEvent(h => { add(); }, h => { remove(); }, s));
  245. }
  246. [TestMethod]
  247. public void FromEvent_Scheduler3()
  248. {
  249. RunWithScheduler((s, add, remove) => Observable.FromEvent<Action<MyEventArgs>, MyEventArgs>(h => { add(); }, h => { remove(); }, s));
  250. }
  251. [TestMethod]
  252. public void FromEvent_Scheduler4()
  253. {
  254. RunWithScheduler((s, add, remove) => Observable.FromEvent<Action, MyEventArgs>(h => () => { }, h => { add(); }, h => { remove(); }, s));
  255. }
  256. private void RunWithScheduler<T>(Func<IScheduler, Action, Action, IObservable<T>> run)
  257. {
  258. var n = 0;
  259. var a = 0;
  260. var r = 0;
  261. var s = new MyEventScheduler(() => n++);
  262. var add = new Action(() => a++);
  263. var rem = new Action(() => r++);
  264. var xs = run(s, add, rem);
  265. Assert.Equal(0, n);
  266. Assert.Equal(0, a);
  267. Assert.Equal(0, r);
  268. var d1 = xs.Subscribe();
  269. Assert.Equal(1, n);
  270. Assert.Equal(1, a);
  271. Assert.Equal(0, r);
  272. var d2 = xs.Subscribe();
  273. Assert.Equal(1, n);
  274. Assert.Equal(1, a);
  275. Assert.Equal(0, r);
  276. d1.Dispose();
  277. Assert.Equal(1, n);
  278. Assert.Equal(1, a);
  279. Assert.Equal(0, r);
  280. d2.Dispose();
  281. Assert.Equal(2, n);
  282. Assert.Equal(1, a);
  283. Assert.Equal(1, r);
  284. }
  285. #endregion
  286. }
  287. }