<PackageReference Include="NUnit" Version="3.6.0" />

DelayedConstraint

Applies a delay to the match so that a match can be evaluated in the future.
using NUnit.Framework.Internal; using System; using System.Diagnostics; using System.Threading; namespace NUnit.Framework.Constraints { public class DelayedConstraint : PrefixConstraint { public class WithRawDelayInterval : DelayedConstraint { private readonly DelayedConstraint _parent; public WithDimensionedDelayInterval Minutes { get { _parent.DelayInterval = _parent.DelayInterval.InMinutes; return new WithDimensionedDelayInterval(_parent); } } public WithDimensionedDelayInterval Seconds { get { base.DelayInterval = base.DelayInterval.InSeconds; return new WithDimensionedDelayInterval(_parent); } } public WithDimensionedDelayInterval MilliSeconds { get { base.DelayInterval = base.DelayInterval.InMilliseconds; return new WithDimensionedDelayInterval(_parent); } } public WithRawDelayInterval(DelayedConstraint parent) : base(parent.BaseConstraint, parent.DelayInterval, parent.PollingInterval) { base.DelayInterval = parent.DelayInterval; _parent = parent; } public WithRawPollingInterval PollEvery(int milliSeconds) { _parent.PollingInterval = new Interval(milliSeconds).InMilliseconds; return new WithRawPollingInterval(_parent); } } public class WithDimensionedDelayInterval : DelayedConstraint { private readonly DelayedConstraint _parent; public WithDimensionedDelayInterval(DelayedConstraint parent) : base(parent.BaseConstraint, parent.DelayInterval, parent.PollingInterval) { base.DelayInterval = parent.DelayInterval; _parent = parent; } public WithRawPollingInterval PollEvery(int milliSeconds) { _parent.PollingInterval = new Interval(milliSeconds).InMilliseconds; return new WithRawPollingInterval(_parent); } } public class WithRawPollingInterval : DelayedConstraint { private readonly DelayedConstraint _parent; public DelayedConstraint Minutes { get { _parent.PollingInterval = _parent.PollingInterval.InMinutes; return _parent; } } public DelayedConstraint Seconds { get { _parent.PollingInterval = _parent.PollingInterval.InSeconds; return _parent; } } public DelayedConstraint MilliSeconds { get { _parent.PollingInterval = _parent.PollingInterval.InMilliseconds; return _parent; } } public WithRawPollingInterval(DelayedConstraint parent) : base(parent.BaseConstraint, parent.DelayInterval, parent.PollingInterval) { _parent = parent; } } protected Interval DelayInterval { get; set; } protected Interval PollingInterval { get; set; } public override string Description => $"{base.BaseConstraint.Description}""{DelayInterval}"""; public DelayedConstraint(IConstraint baseConstraint, int delayInMilliseconds) : this(baseConstraint, delayInMilliseconds, 0) { } public DelayedConstraint(IConstraint baseConstraint, int delayInMilliseconds, int pollingIntervalInMilliseconds) : base(baseConstraint) { if (delayInMilliseconds < 0) throw new ArgumentException("Cannot check a condition in the past", "delayInMilliseconds"); DelayInterval = new Interval(delayInMilliseconds).InMilliseconds; PollingInterval = new Interval(pollingIntervalInMilliseconds).InMilliseconds; } private DelayedConstraint(IConstraint baseConstraint, Interval delayInterval, Interval pollingInterval) : base(baseConstraint) { DelayInterval = delayInterval; PollingInterval = pollingInterval; } public override ConstraintResult ApplyTo<TActual>(TActual actual) { long timestamp = Stopwatch.GetTimestamp(); long num = TimestampOffset(timestamp, DelayInterval.AsTimeSpan); TimeSpan timeSpan; if (PollingInterval.IsNotZero) { long num2 = TimestampOffset(timestamp, PollingInterval.AsTimeSpan); while ((timestamp = Stopwatch.GetTimestamp()) < num) { if (num2 > timestamp) { timeSpan = TimestampDiff((num < num2) ? num : num2, timestamp); Thread.Sleep((int)timeSpan.TotalMilliseconds); } num2 = TimestampOffset(timestamp, PollingInterval.AsTimeSpan); if (base.BaseConstraint.ApplyTo(actual).IsSuccess) return new ConstraintResult(this, actual, true); } } if ((timestamp = Stopwatch.GetTimestamp()) < num) { timeSpan = TimestampDiff(num, timestamp); Thread.Sleep((int)timeSpan.TotalMilliseconds); } return new ConstraintResult(this, actual, base.BaseConstraint.ApplyTo(actual).IsSuccess); } public override ConstraintResult ApplyTo<TActual>(ActualValueDelegate<TActual> del) { long timestamp = Stopwatch.GetTimestamp(); long num = TimestampOffset(timestamp, DelayInterval.AsTimeSpan); TimeSpan timeSpan; object obj; if (PollingInterval.IsNotZero) { long num2 = TimestampOffset(timestamp, PollingInterval.AsTimeSpan); while ((timestamp = Stopwatch.GetTimestamp()) < num) { if (num2 > timestamp) { timeSpan = TimestampDiff((num < num2) ? num : num2, timestamp); Thread.Sleep((int)timeSpan.TotalMilliseconds); } num2 = TimestampOffset(timestamp, PollingInterval.AsTimeSpan); obj = InvokeDelegate(del); try { if (base.BaseConstraint.ApplyTo(obj).IsSuccess) return new ConstraintResult(this, obj, true); } catch (Exception) { } } } if ((timestamp = Stopwatch.GetTimestamp()) < num) { timeSpan = TimestampDiff(num, timestamp); Thread.Sleep((int)timeSpan.TotalMilliseconds); } obj = InvokeDelegate(del); return new ConstraintResult(this, obj, base.BaseConstraint.ApplyTo(obj).IsSuccess); } public override ConstraintResult ApplyTo<TActual>(ref TActual actual) { long timestamp = Stopwatch.GetTimestamp(); long num = TimestampOffset(timestamp, DelayInterval.AsTimeSpan); TimeSpan timeSpan; if (PollingInterval.IsNotZero) { long num2 = TimestampOffset(timestamp, PollingInterval.AsTimeSpan); while ((timestamp = Stopwatch.GetTimestamp()) < num) { if (num2 > timestamp) { timeSpan = TimestampDiff((num < num2) ? num : num2, timestamp); Thread.Sleep((int)timeSpan.TotalMilliseconds); } num2 = TimestampOffset(timestamp, PollingInterval.AsTimeSpan); try { if (base.BaseConstraint.ApplyTo(actual).IsSuccess) return new ConstraintResult(this, actual, true); } catch (Exception) { } } } if ((timestamp = Stopwatch.GetTimestamp()) < num) { timeSpan = TimestampDiff(num, timestamp); Thread.Sleep((int)timeSpan.TotalMilliseconds); } return new ConstraintResult(this, actual, base.BaseConstraint.ApplyTo(actual).IsSuccess); } private static object InvokeDelegate<T>(ActualValueDelegate<T> del) { if (AsyncInvocationRegion.IsAsyncOperation(del)) { using (AsyncInvocationRegion asyncInvocationRegion = AsyncInvocationRegion.Create(del)) { return asyncInvocationRegion.WaitForPendingOperationsToComplete(del()); } } return del(); } protected override string GetStringRepresentation() { return $"""{DelayInterval.AsTimeSpan.TotalMilliseconds}""{base.BaseConstraint}"""; } private static long TimestampOffset(long timestamp, TimeSpan offset) { return timestamp + (long)(offset.TotalSeconds * (double)Stopwatch.Frequency); } private static TimeSpan TimestampDiff(long timestamp1, long timestamp2) { return TimeSpan.FromSeconds((double)(timestamp1 - timestamp2) / (double)Stopwatch.Frequency); } } }