From d5581cae968349d10e35a6bc95c4d2bcaebbc191 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 21 May 2025 13:08:44 +0200 Subject: [PATCH 1/3] Add rename SafeRetry to Try and add Catch methods --- src/CuteUtils.Tests/Misc/SafeRetryTests.cs | 222 -------------------- src/CuteUtils/Misc/{SafeRetry.cs => Try.cs} | 157 +++++++++++++- 2 files changed, 155 insertions(+), 224 deletions(-) delete mode 100644 src/CuteUtils.Tests/Misc/SafeRetryTests.cs rename src/CuteUtils/Misc/{SafeRetry.cs => Try.cs} (51%) diff --git a/src/CuteUtils.Tests/Misc/SafeRetryTests.cs b/src/CuteUtils.Tests/Misc/SafeRetryTests.cs deleted file mode 100644 index dcc597c..0000000 --- a/src/CuteUtils.Tests/Misc/SafeRetryTests.cs +++ /dev/null @@ -1,222 +0,0 @@ -using CuteUtils.Misc; - -namespace CuteUtils.Tests.Misc; - -[TestClass] -public class SafeRetryTests -{ - [TestMethod] - public async Task RetryAsyncT_SucceedsFirstTry() - { - int callCount = 0; - int result = await SafeRetry.RetryAsync(async () => - { - callCount++; - await Task.Delay(10); - return 42; - }); - Assert.AreEqual(1, callCount); - Assert.AreEqual(42, result); - } - - [TestMethod] - public async Task RetryAsyncT_RetriesAndSucceeds() - { - int callCount = 0; - int result = await SafeRetry.RetryAsync(async () => - { - callCount++; - if (callCount < 3) - { - throw new InvalidOperationException(); - } - - await Task.Delay(10); - return 99; - }, maxRetries: 5, delay: TimeSpan.FromMilliseconds(1)); - Assert.AreEqual(3, callCount); - Assert.AreEqual(99, result); - } - - [TestMethod] - public async Task RetryAsyncT_ThrowsAfterMaxRetries() - { - int callCount = 0; - _ = await Assert.ThrowsExceptionAsync(async () => - { - _ = await SafeRetry.RetryAsync(() => - { - callCount++; - throw new InvalidOperationException("fail"); - }, maxRetries: 2, delay: TimeSpan.FromMilliseconds(1)); - }); - Assert.AreEqual(2, callCount); - } - - [TestMethod] - public async Task RetryAsync_SucceedsFirstTry() - { - int callCount = 0; - await SafeRetry.RetryAsync(async () => - { - callCount++; - await Task.Delay(10); - }); - Assert.AreEqual(1, callCount); - } - - [TestMethod] - public async Task RetryAsync_RetriesAndSucceeds() - { - int callCount = 0; - await SafeRetry.RetryAsync(async () => - { - callCount++; - if (callCount < 2) - { - throw new Exception(); - } - - await Task.Delay(10); - }, maxRetries: 3, delay: TimeSpan.FromMilliseconds(1)); - Assert.AreEqual(2, callCount); - } - - [TestMethod] - public async Task RetryAsync_ThrowsAfterMaxRetries() - { - int callCount = 0; - _ = await Assert.ThrowsExceptionAsync(async () => - { - await SafeRetry.RetryAsync(() => - { - callCount++; - throw new Exception(); - }, maxRetries: 2, delay: TimeSpan.FromMilliseconds(1)); - }); - Assert.AreEqual(2, callCount); - } - - [TestMethod] - public void RetryT_SucceedsFirstTry() - { - int callCount = 0; - int result = SafeRetry.Retry(() => - { - callCount++; - return 7; - }); - Assert.AreEqual(1, callCount); - Assert.AreEqual(7, result); - } - - [TestMethod] - public void RetryT_RetriesAndSucceeds() - { - int callCount = 0; - int result = SafeRetry.Retry(() => - { - callCount++; - if (callCount < 4) - { - throw new Exception(); - } - - return 123; - }, maxRetries: 5, delay: TimeSpan.FromMilliseconds(1)); - Assert.AreEqual(4, callCount); - Assert.AreEqual(123, result); - } - - [TestMethod] - public void RetryT_ThrowsAfterMaxRetries() - { - int callCount = 0; - _ = Assert.ThrowsException(() => - { - _ = SafeRetry.Retry(() => - { - callCount++; - throw new Exception(); - }, maxRetries: 3, delay: TimeSpan.FromMilliseconds(1)); - }); - Assert.AreEqual(3, callCount); - } - - [TestMethod] - public void Retry_SucceedsFirstTry() - { - int callCount = 0; - SafeRetry.Retry(() => - { - callCount++; - }); - Assert.AreEqual(1, callCount); - } - - [TestMethod] - public void Retry_RetriesAndSucceeds() - { - int callCount = 0; - SafeRetry.Retry(() => - { - callCount++; - if (callCount < 2) - { - throw new Exception(); - } - }, maxRetries: 3, delay: TimeSpan.FromMilliseconds(1)); - Assert.AreEqual(2, callCount); - } - - [TestMethod] - public void Retry_ThrowsAfterMaxRetries() - { - int callCount = 0; - _ = Assert.ThrowsException(() => - { - SafeRetry.Retry(() => - { - callCount++; - throw new Exception(); - }, maxRetries: 2, delay: TimeSpan.FromMilliseconds(1)); - }); - Assert.AreEqual(2, callCount); - } - - [TestMethod] - public async Task RetryAsyncT_ThrowsArgumentNullException() - { - _ = await Assert.ThrowsExceptionAsync(async () => - { - _ = await SafeRetry.RetryAsync(null!); - }); - } - - [TestMethod] - public async Task RetryAsync_ThrowsArgumentNullException() - { - _ = await Assert.ThrowsExceptionAsync(async () => - { - await SafeRetry.RetryAsync(null!); - }); - } - - [TestMethod] - public void RetryT_ThrowsArgumentNullException() - { - _ = Assert.ThrowsException(() => - { - _ = SafeRetry.Retry(null!); - }); - } - - [TestMethod] - public void Retry_ThrowsArgumentNullException() - { - _ = Assert.ThrowsException(() => - { - SafeRetry.Retry(null!); - }); - } -} \ No newline at end of file diff --git a/src/CuteUtils/Misc/SafeRetry.cs b/src/CuteUtils/Misc/Try.cs similarity index 51% rename from src/CuteUtils/Misc/SafeRetry.cs rename to src/CuteUtils/Misc/Try.cs index d99fd3a..bd41ed6 100644 --- a/src/CuteUtils/Misc/SafeRetry.cs +++ b/src/CuteUtils/Misc/Try.cs @@ -1,9 +1,11 @@ -namespace CuteUtils.Misc; +using System.Diagnostics; + +namespace CuteUtils.Misc; /// /// Provides methods for safely retrying actions and functions with optional delay and retry count. /// -public static class SafeRetry +public static class Try { /// /// Retries an asynchronous function returning a value, up to a specified number of times, with an optional delay between attempts. @@ -127,4 +129,155 @@ public static class SafeRetry } throw new InvalidOperationException($"Failed after {maxRetries} attempts.", lastException); } + + /// + /// Executes a synchronous action and catches any exception, writing it to the debug output. + /// + /// The action to execute. + public static void Catch(Action action) + { + try + { + action(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + /// + /// Executes a synchronous action and catches any exception, writing it to the debug output and returning it via an out parameter. + /// + /// The action to execute. + /// When this method returns, contains the exception that was thrown, or null if no exception was thrown. + public static void Catch(Action action, out Exception? exception) + { + exception = null; + try + { + action(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + exception = ex; + } + } + + /// + /// Executes a synchronous function and catches any exception, writing it to the debug output. Returns the default value if an exception occurs. + /// + /// The return type of the function. + /// The function to execute. + /// The result of the function, or the default value of if an exception occurs. + public static T? Catch(Func action) + { + try + { + return action(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + return default; + } + } + + /// + /// Executes a synchronous function and catches any exception, writing it to the debug output and returning the exception via an out parameter. + /// Returns the default value if an exception occurs. + /// + /// The return type of the function. + /// The function to execute. + /// When this method returns, contains the exception that was thrown, or null if no exception was thrown. + /// The result of the function, or the default value of if an exception occurs. + public static T? Catch(Func action, out Exception? exception) + { + exception = null; + try + { + return action(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + exception = ex; + return default; + } + } + + /// + /// Executes an asynchronous action and catches any exception, writing it to the debug output. + /// + /// The asynchronous action to execute. + /// A task that represents the asynchronous operation. + public static async Task CatchAsync(Func action) + { + try + { + await action(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + /// + /// Executes an asynchronous function and catches any exception, writing it to the debug output. + /// Returns the default value if an exception occurs. + /// + /// The return type of the function. + /// The asynchronous function to execute. + /// The result of the function, or the default value of if an exception occurs. + public static async Task CatchAsync(Func> action) + { + try + { + return await action(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + return default; + } + } + + /// + /// Waits for an asynchronous task to complete and catches any exception, writing it to the debug output. + /// + /// The task to await. + /// A task that represents the asynchronous operation. + public static async Task CatchAsync(Task task) + { + try + { + await task; + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + /// + /// Waits for an asynchronous task that returns a result and catches any exception, writing it to the debug output. + /// Returns the default value if an exception occurs. + /// + /// The return type of the task. + /// The task to await. + /// The result of the task, or the default value of if an exception occurs. + public static async Task CatchAsync(Task task) + { + try + { + return await task; + } + catch (Exception ex) + { + Debug.WriteLine(ex); + return default; + } + } } \ No newline at end of file From f366290d5de86a4792f86aa8d3768d1c631cc61a Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 21 May 2025 13:08:59 +0200 Subject: [PATCH 2/3] Add missing try tests and fix warnings --- src/CuteUtils.Tests/GlobalSuppressions.cs | 8 + src/CuteUtils.Tests/Misc/TryTests.cs | 352 ++++++++++++++++++++++ src/CuteUtils.Tests/Misc/WaitTests.cs | 80 +++-- 3 files changed, 412 insertions(+), 28 deletions(-) create mode 100644 src/CuteUtils.Tests/GlobalSuppressions.cs create mode 100644 src/CuteUtils.Tests/Misc/TryTests.cs diff --git a/src/CuteUtils.Tests/GlobalSuppressions.cs b/src/CuteUtils.Tests/GlobalSuppressions.cs new file mode 100644 index 0000000..26faa04 --- /dev/null +++ b/src/CuteUtils.Tests/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Blocker Code Smell", "S2699:Tests should include assertions", Justification = "")] \ No newline at end of file diff --git a/src/CuteUtils.Tests/Misc/TryTests.cs b/src/CuteUtils.Tests/Misc/TryTests.cs new file mode 100644 index 0000000..5446bee --- /dev/null +++ b/src/CuteUtils.Tests/Misc/TryTests.cs @@ -0,0 +1,352 @@ +using CuteUtils.Misc; + +namespace CuteUtils.Tests.Misc; + +[TestClass] +public class TryTests +{ + [TestMethod] + public async Task RetryAsyncT_SucceedsFirstTry() + { + int callCount = 0; + int result = await Try.RetryAsync(async () => + { + callCount++; + await Task.Delay(10); + return 42; + }); + Assert.AreEqual(1, callCount); + Assert.AreEqual(42, result); + } + + [TestMethod] + public async Task RetryAsyncT_RetriesAndSucceeds() + { + int callCount = 0; + int result = await Try.RetryAsync(async () => + { + callCount++; + if (callCount < 3) + { + throw new InvalidOperationException(); + } + + await Task.Delay(10); + return 99; + }, maxRetries: 5, delay: TimeSpan.FromMilliseconds(1)); + Assert.AreEqual(3, callCount); + Assert.AreEqual(99, result); + } + + [TestMethod] + public async Task RetryAsyncT_ThrowsAfterMaxRetries() + { + int callCount = 0; + _ = await Assert.ThrowsExactlyAsync(async () => + { + _ = await Try.RetryAsync(() => + { + callCount++; + throw new InvalidOperationException("fail"); + }, maxRetries: 2, delay: TimeSpan.FromMilliseconds(1)); + }); + Assert.AreEqual(2, callCount); + } + + [TestMethod] + public async Task RetryAsync_SucceedsFirstTry() + { + int callCount = 0; + await Try.RetryAsync(async () => + { + callCount++; + await Task.Delay(10); + }); + Assert.AreEqual(1, callCount); + } + + [TestMethod] + public async Task RetryAsync_RetriesAndSucceeds() + { + int callCount = 0; + await Try.RetryAsync(async () => + { + callCount++; + if (callCount < 2) + { + throw new Exception(); + } + + await Task.Delay(10); + }, maxRetries: 3, delay: TimeSpan.FromMilliseconds(1)); + Assert.AreEqual(2, callCount); + } + + [TestMethod] + public async Task RetryAsync_ThrowsAfterMaxRetries() + { + int callCount = 0; + _ = await Assert.ThrowsExactlyAsync(async () => + { + await Try.RetryAsync(() => + { + callCount++; + throw new Exception(); + }, maxRetries: 2, delay: TimeSpan.FromMilliseconds(1)); + }); + Assert.AreEqual(2, callCount); + } + + [TestMethod] + public void RetryT_SucceedsFirstTry() + { + int callCount = 0; + int result = Try.Retry(() => + { + callCount++; + return 7; + }); + Assert.AreEqual(1, callCount); + Assert.AreEqual(7, result); + } + + [TestMethod] + public void RetryT_RetriesAndSucceeds() + { + int callCount = 0; + int result = Try.Retry(() => + { + callCount++; + if (callCount < 4) + { + throw new Exception(); + } + + return 123; + }, maxRetries: 5, delay: TimeSpan.FromMilliseconds(1)); + Assert.AreEqual(4, callCount); + Assert.AreEqual(123, result); + } + + [TestMethod] + public void RetryT_ThrowsAfterMaxRetries() + { + int callCount = 0; + _ = Assert.ThrowsExactly(() => + { + _ = Try.Retry(() => + { + callCount++; + throw new Exception(); + }, maxRetries: 3, delay: TimeSpan.FromMilliseconds(1)); + }); + Assert.AreEqual(3, callCount); + } + + [TestMethod] + public void Retry_SucceedsFirstTry() + { + int callCount = 0; + Try.Retry(() => + { + callCount++; + }); + Assert.AreEqual(1, callCount); + } + + [TestMethod] + public void Retry_RetriesAndSucceeds() + { + int callCount = 0; + Try.Retry(() => + { + callCount++; + if (callCount < 2) + { + throw new Exception(); + } + }, maxRetries: 3, delay: TimeSpan.FromMilliseconds(1)); + Assert.AreEqual(2, callCount); + } + + [TestMethod] + public void Retry_ThrowsAfterMaxRetries() + { + int callCount = 0; + _ = Assert.ThrowsExactly(() => + { + Try.Retry(() => + { + callCount++; + throw new Exception(); + }, maxRetries: 2, delay: TimeSpan.FromMilliseconds(1)); + }); + Assert.AreEqual(2, callCount); + } + + [TestMethod] + public async Task RetryAsyncT_ThrowsArgumentNullException() + { + _ = await Assert.ThrowsExactlyAsync(async () => + { + _ = await Try.RetryAsync(null!); + }); + } + + [TestMethod] + public async Task RetryAsync_ThrowsArgumentNullException() + { + _ = await Assert.ThrowsExactlyAsync(async () => + { + await Try.RetryAsync(null!); + }); + } + + [TestMethod] + public void RetryT_ThrowsArgumentNullException() + { + _ = Assert.ThrowsExactly(() => + { + _ = Try.Retry(null!); + }); + } + + [TestMethod] + public void Retry_ThrowsArgumentNullException() + { + _ = Assert.ThrowsExactly(() => + { + Try.Retry(null!); + }); + } + + [TestClass] + public class TryCatchTests + { + [TestMethod] + public void Catch_Action_NoException() + { + bool executed = false; + + _ = Try.Catch(() => executed = true); + + Assert.IsTrue(executed); + } + + [TestMethod] + public void Catch_Action_ExceptionHandled() + { + Try.Catch(() => throw new InvalidOperationException()); + } + + [TestMethod] + public void Catch_Action_OutParam_ExceptionHandled() + { + Try.Catch(() => throw new InvalidOperationException(), out Exception? exception); + + Assert.IsNotNull(exception); + Assert.IsInstanceOfType(exception, typeof(InvalidOperationException)); + } + + [TestMethod] + public void Catch_TFunc_NoException() + { + int result = Try.Catch(() => 42)!; + + Assert.AreEqual(42, result); + } + + [TestMethod] + public void Catch_TFunc_ExceptionHandled_ReturnsDefault() + { + int? result = Try.Catch(() => throw new InvalidOperationException()); + + Assert.AreEqual(default(int), result); + } + + [TestMethod] + public void Catch_TFunc_OutParam_ExceptionHandled() + { + int? result = Try.Catch(() => throw new InvalidOperationException(), out Exception? exception); + + Assert.IsNull(result); + Assert.IsNotNull(exception); + } + + [TestMethod] + public async Task CatchAsync_Delegate_NoException() + { + bool executed = false; + + await Try.CatchAsync(async () => + { + executed = true; + await Task.Delay(10); + }); + + Assert.IsTrue(executed); + } + + [TestMethod] + public async Task CatchAsync_Delegate_ExceptionHandled() + { + await Try.CatchAsync(async () => + { + await Task.Delay(10); + throw new InvalidOperationException(); + }); + } + + [TestMethod] + public async Task CatchAsync_TFunc_NoException() + { + int result = await Try.CatchAsync(async () => + { + await Task.Delay(10); + return 99; + }); + + Assert.AreEqual(99, result); + } + + [TestMethod] + public async Task CatchAsync_TFunc_ExceptionHandled_ReturnsDefault() + { + int result = await Try.CatchAsync(async () => + { + await Task.Delay(10); + throw new InvalidOperationException(); + }); + + Assert.AreEqual(default, result); + } + + [TestMethod] + public async Task CatchAsync_Task_NoException() + { + await Try.CatchAsync(Task.Delay(10)); + } + + [TestMethod] + public async Task CatchAsync_Task_ExceptionHandled() + { + await Try.CatchAsync(Task.Run(() => throw new InvalidOperationException())); + } + + [TestMethod] + public async Task CatchAsync_TaskT_NoException() + { + string? result = await Try.CatchAsync(Task.FromResult("Hello")); + + Assert.AreEqual("Hello", result); + } + + [TestMethod] + public async Task CatchAsync_TaskT_ExceptionHandled_ReturnsDefault() + { + string? result = await Try.CatchAsync(Task.Run(() => ""[0].ToString())); + + Assert.IsNull(result); + } + } +} \ No newline at end of file diff --git a/src/CuteUtils.Tests/Misc/WaitTests.cs b/src/CuteUtils.Tests/Misc/WaitTests.cs index efd14fe..634a7ee 100644 --- a/src/CuteUtils.Tests/Misc/WaitTests.cs +++ b/src/CuteUtils.Tests/Misc/WaitTests.cs @@ -9,9 +9,9 @@ public class WaitTests public async Task UntilAsync_ConditionMet_CompletesSuccessfully() { bool flag = false; - _ = Task.Run(() => + _ = Task.Run(async () => { - Thread.Sleep(200); + await Task.Delay(200); flag = true; }); await Wait.UntilAsync(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2)); @@ -19,19 +19,21 @@ public class WaitTests } [TestMethod] - [ExpectedException(typeof(TimeoutException))] public async Task UntilAsync_ConditionNotMet_ThrowsTimeoutException() { - await Wait.UntilAsync(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200)); + _ = await Assert.ThrowsExactlyAsync(async () => + { + await Wait.UntilAsync(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200)); + }); } [TestMethod] public void Until_ConditionMet_CompletesSuccessfully() { bool flag = false; - _ = Task.Run(() => + _ = Task.Run(async () => { - Thread.Sleep(200); + await Task.Delay(200); flag = true; }); Wait.Until(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2)); @@ -39,10 +41,12 @@ public class WaitTests } [TestMethod] - [ExpectedException(typeof(TimeoutException))] public void Until_ConditionNotMet_ThrowsTimeoutException() { - Wait.Until(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200)); + _ = Assert.ThrowsExactly(() => + { + Wait.Until(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200)); + }); } [TestMethod] @@ -50,9 +54,9 @@ public class WaitTests { void subscribe(Action handler) { - _ = Task.Run(() => + _ = Task.Run(async () => { - Thread.Sleep(200); + await Task.Delay(200); handler(); }); } @@ -60,11 +64,16 @@ public class WaitTests } [TestMethod] - [ExpectedException(typeof(TimeoutException))] public async Task WaitForEventAsync_EventNotRaised_ThrowsTimeoutException() { - void subscribe(Action handler) { } - await Wait.WaitForEventAsync(subscribe, TimeSpan.FromMilliseconds(200)); + void subscribe(Action handler) + { + // Intentionally left empty for negative test case (event never raised) + } + _ = await Assert.ThrowsExactlyAsync(async () => + { + await Wait.WaitForEventAsync(subscribe, TimeSpan.FromMilliseconds(200)); + }); } [TestMethod] @@ -72,9 +81,9 @@ public class WaitTests { void subscribe(Action handler) { - _ = Task.Run(() => + _ = Task.Run(async () => { - Thread.Sleep(200); + await Task.Delay(200); handler(42); }); } @@ -83,11 +92,16 @@ public class WaitTests } [TestMethod] - [ExpectedException(typeof(TimeoutException))] public async Task WaitForEventAsyncT_EventNotRaised_ThrowsTimeoutException() { - void subscribe(Action handler) { } - _ = await Wait.WaitForEventAsync((Action>)subscribe, TimeSpan.FromMilliseconds(200)); + void subscribe(Action handler) + { + // Intentionally left empty for negative test case (event never raised) + } + _ = await Assert.ThrowsExactlyAsync(async () => + { + _ = await Wait.WaitForEventAsync((Action>)subscribe, TimeSpan.FromMilliseconds(200)); + }); } [TestMethod] @@ -95,9 +109,9 @@ public class WaitTests { void subscribe(Action handler) { - _ = Task.Run(() => + _ = Task.Run(async () => { - Thread.Sleep(200); + await Task.Delay(200); handler(); }); } @@ -105,11 +119,16 @@ public class WaitTests } [TestMethod] - [ExpectedException(typeof(TimeoutException))] public void WaitForEvent_EventNotRaised_ThrowsTimeoutException() { - void subscribe(Action handler) { } - Wait.WaitForEvent(subscribe, TimeSpan.FromMilliseconds(200)); + void subscribe(Action handler) + { + // Intentionally left empty for negative test case (event never raised) + } + _ = Assert.ThrowsExactly(() => + { + Wait.WaitForEvent(subscribe, TimeSpan.FromMilliseconds(200)); + }); } [TestMethod] @@ -117,9 +136,9 @@ public class WaitTests { void subscribe(Action handler) { - _ = Task.Run(() => + _ = Task.Run(async () => { - Thread.Sleep(200); + await Task.Delay(200); handler("hello"); }); } @@ -128,10 +147,15 @@ public class WaitTests } [TestMethod] - [ExpectedException(typeof(TimeoutException))] public void WaitForEventT_EventNotRaised_ThrowsTimeoutException() { - void subscribe(Action handler) { } - _ = Wait.WaitForEvent((Action>)subscribe, TimeSpan.FromMilliseconds(200)); + void subscribe(Action handler) + { + // Intentionally left empty for negative test case (event never raised) + } + _ = Assert.ThrowsExactly(() => + { + _ = Wait.WaitForEvent((Action>)subscribe, TimeSpan.FromMilliseconds(200)); + }); } } \ No newline at end of file From c49e29ac7dee9e63f62db8daf7e261d23ca53b70 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 21 May 2025 13:10:20 +0200 Subject: [PATCH 3/3] Update version --- src/CuteUtils/CuteUtils.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CuteUtils/CuteUtils.csproj b/src/CuteUtils/CuteUtils.csproj index 628525a..6411c64 100644 --- a/src/CuteUtils/CuteUtils.csproj +++ b/src/CuteUtils/CuteUtils.csproj @@ -40,7 +40,7 @@ --> $([System.IO.Path]::GetTempPath()) - 1.1.0.0 + 1.1.1.0 A "cute" utility library for C# https://github.com/Stone-Red-Code/CuteUtils Utility, Helper