diff --git a/GitHubActionsTestLogger.Demo/GitHubActionsTestLogger.Demo.csproj b/GitHubActionsTestLogger.Demo/GitHubActionsTestLogger.Demo.csproj index 36cd423..118d4f4 100644 --- a/GitHubActionsTestLogger.Demo/GitHubActionsTestLogger.Demo.csproj +++ b/GitHubActionsTestLogger.Demo/GitHubActionsTestLogger.Demo.csproj @@ -8,6 +8,7 @@ + diff --git a/GitHubActionsTestLogger.Demo/SampleTests.cs b/GitHubActionsTestLogger.Demo/SampleTests.cs index ad259ea..ae4bc34 100644 --- a/GitHubActionsTestLogger.Demo/SampleTests.cs +++ b/GitHubActionsTestLogger.Demo/SampleTests.cs @@ -13,4 +13,4 @@ public class SampleTests [Fact] public void Test3() => Assert.True(false); -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger.Tests/AnnotationSpecs.cs b/GitHubActionsTestLogger.Tests/AnnotationSpecs.cs index cb051bb..723ac76 100644 --- a/GitHubActionsTestLogger.Tests/AnnotationSpecs.cs +++ b/GitHubActionsTestLogger.Tests/AnnotationSpecs.cs @@ -12,8 +12,7 @@ public class AnnotationSpecs { private readonly ITestOutputHelper _testOutput; - public AnnotationSpecs(ITestOutputHelper testOutput) => - _testOutput = testOutput; + public AnnotationSpecs(ITestOutputHelper testOutput) => _testOutput = testOutput; [Fact] public void I_can_use_the_logger_to_produce_annotations_for_failed_tests() @@ -22,10 +21,7 @@ public void I_can_use_the_logger_to_produce_annotations_for_failed_tests() using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), TestLoggerOptions.Default ); @@ -36,14 +32,8 @@ public void I_can_use_the_logger_to_produce_annotations_for_failed_tests() .SetOutcome(TestOutcome.Failed) .SetErrorMessage("ErrorMessage") .Build(), - new TestResultBuilder() - .SetDisplayName("Test2") - .SetOutcome(TestOutcome.Passed) - .Build(), - new TestResultBuilder() - .SetDisplayName("Test3") - .SetOutcome(TestOutcome.Skipped) - .Build() + new TestResultBuilder().SetDisplayName("Test2").SetOutcome(TestOutcome.Passed).Build(), + new TestResultBuilder().SetDisplayName("Test3").SetOutcome(TestOutcome.Skipped).Build() ); // Assert @@ -69,10 +59,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_source_info using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), TestLoggerOptions.Default ); @@ -122,10 +109,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_source_info using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), TestLoggerOptions.Default ); @@ -176,10 +160,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_the_test_na using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), new TestLoggerOptions { AnnotationTitleFormat = "<@test>", @@ -189,10 +170,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_the_test_na // Act context.SimulateTestRun( - new TestResultBuilder() - .SetDisplayName("Test1") - .SetOutcome(TestOutcome.Failed) - .Build() + new TestResultBuilder().SetDisplayName("Test1").SetOutcome(TestOutcome.Failed).Build() ); // Assert @@ -211,10 +189,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_test_traits using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), new TestLoggerOptions { AnnotationTitleFormat = "<@traits.Category -> @test>", @@ -248,10 +223,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_the_error_m using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), new TestLoggerOptions { AnnotationTitleFormat = "<@test: @error>", @@ -284,10 +256,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_the_error_s using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), new TestLoggerOptions { AnnotationTitleFormat = "<@test: @trace>", @@ -320,10 +289,7 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_the_target_ using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), + new GitHubWorkflow(commandWriter, TextWriter.Null), new TestLoggerOptions { AnnotationTitleFormat = "<@test (@framework)>", @@ -358,22 +324,13 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_line_breaks using var commandWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - commandWriter, - TextWriter.Null - ), - new TestLoggerOptions - { - AnnotationMessageFormat = "foo\\nbar" - } + new GitHubWorkflow(commandWriter, TextWriter.Null), + new TestLoggerOptions { AnnotationMessageFormat = "foo\\nbar" } ); // Act context.SimulateTestRun( - new TestResultBuilder() - .SetDisplayName("Test1") - .SetOutcome(TestOutcome.Failed) - .Build() + new TestResultBuilder().SetDisplayName("Test1").SetOutcome(TestOutcome.Failed).Build() ); // Assert @@ -383,4 +340,4 @@ public void I_can_use_the_logger_to_produce_annotations_that_include_line_breaks _testOutput.WriteLine(output); } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger.Tests/Fakes/FakeTestLoggerEvents.cs b/GitHubActionsTestLogger.Tests/Fakes/FakeTestLoggerEvents.cs index 59cd6bd..684933c 100644 --- a/GitHubActionsTestLogger.Tests/Fakes/FakeTestLoggerEvents.cs +++ b/GitHubActionsTestLogger.Tests/Fakes/FakeTestLoggerEvents.cs @@ -16,4 +16,4 @@ internal class FakeTestLoggerEvents : TestLoggerEvents public override event EventHandler? DiscoveryMessage; public override event EventHandler? DiscoveredTests; public override event EventHandler? DiscoveryComplete; -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger.Tests/GitHubActionsTestLogger.Tests.csproj b/GitHubActionsTestLogger.Tests/GitHubActionsTestLogger.Tests.csproj index 71dc955..21c0d2a 100644 --- a/GitHubActionsTestLogger.Tests/GitHubActionsTestLogger.Tests.csproj +++ b/GitHubActionsTestLogger.Tests/GitHubActionsTestLogger.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/GitHubActionsTestLogger.Tests/InitializationSpecs.cs b/GitHubActionsTestLogger.Tests/InitializationSpecs.cs index fa80f00..dc5591d 100644 --- a/GitHubActionsTestLogger.Tests/InitializationSpecs.cs +++ b/GitHubActionsTestLogger.Tests/InitializationSpecs.cs @@ -48,4 +48,4 @@ public void I_can_use_the_logger_with_a_custom_configuration() logger.Context?.Options.SummaryIncludePassedTests.Should().BeTrue(); logger.Context?.Options.SummaryIncludeSkippedTests.Should().BeTrue(); } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger.Tests/SummarySpecs.cs b/GitHubActionsTestLogger.Tests/SummarySpecs.cs index 4cbf9e8..f2696ba 100644 --- a/GitHubActionsTestLogger.Tests/SummarySpecs.cs +++ b/GitHubActionsTestLogger.Tests/SummarySpecs.cs @@ -12,8 +12,7 @@ public class SummarySpecs { private readonly ITestOutputHelper _testOutput; - public SummarySpecs(ITestOutputHelper testOutput) => - _testOutput = testOutput; + public SummarySpecs(ITestOutputHelper testOutput) => _testOutput = testOutput; [Fact] public void I_can_use_the_logger_to_produce_a_summary_that_includes_the_test_suite_name() @@ -22,10 +21,7 @@ public void I_can_use_the_logger_to_produce_a_summary_that_includes_the_test_sui using var summaryWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - TextWriter.Null, - summaryWriter - ), + new GitHubWorkflow(TextWriter.Null, summaryWriter), TestLoggerOptions.Default ); @@ -47,14 +43,8 @@ public void I_can_use_the_logger_to_produce_a_summary_that_includes_the_list_of_ using var summaryWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - TextWriter.Null, - summaryWriter - ), - new TestLoggerOptions - { - SummaryIncludePassedTests = true - } + new GitHubWorkflow(TextWriter.Null, summaryWriter), + new TestLoggerOptions { SummaryIncludePassedTests = true } ); // Act @@ -100,14 +90,8 @@ public void I_can_use_the_logger_to_produce_a_summary_that_includes_the_list_of_ using var summaryWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - TextWriter.Null, - summaryWriter - ), - new TestLoggerOptions - { - SummaryIncludeSkippedTests = true - } + new GitHubWorkflow(TextWriter.Null, summaryWriter), + new TestLoggerOptions { SummaryIncludeSkippedTests = true } ); // Act @@ -153,10 +137,7 @@ public void I_can_use_the_logger_to_produce_a_summary_that_includes_the_list_of_ using var summaryWriter = new StringWriter(); var context = new TestLoggerContext( - new GitHubWorkflow( - TextWriter.Null, - summaryWriter - ), + new GitHubWorkflow(TextWriter.Null, summaryWriter), TestLoggerOptions.Default ); @@ -207,4 +188,4 @@ public void I_can_use_the_logger_to_produce_a_summary_that_includes_the_list_of_ _testOutput.WriteLine(output); } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger.Tests/Utils/Extensions/TestLoggerContextExtensions.cs b/GitHubActionsTestLogger.Tests/Utils/Extensions/TestLoggerContextExtensions.cs index 8895f23..451741e 100644 --- a/GitHubActionsTestLogger.Tests/Utils/Extensions/TestLoggerContextExtensions.cs +++ b/GitHubActionsTestLogger.Tests/Utils/Extensions/TestLoggerContextExtensions.cs @@ -14,49 +14,64 @@ public static void SimulateTestRun( this TestLoggerContext context, string testSuiteFilePath, string targetFrameworkName, - params TestResult[] testResults) + params TestResult[] testResults + ) { - context.HandleTestRunStart(new TestRunStartEventArgs(new TestRunCriteria( - new[] { testSuiteFilePath }, - 1, - true, - // lang=xml - $""" + context.HandleTestRunStart( + new TestRunStartEventArgs( + new TestRunCriteria( + new[] { testSuiteFilePath }, + 1, + true, + // lang=xml + $""" {targetFrameworkName} """ - ))); + ) + ) + ); foreach (var testResult in testResults) context.HandleTestResult(new TestResultEventArgs(testResult)); - context.HandleTestRunComplete(new TestRunCompleteEventArgs( - new TestRunStatistics(new Dictionary - { - [TestOutcome.Passed] = testResults.Count(r => r.Outcome == TestOutcome.Passed), - [TestOutcome.Failed] = testResults.Count(r => r.Outcome == TestOutcome.Failed), - [TestOutcome.Skipped] = testResults.Count(r => r.Outcome == TestOutcome.Skipped), - [TestOutcome.None] = testResults.Count(r => r.Outcome == TestOutcome.None) - }), - false, - false, - null, - new Collection(), - TimeSpan.FromSeconds(1.234) - )); + context.HandleTestRunComplete( + new TestRunCompleteEventArgs( + new TestRunStatistics( + new Dictionary + { + [TestOutcome.Passed] = testResults.Count( + r => r.Outcome == TestOutcome.Passed + ), + [TestOutcome.Failed] = testResults.Count( + r => r.Outcome == TestOutcome.Failed + ), + [TestOutcome.Skipped] = testResults.Count( + r => r.Outcome == TestOutcome.Skipped + ), + [TestOutcome.None] = testResults.Count(r => r.Outcome == TestOutcome.None) + } + ), + false, + false, + null, + new Collection(), + TimeSpan.FromSeconds(1.234) + ) + ); } public static void SimulateTestRun( this TestLoggerContext context, string testSuiteName, - params TestResult[] testResults) => - context.SimulateTestRun(testSuiteName, "FakeTargetFramework", testResults); + params TestResult[] testResults + ) => context.SimulateTestRun(testSuiteName, "FakeTargetFramework", testResults); public static void SimulateTestRun( this TestLoggerContext context, - params TestResult[] testResults) => - context.SimulateTestRun("FakeTests.dll", testResults); -} \ No newline at end of file + params TestResult[] testResults + ) => context.SimulateTestRun("FakeTests.dll", testResults); +} diff --git a/GitHubActionsTestLogger.Tests/Utils/TestResultBuilder.cs b/GitHubActionsTestLogger.Tests/Utils/TestResultBuilder.cs index 2e5f8f6..604404f 100644 --- a/GitHubActionsTestLogger.Tests/Utils/TestResultBuilder.cs +++ b/GitHubActionsTestLogger.Tests/Utils/TestResultBuilder.cs @@ -5,13 +5,16 @@ namespace GitHubActionsTestLogger.Tests.Utils; internal class TestResultBuilder { - private TestResult _testResult = new(new TestCase - { - Id = Guid.NewGuid(), - Source = "FakeTests.dll", - FullyQualifiedName = "FakeTests.FakeTest", - DisplayName = "FakeTest" - }); + private TestResult _testResult = + new( + new TestCase + { + Id = Guid.NewGuid(), + Source = "FakeTests.dll", + FullyQualifiedName = "FakeTests.FakeTest", + DisplayName = "FakeTest" + } + ); public TestResultBuilder SetDisplayName(string displayName) { @@ -56,4 +59,4 @@ public TestResult Build() return testResult; } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/GitHubActionsTestLogger.csproj b/GitHubActionsTestLogger/GitHubActionsTestLogger.csproj index 45d03d5..00eaa23 100644 --- a/GitHubActionsTestLogger/GitHubActionsTestLogger.csproj +++ b/GitHubActionsTestLogger/GitHubActionsTestLogger.csproj @@ -22,6 +22,7 @@ + diff --git a/GitHubActionsTestLogger/GitHubWorkflow.cs b/GitHubActionsTestLogger/GitHubWorkflow.cs index 002952a..346dd05 100644 --- a/GitHubActionsTestLogger/GitHubWorkflow.cs +++ b/GitHubActionsTestLogger/GitHubWorkflow.cs @@ -22,17 +22,16 @@ public GitHubWorkflow(TextWriter commandWriter, TextWriter summaryWriter) private void InvokeCommand( string command, string message, - IReadOnlyDictionary? options = null) + IReadOnlyDictionary? options = null + ) { // URL-encode certain characters to ensure they don't get parsed as command tokens // https://pakstech.com/blog/github-actions-workflow-commands - static string Escape(string value) => value - .Replace("%", "%25") - .Replace("\n", "%0A") - .Replace("\r", "%0D"); + static string Escape(string value) => + value.Replace("%", "%25").Replace("\n", "%0A").Replace("\r", "%0D"); - var formattedOptions = options? - .Select(kvp => Escape(kvp.Key) + '=' + Escape(kvp.Value)) + var formattedOptions = options + ?.Select(kvp => Escape(kvp.Key) + '=' + Escape(kvp.Value)) .Pipe(s => string.Join(",", s)); // Command should start at the beginning of the line, so add a newline @@ -41,9 +40,7 @@ static string Escape(string value) => value // ANSI color codes enabled. _commandWriter.WriteLine(); - _commandWriter.WriteLine( - $"::{command} {formattedOptions}::{Escape(message)}" - ); + _commandWriter.WriteLine($"::{command} {formattedOptions}::{Escape(message)}"); // This newline is just for symmetry _commandWriter.WriteLine(); @@ -56,12 +53,10 @@ public void CreateErrorAnnotation( string message, string? filePath = null, int? line = null, - int? column = null) + int? column = null + ) { - var options = new Dictionary - { - ["title"] = title - }; + var options = new Dictionary { ["title"] = title }; if (!string.IsNullOrWhiteSpace(filePath)) options["file"] = filePath; @@ -91,19 +86,19 @@ public void CreateSummary(string content) public partial class GitHubWorkflow { - public static GitHubWorkflow Default { get; } = new( - // Commands are written to the standard output - Console.Out, - // Summary is written to the file specified by an environment variable. - // We may need to write to the summary file from multiple test suites in parallel, - // so we should use a stream that delays acquiring the file lock until the very last moment, - // and employs retry logic to handle potential race conditions. - Environment - .GetEnvironmentVariable("GITHUB_STEP_SUMMARY")? - .Pipe(f => new ContentionTolerantWriteFileStream(f, FileMode.Append)) - .Pipe(s => new StreamWriter(s)) ?? - TextWriter.Null - ); + public static GitHubWorkflow Default { get; } = + new( + // Commands are written to the standard output + Console.Out, + // Summary is written to the file specified by an environment variable. + // We may need to write to the summary file from multiple test suites in parallel, + // so we should use a stream that delays acquiring the file lock until the very last moment, + // and employs retry logic to handle potential race conditions. + Environment + .GetEnvironmentVariable("GITHUB_STEP_SUMMARY") + ?.Pipe(f => new ContentionTolerantWriteFileStream(f, FileMode.Append)) + .Pipe(s => new StreamWriter(s)) ?? TextWriter.Null + ); public static string? TryGenerateFilePermalink(string filePath, int? line = null) { @@ -112,10 +107,12 @@ public partial class GitHubWorkflow var workspacePath = Environment.GetEnvironmentVariable("GITHUB_WORKSPACE"); var commitHash = Environment.GetEnvironmentVariable("GITHUB_SHA"); - if (string.IsNullOrWhiteSpace(serverUrl) || - string.IsNullOrWhiteSpace(repositorySlug) || - string.IsNullOrWhiteSpace(workspacePath) || - string.IsNullOrWhiteSpace(commitHash)) + if ( + string.IsNullOrWhiteSpace(serverUrl) + || string.IsNullOrWhiteSpace(repositorySlug) + || string.IsNullOrWhiteSpace(workspacePath) + || string.IsNullOrWhiteSpace(commitHash) + ) { return null; } @@ -126,8 +123,8 @@ public partial class GitHubWorkflow // by the Deterministic Build feature of MSBuild. // In this case, we only need to remove the leading /_/ from the file path // to get the correct relative path. - filePath.StartsWith("/_/", StringComparison.Ordinal) && - !workspacePath.StartsWith("/_/", StringComparison.Ordinal) + filePath.StartsWith("/_/", StringComparison.Ordinal) + && !workspacePath.StartsWith("/_/", StringComparison.Ordinal) ? filePath[3..] : PathEx.GetRelativePath(workspacePath, filePath); @@ -136,4 +133,4 @@ public partial class GitHubWorkflow return $"{serverUrl}/{repositorySlug}/blob/{commitHash}/{filePathRoute}{lineMarker}"; } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/TestLogger.cs b/GitHubActionsTestLogger/TestLogger.cs index 521ec49..e610a39 100644 --- a/GitHubActionsTestLogger/TestLogger.cs +++ b/GitHubActionsTestLogger/TestLogger.cs @@ -26,4 +26,4 @@ public void Initialize(TestLoggerEvents events, string testRunDirectory) => public void Initialize(TestLoggerEvents events, Dictionary parameters) => Initialize(events, TestLoggerOptions.Resolve(parameters)); -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/TestLoggerContext.cs b/GitHubActionsTestLogger/TestLoggerContext.cs index a77975a..853fd8b 100644 --- a/GitHubActionsTestLogger/TestLoggerContext.cs +++ b/GitHubActionsTestLogger/TestLoggerContext.cs @@ -109,36 +109,33 @@ public void HandleTestRunComplete(TestRunCompleteEventArgs args) var template = new TestSummaryTemplate { TestSuite = - _testRunCriteria?.Sources?.FirstOrDefault()?.Pipe(Path.GetFileNameWithoutExtension) ?? - "Unknown Test Suite", - + _testRunCriteria + ?.Sources?.FirstOrDefault() + ?.Pipe(Path.GetFileNameWithoutExtension) ?? "Unknown Test Suite", TargetFramework = - _testRunCriteria?.TryGetTargetFramework() ?? - "Unknown Target Framework", - + _testRunCriteria?.TryGetTargetFramework() ?? "Unknown Target Framework", TestRunStatistics = new TestRunStatistics( - (int?)args.TestRunStatistics?[TestOutcome.Passed] ?? - _testResults.Count(r => r.Outcome == TestOutcome.Passed), - - (int?)args.TestRunStatistics?[TestOutcome.Failed] ?? - _testResults.Count(r => r.Outcome == TestOutcome.Failed), - - (int?)args.TestRunStatistics?[TestOutcome.Skipped] ?? - _testResults.Count(r => r.Outcome == TestOutcome.Skipped), - + (int?)args.TestRunStatistics?[TestOutcome.Passed] + ?? _testResults.Count(r => r.Outcome == TestOutcome.Passed), + (int?)args.TestRunStatistics?[TestOutcome.Failed] + ?? _testResults.Count(r => r.Outcome == TestOutcome.Failed), + (int?)args.TestRunStatistics?[TestOutcome.Skipped] + ?? _testResults.Count(r => r.Outcome == TestOutcome.Skipped), (int?)args.TestRunStatistics?.ExecutedTests ?? _testResults.Count, - args.ElapsedTimeInRunningTests ), - - TestResults = _testResults.Where(r => - r.Outcome == TestOutcome.Failed || - r.Outcome == TestOutcome.Passed && Options.SummaryIncludePassedTests || - r.Outcome == TestOutcome.Skipped && Options.SummaryIncludeSkippedTests - ).ToArray() + TestResults = _testResults + .Where( + r => + r.Outcome == TestOutcome.Failed + || r.Outcome == TestOutcome.Passed && Options.SummaryIncludePassedTests + || r.Outcome == TestOutcome.Skipped + && Options.SummaryIncludeSkippedTests + ) + .ToArray() }; _github.CreateSummary(template.Render()); } } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/TestLoggerOptions.cs b/GitHubActionsTestLogger/TestLoggerOptions.cs index d996fcf..c1cb186 100644 --- a/GitHubActionsTestLogger/TestLoggerOptions.cs +++ b/GitHubActionsTestLogger/TestLoggerOptions.cs @@ -18,22 +18,20 @@ public partial class TestLoggerOptions { public static TestLoggerOptions Default { get; } = new(); - public static TestLoggerOptions Resolve(IReadOnlyDictionary parameters) => new() - { - AnnotationTitleFormat = - parameters.GetValueOrDefault("annotations.titleFormat") ?? - Default.AnnotationTitleFormat, - - AnnotationMessageFormat = - parameters.GetValueOrDefault("annotations.messageFormat") ?? - Default.AnnotationMessageFormat, - - SummaryIncludePassedTests = - parameters.GetValueOrDefault("summary.includePassedTests")?.Pipe(bool.Parse) ?? - Default.SummaryIncludePassedTests, - - SummaryIncludeSkippedTests = - parameters.GetValueOrDefault("summary.includeSkippedTests")?.Pipe(bool.Parse) ?? - Default.SummaryIncludeSkippedTests, - }; -} \ No newline at end of file + public static TestLoggerOptions Resolve(IReadOnlyDictionary parameters) => + new() + { + AnnotationTitleFormat = + parameters.GetValueOrDefault("annotations.titleFormat") + ?? Default.AnnotationTitleFormat, + AnnotationMessageFormat = + parameters.GetValueOrDefault("annotations.messageFormat") + ?? Default.AnnotationMessageFormat, + SummaryIncludePassedTests = + parameters.GetValueOrDefault("summary.includePassedTests")?.Pipe(bool.Parse) + ?? Default.SummaryIncludePassedTests, + SummaryIncludeSkippedTests = + parameters.GetValueOrDefault("summary.includeSkippedTests")?.Pipe(bool.Parse) + ?? Default.SummaryIncludeSkippedTests, + }; +} diff --git a/GitHubActionsTestLogger/TestRunStatistics.cs b/GitHubActionsTestLogger/TestRunStatistics.cs index 04a29b8..787b887 100644 --- a/GitHubActionsTestLogger/TestRunStatistics.cs +++ b/GitHubActionsTestLogger/TestRunStatistics.cs @@ -8,7 +8,8 @@ internal record TestRunStatistics( int FailedTestCount, int SkippedTestCount, int TotalTestCount, - TimeSpan OverallDuration) + TimeSpan OverallDuration +) { public TestOutcome OverallOutcome { @@ -26,4 +27,4 @@ public TestOutcome OverallOutcome return TestOutcome.None; } } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/ContentionTolerantWriteFileStream.cs b/GitHubActionsTestLogger/Utils/ContentionTolerantWriteFileStream.cs index a95b53d..06c6be8 100644 --- a/GitHubActionsTestLogger/Utils/ContentionTolerantWriteFileStream.cs +++ b/GitHubActionsTestLogger/Utils/ContentionTolerantWriteFileStream.cs @@ -38,7 +38,7 @@ public ContentionTolerantWriteFileStream(string filePath, FileMode fileMode) // Backoff and retry if the file is locked private FileStream CreateInnerStream() { - for (var retriesRemaining = 10;; retriesRemaining--) + for (var retriesRemaining = 10; ; retriesRemaining--) { try { @@ -73,10 +73,8 @@ public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); [ExcludeFromCodeCoverage] - public override long Seek(long offset, SeekOrigin origin) => - throw new NotSupportedException(); + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); [ExcludeFromCodeCoverage] - public override void SetLength(long value) => - throw new NotSupportedException(); -} \ No newline at end of file + public override void SetLength(long value) => throw new NotSupportedException(); +} diff --git a/GitHubActionsTestLogger/Utils/Extensions/GenericExtensions.cs b/GitHubActionsTestLogger/Utils/Extensions/GenericExtensions.cs index b8a07bb..b4f2290 100644 --- a/GitHubActionsTestLogger/Utils/Extensions/GenericExtensions.cs +++ b/GitHubActionsTestLogger/Utils/Extensions/GenericExtensions.cs @@ -4,5 +4,6 @@ namespace GitHubActionsTestLogger.Utils.Extensions; internal static class GenericExtensions { - public static TOut Pipe(this TIn input, Func transform) => transform(input); -} \ No newline at end of file + public static TOut Pipe(this TIn input, Func transform) => + transform(input); +} diff --git a/GitHubActionsTestLogger/Utils/Extensions/StringExtensions.cs b/GitHubActionsTestLogger/Utils/Extensions/StringExtensions.cs index 9aa0249..fc14675 100644 --- a/GitHubActionsTestLogger/Utils/Extensions/StringExtensions.cs +++ b/GitHubActionsTestLogger/Utils/Extensions/StringExtensions.cs @@ -9,45 +9,41 @@ internal static class StringExtensions public static string SubstringUntil( this string str, string sub, - StringComparison comparison = StringComparison.Ordinal) + StringComparison comparison = StringComparison.Ordinal + ) { var index = str.IndexOf(sub, comparison); - return index < 0 - ? str - : str[..index]; + return index < 0 ? str : str[..index]; } public static string SubstringUntilLast( this string str, string sub, - StringComparison comparison = StringComparison.Ordinal) + StringComparison comparison = StringComparison.Ordinal + ) { var index = str.LastIndexOf(sub, comparison); - return index < 0 - ? str - : str[..index]; + return index < 0 ? str : str[..index]; } public static string SubstringAfter( this string str, string sub, - StringComparison comparison = StringComparison.Ordinal) + StringComparison comparison = StringComparison.Ordinal + ) { var index = str.IndexOf(sub, comparison); - return index >= 0 - ? str.Substring(index + sub.Length, str.Length - index - sub.Length) - : ""; + return index >= 0 ? str.Substring(index + sub.Length, str.Length - index - sub.Length) : ""; } public static string SubstringAfterLast( this string str, string sub, - StringComparison comparison = StringComparison.Ordinal) + StringComparison comparison = StringComparison.Ordinal + ) { var index = str.LastIndexOf(sub, comparison); - return index >= 0 - ? str.Substring(index + sub.Length, str.Length - index - sub.Length) - : ""; + return index >= 0 ? str.Substring(index + sub.Length, str.Length - index - sub.Length) : ""; } public static string Indent(this string str, int spaces) @@ -71,4 +67,4 @@ public static StringBuilder Trim(this StringBuilder builder) return builder; } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/Extensions/TestCaseExtensions.cs b/GitHubActionsTestLogger/Utils/Extensions/TestCaseExtensions.cs index b862a3b..effabd2 100644 --- a/GitHubActionsTestLogger/Utils/Extensions/TestCaseExtensions.cs +++ b/GitHubActionsTestLogger/Utils/Extensions/TestCaseExtensions.cs @@ -21,4 +21,4 @@ public static string GetTypeMinimallyQualifiedName(this TestCase testCase) public static string GetMinimallyQualifiedName(this TestCase testCase) => testCase.FullyQualifiedName.SubstringAfterLast(".", StringComparison.OrdinalIgnoreCase); -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/Extensions/TestResultExtensions.cs b/GitHubActionsTestLogger/Utils/Extensions/TestResultExtensions.cs index 6153317..3081f6c 100644 --- a/GitHubActionsTestLogger/Utils/Extensions/TestResultExtensions.cs +++ b/GitHubActionsTestLogger/Utils/Extensions/TestResultExtensions.cs @@ -28,13 +28,21 @@ internal static class TestResultExtensions return StackFrame .ParseMany(testResult.ErrorStackTrace) - .LastOrDefault(f => - // Sync method call - // e.g. MyTests.EnsureOnePlusOneEqualsTwo() - f.MethodCall.StartsWith(testMethodFullyQualifiedName, StringComparison.OrdinalIgnoreCase) || - // Async method call - // e.g. MyTests.d__3.MoveNext() - f.MethodCall.Contains('<' + testMethodName + '>', StringComparison.OrdinalIgnoreCase) + .LastOrDefault( + f => + // Sync method call + // e.g. MyTests.EnsureOnePlusOneEqualsTwo() + f.MethodCall.StartsWith( + testMethodFullyQualifiedName, + StringComparison.OrdinalIgnoreCase + ) + || + // Async method call + // e.g. MyTests.d__3.MoveNext() + f.MethodCall.Contains( + '<' + testMethodName + '>', + StringComparison.OrdinalIgnoreCase + ) ); } @@ -61,4 +69,4 @@ internal static class TestResultExtensions // Try to extract it from the stack trace (works only if there was an exception) return testResult.TryGetTestStackFrame()?.Line; } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/Extensions/TestRunCriteriaExtensions.cs b/GitHubActionsTestLogger/Utils/Extensions/TestRunCriteriaExtensions.cs index bdcdebf..23f9e8c 100644 --- a/GitHubActionsTestLogger/Utils/Extensions/TestRunCriteriaExtensions.cs +++ b/GitHubActionsTestLogger/Utils/Extensions/TestRunCriteriaExtensions.cs @@ -10,9 +10,10 @@ internal static class TestRunCriteriaExtensions if (string.IsNullOrWhiteSpace(testRunCriteria.TestRunSettings)) return null; - return (string?)XElement - .Parse(testRunCriteria.TestRunSettings) - .Element("RunConfiguration")? - .Element("TargetFrameworkVersion"); + return (string?) + XElement + .Parse(testRunCriteria.TestRunSettings) + .Element("RunConfiguration") + ?.Element("TargetFrameworkVersion"); } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/Extensions/TimeSpanExtensions.cs b/GitHubActionsTestLogger/Utils/Extensions/TimeSpanExtensions.cs index 25afb70..991948b 100644 --- a/GitHubActionsTestLogger/Utils/Extensions/TimeSpanExtensions.cs +++ b/GitHubActionsTestLogger/Utils/Extensions/TimeSpanExtensions.cs @@ -4,11 +4,12 @@ namespace GitHubActionsTestLogger.Utils.Extensions; internal static class TimeSpanExtensions { - public static string ToHumanString(this TimeSpan timeSpan) => timeSpan switch - { - { TotalSeconds: <= 1 } => timeSpan.Milliseconds + "ms", - { TotalMinutes: <= 1 } => timeSpan.Seconds + "s", - { TotalHours: <= 1 } => timeSpan.Minutes + "m" + timeSpan.Seconds + "s", - _ => timeSpan.Hours + "h" + timeSpan.Minutes + "m" - }; -} \ No newline at end of file + public static string ToHumanString(this TimeSpan timeSpan) => + timeSpan switch + { + { TotalSeconds: <= 1 } => timeSpan.Milliseconds + "ms", + { TotalMinutes: <= 1 } => timeSpan.Seconds + "s", + { TotalHours: <= 1 } => timeSpan.Minutes + "m" + timeSpan.Seconds + "s", + _ => timeSpan.Hours + "h" + timeSpan.Minutes + "m" + }; +} diff --git a/GitHubActionsTestLogger/Utils/PathEx.cs b/GitHubActionsTestLogger/Utils/PathEx.cs index 6df4768..545f3fe 100644 --- a/GitHubActionsTestLogger/Utils/PathEx.cs +++ b/GitHubActionsTestLogger/Utils/PathEx.cs @@ -7,16 +7,20 @@ namespace GitHubActionsTestLogger.Utils; internal static class PathEx { - private static readonly StringComparison PathStringComparison = - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? StringComparison.OrdinalIgnoreCase - : StringComparison.Ordinal; + private static readonly StringComparison PathStringComparison = RuntimeInformation.IsOSPlatform( + OSPlatform.Windows + ) + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; // This method exists on .NET 5+ but it's impossible to polyfill static // members, so we'll just use this one on all targets. public static string GetRelativePath(string basePath, string path) { - var basePathSegments = basePath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + var basePathSegments = basePath.Split( + Path.DirectorySeparatorChar, + Path.AltDirectorySeparatorChar + ); var pathSegments = path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var commonSegmentsCount = 0; @@ -33,4 +37,4 @@ public static string GetRelativePath(string basePath, string path) pathSegments.Skip(commonSegmentsCount) ); } -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/RandomEx.cs b/GitHubActionsTestLogger/Utils/RandomEx.cs index f7bef75..cad538c 100644 --- a/GitHubActionsTestLogger/Utils/RandomEx.cs +++ b/GitHubActionsTestLogger/Utils/RandomEx.cs @@ -5,4 +5,4 @@ namespace GitHubActionsTestLogger.Utils; internal static class RandomEx { public static Random Shared { get; } = new(); -} \ No newline at end of file +} diff --git a/GitHubActionsTestLogger/Utils/StackFrame.cs b/GitHubActionsTestLogger/Utils/StackFrame.cs index 1d194c1..0e3b2a5 100644 --- a/GitHubActionsTestLogger/Utils/StackFrame.cs +++ b/GitHubActionsTestLogger/Utils/StackFrame.cs @@ -28,8 +28,9 @@ internal partial class StackFrame private const string Space = @"[\x20\t]"; private const string NotSpace = @"[^\x20\t]"; - private static readonly Regex Pattern = new( - $$""" + private static readonly Regex Pattern = + new( + $$""" ^ {{Space}}* \w+ {{Space}}+ @@ -57,25 +58,25 @@ internal partial class StackFrame \s* $ """, - RegexOptions.IgnoreCase | - RegexOptions.Multiline | - RegexOptions.ExplicitCapture | - RegexOptions.CultureInvariant | - RegexOptions.IgnorePatternWhitespace | - RegexOptions.Compiled, - // Cap the evaluation time to make it obvious should the expression - // fall into the "catastrophic backtracking" trap due to over - // generalization. - // https://github.com/atifaziz/StackTraceParser/issues/4 - TimeSpan.FromSeconds(5)); + RegexOptions.IgnoreCase + | RegexOptions.Multiline + | RegexOptions.ExplicitCapture + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled, + // Cap the evaluation time to make it obvious should the expression + // fall into the "catastrophic backtracking" trap due to over + // generalization. + // https://github.com/atifaziz/StackTraceParser/issues/4 + TimeSpan.FromSeconds(5) + ); public static IEnumerable ParseMany(string text) => from Match m in Pattern.Matches(text) - select m.Groups - into groups + select m.Groups into groups select new StackFrame( groups["type"].Value + '.' + groups["method"].Value, groups["file"].Value, groups["line"].Value.TryParseInt() ); -} \ No newline at end of file +}