Skip to content

Commit eff7bf4

Browse files
Merge pull request #186 from Stravaig-Projects/#184/tcl-casting
#184: Test Capture Logger casting
2 parents 5353aff + efa9e7d commit eff7bf4

File tree

4 files changed

+94
-5
lines changed

4 files changed

+94
-5
lines changed

Reset-WipReleaseNotes.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ $content = @(
55
"",
66
"Date: ???",
77
""
8-
"### Bugs"
8+
"### Bug Fixes"
99
"",
1010
"### Features",
1111
"",
@@ -15,11 +15,11 @@ $content = @(
1515
"",
1616
"- All targets:"
1717
"- .NET 6.0 targets:"
18-
"- .NET 7.0 targets:"
1918
"- .NET 8.0 targets:"
19+
"- .NET 9.0 targets:"
2020
"",
2121
"",
2222
""
2323
)
2424

25-
Set-Content "$PSScriptRoot/release-notes/wip-release-notes.md" $content -Encoding UTF8 -Force
25+
Set-Content "$PSScriptRoot/release-notes/wip-release-notes.md" $content -Encoding UTF8 -Force

release-notes/wip-release-notes.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ Date: ???
99
- Feature #123 changes the `TestCaptureLogger<T>` class to encapsulate an instance of `TestCaptureLogger` rather than inherit from it. If you're code relied on `TestCaptureLogger<T>` inheriting from `TestCaptureLogger` then it will likely break.
1010
- Feature #172 drops support for .NET 7.0. Use .NET 6.0 LTS, .NET 8.0 LTS or .NET 9.0 STS.
1111

12-
### Bugs
13-
1412
### Features
1513

1614
- #123: `TestCaptureLoggerProvider.CreateLogger<T>()`
@@ -20,6 +18,9 @@ Date: ???
2018
- `ITestOutputHelper.WriteLogs(ITestCaptureLogger...)`
2119
- `ITestOutputHelper.WriteLogs(TestCaptureLoggerProvider...)`
2220
- #171: Add `GetLogs(predicate)` to `TestCaptureLogger` and `TestCaptureLoggerProvider`.
21+
- #184: Add casting between `TestCaptureLogger` and `TestCaptureLogger<T>` to compensate for `TestCaptureLogger<T>` no longer inheriting from `TestCaptureLogger`
22+
- `TestCaptureLogger<T>` may be implicitly or explicitly cast to `TestCaptureLogger`
23+
- `TestCaptureLogger` must be explicitly cast to `TestCaptureLogger<T>`. The cast may fail if the category name used by the `TestCaptureLogger` does not match the type name of `T`.
2324

2425
### Miscellaneous
2526

src/Stravaig.Extensions.Logging.Diagnostics.Tests/TestCaptureLoggerOfTTests.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.Extensions.Logging;
33
using NUnit.Framework;
44
using Shouldly;
5+
using Stravaig.Extensions.Logging.Diagnostics.ExternalHelpers;
56

67
namespace Stravaig.Extensions.Logging.Diagnostics.Tests;
78

@@ -23,6 +24,38 @@ public void ConstructorCategoryMismatchThrows()
2324
.Message.ShouldBe("The category name does not match the type of this logger. Expected \"object\", got \"NotTheRightCategory\".");
2425
}
2526

