FromEventTest.cs 13 KB

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