diff --git a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs index 9d7cc85d..5f03d871 100644 --- a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs +++ b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs @@ -343,5 +343,241 @@ public void DontChangeFilesWithoutSelectedFindings(string lineBreakSequence, boo string result = File.ReadAllText(sourceFile); Assert.AreEqual(originalContent, result); } + + /// + /// Test that XML suppression comments are generated correctly + /// + [TestMethod] + public void GenerateXmlSuppression() + { + // Test basic XML suppression generation + string suppression = DevSkimRuleProcessor.GenerateSuppressionByLanguage("xml", "DS123456"); + Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->"); + Assert.IsTrue(suppression.Contains("DevSkim: ignore DS123456"), "XML suppression should contain DevSkim ignore directive"); + } + + /// + /// Test that XML suppression comments with duration are generated correctly + /// + [TestMethod] + public void GenerateXmlSuppressionWithDuration() + { + int duration = 30; + DateTime expectedDate = DateTime.Now.AddDays(duration); + string expectedDateStr = expectedDate.ToString("yyyy-MM-dd"); + + string suppression = DevSkimRuleProcessor.GenerateSuppressionByLanguage("xml", "DS123456", duration: duration); + Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->"); + Assert.IsTrue(suppression.Contains($"until {expectedDateStr}"), "XML suppression should contain expiration date"); + } + + /// + /// Test that XML suppression comments with reviewer are generated correctly + /// + [TestMethod] + public void GenerateXmlSuppressionWithReviewer() + { + string suppression = DevSkimRuleProcessor.GenerateSuppressionByLanguage("xml", "DS123456", reviewerName: "TestReviewer"); + Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->"); + Assert.IsTrue(suppression.Contains("by TestReviewer"), "XML suppression should contain reviewer name"); + } + + /// + /// Test that XML suppression comments are properly recognized by the Suppression parser + /// + [TestMethod] + public void ParseXmlSuppression() + { + string xmlLine = ""; + Suppression suppression = new Suppression(xmlLine); + + Assert.IsTrue(suppression.IsInEffect, "Suppression should be in effect"); + Assert.AreEqual("DS123456", suppression.GetSuppressedIds.First(), "Suppression should contain the correct rule ID"); + } + + /// + /// Test that XML suppression comments with expiration are properly recognized by the Suppression parser + /// + [TestMethod] + public void ParseXmlSuppressionWithExpiration() + { + string futureDate = DateTime.Now.AddDays(30).ToString("yyyy-MM-dd"); + string xmlLine = $""; + Suppression suppression = new Suppression(xmlLine); + + Assert.IsTrue(suppression.IsInEffect, "Suppression should be in effect"); + Assert.AreEqual("DS123456", suppression.GetSuppressedIds.First(), "Suppression should contain the correct rule ID"); + Assert.AreEqual(DateTime.ParseExact(futureDate, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture), + suppression.ExpirationDate, "Suppression should have the correct expiration date"); + } + + /// + /// Test that expired XML suppression comments are not in effect + /// + [TestMethod] + public void ParseExpiredXmlSuppression() + { + string pastDate = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd"); + string xmlLine = $""; + Suppression suppression = new Suppression(xmlLine); + + Assert.IsFalse(suppression.IsInEffect, "Expired suppression should not be in effect"); + Assert.IsTrue(suppression.IsExpired, "Suppression should be marked as expired"); + } + + /// + /// Test that XML suppression comments with reviewer are properly recognized by the Suppression parser + /// + [TestMethod] + public void ParseXmlSuppressionWithReviewer() + { + string xmlLine = ""; + Suppression suppression = new Suppression(xmlLine); + + Assert.IsTrue(suppression.IsInEffect, "Suppression should be in effect"); + Assert.AreEqual("DS123456", suppression.GetSuppressedIds.First(), "Suppression should contain the correct rule ID"); + Assert.AreEqual("TestReviewer", suppression.Reviewer, "Suppression should have the correct reviewer"); + } + + /// + /// Integration test: Execute suppressions for XML files + /// + [TestMethod] + public void ExecuteSuppressionsForXml() + { + // XML content with an MD5 reference that triggers DevSkim rule + string xmlContent = @"MD5"; + + (string basePath, string sourceFile, string sarifPath) = runAnalysis(xmlContent, "xml"); + + SuppressionCommandOptions opts = new SuppressionCommandOptions + { + Path = basePath, + SarifInput = sarifPath, + ApplyAllSuppression = true + }; + + int resultCode = new SuppressionCommand(opts).Run(); + Assert.AreEqual(0, resultCode); + + string result = File.ReadAllText(sourceFile); + + // Verify that XML-style suppressions were added + Assert.IsTrue(result.Contains(""), "XML suppression comment should be properly closed"); + + // Verify suppression can be parsed + string[] lines = File.ReadAllLines(sourceFile); + var suppressions = lines + .Where(line => line.Contains(""), "XML suppression comment should be properly closed"); + + // Verify suppression contains expected parts + string[] lines = File.ReadAllLines(sourceFile); + var suppressionLines = lines.Where(line => line.Contains(""; + + string tempFileName = $"{Path.GetTempFileName()}.xml"; + File.WriteAllText(tempFileName, xmlContent); + + try + { + DevSkimRuleSet devSkimRuleSet = DevSkimRuleSet.GetDefaultRuleSet(); + DevSkimRuleProcessor processor = new DevSkimRuleProcessor(devSkimRuleSet, new DevSkimRuleProcessorOptions() + { + EnableSuppressions = true + }); + + IEnumerable issues = processor.Analyze(xmlContent, tempFileName); + + // The DS126858 (MD5) issue should be suppressed + var unsuppressedIssues = issues.Where(i => !i.IsSuppressionInfo && i.Rule.Id == "DS126858"); + Assert.AreEqual(0, unsuppressedIssues.Count(), "MD5 issue should be suppressed"); + } + finally + { + if (File.Exists(tempFileName)) + { + File.Delete(tempFileName); + } + } + } + + /// + /// Test that XML suppression is generated correctly via filename-based method + /// + [TestMethod] + public void GenerateXmlSuppressionByFilename() + { + string suppression = DevSkimRuleProcessor.GenerateSuppressionByFileName("test.xml", "DS123456"); + Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->"); + Assert.IsTrue(suppression.Contains("DevSkim: ignore DS123456"), "XML suppression should contain DevSkim ignore directive"); + } } } \ No newline at end of file diff --git a/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json b/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json index e892c1dd..540ab45f 100644 --- a/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json +++ b/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json @@ -74,5 +74,12 @@ "inline": "::", "prefix": "Rem", "suffix": "\n" + }, + { + "language": [ + "xml" + ], + "prefix": "" } ] \ No newline at end of file