mirror of
https://github.com/Stone-Red-Code/CuteUtils.git
synced 2026-09-09 15:56:13 +02:00
@@ -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 = "<Pending>")]
|
||||||
@@ -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!);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<InvalidOperationException>(async () =>
|
||||||
|
{
|
||||||
|
_ = await Try.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 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<InvalidOperationException>(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<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
_ = Try.Retry<int>(() =>
|
||||||
|
{
|
||||||
|
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<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
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<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
_ = await Try.RetryAsync<int>(null!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task RetryAsync_ThrowsArgumentNullException()
|
||||||
|
{
|
||||||
|
_ = await Assert.ThrowsExactlyAsync<ArgumentNullException>(async () =>
|
||||||
|
{
|
||||||
|
await Try.RetryAsync(null!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void RetryT_ThrowsArgumentNullException()
|
||||||
|
{
|
||||||
|
_ = Assert.ThrowsExactly<ArgumentNullException>(() =>
|
||||||
|
{
|
||||||
|
_ = Try.Retry<int>(null!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Retry_ThrowsArgumentNullException()
|
||||||
|
{
|
||||||
|
_ = Assert.ThrowsExactly<ArgumentNullException>(() =>
|
||||||
|
{
|
||||||
|
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<int>(() => throw new InvalidOperationException());
|
||||||
|
|
||||||
|
Assert.AreEqual(default(int), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Catch_TFunc_OutParam_ExceptionHandled()
|
||||||
|
{
|
||||||
|
int? result = Try.Catch<int?>(() => 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<int>(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<string>(Task.Run<string>(() => ""[0].ToString()));
|
||||||
|
|
||||||
|
Assert.IsNull(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,9 +9,9 @@ public class WaitTests
|
|||||||
public async Task UntilAsync_ConditionMet_CompletesSuccessfully()
|
public async Task UntilAsync_ConditionMet_CompletesSuccessfully()
|
||||||
{
|
{
|
||||||
bool flag = false;
|
bool flag = false;
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Thread.Sleep(200);
|
await Task.Delay(200);
|
||||||
flag = true;
|
flag = true;
|
||||||
});
|
});
|
||||||
await Wait.UntilAsync(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2));
|
await Wait.UntilAsync(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2));
|
||||||
@@ -19,19 +19,21 @@ public class WaitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(TimeoutException))]
|
|
||||||
public async Task UntilAsync_ConditionNotMet_ThrowsTimeoutException()
|
public async Task UntilAsync_ConditionNotMet_ThrowsTimeoutException()
|
||||||
{
|
{
|
||||||
await Wait.UntilAsync(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200));
|
_ = await Assert.ThrowsExactlyAsync<TimeoutException>(async () =>
|
||||||
|
{
|
||||||
|
await Wait.UntilAsync(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Until_ConditionMet_CompletesSuccessfully()
|
public void Until_ConditionMet_CompletesSuccessfully()
|
||||||
{
|
{
|
||||||
bool flag = false;
|
bool flag = false;
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Thread.Sleep(200);
|
await Task.Delay(200);
|
||||||
flag = true;
|
flag = true;
|
||||||
});
|
});
|
||||||
Wait.Until(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2));
|
Wait.Until(() => flag, TimeSpan.FromMilliseconds(50), TimeSpan.FromSeconds(2));
|
||||||
@@ -39,10 +41,12 @@ public class WaitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(TimeoutException))]
|
|
||||||
public void Until_ConditionNotMet_ThrowsTimeoutException()
|
public void Until_ConditionNotMet_ThrowsTimeoutException()
|
||||||
{
|
{
|
||||||
Wait.Until(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200));
|
_ = Assert.ThrowsExactly<TimeoutException>(() =>
|
||||||
|
{
|
||||||
|
Wait.Until(() => false, TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(200));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@@ -50,9 +54,9 @@ public class WaitTests
|
|||||||
{
|
{
|
||||||
void subscribe(Action handler)
|
void subscribe(Action handler)
|
||||||
{
|
{
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Thread.Sleep(200);
|
await Task.Delay(200);
|
||||||
handler();
|
handler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -60,11 +64,16 @@ public class WaitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(TimeoutException))]
|
|
||||||
public async Task WaitForEventAsync_EventNotRaised_ThrowsTimeoutException()
|
public async Task WaitForEventAsync_EventNotRaised_ThrowsTimeoutException()
|
||||||
{
|
{
|
||||||
void subscribe(Action handler) { }
|
void subscribe(Action handler)
|
||||||
await Wait.WaitForEventAsync(subscribe, TimeSpan.FromMilliseconds(200));
|
{
|
||||||
|
// Intentionally left empty for negative test case (event never raised)
|
||||||
|
}
|
||||||
|
_ = await Assert.ThrowsExactlyAsync<TimeoutException>(async () =>
|
||||||
|
{
|
||||||
|
await Wait.WaitForEventAsync(subscribe, TimeSpan.FromMilliseconds(200));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@@ -72,9 +81,9 @@ public class WaitTests
|
|||||||
{
|
{
|
||||||
void subscribe(Action<int> handler)
|
void subscribe(Action<int> handler)
|
||||||
{
|
{
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Thread.Sleep(200);
|
await Task.Delay(200);
|
||||||
handler(42);
|
handler(42);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -83,11 +92,16 @@ public class WaitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(TimeoutException))]
|
|
||||||
public async Task WaitForEventAsyncT_EventNotRaised_ThrowsTimeoutException()
|
public async Task WaitForEventAsyncT_EventNotRaised_ThrowsTimeoutException()
|
||||||
{
|
{
|
||||||
void subscribe(Action<int> handler) { }
|
void subscribe(Action<int> handler)
|
||||||
_ = await Wait.WaitForEventAsync((Action<Action<int>>)subscribe, TimeSpan.FromMilliseconds(200));
|
{
|
||||||
|
// Intentionally left empty for negative test case (event never raised)
|
||||||
|
}
|
||||||
|
_ = await Assert.ThrowsExactlyAsync<TimeoutException>(async () =>
|
||||||
|
{
|
||||||
|
_ = await Wait.WaitForEventAsync((Action<Action<int>>)subscribe, TimeSpan.FromMilliseconds(200));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@@ -95,9 +109,9 @@ public class WaitTests
|
|||||||
{
|
{
|
||||||
void subscribe(Action handler)
|
void subscribe(Action handler)
|
||||||
{
|
{
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Thread.Sleep(200);
|
await Task.Delay(200);
|
||||||
handler();
|
handler();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -105,11 +119,16 @@ public class WaitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(TimeoutException))]
|
|
||||||
public void WaitForEvent_EventNotRaised_ThrowsTimeoutException()
|
public void WaitForEvent_EventNotRaised_ThrowsTimeoutException()
|
||||||
{
|
{
|
||||||
void subscribe(Action handler) { }
|
void subscribe(Action handler)
|
||||||
Wait.WaitForEvent(subscribe, TimeSpan.FromMilliseconds(200));
|
{
|
||||||
|
// Intentionally left empty for negative test case (event never raised)
|
||||||
|
}
|
||||||
|
_ = Assert.ThrowsExactly<TimeoutException>(() =>
|
||||||
|
{
|
||||||
|
Wait.WaitForEvent(subscribe, TimeSpan.FromMilliseconds(200));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
@@ -117,9 +136,9 @@ public class WaitTests
|
|||||||
{
|
{
|
||||||
void subscribe(Action<string> handler)
|
void subscribe(Action<string> handler)
|
||||||
{
|
{
|
||||||
_ = Task.Run(() =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Thread.Sleep(200);
|
await Task.Delay(200);
|
||||||
handler("hello");
|
handler("hello");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -128,10 +147,15 @@ public class WaitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(TimeoutException))]
|
|
||||||
public void WaitForEventT_EventNotRaised_ThrowsTimeoutException()
|
public void WaitForEventT_EventNotRaised_ThrowsTimeoutException()
|
||||||
{
|
{
|
||||||
void subscribe(Action<string> handler) { }
|
void subscribe(Action<string> handler)
|
||||||
_ = Wait.WaitForEvent((Action<Action<string>>)subscribe, TimeSpan.FromMilliseconds(200));
|
{
|
||||||
|
// Intentionally left empty for negative test case (event never raised)
|
||||||
|
}
|
||||||
|
_ = Assert.ThrowsExactly<TimeoutException>(() =>
|
||||||
|
{
|
||||||
|
_ = Wait.WaitForEvent((Action<Action<string>>)subscribe, TimeSpan.FromMilliseconds(200));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
-->
|
-->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<UserTempFolder>$([System.IO.Path]::GetTempPath())</UserTempFolder>
|
<UserTempFolder>$([System.IO.Path]::GetTempPath())</UserTempFolder>
|
||||||
<Version>1.1.0.0</Version>
|
<Version>1.1.1.0</Version>
|
||||||
<Description>A "cute" utility library for C#</Description>
|
<Description>A "cute" utility library for C#</Description>
|
||||||
<RepositoryUrl>https://github.com/Stone-Red-Code/CuteUtils</RepositoryUrl>
|
<RepositoryUrl>https://github.com/Stone-Red-Code/CuteUtils</RepositoryUrl>
|
||||||
<PackageTags>Utility, Helper</PackageTags>
|
<PackageTags>Utility, Helper</PackageTags>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
namespace CuteUtils.Misc;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace CuteUtils.Misc;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides methods for safely retrying actions and functions with optional delay and retry count.
|
/// Provides methods for safely retrying actions and functions with optional delay and retry count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class SafeRetry
|
public static class Try
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retries an asynchronous function returning a value, up to a specified number of times, with an optional delay between attempts.
|
/// 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);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user