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);
}
///