/// <summary> /// Asserts that the current <see cref="Delegate"/> stops throwing any exception /// after a specified amount of time. /// </summary> /// <remarks> /// The delegate is invoked. If it raises an exception, /// the invocation is repeated until it either stops raising any exceptions /// or the specified wait time is exceeded. /// </remarks> /// <param name="waitTime"> /// The time after which the delegate should have stopped throwing any exception. /// </param> /// <param name="pollInterval"> /// The time between subsequent invocations of the delegate. /// </param> /// <param name="because"> /// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically. /// </param> /// <param name="becauseArgs"> /// Zero or more objects to format using the placeholders in <see cref="because" />. /// </param> /// <exception cref="ArgumentOutOfRangeException">Throws if waitTime or pollInterval are negative.</exception> public void NotThrowAfter(TimeSpan waitTime, TimeSpan pollInterval, string because = "", params object[] becauseArgs) { FailIfSubjectIsAsyncVoid(); if (waitTime < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(waitTime), $"The value of {nameof(waitTime)} must be non-negative."); } if (pollInterval < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(pollInterval), $"The value of {nameof(pollInterval)} must be non-negative."); } TimeSpan? invocationEndTime = null; Exception exception = null; var timer = clock.StartTimer(); while (invocationEndTime is null || invocationEndTime < waitTime) { exception = InvokeSubjectWithInterception(); if (exception is null) { return; } clock.Delay(pollInterval); invocationEndTime = timer.Elapsed; } Execute.Assertion .BecauseOf(because, becauseArgs) .FailWith("Did not expect any exceptions after {0}{reason}, but found {1}.", waitTime, exception); }
public static async Task ScheduleAsync( this IClock clock, TimeSpan span, Func <Task> f, CancellationToken cancellationToken) { await clock.Delay(span, cancellationToken).ConfigureAwait(false); await f().ConfigureAwait(false); }
public static async Task <TResult> ScheduleAsync <TResult>( this IClock clock, TimeSpan span, Func <Task <TResult> > f, CancellationToken cancellationToken) { await clock.Delay(span, cancellationToken).ConfigureAwait(false); return(await f().ConfigureAwait(false)); }
public static async Task DelayTo(this IClock clock, DateTime delayTo, CancellationToken cancellationToken) { var span = clock.TimeTo(delayTo); if (span > TimeSpan.Zero) { await clock.Delay(span, cancellationToken).ConfigureAwait(false); } }
private async Task <T> WithTimeout <T>(Task <T> mainTask, int timeout, CancellationTokenSource source) { Task timeoutTask = clock.Delay(timeout, source.Token); Task result = await Task.WhenAny(mainTask, timeoutTask); if (result.Equals(mainTask)) { return(mainTask.Result); } throw new TimeoutException(); }
public static async Task <Server> GetLastServer(string path, IClock clock, CancellationTokenSource source) { try { return(await GetLastServerInternal(path)); } catch (IOException) { await clock.Delay(1000, source.Token); return(await GetLastServerInternal(path)); } }
/// <summary> /// Asserts that the current <see cref="Func{T}"/> stops throwing any exception /// after a specified amount of time. /// </summary> /// <remarks> /// The <see cref="Func{T}"/> is invoked. If it raises an exception, /// the invocation is repeated until it either stops raising any exceptions /// or the specified wait time is exceeded. /// </remarks> /// <param name="waitTime"> /// The time after which the <see cref="Func{T}"/> should have stopped throwing any exception. /// </param> /// <param name="pollInterval"> /// The time between subsequent invocations of the <see cref="Func{T}"/>. /// </param> /// <param name="because"> /// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically. /// </param> /// <param name="becauseArgs"> /// Zero or more objects to format using the placeholders in <see cref="because" />. /// </param> /// <exception cref="ArgumentOutOfRangeException">Throws if waitTime or pollInterval are negative.</exception> public new AndWhichConstraint <FunctionAssertions <T>, T> NotThrowAfter(TimeSpan waitTime, TimeSpan pollInterval, string because = "", params object[] becauseArgs) { if (waitTime < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(waitTime), $"The value of {nameof(waitTime)} must be non-negative."); } if (pollInterval < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(pollInterval), $"The value of {nameof(pollInterval)} must be non-negative."); } Execute.Assertion .ForCondition(!ReferenceEquals(Subject, null)) .BecauseOf(because, becauseArgs) .FailWith("Expected {context} not to throw any exceptions after {0}{reason}, but found <null>.", waitTime); TimeSpan? invocationEndTime = null; Exception exception = null; ITimer timer = clock.StartTimer(); while (invocationEndTime is null || invocationEndTime < waitTime) { try { T result = Subject(); return(new AndWhichConstraint <FunctionAssertions <T>, T>(this, result)); } catch (Exception e) { exception = e; } clock.Delay(pollInterval); invocationEndTime = timer.Elapsed; } Execute.Assertion .BecauseOf(because, becauseArgs) .FailWith("Did not expect any exceptions after {0}{reason}, but found {1}.", waitTime, exception); return(new AndWhichConstraint <FunctionAssertions <T>, T>(this, default(T))); }