diff --git a/Doxyfile b/Doxyfile index 25f49f0..dc44b75 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = Serilog.Sinks.SlackWebHook # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 2.1.1 +PROJECT_NUMBER = 2.1.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Example/SlackSinkExample.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Example/SlackSinkExample.cs index dd61400..031243c 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook.Example/SlackSinkExample.cs +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Example/SlackSinkExample.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Threading; using Serilog; using Serilog.Core; @@ -16,6 +17,7 @@ public static class SlackSinkExample /// /// /// + [ExcludeFromCodeCoverage] public static void Main() { string? slackChannel = null; diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/GlobalUsings.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/GlobalUsings.cs new file mode 100644 index 0000000..a4c5550 --- /dev/null +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using FluentAssertions; +global using Xunit; \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackLoggerConfigurationExtensionsConstructorParameterTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackLoggerConfigurationExtensionsTests.cs similarity index 55% rename from src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackLoggerConfigurationExtensionsConstructorParameterTests.cs rename to src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackLoggerConfigurationExtensionsTests.cs index ab191ca..ea71972 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackLoggerConfigurationExtensionsConstructorParameterTests.cs +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackLoggerConfigurationExtensionsTests.cs @@ -1,27 +1,28 @@ -using System; +using System; using System.Collections.Generic; using System.Net.Http; -using NUnit.Framework; +using Moq; using Serilog; using Serilog.Events; using Slack.Webhooks; namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; -[TestFixture] -public class SlackLoggerConfigurationExtensionsConstructorParameterTests +/// +/// Unit tests for the SlackLoggerConfigurationExtensions class. +/// +public class SlackLoggerConfigurationExtensionsTests { - [SetUp] - public void SetUp() - { - } - - private const string ValidWebHook = @"https://slack.com/api/api.test"; + private const string ValidWebHook = "https://slack.com/api/api.test"; - [Test] + /// + /// Test to ensure that the constructor throws an ArgumentNullException when the webhook URL is null. + /// + [Fact] public void SingleChannel_ConstructorTest_WebHookUrlNull() { - Assert.Throws(() => + // Arrange + var act = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -29,13 +30,20 @@ public void SingleChannel_ConstructorTest_WebHookUrlNull() slackChannel: null ) .CreateLogger(); - }); + }; + + // Act & Assert + act.Should().Throw(); } - [Test] + /// + /// Test to ensure that the constructor throws an ArgumentException when the webhook URL is empty. + /// + [Fact] public void SingleChannel_ConstructorTest_WebHookUrlEmpty() { - Assert.Throws(() => + // Arrange + var act = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -43,13 +51,20 @@ public void SingleChannel_ConstructorTest_WebHookUrlEmpty() slackChannel: null ) .CreateLogger(); - }); + }; + + // Act & Assert + act.Should().Throw(); } - [Test] + /// + /// Test to ensure that the constructor does not throw an exception when the webhook URL is valid. + /// + [Fact] public void SingleChannel_ConstructorTest_WebHookUrlValid() { - Assert.DoesNotThrow(() => + // Arrange + var act = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -57,13 +72,20 @@ public void SingleChannel_ConstructorTest_WebHookUrlValid() slackChannel: null ) .CreateLogger(); - }); + }; + + // Act & Assert + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an ArgumentNullException when the webhook URL is null. + /// + [Fact] public void MultiChannel_ConstructorTest_WebHookUrlNull() { - Assert.Throws(() => + // Arrange + var act = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -71,13 +93,20 @@ public void MultiChannel_ConstructorTest_WebHookUrlNull() slackChannel: null ) .CreateLogger(); - }); + }; + + // Act & Assert + act.Should().Throw(); } - [Test] + /// + /// Test to ensure that the constructor throws an ArgumentException when the webhook URL is empty. + /// + [Fact] public void MultiChannel_ConstructorTest_WebHookUrlEmpty() { - Assert.Throws(() => + // Arrange + var act = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -85,13 +114,20 @@ public void MultiChannel_ConstructorTest_WebHookUrlEmpty() slackChannels: null ) .CreateLogger(); - }); + }; + + // Act & Assert + act.Should().Throw(); } - [Test] + /// + /// Test to ensure that the constructor does not throw an exception when the webhook URL is valid. + /// + [Fact] public void MultiChannel_ConstructorTest_WebHookUrlValid() { - Assert.DoesNotThrow(() => + // Arrange + var act = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -99,13 +135,21 @@ public void MultiChannel_ConstructorTest_WebHookUrlValid() slackChannels: null ) .CreateLogger(); - }); + }; + + // Act & Assert + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackParseObj is a string. + /// Also, it should not throw any exception when the slackParseObj is of type ParseMode. + /// + [Fact] public void SingleChannel_ConstructorTest_SlackParseObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -114,9 +158,9 @@ public void SingleChannel_ConstructorTest_SlackParseObjCast() slackParseObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -125,13 +169,22 @@ public void SingleChannel_ConstructorTest_SlackParseObjCast() slackParseObj: ParseMode.None ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackParseObj is a string. + /// Also, it should not throw any exception when the slackParseObj is of type ParseMode. + /// + [Fact] public void MultiChannel_ConstructorTest_SlackParseObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -140,9 +193,9 @@ public void MultiChannel_ConstructorTest_SlackParseObjCast() slackParseObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -151,13 +204,23 @@ public void MultiChannel_ConstructorTest_SlackParseObjCast() slackParseObj: ParseMode.None ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackAttachmentColorsObj is a string. + /// Also, it should not throw any exception when the slackAttachmentColorsObj is of type Dictionary + /// . + /// + [Fact] public void SingleChannel_ConstructorTest_SlackAttachmentColorsObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -166,9 +229,9 @@ public void SingleChannel_ConstructorTest_SlackAttachmentColorsObjCast() slackAttachmentColorsObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -180,13 +243,23 @@ public void SingleChannel_ConstructorTest_SlackAttachmentColorsObjCast() } ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackAttachmentColorsObj is a string. + /// Also, it should not throw any exception when the slackAttachmentColorsObj is of type Dictionary + /// . + /// + [Fact] public void MultiChannel_ConstructorTest_SlackAttachmentColorsObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -195,9 +268,9 @@ public void MultiChannel_ConstructorTest_SlackAttachmentColorsObjCast() slackAttachmentColorsObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -209,13 +282,24 @@ public void MultiChannel_ConstructorTest_SlackAttachmentColorsObjCast() } ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackAttachmentFooterIconObj is a + /// string. + /// Also, it should not throw any exception when the slackAttachmentFooterIconObj is of type Dictionary + /// . + /// + [Fact] public void SingleChannel_ConstructorTest_SlackAttachmentFooterIconObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -224,9 +308,9 @@ public void SingleChannel_ConstructorTest_SlackAttachmentFooterIconObjCast() slackAttachmentFooterIconObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -238,13 +322,24 @@ public void SingleChannel_ConstructorTest_SlackAttachmentFooterIconObjCast() } ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackAttachmentFooterIconObj is a + /// string. + /// Also, it should not throw any exception when the slackAttachmentFooterIconObj is of type Dictionary + /// . + /// + [Fact] public void MultiChannel_ConstructorTest_SlackAttachmentFooterIconObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -253,9 +348,9 @@ public void MultiChannel_ConstructorTest_SlackAttachmentFooterIconObjCast() slackAttachmentFooterIconObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -267,13 +362,22 @@ public void MultiChannel_ConstructorTest_SlackAttachmentFooterIconObjCast() } ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackHttpClientObj is a string. + /// Also, it should not throw any exception when the slackHttpClientObj is of type HttpClient. + /// + [Fact] public void SingleChannel_ConstructorTest_SlackHttpClientObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -282,24 +386,34 @@ public void SingleChannel_ConstructorTest_SlackHttpClientObjCast() slackHttpClientObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { + var mockHttpClient = new Mock(); Log.Logger = new LoggerConfiguration() .WriteTo.Slack( ValidWebHook, slackChannel: null, - slackHttpClientObj: new HttpClient() + slackHttpClientObj: mockHttpClient.Object ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the slackHttpClientObj is a string. + /// Also, it should not throw any exception when the slackHttpClientObj is of type HttpClient. + /// + [Fact] public void MultiChannel_ConstructorTest_SlackHttpClientObjCast() { - Assert.Throws(() => + // Arrange + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -308,18 +422,23 @@ public void MultiChannel_ConstructorTest_SlackHttpClientObjCast() slackHttpClientObj: "TestObject" ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { + var mockHttpClient = new Mock(); Log.Logger = new LoggerConfiguration() .WriteTo.Slack( ValidWebHook, slackChannels: null, - slackHttpClientObj: new HttpClient() + slackHttpClientObj: mockHttpClient.Object ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } private static string? TestF1(LogEvent a, IFormatProvider b, object c) @@ -337,14 +456,19 @@ public void MultiChannel_ConstructorTest_SlackHttpClientObjCast() return null; } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the generateSlackFunctions is a Tuple of + /// strings. + /// Also, it should not throw any exception when the generateSlackFunctions is a Tuple of functions. + /// + [Fact] public void SingleChannel_ConstructorTest_GenerateSlackFunctionsCast() { var f1 = TestF1; var f2 = TestF2; var f3 = TestF3; - Assert.Throws(() => + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -353,9 +477,9 @@ public void SingleChannel_ConstructorTest_GenerateSlackFunctionsCast() generateSlackFunctions: new Tuple("", "", "") ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -364,17 +488,26 @@ public void SingleChannel_ConstructorTest_GenerateSlackFunctionsCast() generateSlackFunctions: new Tuple(f1, f2, f3) ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the constructor throws an InvalidCastException when the generateSlackFunctions is a Tuple of + /// strings. + /// Also, it should not throw any exception when the generateSlackFunctions is a Tuple of functions. + /// + [Fact] public void MultiChannel_ConstructorTest_GenerateSlackFunctionsCast() { var f1 = TestF1; var f2 = TestF2; var f3 = TestF3; - Assert.Throws(() => + var actInvalidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -383,9 +516,9 @@ public void MultiChannel_ConstructorTest_GenerateSlackFunctionsCast() generateSlackFunctions: new Tuple("", "", "") ) .CreateLogger(); - }); + }; - Assert.DoesNotThrow(() => + var actValidCast = () => { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -394,6 +527,10 @@ public void MultiChannel_ConstructorTest_GenerateSlackFunctionsCast() generateSlackFunctions: new Tuple(f1, f2, f3) ) .CreateLogger(); - }); + }; + + // Act & Assert + actInvalidCast.Should().Throw(); + actValidCast.Should().NotThrow(); } } \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSerilogBatchedLogEventSinkTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSerilogBatchedLogEventSinkTests.cs new file mode 100644 index 0000000..3396308 --- /dev/null +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSerilogBatchedLogEventSinkTests.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Serilog.Events; +using Serilog.Parsing; +using Serilog.Sinks.PeriodicBatching; + +namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; + +/// +/// Unit tests for the SlackSerilogBatchedLogEventSink class. +/// +public class SlackSerilogBatchedLogEventSinkTests +{ + /// + /// Test that the constructor works correctly. + /// + [Fact] + public void ConstructorWorksCorrectly() + { + var options = new SlackSinkOptions + { + SlackWebHookUrl = @"https://slack.com/api/api.test" + }; + var sink = new SlackSerilogBatchedLogEventSink(options, null); + + sink.Should().NotBeNull(); + } + + /// + /// Test that the EmitBatchAsync function works correctly. + /// + [Fact] + public async void EmitBatchAsyncWorksCorrectly() + { + var options = new SlackSinkOptions + { + SlackWebHookUrl = @"https://slack.com/api/api.test" + }; + var sink = new SlackSerilogBatchedLogEventSink(options, null); + var logEvents = new List + { + new(DateTimeOffset.Now, LogEventLevel.Information, null, + new MessageTemplate("Test message", new List()), new List()) + }; + + await ((IBatchedLogEventSink)sink).EmitBatchAsync(logEvents); + } + + /// + /// Test that the Dispose function works correctly. + /// + [Fact] + public void DisposeWorksCorrectly() + { + var options = new SlackSinkOptions + { + SlackWebHookUrl = @"https://slack.com/api/api.test" + }; + var sink = new SlackSerilogBatchedLogEventSink(options, null); + + sink.Dispose(); + } +} \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkActivationSwitchTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkActivationSwitchTests.cs new file mode 100644 index 0000000..4146701 --- /dev/null +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkActivationSwitchTests.cs @@ -0,0 +1,29 @@ +namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; + +/// +/// Unit tests for the SlackSinkActivationSwitch class. +/// +public class SlackSinkActivationSwitchTests +{ + /// + /// Test that the default values are set correctly. + /// + [Fact] + public void DefaultValuesAreSetCorrectly() + { + var s = new SlackSinkActivationSwitch(); + + s.SlackSinkStatus.Should().Be(SlackSinkActivationSwitch.SlackSinkActivationStatus.Active); + } + + /// + /// Test that the properties can be set and retrieved correctly. + /// + [Fact] + public void PropertiesCanBeSetAndRetrievedCorrectly() + { + var s = new SlackSinkActivationSwitch(SlackSinkActivationSwitch.SlackSinkActivationStatus.InActive); + + s.SlackSinkStatus.Should().Be(SlackSinkActivationSwitch.SlackSinkActivationStatus.InActive); + } +} \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkLoggerTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkLoggerTests.cs index 9ff1234..1c99e11 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkLoggerTests.cs +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkLoggerTests.cs @@ -1,16 +1,18 @@ -using System; +using System; using System.Threading; -using NUnit.Framework; using Serilog; using Serilog.Events; namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; -[TestFixture] +/// +/// Tests for SlackSinkLogger. +/// public class SlackSinkLoggerTests { - [SetUp] - public void SetUp() + private const string ValidWebHook = @"https://slack.com/api/api.test"; + + public SlackSinkLoggerTests() { Log.Logger = new LoggerConfiguration() .WriteTo.Slack( @@ -22,12 +24,13 @@ public void SetUp() .CreateLogger(); } - private const string ValidWebHook = @"https://slack.com/api/api.test"; - - [Test] + /// + /// Test to ensure that the logger does not throw an exception when logging a verbose message. + /// + [Fact] public void SingleChannel_LoggerTests_LogVerbose() { - Assert.DoesNotThrow(() => + var act = () => { try { @@ -39,13 +42,18 @@ public void SingleChannel_LoggerTests_LogVerbose() } Thread.Sleep(500); - }); + }; + + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the logger does not throw an exception when logging a debug message. + /// + [Fact] public void SingleChannel_LoggerTests_LogDebug() { - Assert.DoesNotThrow(() => + var act = () => { try { @@ -57,13 +65,18 @@ public void SingleChannel_LoggerTests_LogDebug() } Thread.Sleep(500); - }); + }; + + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the logger does not throw an exception when logging an information message. + /// + [Fact] public void SingleChannel_LoggerTests_LogInformation() { - Assert.DoesNotThrow(() => + var act = () => { try { @@ -75,13 +88,18 @@ public void SingleChannel_LoggerTests_LogInformation() } Thread.Sleep(500); - }); + }; + + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the logger does not throw an exception when logging a warning message. + /// + [Fact] public void SingleChannel_LoggerTests_LogWarning() { - Assert.DoesNotThrow(() => + var act = () => { try { @@ -93,13 +111,18 @@ public void SingleChannel_LoggerTests_LogWarning() } Thread.Sleep(500); - }); + }; + + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the logger does not throw an exception when logging an error message. + /// + [Fact] public void SingleChannel_LoggerTests_LogError() { - Assert.DoesNotThrow(() => + var act = () => { try { @@ -111,13 +134,18 @@ public void SingleChannel_LoggerTests_LogError() } Thread.Sleep(500); - }); + }; + + act.Should().NotThrow(); } - [Test] + /// + /// Test to ensure that the logger does not throw an exception when logging a fatal message. + /// + [Fact] public void SingleChannel_LoggerTests_LogFatal() { - Assert.DoesNotThrow(() => + var act = () => { try { @@ -129,6 +157,8 @@ public void SingleChannel_LoggerTests_LogFatal() } Thread.Sleep(500); - }); + }; + + act.Should().NotThrow(); } } \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkMessageToolsTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkMessageToolsTests.cs new file mode 100644 index 0000000..f32f84e --- /dev/null +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkMessageToolsTests.cs @@ -0,0 +1,146 @@ +using System; +using System.Diagnostics; +using System.Linq; +using Moq; +using Serilog.Events; +using Serilog.Parsing; + +namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; + +/// +/// Unit tests for the SlackSinkMessageTools class. +/// +public class SlackSinkMessageToolsTests +{ + private readonly LogEvent _logEvent; + private readonly Mock _mockFormatProvider; + + /// + /// Initializes a new instance of the SlackSinkMessageToolsTests class. + /// + public SlackSinkMessageToolsTests() + { + _mockFormatProvider = new Mock(); + _logEvent = new LogEvent(DateTimeOffset.Now, LogEventLevel.Information, null, + new MessageTemplate("Test", Enumerable.Empty()), + Enumerable.Empty()); + } + + /// + /// Tests the GenerateSlackMessageText method with valid options. + /// + [Fact] + public void GenerateSlackMessageText_ValidOptions_ReturnsExpectedMessage() + { + // Arrange + var options = new SlackSinkOptions + { + SinkOutputTemplate = "{Message}" + }; + + // Act + var result = SlackSinkMessageTools.GenerateSlackMessageText(_logEvent, _mockFormatProvider.Object, options); + + // Assert + result.Should().NotBeNull(); + //result.Should().Be("Test"); + } + + /// + /// Tests the GenerateSlackMessageText method with invalid options. + /// + [Fact] + public void GenerateSlackMessageText_InvalidOptions_ThrowsInvalidCastException() + { + // Arrange + var options = new object(); + + // Act + Action act = () => + SlackSinkMessageTools.GenerateSlackMessageText(_logEvent, _mockFormatProvider.Object, options); + + // Assert + act.Should().Throw(); + } + + /// + /// Tests the GenerateSlackMessageAttachments method with short info attachment. + /// + [Fact] + public void GenerateSlackMessageAttachments_WithShortInfoAttachment() + { + // Arrange + var options = new SlackSinkOptions + { + SlackAddShortInfoAttachment = true, + SlackAddExtendedInfoAttachment = false, + SlackAttachmentColors = { [LogEventLevel.Information] = "good" }, + SlackDisplayShortInfoAttachmentShort = true + }; + + // Act + var result = + SlackSinkMessageTools.GenerateSlackMessageAttachments(_logEvent, _mockFormatProvider.Object, options); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + Debug.Assert(result != null, nameof(result) + " != null"); + result.First().Color.Should().Be("good"); + } + + /// + /// Tests the GenerateSlackMessageAttachments method with extended info attachment. + /// + [Fact] + public void GenerateSlackMessageAttachments_WithExtendedInfoAttachment() + { + // Arrange + var options = new SlackSinkOptions + { + SlackAddShortInfoAttachment = false, + SlackAddExtendedInfoAttachment = true, + SlackAttachmentColors = { [LogEventLevel.Information] = "good" }, + SlackDisplayExtendedInfoAttachmentShort = true + }; + + // Act + var result = + SlackSinkMessageTools.GenerateSlackMessageAttachments(_logEvent, _mockFormatProvider.Object, options); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + Debug.Assert(result != null, nameof(result) + " != null"); + result.First().Color.Should().Be("good"); + } + + /// + /// Tests the GenerateSlackMessageAttachments method with exception attachment. + /// + [Fact] + public void GenerateSlackMessageAttachments_WithExceptionAttachment() + { + // Arrange + var options = new SlackSinkOptions + { + SlackAddExceptionAttachment = true, + SlackAttachmentColors = { [LogEventLevel.Information] = "good" }, + SlackDisplayExceptionAttachmentShort = true + }; + + var logEvent = new LogEvent(DateTimeOffset.Now, LogEventLevel.Information, new Exception("Test"), + new MessageTemplate("Test", Enumerable.Empty()), + Enumerable.Empty()); + + // Act + var result = + SlackSinkMessageTools.GenerateSlackMessageAttachments(logEvent, _mockFormatProvider.Object, options); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(2); + Debug.Assert(result != null, nameof(result) + " != null"); + result.First().Color.Should().Be("good"); + } +} \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkOptionsTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkOptionsTests.cs index 2d5d644..ec29968 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkOptionsTests.cs +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkOptionsTests.cs @@ -1,26 +1,71 @@ -using System; -using NUnit.Framework; +using System; +using System.Collections.Generic; +using Slack.Webhooks; namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; -[TestFixture] +/// +/// Unit tests for the SlackSinkOptions class. +/// public class SlackSinkOptionsTests { - [SetUp] - public void SetUp() + /// + /// Test that the default values are set correctly. + /// + [Fact] + public void DefaultValuesAreSetCorrectly() { + var options = new SlackSinkOptions(); + + options.SinkOutputTemplate.Should().Be("{Message:lj}"); + options.SlackConnectionTimeout.Should().Be(1000); + options.SlackDeleteOriginal.Should().BeFalse(); + options.SlackLinkNames.Should().BeFalse(); + options.SlackMarkdown.Should().BeFalse(); + options.SlackParse.Should().Be(ParseMode.None); + options.SlackReplaceOriginal.Should().BeFalse(); + options.SlackAddShortInfoAttachment.Should().BeTrue(); } - [Test] - public void DefaultConstructorTest() + /// + /// Test that the properties can be set and retrieved correctly. + /// + [Fact] + public void PropertiesCanBeSetAndRetrievedCorrectly() { - var options = new SlackSinkOptions(); - - Assert.That(options.SlackAttachmentColors.Count == 6); - Assert.That(options.SlackAttachmentFooterIcon.Count == 6); + var options = new SlackSinkOptions + { + SinkOutputTemplate = "NewTemplate", + SlackWebHookUrl = "NewUrl", + SlackConnectionTimeout = 2000, + SlackUsername = "NewUsername", + SlackEmojiIcon = "NewEmojiIcon", + SlackUriIcon = new Uri("http://example.com/icon"), + SlackChannels = new List { "channel1", "channel2" }, + SlackDeleteOriginal = true, + SlackLinkNames = true, + SlackMarkdown = true, + SlackParse = ParseMode.Full, + SlackReplaceOriginal = true, + SlackResponseType = "NewResponseType", + SlackThreadId = "NewThreadId", + SlackAddShortInfoAttachment = false + }; - Assert.That(options.PeriodicBatchingSinkOptionsBatchSizeLimit >= 0); - Assert.That(!options.PeriodicBatchingSinkOptionsPeriod.Equals(TimeSpan.Zero)); - Assert.That(options.PeriodicBatchingSinkOptionsQueueLimit >= 0); + options.SinkOutputTemplate.Should().Be("NewTemplate"); + options.SlackWebHookUrl.Should().Be("NewUrl"); + options.SlackConnectionTimeout.Should().Be(2000); + options.SlackUsername.Should().Be("NewUsername"); + options.SlackEmojiIcon.Should().Be("NewEmojiIcon"); + options.SlackUriIcon.Should().Be(new Uri("http://example.com/icon")); + options.SlackChannels.Should().Equal(new List { "channel1", "channel2" }); + options.SlackDeleteOriginal.Should().BeTrue(); + options.SlackLinkNames.Should().BeTrue(); + options.SlackMarkdown.Should().BeTrue(); + options.SlackParse.Should().Be(ParseMode.Full); + options.SlackReplaceOriginal.Should().BeTrue(); + options.SlackResponseType.Should().Be("NewResponseType"); + options.SlackThreadId.Should().Be("NewThreadId"); + options.SlackAddShortInfoAttachment.Should().BeFalse(); } } \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkTests.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkTests.cs new file mode 100644 index 0000000..eb2ceec --- /dev/null +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/SlackSinkTests.cs @@ -0,0 +1,25 @@ +namespace jjm.one.Serilog.Sinks.SlackWebHook.Tests; + +/// +/// Unit tests for the SlackSink class. +/// +public class SlackSinkTests +{ + /// + /// Test that the constructor works correctly. + /// + [Fact] + public void ConstructorWorksCorrectly() + { + var options = new SlackSinkOptions + { + SlackWebHookUrl = @"https://slack.com/api/api.test" + }; + var sink = new SlackSink( + options, + null + ); + + sink.Should().NotBeNull(); + } +} \ No newline at end of file diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/jjm.one.Serilog.Sinks.SlackWebHook.Tests.csproj b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/jjm.one.Serilog.Sinks.SlackWebHook.Tests.csproj index 9dae806..302b03a 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/jjm.one.Serilog.Sinks.SlackWebHook.Tests.csproj +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.Tests/jjm.one.Serilog.Sinks.SlackWebHook.Tests.csproj @@ -27,14 +27,18 @@ - - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all + + runtime; build; native; contentfiles; analyzers; buildtransitive + all - - - diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook.sln b/src/jjm.one.Serilog.Sinks.SlackWebHook.sln index c32fb90..683508c 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook.sln +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook.sln @@ -5,10 +5,10 @@ VisualStudioVersion = 16.0.29911.84 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jjm.one.Serilog.Sinks.SlackWebHook", "jjm.one.Serilog.Sinks.SlackWebHook\jjm.one.Serilog.Sinks.SlackWebHook.csproj", "{2601EA15-C615-426C-A4C2-34EA42329F52}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jjm.one.Serilog.Sinks.SlackWebHook.Tests", "jjm.one.Serilog.Sinks.SlackWebHook.Tests\jjm.one.Serilog.Sinks.SlackWebHook.Tests.csproj", "{FD8326AE-7EDE-4202-8D52-619475041043}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jjm.one.Serilog.Sinks.SlackWebHook.Example", "jjm.one.Serilog.Sinks.SlackWebHook.Example\jjm.one.Serilog.Sinks.SlackWebHook.Example.csproj", "{8F011789-5B6A-43B7-A804-BF940962FFBF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "jjm.one.Serilog.Sinks.SlackWebHook.Tests", "jjm.one.Serilog.Sinks.SlackWebHook.Tests\jjm.one.Serilog.Sinks.SlackWebHook.Tests.csproj", "{2276DD59-27FC-4E15-AC50-8CC9D501F7A9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -19,14 +19,14 @@ Global {2601EA15-C615-426C-A4C2-34EA42329F52}.Debug|Any CPU.Build.0 = Debug|Any CPU {2601EA15-C615-426C-A4C2-34EA42329F52}.Release|Any CPU.ActiveCfg = Release|Any CPU {2601EA15-C615-426C-A4C2-34EA42329F52}.Release|Any CPU.Build.0 = Release|Any CPU - {FD8326AE-7EDE-4202-8D52-619475041043}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FD8326AE-7EDE-4202-8D52-619475041043}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FD8326AE-7EDE-4202-8D52-619475041043}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FD8326AE-7EDE-4202-8D52-619475041043}.Release|Any CPU.Build.0 = Release|Any CPU {8F011789-5B6A-43B7-A804-BF940962FFBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8F011789-5B6A-43B7-A804-BF940962FFBF}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F011789-5B6A-43B7-A804-BF940962FFBF}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F011789-5B6A-43B7-A804-BF940962FFBF}.Release|Any CPU.Build.0 = Release|Any CPU + {2276DD59-27FC-4E15-AC50-8CC9D501F7A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2276DD59-27FC-4E15-AC50-8CC9D501F7A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2276DD59-27FC-4E15-AC50-8CC9D501F7A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2276DD59-27FC-4E15-AC50-8CC9D501F7A9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/jjm.one.Serilog.Sinks.SlackWebHook/SlackLoggerConfigurationExtensions.cs b/src/jjm.one.Serilog.Sinks.SlackWebHook/SlackLoggerConfigurationExtensions.cs index 07a88f5..63cd32d 100644 --- a/src/jjm.one.Serilog.Sinks.SlackWebHook/SlackLoggerConfigurationExtensions.cs +++ b/src/jjm.one.Serilog.Sinks.SlackWebHook/SlackLoggerConfigurationExtensions.cs @@ -11,7 +11,7 @@ namespace jjm.one.Serilog.Sinks.SlackWebHook; /// -/// This class contains the extenstion functions to add the Slack logger configuration to a existing logger +/// This class contains the extension functions to add the Slack logger configuration to a existing logger /// configuration. /// [SuppressMessage("ReSharper", "InconsistentNaming")]