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

DelayedConstraint

Applies a delay to the match so that a match can be evaluated in the future.
using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace NUnit.Framework.Constraints { [NullableContext(1)] [Nullable(0)] public class DelayedConstraint : PrefixConstraint { [Nullable(0)] 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) { if (milliSeconds < 0) throw new ArgumentException("Interval cannot be negative"); _parent.PollingInterval = new Interval(milliSeconds).InMilliseconds; return new WithRawPollingInterval(_parent); } } [Nullable(0)] 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) { if (milliSeconds < 0) throw new ArgumentException("Interval cannot be negative"); _parent.PollingInterval = new Interval(milliSeconds).InMilliseconds; return new WithRawPollingInterval(_parent); } } [Nullable(0)] 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; } } [Nullable(0)] private class DelegatingConstraintResult : ConstraintResult { private readonly ConstraintResult _innerResult; public DelegatingConstraintResult(IConstraint constraint, ConstraintResult innerResult) : base(constraint, innerResult.ActualValue, innerResult.Status) { _innerResult = innerResult; } public override void WriteMessageTo(MessageWriter writer) { writer.WriteMessageLine(base.Description, Array.Empty<object>()); _innerResult.WriteMessageTo(writer); } } protected Interval DelayInterval { get; set; } protected Interval PollingInterval { get; set; } public override string Description { get { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(12, 1); defaultInterpolatedStringHandler.AppendLiteral("After "); defaultInterpolatedStringHandler.AppendFormatted(DelayInterval); defaultInterpolatedStringHandler.AppendLiteral(" delay"); return defaultInterpolatedStringHandler.ToStringAndClear(); } } public DelayedConstraint(IConstraint baseConstraint, int delayInMilliseconds) : this(baseConstraint, delayInMilliseconds, 0) { } public DelayedConstraint(IConstraint baseConstraint, int delayInMilliseconds, int pollingIntervalInMilliseconds) : base(baseConstraint, string.Empty) { if (delayInMilliseconds < 0) throw new ArgumentException("Cannot check a condition in the past", "delayInMilliseconds"); if (pollingIntervalInMilliseconds < 0) throw new ArgumentException("Interval cannot be negative", "pollingIntervalInMilliseconds"); DelayInterval = new Interval(delayInMilliseconds).InMilliseconds; PollingInterval = new Interval(pollingIntervalInMilliseconds).InMilliseconds; } private DelayedConstraint(IConstraint baseConstraint, Interval delayInterval, Interval pollingInterval) : base(baseConstraint, string.Empty) { DelayInterval = delayInterval; PollingInterval = pollingInterval; } public override ConstraintResult ApplyTo<[Nullable(2)] TActual>(TActual actual) { return PollLoop(() => base.BaseConstraint.ApplyTo<TActual>(actual)); } public override ConstraintResult ApplyTo<[Nullable(2)] TActual>(ActualValueDelegate<TActual> del) { return PollLoop(() => base.BaseConstraint.ApplyTo<TActual>(del)); } [AsyncStateMachine(typeof(<ApplyToAsync>d__18<>))] public override Task<ConstraintResult> ApplyToAsync<[Nullable(2)] TActual>(Func<Task<TActual>> taskDel) { <ApplyToAsync>d__18<TActual> stateMachine = default(<ApplyToAsync>d__18<TActual>); stateMachine.<>t__builder = AsyncTaskMethodBuilder<ConstraintResult>.Create(); stateMachine.<>4__this = this; stateMachine.taskDel = taskDel; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } [AsyncStateMachine(typeof(<PollingDelayAsync>d__19))] private Task<bool> PollingDelayAsync(Stopwatch stopwatch) { <PollingDelayAsync>d__19 stateMachine = default(<PollingDelayAsync>d__19); stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.Create(); stateMachine.<>4__this = this; stateMachine.stopwatch = stopwatch; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } private Task FinalDelayAsync(Stopwatch stopwatch) { TimeSpan timeSpan = DelayInterval.AsTimeSpan - stopwatch.Elapsed; if (timeSpan > TimeSpan.Zero) return Task.Delay(timeSpan); return Task.CompletedTask; } private ConstraintResult PollLoop(Func<ConstraintResult> applyBaseConstraint) { Stopwatch stopwatch = Stopwatch.StartNew(); if (PollingInterval.IsNotZero) { while (PollingDelay(stopwatch)) { try { ConstraintResult constraintResult = applyBaseConstraint(); if (constraintResult.IsSuccess) return new DelegatingConstraintResult(this, constraintResult); } catch (Exception) { } } } FinalDelay(stopwatch); return new DelegatingConstraintResult(this, applyBaseConstraint()); } private bool PollingDelay(Stopwatch stopwatch) { TimeSpan elapsed = stopwatch.Elapsed; TimeSpan timeSpan = DelayInterval.AsTimeSpan - elapsed; TimeSpan timeSpan2 = (timeSpan < PollingInterval.AsTimeSpan) ? timeSpan : PollingInterval.AsTimeSpan; bool flag = timeSpan2 > TimeSpan.Zero; if (flag) { Thread.Sleep(timeSpan2); TimeSpan timeSpan3 = elapsed + timeSpan2; while ((elapsed = stopwatch.Elapsed) < timeSpan3) { Thread.Sleep(timeSpan3 - elapsed); } } return flag; } private void FinalDelay(Stopwatch stopwatch) { TimeSpan timeSpan = DelayInterval.AsTimeSpan - stopwatch.Elapsed; if (timeSpan > TimeSpan.Zero) Thread.Sleep(timeSpan); } protected override string GetStringRepresentation() { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(9, 2); defaultInterpolatedStringHandler.AppendLiteral("<after "); defaultInterpolatedStringHandler.AppendFormatted(DelayInterval.AsTimeSpan.TotalMilliseconds); defaultInterpolatedStringHandler.AppendLiteral(" "); defaultInterpolatedStringHandler.AppendFormatted(base.BaseConstraint); defaultInterpolatedStringHandler.AppendLiteral(">"); return defaultInterpolatedStringHandler.ToStringAndClear(); } } }