using System;
using System.Threading.Tasks;
using Xunit.Sdk;
using Nito.AsyncEx;
using System.Threading;
namespace CefSharp.Test
{
internal static class AssertEx
{
///
/// Verifies that a event with the exact event args (and not a derived type) is raised
/// This method differs from
/// in that it waits for the event to be raised before returning (or is cancelled).
///
/// The type of the event arguments to expect
/// number of miliseconds to wait before the timeout
/// Code to attach the event handler
/// Code to detach the event handler
/// A delegate to the code to be tested
/// The event sender and arguments wrapped in an object
/// Thrown when the expected event was not raised.
public static async Task> RaisesAsync(
int cancelAfter,
Action> attach,
Action> detach,
Action testCode) where T : EventArgs
{
var raisedEvent = await RaisesAsyncInternal(cancelAfter, attach, detach, testCode);
if (raisedEvent == null)
throw new RaisesException(typeof(T));
if (raisedEvent.Arguments != null && !raisedEvent.Arguments.GetType().Equals(typeof(T)))
throw new RaisesException(typeof(T), raisedEvent.Arguments.GetType());
return raisedEvent;
}
private static async Task> RaisesAsyncInternal(
int cancelAfter,
Action> attach,
Action> detach,
Action testCode) where T : EventArgs
{
GuardArgumentNotNull(nameof(attach), attach);
GuardArgumentNotNull(nameof(detach), detach);
GuardArgumentNotNull(nameof(testCode), testCode);
using var cts = new CancellationTokenSource();
var manualResetEvent = new AsyncManualResetEvent();
cts.CancelAfter(cancelAfter);
Xunit.Assert.RaisedEvent raisedEvent = null;
attach(Handler);
testCode();
await manualResetEvent.WaitAsync(cts.Token);
detach(Handler);
return raisedEvent;
void Handler(object s, T args)
{
raisedEvent = new Xunit.Assert.RaisedEvent(s, args);
manualResetEvent.Set();
}
}
internal static void GuardArgumentNotNull(string argName, object argValue)
{
if (argValue == null)
{
throw new ArgumentNullException(argName);
}
}
}
}