ControlSchedulerTest.cs 9.8 KB

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