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