Add rename SafeRetry to Try and add Catch methods

This commit is contained in:
Stone_Red
2025-05-21 13:08:44 +02:00
parent 5f4d77d3b3
commit d5581cae96
2 changed files with 155 additions and 224 deletions
-222
View File
@@ -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<InvalidOperationException>(async () =>
{
_ = await SafeRetry.RetryAsync<int>(() =>
{
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<InvalidOperationException>(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<InvalidOperationException>(() =>
{
_ = SafeRetry.Retry<int>(() =>
{
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<InvalidOperationException>(() =>
{
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<ArgumentNullException>(async () =>
{
_ = await SafeRetry.RetryAsync<int>(null!);
});
}
[TestMethod]
public async Task RetryAsync_ThrowsArgumentNullException()
{
_ = await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () =>
{
await SafeRetry.RetryAsync(null!);
});
}
[TestMethod]
public void RetryT_ThrowsArgumentNullException()
{
_ = Assert.ThrowsException<ArgumentNullException>(() =>
{
_ = SafeRetry.Retry<int>(null!);
});
}
[TestMethod]
public void Retry_ThrowsArgumentNullException()
{
_ = Assert.ThrowsException<ArgumentNullException>(() =>
{
SafeRetry.Retry(null!);
});
}
}
@@ -1,9 +1,11 @@
namespace CuteUtils.Misc;
using System.Diagnostics;
namespace CuteUtils.Misc;
/// <summary>
/// Provides methods for safely retrying actions and functions with optional delay and retry count.
/// </summary>
public static class SafeRetry
public static class Try
{
/// <summary>
/// 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);
}
/// <summary>
/// Executes a synchronous action and catches any exception, writing it to the debug output.
/// </summary>
/// <param name="action">The action to execute.</param>
public static void Catch(Action action)
{
try
{
action();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
/// <summary>
/// Executes a synchronous action and catches any exception, writing it to the debug output and returning it via an out parameter.
/// </summary>
/// <param name="action">The action to execute.</param>
/// <param name="exception">When this method returns, contains the exception that was thrown, or null if no exception was thrown.</param>
public static void Catch(Action action, out Exception? exception)
{
exception = null;
try
{
action();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
exception = ex;
}
}
/// <summary>
/// Executes a synchronous function and catches any exception, writing it to the debug output. Returns the default value if an exception occurs.
/// </summary>
/// <typeparam name="T">The return type of the function.</typeparam>
/// <param name="action">The function to execute.</param>
/// <returns>The result of the function, or the default value of <typeparamref name="T"/> if an exception occurs.</returns>
public static T? Catch<T>(Func<T> action)
{
try
{
return action();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return default;
}
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">The return type of the function.</typeparam>
/// <param name="action">The function to execute.</param>
/// <param name="exception">When this method returns, contains the exception that was thrown, or null if no exception was thrown.</param>
/// <returns>The result of the function, or the default value of <typeparamref name="T"/> if an exception occurs.</returns>
public static T? Catch<T>(Func<T> action, out Exception? exception)
{
exception = null;
try
{
return action();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
exception = ex;
return default;
}
}
/// <summary>
/// Executes an asynchronous action and catches any exception, writing it to the debug output.
/// </summary>
/// <param name="action">The asynchronous action to execute.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public static async Task CatchAsync(Func<Task> action)
{
try
{
await action();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
/// <summary>
/// Executes an asynchronous function and catches any exception, writing it to the debug output.
/// Returns the default value if an exception occurs.
/// </summary>
/// <typeparam name="T">The return type of the function.</typeparam>
/// <param name="action">The asynchronous function to execute.</param>
/// <returns>The result of the function, or the default value of <typeparamref name="T"/> if an exception occurs.</returns>
public static async Task<T?> CatchAsync<T>(Func<Task<T>> action)
{
try
{
return await action();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return default;
}
}
/// <summary>
/// Waits for an asynchronous task to complete and catches any exception, writing it to the debug output.
/// </summary>
/// <param name="task">The task to await.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public static async Task CatchAsync(Task task)
{
try
{
await task;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">The return type of the task.</typeparam>
/// <param name="task">The task to await.</param>
/// <returns>The result of the task, or the default value of <typeparamref name="T"/> if an exception occurs.</returns>
public static async Task<T?> CatchAsync<T>(Task<T> task)
{
try
{
return await task;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return default;
}
}
}