6 Commits

Author SHA1 Message Date
Josh Creek aabbfcaf70 feat(*): Update readme with exception extensions 2021-11-28 22:07:13 +00:00
Josh Creek 7b585dfc1e build(*): Update package version 2021-11-28 22:02:21 +00:00
Josh Creek eb463a0f36 feat(*): Add ExceptionExtension unit tests 2021-11-28 22:02:07 +00:00
Josh Creek 7037e2dc5e feat(*): Add ExceptionExtension class 2021-11-28 22:01:57 +00:00
Josh Creek af60820c10 feat(*): Add SystemTime.Now documentation to readme 2021-09-02 20:00:55 +01:00
Josh Creek 14530efb0f feat(*): Add SystemTime.Now method 2021-09-02 20:00:46 +01:00
5 changed files with 336 additions and 2 deletions
@@ -19,8 +19,8 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryType>git</RepositoryType>
<PackageTags>creek</PackageTags>
<Version>1.1.0</Version>
<AssemblyVersion>1.1.0.0</AssemblyVersion>
<Version>1.3.0</Version>
<AssemblyVersion>1.3.0.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup>
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Creek.HelpfulExtensions
{
public static class ExceptionExtension
{
/// <summary>
/// Returns a string of the message of the first/root/base exception in an exception stack.
/// </summary>
/// <param name="ex">The Exception stack to find the first/root/base exception within.</param>
/// <returns>Returns the first/root/base exception message string.</returns>
public static string BaseExceptionMessage(this Exception ex)
{
Exception baseEx = ex.GetBaseException();
return baseEx.Message;
}
/// <summary>
/// Returns a single string of the message and stack trace of the first/root/base exception in an exception stack.
/// </summary>
/// <param name="ex">The Exception stack to find the first/root/base exception within.</param>
/// <returns>Returns the first/root/base exception message and stack trace as a single string, separated by " :: ".</returns>
public static string BaseExceptionMessageAndStackTrace(this Exception ex)
{
Exception baseEx = ex.GetBaseException();
return GenerateMessageAndStackTraceString(baseEx);
}
/// <summary>
/// Returns a list of the exception messages of each nested exception in an exception stack.
/// </summary>
/// <param name="ex">The Exception stack.</param>
/// <returns>Returns a list of the exception messages of each nested exception in an exception stack.</returns>
public static List<string> AllInnerExceptionMessages(this Exception ex)
{
return GetAllInnerExceptionMessagesAndStackTraces(ex, includeStackTraces: false);
}
/// <summary>
/// Returns a list of single strings of the message and stack trace of each nested exception in an exception stack.
/// </summary>
/// <param name="ex">The Exception stack.</param>
/// <returns>Returns a list with a string for each nested exception in an exception stack containing the exception message and stack trace as a single string, separated by " :: ".</returns>
public static List<string> AllInnerExceptionMessagesAndStackTraces(this Exception ex)
{
return GetAllInnerExceptionMessagesAndStackTraces(ex, includeStackTraces: true);
}
private static List<string> GetAllInnerExceptionMessagesAndStackTraces(Exception ex, bool includeStackTraces)
{
List<string> exceptionMessagesAndStackTraces = new List<string>();
Exception inner = ex.InnerException;
exceptionMessagesAndStackTraces.Add(
includeStackTraces ? GenerateMessageAndStackTraceString(ex)
: ex.Message);
while (inner != null)
{
exceptionMessagesAndStackTraces.Add(
includeStackTraces ? GenerateMessageAndStackTraceString(inner)
: inner.Message);
inner = inner.InnerException;
}
// We've now reached the end of the exceptions, so can return the error messages
return exceptionMessagesAndStackTraces;
}
private static string GenerateMessageAndStackTraceString(Exception ex)
{
return $"{ex.Message} :: {ex.StackTrace}";
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Creek.HelpfulExtensions
{
public static class SystemTime
{
/// <summary>
/// This method exposes DateTime.Now as an instance of a function, that can be replaced in tests.
/// </summary>
#pragma warning disable S1104 // Fields should not have public accessibility
#pragma warning disable S2223 // Non-constant static fields should not be visible
public static Func<DateTime> Now = () => DateTime.Now;
#pragma warning restore S2223 // Non-constant static fields should not be visible
#pragma warning restore S1104 // Fields should not have public accessibility
}
}
+94
View File
@@ -40,3 +40,97 @@ foreach (var (item, index) in list.WithIndex())
// ...
}
```
## DateTime Extensions
### SystemTime.Now
This is technically not an extension, but fits well in this package. It's taken from [this blog](https://lostechies.com/jimmybogard/2008/11/09/systemtime-versus-isystemclock-dependencies-revisited/). This method exposes DateTime.Now as an instance of a function, that can be replaced in tests.
If you want to replace SystemTime.Now in a test you can do it like this:
```csharp
[Test]
public void Should_test_something_here()
{
var systemTimeDate = new DateTime(2021, 9, 2);
SystemTime.Now = () => new DateTime(2021, 9, 2);
DateTime dateTimeToBeTested = systemTimeDate;
// ...
}
```
You can also set SystemTime.Now to any function that returns a DateTime:
```csharp
var startDate = new DateTime(2021, 9, 2);
SystemTime.Now = () => startDate.AddDays(2);
```
## Exception Extensions
### BaseExceptionMessage
Returns a string of the message of the first/root/base exception in an exception stack.
```csharp
try
{
...
}
catch (Exception ex)
{
string baseExceptionMessage = ex.BaseExceptionMessage();
...
}
```
### BaseExceptionMessageAndStackTrace
Returns a single string of the message and stack trace of the first/root/base exception in an exception stack.
```csharp
try
{
...
}
catch (Exception ex)
{
string baseExceptionMessageAndStackTrace = ex.BaseExceptionMessageAndStackTrace();
...
}
```
### AllInnerExceptionMessages
Returns a list of the exception messages of each nested exception in an exception stack.
```csharp
try
{
...
}
catch (Exception ex)
{
List<string> allInnerExceptionMessages = ex.AllInnerExceptionMessages();
...
}
```
### AllInnerExceptionMessagesAndStackTraces
Returns a list of single strings of the message and stack trace of each nested exception in an exception stack.
```csharp
try
{
...
}
catch (Exception ex)
{
List<string> allInnerExceptionMessagesAndStackTraces = ex.AllInnerExceptionMessagesAndStackTraces();
...
}
```
+144
View File
@@ -0,0 +1,144 @@
using NUnit.Framework;
using Creek.HelpfulExtensions;
using System;
using System.Collections.Generic;
namespace UnitTests
{
public class ExceptionExtensionTests
{
[SetUp]
public void Setup()
{
}
[Test]
public void ShouldReturnBaseExceptionMessage()
{
try
{
// This function calls another that forces a
// division by 0.
Rethrow();
}
catch (Exception ex)
{
string baseExceptionMessage = ex.BaseExceptionMessage();
Assert.AreEqual("Attempted to divide by zero.", baseExceptionMessage);
}
}
[Test]
public void ShouldReturnBaseExceptionMessageAndStackTrace()
{
try
{
// This function calls another that forces a
// division by 0.
Rethrow();
}
catch (Exception ex)
{
string baseExceptionMessageAndStackTrace = ex.BaseExceptionMessageAndStackTrace();
StringAssert.StartsWith("Attempted to divide by zero.", baseExceptionMessageAndStackTrace);
Assert.AreNotEqual("Attempted to divide by zero.", baseExceptionMessageAndStackTrace);
}
}
[Test]
public void ShouldReturnAllInnerExceptionMessages()
{
try
{
// This function calls another that forces a
// division by 0.
Rethrow();
}
catch (Exception ex)
{
List<string> allInnerExceptionMessages = ex.AllInnerExceptionMessages();
List<string> expected = new List<string>()
{
"Caught the second exception and threw a third in response.",
"Forced a division by 0 and threw a second exception.",
"Attempted to divide by zero.",
};
CollectionAssert.AreEqual(expected, allInnerExceptionMessages);
}
}
[Test]
public void ShouldReturnAllInnerExceptionMessagesAndStackTraces()
{
try
{
// This function calls another that forces a
// division by 0.
Rethrow();
}
catch (Exception ex)
{
List<string> allInnerExceptionMessagesAndStackTraces = ex.AllInnerExceptionMessagesAndStackTraces();
List<string> expected = new List<string>()
{
"Caught the second exception and threw a third in response.",
"Forced a division by 0 and threw a second exception.",
"Attempted to divide by zero.",
};
foreach (var (baseExceptionMessageAndStackTrace, index) in allInnerExceptionMessagesAndStackTraces.WithIndex())
{
StringAssert.StartsWith(expected[index], baseExceptionMessageAndStackTrace);
Assert.AreNotEqual(expected[index], baseExceptionMessageAndStackTrace);
}
}
}
// This function catches the exception from the called
// function DivideBy0( ) and throws another in response.
private void Rethrow()
{
try
{
DivideBy0();
}
catch (Exception ex)
{
throw new ThirdLevelException("Caught the second exception and threw a third in response.", ex);
}
}
// This function forces a division by 0 and throws a second
// exception.
private void DivideBy0()
{
try
{
int zero = 0;
int ecks = 1 / zero;
}
catch (Exception ex)
{
throw new SecondLevelException("Forced a division by 0 and threw a second exception.", ex);
}
}
// Define two derived exceptions to demonstrate nested exceptions.
private class SecondLevelException : Exception
{
public SecondLevelException(string message, Exception inner)
: base(message, inner)
{ }
}
private class ThirdLevelException : Exception
{
public ThirdLevelException(string message, Exception inner)
: base(message, inner)
{ }
}
}
}