Skip to content

Commit

Permalink
nullable annotation and extraction of RaisesAsync from modified `As…
Browse files Browse the repository at this point in the history
…sert` class to new `MyAssert` class. (#249)
  • Loading branch information
AoshiW authored Oct 4, 2023
1 parent 4f908e6 commit 0c05d2e
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 884 deletions.
2 changes: 1 addition & 1 deletion TwitchLib.Client.Test/CommandInfoTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class CommandInfoTest
[InlineData("! command")]
public void ParsingFailAndReturnNull(string s)
{
Assert.False(CommandInfo.TryParse(s, out CommandInfo commandInfo));
Assert.False(CommandInfo.TryParse(s, out var commandInfo));
Assert.Null(commandInfo);
}
}
31 changes: 15 additions & 16 deletions TwitchLib.Client.Test/MockIClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Threading.Tasks;
using TwitchLib.Communication.Events;
using TwitchLib.Communication.Interfaces;
using TwitchLib.Communication.Models;

namespace TwitchLib.Client.Test
{
Expand All @@ -12,17 +13,17 @@ public class MockIClient : IClient
public int SendQueueLength => throw new NotImplementedException();

public bool IsConnected { get; private set; }
public IClientOptions Options { get; set; }
public IClientOptions Options { get; set; } = new ClientOptions();

public int WhisperQueueLength => throw new NotImplementedException();

public event AsyncEventHandler<OnConnectedEventArgs> OnConnected;
public event AsyncEventHandler<OnDisconnectedEventArgs> OnDisconnected;
public event AsyncEventHandler<OnErrorEventArgs> OnError;
public event AsyncEventHandler<OnFatalErrorEventArgs> OnFatality;
public event AsyncEventHandler<OnMessageEventArgs> OnMessage;
public event AsyncEventHandler<OnSendFailedEventArgs> OnSendFailed;
public event AsyncEventHandler<OnConnectedEventArgs> OnReconnected;
public event AsyncEventHandler<OnConnectedEventArgs>? OnConnected;
public event AsyncEventHandler<OnDisconnectedEventArgs>? OnDisconnected;
public event AsyncEventHandler<OnErrorEventArgs>? OnError;
public event AsyncEventHandler<OnFatalErrorEventArgs>? OnFatality;
public event AsyncEventHandler<OnMessageEventArgs>? OnMessage;
public event AsyncEventHandler<OnSendFailedEventArgs>? OnSendFailed;
public event AsyncEventHandler<OnConnectedEventArgs>? OnReconnected;

public Task CloseAsync()
{
Expand All @@ -34,20 +35,19 @@ public Task CloseAsync()
public void Dispose()
{ }

public void Dispose(bool waitForSendsToComplete)
{ }

public async Task<bool> OpenAsync()
{
IsConnected = true;
await OnConnected?.Invoke(this, new OnConnectedEventArgs());
if (OnConnected is not null)
await OnConnected.Invoke(this, new OnConnectedEventArgs());
return true;
}

public async Task<bool> ReconnectAsync()
{
IsConnected = true;
await OnReconnected?.Invoke(this, new OnConnectedEventArgs());
if (OnReconnected is not null)
await OnReconnected.Invoke(this, new OnConnectedEventArgs());
return true;
}

Expand All @@ -68,9 +68,8 @@ public Task<bool> SendAsync(string data)

public async Task ReceiveMessage(string message)
{

await OnMessage?.Invoke(this, new OnMessageEventArgs(message));

if (OnMessage is not null)
await OnMessage.Invoke(this, new OnMessageEventArgs(message));
}

public bool SendWhisper(string data)
Expand Down
99 changes: 99 additions & 0 deletions TwitchLib.Client.Test/MyAssert.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using Xunit;
using TwitchLib.Communication.Events;
using System.Threading.Tasks;
using Xunit.Sdk;

namespace TwitchLib.Client.Test;

//TL;DR: XUNIT with modification to accept async event Handler
public partial class MyAssert
{
/// <summary>
/// Verifies that a event with the exact event args (and not a derived type) is raised.
/// </summary>
/// <typeparam name="T">The type of the event arguments to expect</typeparam>
/// <param name="attach">Code to attach the event handler</param>
/// <param name="detach">Code to detach the event handler</param>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The event sender and arguments wrapped in an object</returns>
/// <exception cref="RaisesException">Thrown when the expected event was not raised.</exception>
public static async Task<RaisedEvent<T>> RaisesAsync<T>(Action<AsyncEventHandler<T>> attach, Action<AsyncEventHandler<T>> detach, Func<Task> testCode)
{
var raisedEvent = await RaisesAsyncInternal(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;
}

/// <summary>
/// Verifies that an event with the exact or a derived event args is raised.
/// </summary>
/// <typeparam name="T">The type of the event arguments to expect</typeparam>
/// <param name="attach">Code to attach the event handler</param>
/// <param name="detach">Code to detach the event handler</param>
/// <param name="testCode">A delegate to the code to be tested</param>
/// <returns>The event sender and arguments wrapped in an object</returns>
/// <exception cref="RaisesException">Thrown when the expected event was not raised.</exception>
public static async Task<RaisedEvent<T>> RaisesAnyAsync<T>(Action<AsyncEventHandler<T>> attach, Action<AsyncEventHandler<T>> detach, Func<Task> testCode)
{
var raisedEvent = await RaisesAsyncInternal(attach, detach, testCode);

if (raisedEvent == null)
throw new RaisesException(typeof(T));

return raisedEvent;
}

static async Task<RaisedEvent<T>?> RaisesAsyncInternal<T>(Action<AsyncEventHandler<T>> attach, Action<AsyncEventHandler<T>> detach, Func<Task> testCode)
{
Assert.NotNull(attach);
Assert.NotNull(detach);
Assert.NotNull(testCode);

RaisedEvent<T>? raisedEvent = null;
AsyncEventHandler<T> value = (object? s, T args) =>
{
raisedEvent = new RaisedEvent<T>(s, args);
return Task.CompletedTask;
};
AsyncEventHandler<T> handler = value;
attach(handler);
await testCode();
detach(handler);
return raisedEvent;
}

/// <summary>
/// Represents a raised event after the fact.
/// </summary>
/// <typeparam name="T">The type of the event arguments.</typeparam>
public class RaisedEvent<T>
{
/// <summary>
/// The sender of the event.
/// </summary>
public object? Sender { get; }

/// <summary>
/// The event arguments.
/// </summary>
public T Arguments { get; }

/// <summary>
/// Creates a new instance of the <see cref="RaisedEvent{T}" /> class.
/// </summary>
/// <param name="sender">The sender of the event.</param>
/// <param name="args">The event arguments</param>
public RaisedEvent(object? sender, T args)
{
Sender = sender;
Arguments = args;
}
}
}
2 changes: 1 addition & 1 deletion TwitchLib.Client.Test/ThrottlingServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void EnqueueMessageTests(bool isConnected, uint queueCapacity, bool withM
.Returns(isConnected);
var client = clientMock.Object;
var throttlerService = new ThrottlingService(client, sendOptions);
OutboundChatMessage message = null;
OutboundChatMessage? message = null;

if (withMessage)
{
Expand Down
Loading

0 comments on commit 0c05d2e

Please sign in to comment.