FromEventTest.cs 13 KB

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