27+
[Test]
28+
public void ExplicitCastCategoryMismatchThrows()
29+
{
30+
var underlyingLogger = new TestCaptureLogger("NotTheRightCategory");
31+
Should.Throw<InvalidCastException>(() =>
32+
{
33+
_ = (TestCaptureLogger<object>)underlyingLogger; // explicit cast
34+
})
35+
.Message.ShouldBe("The category name does not match the type of this logger. Cannot cast a TestCaptureLogger with category name NotTheRightCategory to TestCaptureLogger<object>.");
36+
}
37+
38+
[Test]
39+
public void ConstructorCategoryCorrectNameIsConstructed()
40+
{
41+
var categoryName = TypeNameHelper.GetTypeDisplayName(typeof(object));
42+
var underlyingLogger = new TestCaptureLogger(categoryName);
43+
var typedLogger = new TestCaptureLogger<object>(underlyingLogger);
44+
typedLogger.ShouldNotBeNull();
45+
typedLogger.CategoryName.ShouldBe(categoryName);
46+
}
47+
48+
[Test]
49+
public void ExplicitCastCategoryCorrectNameIsConstructed()
50+
{
51+
var categoryName = TypeNameHelper.GetTypeDisplayName(typeof(object));
52+
var underlyingLogger = new TestCaptureLogger(categoryName);
53+
var typedLogger = (TestCaptureLogger<object>)underlyingLogger;
54+
typedLogger.ShouldNotBeNull();
55+
typedLogger.CategoryName.ShouldBe(categoryName);
56+
typedLogger.ShouldBeOfType<TestCaptureLogger<object>>();
57+
}
58+
2659
[Test]
2760
public void CategoryNameIsBasedOnType()
2861
{
@@ -83,4 +116,24 @@ public void GetLogsMatchingPredicateWillFilterOutUnwantedLogs()
83116
.Count.ShouldBe(1);
84117
logger.GetLogs().Count.ShouldBe(4);
85118
}
119+
120+
[Test]
121+
public void TheImplicitCastOperatorReturnsTheInternalLogger()
122+
{
123+
var categoryName = TypeNameHelper.GetTypeDisplayName(typeof(TestCaptureLoggerOfTTests));
124+
var originalLogger = new TestCaptureLogger(categoryName);
125+
var logger = new TestCaptureLogger<TestCaptureLoggerOfTTests>(originalLogger);
126+
TestCaptureLogger internalLogger = logger; // implicit cast
127+
internalLogger.ShouldBe(originalLogger);
128+
}
129+
130+
[Test]
131+
public void TheExplicitCastReturnsTheInternalLogger()
132+
{
133+
var categoryName = TypeNameHelper.GetTypeDisplayName(typeof(TestCaptureLoggerOfTTests));
134+
var originalLogger = new TestCaptureLogger(categoryName);
135+
var logger = new TestCaptureLogger<TestCaptureLoggerOfTTests>(originalLogger);
136+
var internalLogger = (TestCaptureLogger)logger; // explicit cast
137+
internalLogger.ShouldBe(originalLogger);
138+
}
86139
}

src/Stravaig.Extensions.Logging.Diagnostics/TestCaptureLogger(OfTCategoryType).cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,41 @@ public TestCaptureLogger(TestCaptureLogger logger)
3636
_logger = logger;
3737
}
3838

39+
/// <summary>
40+
/// Converts a <see cref="TestCaptureLogger{TCategoryType}"/> instance to a <see cref="TestCaptureLogger"/> instance.
41+
/// </summary>
42+
/// <param name="logger">The <see cref="TestCaptureLogger{TCategoryType}"/> instance to convert.</param>
43+
/// <returns>A <see cref="TestCaptureLogger"/> instance.</returns>
44+
public static implicit operator TestCaptureLogger(TestCaptureLogger<TCategoryType> logger)
45+
{
46+
return logger._logger;
47+
}
48+
49+
/// <summary>
50+
/// Defines an explicit conversion from a non-generic <see cref="TestCaptureLogger"/>
51+
/// to a generic <see cref="TestCaptureLogger{TCategoryType}"/>.
52+
/// </summary>
53+
/// <param name="logger">The instance of the non-generic <see cref="TestCaptureLogger"/> to convert.</param>
54+
/// <returns>
55+
/// A new instance of <see cref="TestCaptureLogger{TCategoryType}"/> if the category name
56+
/// of the provided logger matches the type of the category.
57+
/// </returns>
58+
/// <exception cref="InvalidCastException">
59+
/// Thrown if the category name of the provided logger does not match the expected
60+
/// category name for the specified <typeparamref name="TCategoryType"/>.
61+
/// </exception>
62+
public static explicit operator TestCaptureLogger<TCategoryType>(TestCaptureLogger logger)
63+
{
64+
// Check the category name to see if it matches or can be used for this type
65+
var expectedCategoryName = TypeNameHelper.GetTypeDisplayName(typeof(TCategoryType));
66+
if (logger.CategoryName != expectedCategoryName)
67+
throw new InvalidCastException(
68+
$"The category name does not match the type of this logger. Cannot cast a TestCaptureLogger with category name {logger.CategoryName} to TestCaptureLogger<{expectedCategoryName}>.");
69+
70+
// Return a new generic logger using the existing logger
71+
return new TestCaptureLogger<TCategoryType>(logger);
72+
}
73+
3974
/// <inheritdoc />
4075
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
4176
=> _logger.Log(logLevel, eventId, state, exception, formatter);

0 commit comments

Comments
 (0)