From b35f81bfa8a4f4409b612d2f86595ac9be98e19f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:24:22 +0000 Subject: [PATCH 1/4] Initial plan From 691fcb439d950a11a2987ad334a4f5ef77a11063 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:28:24 +0000 Subject: [PATCH 2/4] Add line breaks between issues and hot-spots in markdown output Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../SonarQualityResult.cs | 6 +- .../SonarQualityResultTests.cs | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/DemaConsulting.SonarMark/SonarQualityResult.cs b/src/DemaConsulting.SonarMark/SonarQualityResult.cs index c7860bb..ca67c64 100644 --- a/src/DemaConsulting.SonarMark/SonarQualityResult.cs +++ b/src/DemaConsulting.SonarMark/SonarQualityResult.cs @@ -147,9 +147,8 @@ private void AppendIssuesSection(System.Text.StringBuilder sb, string subHeading var component = CleanComponent(issue.Component); var lineInfo = issue.Line.HasValue ? $"({issue.Line})" : ""; sb.AppendLine($"{component}{lineInfo}: {issue.Severity} {issue.Type} [{issue.Rule}] {issue.Message}"); + sb.AppendLine(); } - - sb.AppendLine(); } } @@ -172,9 +171,8 @@ private void AppendHotSpotsSection(System.Text.StringBuilder sb, string subHeadi var lineInfo = hotSpot.Line.HasValue ? $"({hotSpot.Line})" : ""; sb.AppendLine( $"{component}{lineInfo}: {hotSpot.VulnerabilityProbability} [{hotSpot.SecurityCategory}] {hotSpot.Message}"); + sb.AppendLine(); } - - sb.AppendLine(); } } diff --git a/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs b/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs index f714fb6..04af32b 100644 --- a/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs @@ -462,6 +462,72 @@ public void SonarQualityResult_ToMarkdown_WithSingularCounts_ShowsCorrectText() Assert.DoesNotContain("Found 1 security hot-spots", markdown); } + /// + /// Test ToMarkdown with multiple issues includes blank lines between items + /// + [TestMethod] + public void SonarQualityResult_ToMarkdown_WithMultipleIssues_IncludesBlankLinesBetweenItems() + { + // Arrange + IReadOnlyList issues = + [ + new("key1", "rule1", "MAJOR", "test_project:src/File1.cs", 10, "First issue", "BUG"), + new("key2", "rule2", "MINOR", "test_project:src/File2.cs", 20, "Second issue", "CODE_SMELL"), + new("key3", "rule3", "CRITICAL", "test_project:src/File3.cs", 30, "Third issue", "VULNERABILITY") + ]; + + var result = new SonarQualityResult( + "https://sonarcloud.io", + "test_project", + "Test Project", + "OK", + [], + new Dictionary(), + issues, + []); + + // Act + var markdown = result.ToMarkdown(1); + + // Assert - verify each issue is followed by a blank line + Assert.Contains("src/File1.cs(10): MAJOR BUG [rule1] First issue\n\n", markdown); + Assert.Contains("src/File2.cs(20): MINOR CODE_SMELL [rule2] Second issue\n\n", markdown); + Assert.Contains("src/File3.cs(30): CRITICAL VULNERABILITY [rule3] Third issue\n\n", markdown); + } + + /// + /// Test ToMarkdown with multiple hot-spots includes blank lines between items + /// + [TestMethod] + public void SonarQualityResult_ToMarkdown_WithMultipleHotSpots_IncludesBlankLinesBetweenItems() + { + // Arrange + IReadOnlyList hotSpots = + [ + new("hs1", "test_project:src/Secure1.cs", 10, "First hot-spot", "sql-injection", "HIGH"), + new("hs2", "test_project:src/Secure2.cs", 20, "Second hot-spot", "weak-cryptography", "MEDIUM"), + new("hs3", "test_project:src/Secure3.cs", 30, "Third hot-spot", "xss", "LOW") + ]; + + var result = new SonarQualityResult( + "https://sonarcloud.io", + "test_project", + "Test Project", + "OK", + [], + new Dictionary(), + [], + hotSpots); + + // Act + var markdown = result.ToMarkdown(1); + + // Assert - verify each hot-spot is followed by a blank line + Assert.Contains("src/Secure1.cs(10): HIGH [sql-injection] First hot-spot\n\n", markdown); + Assert.Contains("src/Secure2.cs(20): MEDIUM [weak-cryptography] Second hot-spot\n\n", markdown); + Assert.Contains("src/Secure3.cs(30): LOW [xss] Third hot-spot\n\n", markdown); + } + /// /// Test SonarQualityCondition can be created with all properties /// From 82190bb84890bf04d4f3e1626b8d4c6a7dcc9d8f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:35:57 +0000 Subject: [PATCH 3/4] Use two trailing spaces for line breaks instead of blank lines Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../SonarQualityResult.cs | 10 ++++++---- .../SonarQualityResultTests.cs | 20 +++++++++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/DemaConsulting.SonarMark/SonarQualityResult.cs b/src/DemaConsulting.SonarMark/SonarQualityResult.cs index ca67c64..e0f2b34 100644 --- a/src/DemaConsulting.SonarMark/SonarQualityResult.cs +++ b/src/DemaConsulting.SonarMark/SonarQualityResult.cs @@ -146,9 +146,10 @@ private void AppendIssuesSection(System.Text.StringBuilder sb, string subHeading { var component = CleanComponent(issue.Component); var lineInfo = issue.Line.HasValue ? $"({issue.Line})" : ""; - sb.AppendLine($"{component}{lineInfo}: {issue.Severity} {issue.Type} [{issue.Rule}] {issue.Message}"); - sb.AppendLine(); + sb.AppendLine($"{component}{lineInfo}: {issue.Severity} {issue.Type} [{issue.Rule}] {issue.Message} "); } + + sb.AppendLine(); } } @@ -170,9 +171,10 @@ private void AppendHotSpotsSection(System.Text.StringBuilder sb, string subHeadi var component = CleanComponent(hotSpot.Component); var lineInfo = hotSpot.Line.HasValue ? $"({hotSpot.Line})" : ""; sb.AppendLine( - $"{component}{lineInfo}: {hotSpot.VulnerabilityProbability} [{hotSpot.SecurityCategory}] {hotSpot.Message}"); - sb.AppendLine(); + $"{component}{lineInfo}: {hotSpot.VulnerabilityProbability} [{hotSpot.SecurityCategory}] {hotSpot.Message} "); } + + sb.AppendLine(); } } diff --git a/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs b/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs index 04af32b..7ee74c7 100644 --- a/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs @@ -463,7 +463,7 @@ public void SonarQualityResult_ToMarkdown_WithSingularCounts_ShowsCorrectText() } /// - /// Test ToMarkdown with multiple issues includes blank lines between items + /// Test ToMarkdown with multiple issues includes line breaks between items /// [TestMethod] public void SonarQualityResult_ToMarkdown_WithMultipleIssues_IncludesBlankLinesBetweenItems() @@ -489,14 +489,14 @@ public void SonarQualityResult_ToMarkdown_WithMultipleIssues_IncludesBlankLinesB // Act var markdown = result.ToMarkdown(1); - // Assert - verify each issue is followed by a blank line - Assert.Contains("src/File1.cs(10): MAJOR BUG [rule1] First issue\n\n", markdown); - Assert.Contains("src/File2.cs(20): MINOR CODE_SMELL [rule2] Second issue\n\n", markdown); - Assert.Contains("src/File3.cs(30): CRITICAL VULNERABILITY [rule3] Third issue\n\n", markdown); + // Assert - verify each issue ends with two spaces (hard line break) + Assert.Contains("src/File1.cs(10): MAJOR BUG [rule1] First issue ", markdown); + Assert.Contains("src/File2.cs(20): MINOR CODE_SMELL [rule2] Second issue ", markdown); + Assert.Contains("src/File3.cs(30): CRITICAL VULNERABILITY [rule3] Third issue ", markdown); } /// - /// Test ToMarkdown with multiple hot-spots includes blank lines between items + /// Test ToMarkdown with multiple hot-spots includes line breaks between items /// [TestMethod] public void SonarQualityResult_ToMarkdown_WithMultipleHotSpots_IncludesBlankLinesBetweenItems() @@ -522,10 +522,10 @@ public void SonarQualityResult_ToMarkdown_WithMultipleHotSpots_IncludesBlankLine // Act var markdown = result.ToMarkdown(1); - // Assert - verify each hot-spot is followed by a blank line - Assert.Contains("src/Secure1.cs(10): HIGH [sql-injection] First hot-spot\n\n", markdown); - Assert.Contains("src/Secure2.cs(20): MEDIUM [weak-cryptography] Second hot-spot\n\n", markdown); - Assert.Contains("src/Secure3.cs(30): LOW [xss] Third hot-spot\n\n", markdown); + // Assert - verify each hot-spot ends with two spaces (hard line break) + Assert.Contains("src/Secure1.cs(10): HIGH [sql-injection] First hot-spot ", markdown); + Assert.Contains("src/Secure2.cs(20): MEDIUM [weak-cryptography] Second hot-spot ", markdown); + Assert.Contains("src/Secure3.cs(30): LOW [xss] Third hot-spot ", markdown); } /// From 215026a4dece5daaf3ca84f8f6447441913fddd5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:40:44 +0000 Subject: [PATCH 4/4] Use Environment.NewLine in tests to verify trailing spaces before line ending Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../SonarQualityResultTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs b/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs index 7ee74c7..9172d68 100644 --- a/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/SonarQualityResultTests.cs @@ -489,10 +489,10 @@ public void SonarQualityResult_ToMarkdown_WithMultipleIssues_IncludesBlankLinesB // Act var markdown = result.ToMarkdown(1); - // Assert - verify each issue ends with two spaces (hard line break) - Assert.Contains("src/File1.cs(10): MAJOR BUG [rule1] First issue ", markdown); - Assert.Contains("src/File2.cs(20): MINOR CODE_SMELL [rule2] Second issue ", markdown); - Assert.Contains("src/File3.cs(30): CRITICAL VULNERABILITY [rule3] Third issue ", markdown); + // Assert - verify each issue ends with two spaces immediately before line ending + Assert.Contains($"src/File1.cs(10): MAJOR BUG [rule1] First issue {Environment.NewLine}", markdown); + Assert.Contains($"src/File2.cs(20): MINOR CODE_SMELL [rule2] Second issue {Environment.NewLine}", markdown); + Assert.Contains($"src/File3.cs(30): CRITICAL VULNERABILITY [rule3] Third issue {Environment.NewLine}", markdown); } /// @@ -522,10 +522,10 @@ public void SonarQualityResult_ToMarkdown_WithMultipleHotSpots_IncludesBlankLine // Act var markdown = result.ToMarkdown(1); - // Assert - verify each hot-spot ends with two spaces (hard line break) - Assert.Contains("src/Secure1.cs(10): HIGH [sql-injection] First hot-spot ", markdown); - Assert.Contains("src/Secure2.cs(20): MEDIUM [weak-cryptography] Second hot-spot ", markdown); - Assert.Contains("src/Secure3.cs(30): LOW [xss] Third hot-spot ", markdown); + // Assert - verify each hot-spot ends with two spaces immediately before line ending + Assert.Contains($"src/Secure1.cs(10): HIGH [sql-injection] First hot-spot {Environment.NewLine}", markdown); + Assert.Contains($"src/Secure2.cs(20): MEDIUM [weak-cryptography] Second hot-spot {Environment.NewLine}", markdown); + Assert.Contains($"src/Secure3.cs(30): LOW [xss] Third hot-spot {Environment.NewLine}", markdown); } ///