diff --git a/TwitchLib.Client.Test/CommandInfoTest.cs b/TwitchLib.Client.Test/CommandInfoTest.cs index 1ac0e754..c8fc7353 100644 --- a/TwitchLib.Client.Test/CommandInfoTest.cs +++ b/TwitchLib.Client.Test/CommandInfoTest.cs @@ -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); } } diff --git a/TwitchLib.Client.Test/MockIClient.cs b/TwitchLib.Client.Test/MockIClient.cs index afeb631b..79338ce8 100644 --- a/TwitchLib.Client.Test/MockIClient.cs +++ b/TwitchLib.Client.Test/MockIClient.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using TwitchLib.Communication.Events; using TwitchLib.Communication.Interfaces; +using TwitchLib.Communication.Models; namespace TwitchLib.Client.Test { @@ -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 OnConnected; - public event AsyncEventHandler OnDisconnected; - public event AsyncEventHandler OnError; - public event AsyncEventHandler OnFatality; - public event AsyncEventHandler OnMessage; - public event AsyncEventHandler OnSendFailed; - public event AsyncEventHandler OnReconnected; + public event AsyncEventHandler? OnConnected; + public event AsyncEventHandler? OnDisconnected; + public event AsyncEventHandler? OnError; + public event AsyncEventHandler? OnFatality; + public event AsyncEventHandler? OnMessage; + public event AsyncEventHandler? OnSendFailed; + public event AsyncEventHandler? OnReconnected; public Task CloseAsync() { @@ -34,20 +35,19 @@ public Task CloseAsync() public void Dispose() { } - public void Dispose(bool waitForSendsToComplete) - { } - public async Task 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 ReconnectAsync() { IsConnected = true; - await OnReconnected?.Invoke(this, new OnConnectedEventArgs()); + if (OnReconnected is not null) + await OnReconnected.Invoke(this, new OnConnectedEventArgs()); return true; } @@ -68,9 +68,8 @@ public Task 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) diff --git a/TwitchLib.Client.Test/MyAssert.cs b/TwitchLib.Client.Test/MyAssert.cs new file mode 100644 index 00000000..11ebded4 --- /dev/null +++ b/TwitchLib.Client.Test/MyAssert.cs @@ -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 +{ + /// + /// Verifies that a event with the exact event args (and not a derived type) is raised. + /// + /// The type of the event arguments to expect + /// 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(Action> attach, Action> detach, Func 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; + } + + /// + /// Verifies that an event with the exact or a derived event args is raised. + /// + /// The type of the event arguments to expect + /// 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> RaisesAnyAsync(Action> attach, Action> detach, Func testCode) + { + var raisedEvent = await RaisesAsyncInternal(attach, detach, testCode); + + if (raisedEvent == null) + throw new RaisesException(typeof(T)); + + return raisedEvent; + } + + static async Task?> RaisesAsyncInternal(Action> attach, Action> detach, Func testCode) + { + Assert.NotNull(attach); + Assert.NotNull(detach); + Assert.NotNull(testCode); + + RaisedEvent? raisedEvent = null; + AsyncEventHandler value = (object? s, T args) => + { + raisedEvent = new RaisedEvent(s, args); + return Task.CompletedTask; + }; + AsyncEventHandler handler = value; + attach(handler); + await testCode(); + detach(handler); + return raisedEvent; + } + + /// + /// Represents a raised event after the fact. + /// + /// The type of the event arguments. + public class RaisedEvent + { + /// + /// The sender of the event. + /// + public object? Sender { get; } + + /// + /// The event arguments. + /// + public T Arguments { get; } + + /// + /// Creates a new instance of the class. + /// + /// The sender of the event. + /// The event arguments + public RaisedEvent(object? sender, T args) + { + Sender = sender; + Arguments = args; + } + } +} diff --git a/TwitchLib.Client.Test/ThrottlingServiceTests.cs b/TwitchLib.Client.Test/ThrottlingServiceTests.cs index 64242f5b..0ee33327 100644 --- a/TwitchLib.Client.Test/ThrottlingServiceTests.cs +++ b/TwitchLib.Client.Test/ThrottlingServiceTests.cs @@ -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) { diff --git a/TwitchLib.Client.Test/TwitchClientEventTests.cs b/TwitchLib.Client.Test/TwitchClientEventTests.cs index 3e6e7aef..0479ec3c 100644 --- a/TwitchLib.Client.Test/TwitchClientEventTests.cs +++ b/TwitchLib.Client.Test/TwitchClientEventTests.cs @@ -1,12 +1,9 @@ using System; -using Xunit; -using TwitchLib.Client.Events; -using TwitchLib.Communication.Events; using System.Threading; -using System.Text.RegularExpressions; using System.Threading.Tasks; -using Xunit.Sdk; -using System.Globalization; +using TwitchLib.Client.Events; +using TwitchLib.Communication.Events; +using Xunit; namespace TwitchLib.Client.Test { @@ -25,7 +22,7 @@ public TwitchClientEventTests() public async Task ClientCanReceiveData() { var client = new TwitchClient(_mockClient); - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnSendReceiveData += h, h => client.OnSendReceiveData -= h, async () => @@ -46,7 +43,7 @@ public async Task ClientCanJoinChannels() await ReceivedRoomState(); }; - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnJoinedChannel += h, h => client.OnJoinedChannel -= h, async () => @@ -82,7 +79,7 @@ public async void ClientRaisesOnConnected() { var client = new TwitchClient(_mockClient); - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnConnected += h, h => client.OnConnected -= h, async () => @@ -98,7 +95,7 @@ public async Task ClientRaisesOnMessageReceived() { var client = new TwitchClient(_mockClient); - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnMessageReceived += h, h => client.OnMessageReceived -= h, async () => @@ -114,7 +111,7 @@ public async Task ClientRaisesOnJoinedChannel() { var client = new TwitchClient(_mockClient); - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnJoinedChannel += h, h => client.OnJoinedChannel -= h, async () => @@ -144,7 +141,7 @@ public async Task ClientRaisesOnDisconnected() { var client = new TwitchClient(_mockClient); - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnDisconnected += h, h => client.OnDisconnected -= h, async () => @@ -165,7 +162,7 @@ public async Task ClientReconnectsOk() var pauseConnected = new ManualResetEvent(false); var pauseReconnected = new ManualResetEvent(false); - await Assert.RaisesAsync( + await MyAssert.RaisesAsync( h => client.OnReconnected += h, h => client.OnReconnected -= h, async () => @@ -189,7 +186,6 @@ public async Task ClientReconnectsOk() } #region Messages for Tests - private async Task ReceivedUserNoticeMessage() { await _mockClient.ReceiveMessage("@badges=subscriber/0;color=#0000FF;display-name=KittyJinxu;emotes=30259:0-6;id=1154b7c0-8923-464e-a66b-3ef55b1d4e50;login=kittyjinxu;mod=0;msg-id=ritual;msg-param-ritual-name=new_chatter;room-id=35740817;subscriber=1;system-msg=@KittyJinxu\\sis\\snew\\shere.\\sSay\\shello!;tmi-sent-ts=1514387871555;turbo=0;user-id=187446639;user-type= USERNOTICE #testchannel kittyjinxu > #testchannel: HeyGuys"); @@ -219,857 +215,6 @@ private async Task ReceivedRoomState() { await _mockClient.ReceiveMessage($"@broadcaster-lang=;r9k=0;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #{TWITCH_CHANNEL}"); } - #endregion - - #region Modified Assert - //TL;DR: Extracted version of XUNIT with - //modification to accept new event Handler - - public partial class Assert - { - - /// - /// Verifies that a event with the exact event args (and not a derived type) is raised. - /// - /// The type of the event arguments to expect - /// 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(Action> attach, Action> detach, Func 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; - } - - /// - /// Verifies that an event with the exact or a derived event args is raised. - /// - /// The type of the event arguments to expect - /// 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> RaisesAnyAsync(Action> attach, Action> detach, Func testCode) - { - var raisedEvent = await RaisesAsyncInternal(attach, detach, testCode); - - if (raisedEvent == null) - throw new RaisesException(typeof(T)); - - return raisedEvent; - } - -#if XUNIT_NULLABLE - static async Task?> RaisesAsyncInternal(Action> attach, Action> detach, Func testCode) -#else - static async Task> RaisesAsyncInternal(Action> attach, Action> detach, Func testCode) -#endif - { - NotNull(attach); - NotNull(detach); - NotNull(testCode); - -#if XUNIT_NULLABLE - RaisedEvent? raisedEvent = null; - void handler(object? s, T args) => raisedEvent = new RaisedEvent(s, args); -#else - RaisedEvent raisedEvent = null; - AsyncEventHandler value = (object s, T args) => - { - raisedEvent = new RaisedEvent(s, args); - return Task.CompletedTask; - }; - AsyncEventHandler handler = value; -#endif - attach(handler); - await testCode(); - detach(handler); - return raisedEvent; - } - - /// - /// Represents a raised event after the fact. - /// - /// The type of the event arguments. - public class RaisedEvent - { - /// - /// The sender of the event. - /// -#if XUNIT_NULLABLE - public object? Sender { get; } -#else - public object Sender { get; } -#endif - - /// - /// The event arguments. - /// - public T Arguments { get; } - - /// - /// Creates a new instance of the class. - /// - /// The sender of the event. - /// The event arguments -#if XUNIT_NULLABLE - public RaisedEvent(object? sender, T args) -#else - public RaisedEvent(object sender, T args) -#endif - { - Sender = sender; - Arguments = args; - } - } - - -#if XUNIT_NULLABLE - public static void False([DoesNotReturnIf(parameterValue: true)] bool condition) -#else - public static void False(bool condition) -#endif - { - False((bool?)condition, null); - } - - /// - /// Verifies that the condition is false. - /// - /// The condition to be tested - /// Thrown if the condition is not false -#if XUNIT_NULLABLE - public static void False([DoesNotReturnIf(parameterValue: true)] bool? condition) -#else - public static void False(bool? condition) -#endif - { - False(condition, null); - } - - /// - /// Verifies that the condition is false. - /// - /// The condition to be tested - /// The message to show when the condition is not false - /// Thrown if the condition is not false -#if XUNIT_NULLABLE - public static void False([DoesNotReturnIf(parameterValue: true)] bool condition, string? userMessage) -#else - public static void False(bool condition, string userMessage) -#endif - { - False((bool?)condition, userMessage); - } - - /// - /// Verifies that the condition is false. - /// - /// The condition to be tested - /// The message to show when the condition is not false - /// Thrown if the condition is not false -#if XUNIT_NULLABLE - public static void False([DoesNotReturnIf(parameterValue: true)] bool? condition, string? userMessage) -#else - public static void False(bool? condition, string userMessage) -#endif - { - if (!condition.HasValue || condition.GetValueOrDefault()) - throw new FalseException(userMessage, condition); - } - - /// - /// Verifies that an expression is true. - /// - /// The condition to be inspected - /// Thrown when the condition is false -#if XUNIT_NULLABLE - public static void True([DoesNotReturnIf(parameterValue: false)] bool condition) -#else - public static void True(bool condition) -#endif - { - True((bool?)condition, null); - } - - /// - /// Verifies that an expression is true. - /// - /// The condition to be inspected - /// Thrown when the condition is false -#if XUNIT_NULLABLE - public static void True([DoesNotReturnIf(parameterValue: false)] bool? condition) -#else - public static void True(bool? condition) -#endif - { - True(condition, null); - } - - /// - /// Verifies that an expression is true. - /// - /// The condition to be inspected - /// The message to be shown when the condition is false - /// Thrown when the condition is false -#if XUNIT_NULLABLE - public static void True([DoesNotReturnIf(parameterValue: false)] bool condition, string? userMessage) -#else - public static void True(bool condition, string userMessage) -#endif - { - True((bool?)condition, userMessage); - } - - /// - /// Verifies that an expression is true. - /// - /// The condition to be inspected - /// The message to be shown when the condition is false - /// Thrown when the condition is false -#if XUNIT_NULLABLE - public static void True([DoesNotReturnIf(parameterValue: false)] bool? condition, string? userMessage) -#else - public static void True(bool? condition, string userMessage) -#endif - { - if (!condition.HasValue || !condition.GetValueOrDefault()) - throw new TrueException(userMessage, condition); - } - - /// - /// Verifies that a string contains a given sub-string, using the current culture. - /// - /// The sub-string expected to be in the string - /// The string to be inspected - /// Thrown when the sub-string is not present inside the string -#if XUNIT_NULLABLE - public static void Contains(string expectedSubstring, string? actualString) -#else - public static void Contains(string expectedSubstring, string actualString) -#endif - { - Contains(expectedSubstring, actualString, StringComparison.CurrentCulture); - } - - /// - /// Verifies that a string contains a given sub-string, using the given comparison type. - /// - /// The sub-string expected to be in the string - /// The string to be inspected - /// The type of string comparison to perform - /// Thrown when the sub-string is not present inside the string -#if XUNIT_NULLABLE - public static void Contains(string expectedSubstring, string? actualString, StringComparison comparisonType) -#else - public static void Contains(string expectedSubstring, string actualString, StringComparison comparisonType) -#endif - { - NotNull(expectedSubstring); - - if (actualString == null || actualString.IndexOf(expectedSubstring, comparisonType) < 0) - throw new ContainsException(expectedSubstring, actualString); - } - - /// - /// Verifies that a string does not contain a given sub-string, using the current culture. - /// - /// The sub-string which is expected not to be in the string - /// The string to be inspected - /// Thrown when the sub-string is present inside the string -#if XUNIT_NULLABLE - public static void DoesNotContain(string expectedSubstring, string? actualString) -#else - public static void DoesNotContain(string expectedSubstring, string actualString) -#endif - { - DoesNotContain(expectedSubstring, actualString, StringComparison.CurrentCulture); - } - - /// - /// Verifies that a string does not contain a given sub-string, using the current culture. - /// - /// The sub-string which is expected not to be in the string - /// The string to be inspected - /// The type of string comparison to perform - /// Thrown when the sub-string is present inside the given string -#if XUNIT_NULLABLE - public static void DoesNotContain(string expectedSubstring, string? actualString, StringComparison comparisonType) -#else - public static void DoesNotContain(string expectedSubstring, string actualString, StringComparison comparisonType) -#endif - { - NotNull(expectedSubstring); - - if (actualString != null && actualString.IndexOf(expectedSubstring, comparisonType) >= 0) - throw new DoesNotContainException(expectedSubstring, actualString); - } - - /// - /// Verifies that a string starts with a given string, using the current culture. - /// - /// The string expected to be at the start of the string - /// The string to be inspected - /// Thrown when the string does not start with the expected string -#if XUNIT_NULLABLE - public static void StartsWith(string? expectedStartString, string? actualString) -#else - public static void StartsWith(string expectedStartString, string actualString) -#endif - { - StartsWith(expectedStartString, actualString, StringComparison.CurrentCulture); - } - - /// - /// Verifies that a string starts with a given string, using the given comparison type. - /// - /// The string expected to be at the start of the string - /// The string to be inspected - /// The type of string comparison to perform - /// Thrown when the string does not start with the expected string -#if XUNIT_NULLABLE - public static void StartsWith(string? expectedStartString, string? actualString, StringComparison comparisonType) -#else - public static void StartsWith(string expectedStartString, string actualString, StringComparison comparisonType) -#endif - { - if (expectedStartString == null || actualString == null || !actualString.StartsWith(expectedStartString, comparisonType)) - throw new StartsWithException(expectedStartString, actualString); - } - - /// - /// Verifies that a string ends with a given string, using the current culture. - /// - /// The string expected to be at the end of the string - /// The string to be inspected - /// Thrown when the string does not end with the expected string -#if XUNIT_NULLABLE - public static void EndsWith(string? expectedEndString, string? actualString) -#else - public static void EndsWith(string expectedEndString, string actualString) -#endif - { - EndsWith(expectedEndString, actualString, StringComparison.CurrentCulture); - } - - /// - /// Verifies that a string ends with a given string, using the given comparison type. - /// - /// The string expected to be at the end of the string - /// The string to be inspected - /// The type of string comparison to perform - /// Thrown when the string does not end with the expected string -#if XUNIT_NULLABLE - public static void EndsWith(string? expectedEndString, string? actualString, StringComparison comparisonType) -#else - public static void EndsWith(string expectedEndString, string actualString, StringComparison comparisonType) -#endif - { - if (expectedEndString == null || actualString == null || !actualString.EndsWith(expectedEndString, comparisonType)) - throw new EndsWithException(expectedEndString, actualString); - } - - /// - /// Verifies that a string matches a regular expression. - /// - /// The regex pattern expected to match - /// The string to be inspected - /// Thrown when the string does not match the regex pattern -#if XUNIT_NULLABLE - public static void Matches(string expectedRegexPattern, string? actualString) -#else - public static void Matches(string expectedRegexPattern, string actualString) -#endif - { - NotNull(expectedRegexPattern); - - if (actualString == null || !Regex.IsMatch(actualString, expectedRegexPattern)) - throw new MatchesException(expectedRegexPattern, actualString); - } - - /// - /// Verifies that a string matches a regular expression. - /// - /// The regex expected to match - /// The string to be inspected - /// Thrown when the string does not match the regex -#if XUNIT_NULLABLE - public static void Matches(Regex expectedRegex, string? actualString) -#else - public static void Matches(Regex expectedRegex, string actualString) -#endif - { - NotNull(expectedRegex); - - if (actualString == null || !expectedRegex.IsMatch(actualString)) - throw new MatchesException(expectedRegex.ToString(), actualString); - } - - /// - /// Verifies that a string does not match a regular expression. - /// - /// The regex pattern expected not to match - /// The string to be inspected - /// Thrown when the string matches the regex pattern -#if XUNIT_NULLABLE - public static void DoesNotMatch(string expectedRegexPattern, string? actualString) -#else - public static void DoesNotMatch(string expectedRegexPattern, string actualString) -#endif - { - NotNull(expectedRegexPattern); - - if (actualString != null && Regex.IsMatch(actualString, expectedRegexPattern)) - throw new DoesNotMatchException(expectedRegexPattern, actualString); - } - - /// - /// Verifies that a string does not match a regular expression. - /// - /// The regex expected not to match - /// The string to be inspected - /// Thrown when the string matches the regex -#if XUNIT_NULLABLE - public static void DoesNotMatch(Regex expectedRegex, string? actualString) -#else - public static void DoesNotMatch(Regex expectedRegex, string actualString) -#endif - { - NotNull(expectedRegex); - - if (actualString != null && expectedRegex.IsMatch(actualString)) - throw new DoesNotMatchException(expectedRegex.ToString(), actualString); - } - - /// - /// Verifies that two strings are equivalent. - /// - /// The expected string value. - /// The actual string value. - /// Thrown when the strings are not equivalent. -#if XUNIT_NULLABLE - public static void Equal(string? expected, string? actual) -#else - public static void Equal(string expected, string actual) -#endif - { - Equal(expected, actual, false, false, false); - } - - /// - /// Verifies that two strings are equivalent. - /// - /// The expected string value. - /// The actual string value. - /// If set to true, ignores cases differences. The invariant culture is used. - /// If set to true, treats \r\n, \r, and \n as equivalent. - /// If set to true, treats spaces and tabs (in any non-zero quantity) as equivalent. - /// Thrown when the strings are not equivalent. -#if XUNIT_NULLABLE - public static void Equal( - string? expected, - string? actual, - bool ignoreCase = false, - bool ignoreLineEndingDifferences = false, - bool ignoreWhiteSpaceDifferences = false) -#else - public static void Equal( - string expected, - string actual, - bool ignoreCase = false, - bool ignoreLineEndingDifferences = false, - bool ignoreWhiteSpaceDifferences = false) -#endif - { -#if XUNIT_SPAN - if (expected == null && actual == null) - return; - if (expected == null || actual == null) - throw new EqualException(expected, actual, -1, -1); - - Equal(expected.AsSpan(), actual.AsSpan(), ignoreCase, ignoreLineEndingDifferences, ignoreWhiteSpaceDifferences); -#else - // Start out assuming the one of the values is null - int expectedIndex = -1; - int actualIndex = -1; - int expectedLength = 0; - int actualLength = 0; - - if (expected == null) - { - if (actual == null) - return; - } - else if (actual != null) - { - // Walk the string, keeping separate indices since we can skip variable amounts of - // data based on ignoreLineEndingDifferences and ignoreWhiteSpaceDifferences. - expectedIndex = 0; - actualIndex = 0; - expectedLength = expected.Length; - actualLength = actual.Length; - - while (expectedIndex < expectedLength && actualIndex < actualLength) - { - char expectedChar = expected[expectedIndex]; - char actualChar = actual[actualIndex]; - - if (ignoreLineEndingDifferences && IsLineEnding(expectedChar) && IsLineEnding(actualChar)) - { - expectedIndex = SkipLineEnding(expected, expectedIndex); - actualIndex = SkipLineEnding(actual, actualIndex); - } - else if (ignoreWhiteSpaceDifferences && IsWhiteSpace(expectedChar) && IsWhiteSpace(actualChar)) - { - expectedIndex = SkipWhitespace(expected, expectedIndex); - actualIndex = SkipWhitespace(actual, actualIndex); - } - else - { - if (ignoreCase) - { - expectedChar = Char.ToUpperInvariant(expectedChar); - actualChar = Char.ToUpperInvariant(actualChar); - } - - if (expectedChar != actualChar) - { - break; - } - - expectedIndex++; - actualIndex++; - } - } - } - - if (expectedIndex < expectedLength || actualIndex < actualLength) - { - throw new EqualException(expected, actual, expectedIndex, actualIndex); - } -#endif - } - static bool IsLineEnding(char c) - { - return c == '\r' || c == '\n'; - } - - static bool IsWhiteSpace(char c) - { - return c == ' ' || c == '\t'; - } - - static int SkipLineEnding(string value, int index) - { - if (value[index] == '\r') - { - ++index; - } - if (index < value.Length && value[index] == '\n') - { - ++index; - } - - return index; - } - - static int SkipWhitespace(string value, int index) - { - while (index < value.Length) - { - switch (value[index]) - { - case ' ': - case '\t': - index++; - break; - - default: - return index; - } - } - - return index; - } - - /// - /// Verifies that an object reference is not null. - /// - /// The object to be validated - /// Thrown when the object reference is null -#if XUNIT_NULLABLE - public static void NotNull([NotNull] object? @object) -#else - public static void NotNull(object @object) -#endif - { - if (@object == null) - throw new NotNullException(); - } - - /// - /// Verifies that an object reference is null. - /// - /// The object to be inspected - /// Thrown when the object reference is not null -#if XUNIT_NULLABLE - public static void Null([MaybeNull] object? @object) -#else - public static void Null(object @object) -#endif - { - if (@object != null) - throw new NullException(@object); - } - - /// - /// Indicates that the test should immediately fail. - /// - /// The failure message -#if XUNIT_NULLABLE - [DoesNotReturn] -#endif - public static void Fail(string message) - { - NotNull(message); - - throw new FailException(message); - } - -#if XUNIT_SPAN - /// - /// Verifies that two arrays of unmanaged type T are equal, using Span<T>.SequenceEqual. - /// - /// The type of items whose arrays are to be compared - /// The expected value - /// The value to be compared against - /// Thrown when the arrays are not equal - /// - /// If Span<T>.SequenceEqual fails, a call to Assert.Equal(object, object) is made, - /// to provide a more meaningful error message. - /// -#if XUNIT_NULLABLE - public static void Equal([AllowNull] T[] expected, [AllowNull] T[] actual) -#else - public static void Equal(T[] expected, T[] actual) -#endif - where T : unmanaged, IEquatable - { - if (expected == null && actual == null) - return; - - // Call into Equal so we get proper formatting of the sequence - if (expected == null || actual == null || !expected.AsSpan().SequenceEqual(actual)) - Equal(expected, actual); - } -#endif - - /// - /// Verifies that two values are equal, within the number of decimal - /// places given by . The values are rounded before comparison. - /// - /// The expected value - /// The value to be compared against - /// The number of decimal places (valid values: 0-15) - /// Thrown when the values are not equal - public static void Equal(double expected, double actual, int precision) - { - var expectedRounded = Math.Round(expected, precision); - var actualRounded = Math.Round(actual, precision); - - if (!Object.Equals(expectedRounded, actualRounded)) - throw new EqualException( - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", expectedRounded, expected), - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", actualRounded, actual) - ); - } - - /// - /// Verifies that two values are equal, within the number of decimal - /// places given by . The values are rounded before comparison. - /// The rounding method to use is given by - /// - /// The expected value - /// The value to be compared against - /// The number of decimal places (valid values: 0-15) - /// Rounding method to use to process a number that is midway between two numbers - public static void Equal(double expected, double actual, int precision, MidpointRounding rounding) - { - var expectedRounded = Math.Round(expected, precision, rounding); - var actualRounded = Math.Round(actual, precision, rounding); - - if (!Object.Equals(expectedRounded, actualRounded)) - throw new EqualException( - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", expectedRounded, expected), - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", actualRounded, actual) - ); - } - - /// - /// Verifies that two values are equal, within the tolerance given by - /// (positive or negative). - /// - /// The expected value - /// The value to be compared against - /// The allowed difference between values - /// Thrown when supplied tolerance is invalid" - /// Thrown when the values are not equal - public static void Equal(double expected, double actual, double tolerance) - { - if (double.IsNaN(tolerance) || double.IsNegativeInfinity(tolerance) || tolerance < 0.0) - throw new ArgumentException("Tolerance must be greater than or equal to zero", nameof(tolerance)); - - if (!(double.Equals(expected, actual) || Math.Abs(expected - actual) <= tolerance)) - throw new EqualException( - string.Format(CultureInfo.CurrentCulture, "{0:G17}", expected), - string.Format(CultureInfo.CurrentCulture, "{0:G17}", actual) - ); - } - - /// - /// Verifies that two values are equal, within the tolerance given by - /// (positive or negative). - /// - /// The expected value - /// The value to be compared against - /// The allowed difference between values - /// Thrown when supplied tolerance is invalid" - /// Thrown when the values are not equal - public static void Equal(float expected, float actual, float tolerance) - { - if (float.IsNaN(tolerance) || float.IsNegativeInfinity(tolerance) || tolerance < 0.0) - throw new ArgumentException("Tolerance must be greater than or equal to zero", nameof(tolerance)); - - if (!(float.Equals(expected, actual) || Math.Abs(expected - actual) <= tolerance)) - throw new EqualException( - string.Format(CultureInfo.CurrentCulture, "{0:G9}", expected), - string.Format(CultureInfo.CurrentCulture, "{0:G9}", actual) - ); - } - - /// - /// Verifies that two values are equal, within the number of decimal - /// places given by . The values are rounded before comparison. - /// - /// The expected value - /// The value to be compared against - /// The number of decimal places (valid values: 0-28) - /// Thrown when the values are not equal - public static void Equal(decimal expected, decimal actual, int precision) - { - var expectedRounded = Math.Round(expected, precision); - var actualRounded = Math.Round(actual, precision); - - if (expectedRounded != actualRounded) - throw new EqualException( - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", expectedRounded, expected), - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", actualRounded, actual) - ); - } - - /// - /// Verifies that two values are equal, within the precision - /// given by . - /// - /// The expected value - /// The value to be compared against - /// The allowed difference in time where the two dates are considered equal - /// Thrown when the values are not equal - public static void Equal(DateTime expected, DateTime actual, TimeSpan precision) - { - var difference = (expected - actual).Duration(); - if (difference > precision) - { - throw new EqualException( - string.Format(CultureInfo.CurrentCulture, "{0} ", expected), - string.Format(CultureInfo.CurrentCulture, "{0} difference {1} is larger than {2}", - actual, - difference.ToString(), - precision.ToString() - )); - } - } - -#if XUNIT_SPAN - /// - /// Verifies that two arrays of unmanaged type T are not equal, using Span<T>.SequenceEqual. - /// - /// The type of items whose arrays are to be compared - /// The expected value - /// The value to be compared against - /// Thrown when the arrays are equal -#if XUNIT_NULLABLE - public static void NotEqual([AllowNull] T[] expected, [AllowNull] T[] actual) -#else - public static void NotEqual(T[] expected, T[] actual) -#endif - where T : unmanaged, IEquatable - { - // Call into NotEqual so we get proper formatting of the sequence - if (expected == null && actual == null) - NotEqual(expected, actual); - if (expected == null || actual == null) - return; - if (expected.AsSpan().SequenceEqual(actual)) - NotEqual(expected, actual); - } -#endif - - /// - /// Verifies that two values are not equal, within the number of decimal - /// places given by . - /// - /// The expected value - /// The value to be compared against - /// The number of decimal places (valid values: 0-15) - /// Thrown when the values are equal - public static void NotEqual(double expected, double actual, int precision) - { - var expectedRounded = Math.Round(expected, precision); - var actualRounded = Math.Round(actual, precision); - - if (Object.Equals(expectedRounded, actualRounded)) - throw new NotEqualException( - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", expectedRounded, expected), - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", actualRounded, actual) - ); - } - - /// - /// Verifies that two values are not equal, within the number of decimal - /// places given by . - /// - /// The expected value - /// The value to be compared against - /// The number of decimal places (valid values: 0-28) - /// Thrown when the values are equal - public static void NotEqual(decimal expected, decimal actual, int precision) - { - var expectedRounded = Math.Round(expected, precision); - var actualRounded = Math.Round(actual, precision); - - if (expectedRounded == actualRounded) - throw new NotEqualException( - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", expectedRounded, expected), - string.Format(CultureInfo.CurrentCulture, "{0} (rounded from {1})", actualRounded, actual) - ); - } - - - - #endregion - - } - } + } } diff --git a/TwitchLib.Client.Test/TwitchLib.Client.Test.csproj b/TwitchLib.Client.Test/TwitchLib.Client.Test.csproj index fb5b27f7..eab1f5dd 100644 --- a/TwitchLib.Client.Test/TwitchLib.Client.Test.csproj +++ b/TwitchLib.Client.Test/TwitchLib.Client.Test.csproj @@ -3,6 +3,7 @@ net7.0 false + enable