ControlSchedulerTest.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. #if HAS_WINFORMS
  5. using System;
  6. using System.Reactive.Concurrency;
  7. using System.Reactive.Disposables;
  8. using System.Diagnostics;
  9. using System.Threading;
  10. using System.Windows.Forms;
  11. using Xunit;
  12. using Microsoft.Reactive.Testing;
  13. namespace ReactiveTests.Tests
  14. {
  15. public class ControlSchedulerTest
  16. {
  17. [Fact]
  18. public void Ctor_ArgumentChecking()
  19. {
  20. ReactiveAssert.Throws<ArgumentNullException>(() => new ControlScheduler(null));
  21. }
  22. [Fact]
  23. public void Control()
  24. {
  25. var lbl = new Label();
  26. Assert.Same(lbl, new ControlScheduler(lbl).Control);
  27. }
  28. [Fact]
  29. public void Now()
  30. {
  31. var res = new ControlScheduler(new Label()).Now - DateTime.Now;
  32. Assert.True(res.Seconds < 1);
  33. }
  34. [Fact]
  35. public void Schedule_ArgumentChecking()
  36. {
  37. var s = new ControlScheduler(new Label());
  38. ReactiveAssert.Throws<ArgumentNullException>(() => s.Schedule(42, default(Func<IScheduler, int, IDisposable>)));
  39. ReactiveAssert.Throws<ArgumentNullException>(() => s.Schedule(42, TimeSpan.FromSeconds(1), default(Func<IScheduler, int, IDisposable>)));
  40. ReactiveAssert.Throws<ArgumentNullException>(() => s.Schedule(42, DateTimeOffset.Now, default(Func<IScheduler, int, IDisposable>)));
  41. }
  42. [Fact(Skip="Run Locally")]
  43. public void Schedule()
  44. {
  45. var evt = new ManualResetEvent(false);
  46. var id = Thread.CurrentThread.ManagedThreadId;
  47. var lbl = CreateLabel();
  48. var sch = new ControlScheduler(lbl);
  49. sch.Schedule(() => { lbl.Text = "Okay"; Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId); });
  50. sch.Schedule(() => { Assert.Equal("Okay", lbl.Text); Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId); evt.Set(); });
  51. evt.WaitOne();
  52. Application.Exit();
  53. }
  54. [Fact(Skip="Run Locally")]
  55. public void ScheduleError()
  56. {
  57. var evt = new ManualResetEvent(false);
  58. var ex = new Exception();
  59. var lbl = CreateLabelWithHandler(e => {
  60. Assert.Same(ex, e);
  61. evt.Set();
  62. });
  63. var sch = new ControlScheduler(lbl);
  64. sch.Schedule(() => { throw ex; });
  65. evt.WaitOne();
  66. Application.Exit();
  67. }
  68. [Fact(Skip="Run Locally")]
  69. public void ScheduleRelative()
  70. {
  71. ScheduleRelative_(TimeSpan.FromSeconds(0.1));
  72. }
  73. [Fact(Skip="Run Locally")]
  74. public void ScheduleRelative_Zero()
  75. {
  76. ScheduleRelative_(TimeSpan.Zero);
  77. }
  78. private void ScheduleRelative_(TimeSpan delay)
  79. {
  80. var evt = new ManualResetEvent(false);
  81. var id = Thread.CurrentThread.ManagedThreadId;
  82. var lbl = CreateLabel();
  83. var sch = new ControlScheduler(lbl);
  84. sch.Schedule(delay, () =>
  85. {
  86. lbl.Text = "Okay";
  87. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  88. sch.Schedule(() =>
  89. {
  90. Assert.Equal("Okay", lbl.Text);
  91. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  92. evt.Set();
  93. });
  94. });
  95. evt.WaitOne();
  96. Application.Exit();
  97. }
  98. [Fact(Skip="Run Locally")]
  99. public void ScheduleRelative_Nested()
  100. {
  101. var evt = new ManualResetEvent(false);
  102. var id = Thread.CurrentThread.ManagedThreadId;
  103. var lbl = CreateLabel();
  104. var sch = new ControlScheduler(lbl);
  105. sch.Schedule(TimeSpan.FromSeconds(0.1), () =>
  106. {
  107. sch.Schedule(TimeSpan.FromSeconds(0.1), () =>
  108. {
  109. lbl.Text = "Okay";
  110. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  111. sch.Schedule(() =>
  112. {
  113. Assert.Equal("Okay", lbl.Text);
  114. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  115. evt.Set();
  116. });
  117. });
  118. });
  119. evt.WaitOne();
  120. Application.Exit();
  121. }
  122. [Fact(Skip="Run Locally")]
  123. public void ScheduleRelative_Cancel()
  124. {
  125. var evt = new ManualResetEvent(false);
  126. var id = Thread.CurrentThread.ManagedThreadId;
  127. var lbl = CreateLabel();
  128. var sch = new ControlScheduler(lbl);
  129. sch.Schedule(TimeSpan.FromSeconds(0.1), () =>
  130. {
  131. lbl.Text = "Okay";
  132. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  133. var d = sch.Schedule(TimeSpan.FromSeconds(0.1), () =>
  134. {
  135. lbl.Text = "Oops!";
  136. });
  137. sch.Schedule(() =>
  138. {
  139. d.Dispose();
  140. });
  141. sch.Schedule(TimeSpan.FromSeconds(0.2), () =>
  142. {
  143. Assert.Equal("Okay", lbl.Text);
  144. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  145. evt.Set();
  146. });
  147. });
  148. evt.WaitOne();
  149. Application.Exit();
  150. }
  151. [Fact]
  152. public void SchedulePeriodic_ArgumentChecking()
  153. {
  154. var s = new ControlScheduler(new Label());
  155. ReactiveAssert.Throws<ArgumentNullException>(() => s.SchedulePeriodic(42, TimeSpan.FromSeconds(1), default(Func<int, int>)));
  156. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => s.SchedulePeriodic(42, TimeSpan.Zero, x => x));
  157. ReactiveAssert.Throws<ArgumentOutOfRangeException>(() => s.SchedulePeriodic(42, TimeSpan.FromMilliseconds(1).Subtract(TimeSpan.FromTicks(1)), x => x));
  158. }
  159. [Fact(Skip="Run Locally")]
  160. public void SchedulePeriodic()
  161. {
  162. var evt = new ManualResetEvent(false);
  163. var id = Thread.CurrentThread.ManagedThreadId;
  164. var lbl = CreateLabel();
  165. var sch = new ControlScheduler(lbl);
  166. var d = new SingleAssignmentDisposable();
  167. d.Disposable = sch.SchedulePeriodic(1, TimeSpan.FromSeconds(0.1), n =>
  168. {
  169. lbl.Text = "Okay " + n;
  170. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  171. if (n == 3)
  172. {
  173. d.Dispose();
  174. sch.Schedule(TimeSpan.FromSeconds(0.2), () =>
  175. {
  176. Assert.Equal("Okay 3", lbl.Text);
  177. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  178. evt.Set();
  179. });
  180. }
  181. if (n > 3)
  182. {
  183. Assert.True(false);
  184. }
  185. return n + 1;
  186. });
  187. evt.WaitOne();
  188. Application.Exit();
  189. }
  190. [Fact(Skip="Run Locally")]
  191. public void SchedulePeriodic_Nested()
  192. {
  193. var evt = new ManualResetEvent(false);
  194. var id = Thread.CurrentThread.ManagedThreadId;
  195. var lbl = CreateLabel();
  196. var sch = new ControlScheduler(lbl);
  197. sch.Schedule(() =>
  198. {
  199. lbl.Text = "Okay";
  200. var d = new SingleAssignmentDisposable();
  201. d.Disposable = sch.SchedulePeriodic(1, TimeSpan.FromSeconds(0.1), n =>
  202. {
  203. lbl.Text = "Okay " + n;
  204. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  205. if (n == 3)
  206. {
  207. d.Dispose();
  208. sch.Schedule(TimeSpan.FromSeconds(0.2), () =>
  209. {
  210. Assert.Equal("Okay 3", lbl.Text);
  211. Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId);
  212. evt.Set();
  213. });
  214. }
  215. return n + 1;
  216. });
  217. });
  218. evt.WaitOne();
  219. Application.Exit();
  220. }
  221. private Label CreateLabel()
  222. {
  223. var loaded = new ManualResetEvent(false);
  224. var lbl = default(Label);
  225. var t = new Thread(() =>
  226. {
  227. lbl = new Label();
  228. var frm = new Form { Controls = { lbl }, Width = 0, Height = 0, FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false };
  229. frm.Load += (_, __) =>
  230. {
  231. loaded.Set();
  232. };
  233. Application.Run(frm);
  234. });
  235. t.SetApartmentState(ApartmentState.STA);
  236. t.Start();
  237. loaded.WaitOne();
  238. return lbl;
  239. }
  240. private Label CreateLabelWithHandler(Action<Exception> handler)
  241. {
  242. var loaded = new ManualResetEvent(false);
  243. var lbl = default(Label);
  244. var t = new Thread(() =>
  245. {
  246. lbl = new Label();
  247. var frm = new Form { Controls = { lbl }, Width = 0, Height = 0, FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false };
  248. frm.Load += (_, __) =>
  249. {
  250. loaded.Set();
  251. };
  252. Application.ThreadException += (o, e) =>
  253. {
  254. handler(e.Exception);
  255. };
  256. Application.Run(frm);
  257. });
  258. t.SetApartmentState(ApartmentState.STA);
  259. t.Start();
  260. loaded.WaitOne();
  261. return lbl;
  262. }
  263. }
  264. }
  265. #endif