// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. #if !NO_WINDOWS_THREADING using System; using System.Diagnostics; using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Threading; using System.Windows.Threading; using Microsoft.Reactive.Testing; #if NUNIT using NUnit.Framework; using TestClassAttribute = NUnit.Framework.TestFixtureAttribute; using TestMethodAttribute = NUnit.Framework.TestAttribute; using TestInitializeAttribute = NUnit.Framework.SetUpAttribute; #else using Microsoft.VisualStudio.TestTools.UnitTesting; #endif #if SILVERLIGHT && !SILVERLIGHTM7 using Microsoft.Silverlight.Testing; #endif namespace ReactiveTests.Tests { [TestClass] public class DispatcherSchedulerTest : TestBase { [TestMethod] public void Ctor_ArgumentChecking() { ReactiveAssert.Throws(() => new DispatcherScheduler(null)); } [TestMethod] public void Current() { var d = DispatcherHelpers.EnsureDispatcher(); var e = new ManualResetEvent(false); d.BeginInvoke(() => { var c = DispatcherScheduler.Current; c.Schedule(() => { e.Set(); }); }); e.WaitOne(); } [TestMethod] public void Current_None() { var e = default(Exception); var t = new Thread(() => { try { var ignored = DispatcherScheduler.Current; } catch (Exception ex) { e = ex; } }); t.Start(); t.Join(); Assert.IsTrue(e != null && e is InvalidOperationException); } [TestMethod] public void Dispatcher() { var disp = DispatcherHelpers.EnsureDispatcher(); Assert.AreSame(disp.Dispatcher, new DispatcherScheduler(disp).Dispatcher); } [TestMethod] public void Now() { var disp = DispatcherHelpers.EnsureDispatcher(); var res = new DispatcherScheduler(disp).Now - DateTime.Now; Assert.IsTrue(res.Seconds < 1); } [TestMethod] public void Schedule_ArgumentChecking() { var disp = DispatcherHelpers.EnsureDispatcher(); var s = new DispatcherScheduler(disp); ReactiveAssert.Throws(() => s.Schedule(42, default(Func))); ReactiveAssert.Throws(() => s.Schedule(42, TimeSpan.FromSeconds(1), default(Func))); ReactiveAssert.Throws(() => s.Schedule(42, DateTimeOffset.Now, default(Func))); } [TestMethod] [Asynchronous] public void Schedule() { var disp = DispatcherHelpers.EnsureDispatcher(); RunAsync(evt => { var id = Thread.CurrentThread.ManagedThreadId; var sch = new DispatcherScheduler(disp); sch.Schedule(() => { #if SILVERLIGHT Assert.AreEqual(id, Thread.CurrentThread.ManagedThreadId); // Single-threaded test framework #else Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); #endif disp.InvokeShutdown(); evt.Set(); }); }); } #if !USE_SL_DISPATCHER [TestMethod] public void ScheduleError() { var ex = new Exception(); var id = Thread.CurrentThread.ManagedThreadId; var disp = DispatcherHelpers.EnsureDispatcher(); var evt = new ManualResetEvent(false); disp.UnhandledException += (o, e) => { #if DESKTOPCLR40 || DESKTOPCLR45 Assert.AreSame(ex, e.Exception); // CHECK #else Assert.AreSame(ex, e.Exception.InnerException); // CHECK #endif evt.Set(); e.Handled = true; }; var sch = new DispatcherScheduler(disp); sch.Schedule(() => { throw ex; }); evt.WaitOne(); disp.InvokeShutdown(); } [TestMethod] public void ScheduleRelative() { ScheduleRelative_(TimeSpan.FromSeconds(0.2)); } [TestMethod] public void ScheduleRelative_Zero() { ScheduleRelative_(TimeSpan.Zero); } private void ScheduleRelative_(TimeSpan delay) { var evt = new ManualResetEvent(false); var id = Thread.CurrentThread.ManagedThreadId; var disp = DispatcherHelpers.EnsureDispatcher(); var sch = new DispatcherScheduler(disp); sch.Schedule(delay, () => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); sch.Schedule(delay, () => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); evt.Set(); }); }); evt.WaitOne(); disp.InvokeShutdown(); } [TestMethod] public void ScheduleRelative_Cancel() { var evt = new ManualResetEvent(false); var id = Thread.CurrentThread.ManagedThreadId; var disp = DispatcherHelpers.EnsureDispatcher(); var sch = new DispatcherScheduler(disp); sch.Schedule(TimeSpan.FromSeconds(0.1), () => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); var d = sch.Schedule(TimeSpan.FromSeconds(0.1), () => { Assert.Fail(); evt.Set(); }); sch.Schedule(() => { d.Dispose(); }); sch.Schedule(TimeSpan.FromSeconds(0.2), () => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); evt.Set(); }); }); evt.WaitOne(); disp.InvokeShutdown(); } [TestMethod] public void SchedulePeriodic_ArgumentChecking() { var disp = DispatcherHelpers.EnsureDispatcher(); var s = new DispatcherScheduler(disp); ReactiveAssert.Throws(() => s.SchedulePeriodic(42, TimeSpan.FromSeconds(1), default(Func))); ReactiveAssert.Throws(() => s.SchedulePeriodic(42, TimeSpan.FromSeconds(-1), x => x)); } [TestMethod] public void SchedulePeriodic() { var evt = new ManualResetEvent(false); var id = Thread.CurrentThread.ManagedThreadId; var disp = DispatcherHelpers.EnsureDispatcher(); var sch = new DispatcherScheduler(disp); var d = new SingleAssignmentDisposable(); d.Disposable = sch.SchedulePeriodic(1, TimeSpan.FromSeconds(0.1), n => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); if (n == 3) { d.Dispose(); sch.Schedule(TimeSpan.FromSeconds(0.2), () => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); evt.Set(); }); } if (n > 3) { Assert.Fail(); } return n + 1; }); evt.WaitOne(); disp.InvokeShutdown(); } #endif } } #endif