// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Diagnostics; using System.Reactive.Concurrency; using System.Reactive.Linq; using System.Threading; using Microsoft.Reactive.Testing; using Xunit; namespace ReactiveTests.Tests { public class VirtualSchedulerTest { class VirtualSchedulerTestScheduler : VirtualTimeScheduler { public VirtualSchedulerTestScheduler() { } public VirtualSchedulerTestScheduler(string initialClock, IComparer comparer) : base(initialClock, comparer) { } protected override string Add(string absolute, char relative) { return (absolute ?? string.Empty) + relative; } protected override DateTimeOffset ToDateTimeOffset(string absolute) { return new DateTimeOffset((absolute ?? string.Empty).Length, TimeSpan.Zero); } protected override char ToRelative(TimeSpan timeSpan) { return (char)(timeSpan.Ticks % char.MaxValue); } } [Fact] public void Virtual_Now() { var res = new VirtualSchedulerTestScheduler().Now - DateTime.Now; Assert.True(res.Seconds < 1); } #if !NO_THREAD [Fact] public void Virtual_ScheduleAction() { var id = Thread.CurrentThread.ManagedThreadId; var ran = false; var scheduler = new VirtualSchedulerTestScheduler(); scheduler.Schedule(() => { Assert.Equal(id, Thread.CurrentThread.ManagedThreadId); ran = true; }); scheduler.Start(); Assert.True(ran); } #endif [Fact] public void Virtual_ScheduleActionError() { var ex = new Exception(); try { var scheduler = new VirtualSchedulerTestScheduler(); scheduler.Schedule(() => { throw ex; }); scheduler.Start(); Assert.True(false); } catch (Exception e) { Assert.Same(e, ex); } } [Fact] public void Virtual_InitialAndComparer_Now() { var s = new VirtualSchedulerTestScheduler("Bar", Comparer.Default); Assert.Equal(3, s.Now.Ticks); } [Fact] public void Virtual_ArgumentChecking() { ReactiveAssert.Throws(() => new VirtualSchedulerTestScheduler("", null)); ReactiveAssert.Throws(() => new VirtualSchedulerTestScheduler().ScheduleRelative(0, 'a', null)); ReactiveAssert.Throws(() => new VirtualSchedulerTestScheduler().ScheduleAbsolute(0, "", null)); ReactiveAssert.Throws(() => new VirtualSchedulerTestScheduler().Schedule(0, default(Func))); ReactiveAssert.Throws(() => new VirtualSchedulerTestScheduler().Schedule(0, TimeSpan.Zero, default(Func))); ReactiveAssert.Throws(() => new VirtualSchedulerTestScheduler().Schedule(0, DateTimeOffset.UtcNow, default(Func))); ReactiveAssert.Throws(() => VirtualTimeSchedulerExtensions.ScheduleAbsolute(default(VirtualSchedulerTestScheduler), "", () => {})); ReactiveAssert.Throws(() => VirtualTimeSchedulerExtensions.ScheduleAbsolute(new VirtualSchedulerTestScheduler(), "", default(Action))); ReactiveAssert.Throws(() => VirtualTimeSchedulerExtensions.ScheduleRelative(default(VirtualSchedulerTestScheduler), 'a', () => { })); ReactiveAssert.Throws(() => VirtualTimeSchedulerExtensions.ScheduleRelative(new VirtualSchedulerTestScheduler(), 'a', default(Action))); } [Fact] public void Historical_ArgumentChecking() { ReactiveAssert.Throws(() => new HistoricalScheduler(DateTime.Now, default(IComparer))); ReactiveAssert.Throws(() => new HistoricalScheduler().ScheduleAbsolute(42, DateTime.Now, default(Func))); ReactiveAssert.Throws(() => new HistoricalScheduler().ScheduleRelative(42, TimeSpan.FromSeconds(1), default(Func))); } #if !SILVERLIGHT && !NO_THREAD [Fact(Skip = "Ignored")] public void Virtual_ScheduleActionDue() { var id = Thread.CurrentThread.ManagedThreadId; var ran = false; var sw = new Stopwatch(); sw.Start(); var scheduler = new VirtualSchedulerTestScheduler(); scheduler.Schedule(TimeSpan.FromSeconds(0.2), () => { sw.Stop(); Assert.Equal(id, Thread.CurrentThread.ManagedThreadId); ran = true; }); scheduler.Start(); Assert.True(ran, "ran"); Assert.True(sw.ElapsedMilliseconds > 180, "due " + sw.ElapsedMilliseconds); } #endif #if DESKTOPCLR [Fact] public void Virtual_ThreadSafety() { for (var i = 0; i < 10; i++) { var scheduler = new TestScheduler(); var seq = Observable.Never(); ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(50); seq.Timeout(TimeSpan.FromSeconds(10), scheduler).Subscribe(s => { }); }); var watch = scheduler.StartStopwatch(); try { while (watch.Elapsed < TimeSpan.FromSeconds(20)) { scheduler.AdvanceBy(10); } } catch (TimeoutException) { } catch (Exception ex) { Assert.Fail("Virtual time {0}, exception {1}", watch.Elapsed, ex); } } } #endif } }