diff --git a/src/Microsoft.Sbom.Api/Workflows/SBOMParserBasedValidationWorkflow.cs b/src/Microsoft.Sbom.Api/Workflows/SBOMParserBasedValidationWorkflow.cs index f0b47beb..7c6dc23d 100644 --- a/src/Microsoft.Sbom.Api/Workflows/SBOMParserBasedValidationWorkflow.cs +++ b/src/Microsoft.Sbom.Api/Workflows/SBOMParserBasedValidationWorkflow.cs @@ -206,7 +206,7 @@ private void LogIndividualFileResults(IEnumerable validFai return; } - var caseSensitiveComment = validFailures.Any() && this.osUtils.IsCaseSensitiveOS() ? + var caseSensitiveComment = !validFailures.Any() || this.osUtils.IsCaseSensitiveOS() ? string.Empty : "\r\n Note: If the manifest file was originally created using a" + "\r\n case-sensitive OS, you may also need to validate it" + diff --git a/test/Microsoft.Sbom.Api.Tests/ConsoleCapture.cs b/test/Microsoft.Sbom.Api.Tests/ConsoleCapture.cs new file mode 100644 index 00000000..62f95641 --- /dev/null +++ b/test/Microsoft.Sbom.Api.Tests/ConsoleCapture.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Sbom.Api.Tests; + +using System; +using System.IO; + +/// +/// A simple class to capture console output. Always wrap it in a try/finally block to +/// ensure that the original console output is restored. +/// +internal class ConsoleCapture +{ + private readonly TextWriter oldStdOut = Console.Out; + private readonly TextWriter oldStdError = Console.Error; + private TextWriter? stdOutWriter; + private TextWriter? stdErrWriter; + + /// + /// The content of the captured output to StdOut. Is only valid after the Restore method has been called. + /// + public string CapturedStdOut { get; private set; } = string.Empty; + + /// + /// The content of the captured output to StdError. Is only valid after the Restore method has been called. + /// + public string CapturedStdError { get; private set; } = string.Empty; + + public ConsoleCapture() + { + stdOutWriter = new StringWriter(); + Console.SetOut(stdOutWriter); + + stdErrWriter = new StringWriter(); + Console.SetError(stdErrWriter); + } + + /// + /// Restores the original console output and sets the Captured* properties + /// + public void Restore() + { + if (stdOutWriter is not null) + { + CapturedStdOut = stdOutWriter?.ToString() ?? string.Empty; + Console.SetOut(oldStdOut); + stdOutWriter?.Dispose(); + stdOutWriter = null; + } + + if (stdErrWriter is not null) + { + CapturedStdError = stdErrWriter?.ToString() ?? string.Empty; + Console.SetError(oldStdError); + stdErrWriter?.Dispose(); + stdErrWriter = null; + } + } +} diff --git a/test/Microsoft.Sbom.Api.Tests/Workflows/SbomParserBasedValidationWorkflowTests.cs b/test/Microsoft.Sbom.Api.Tests/Workflows/SbomParserBasedValidationWorkflowTests.cs index 532ac92c..14604f39 100644 --- a/test/Microsoft.Sbom.Api.Tests/Workflows/SbomParserBasedValidationWorkflowTests.cs +++ b/test/Microsoft.Sbom.Api.Tests/Workflows/SbomParserBasedValidationWorkflowTests.cs @@ -43,6 +43,8 @@ namespace Microsoft.Sbom.Workflows; [TestClass] public class SbomParserBasedValidationWorkflowTests : ValidationWorkflowTestsBase { + private const string CaseSensitiveMessageMarker = "case-sensitive"; + private readonly Mock mockLogger = new(); private readonly Mock mockOSUtils = new(); private readonly Mock fileSystemUtilsExtensionMock = new(); @@ -183,8 +185,18 @@ public async Task SbomParserBasedValidationWorkflowTests_ReturnsSuccessAndValida fileSystemMock.Object, osUtilsMock.Object); - var result = await validator.RunAsync(); - Assert.IsTrue(result); + var cc = new ConsoleCapture(); + + try + { + var result = await validator.RunAsync(); + Assert.IsTrue(result); + } + finally + { + cc.Restore(); + } + var nodeValidationResults = validationResultGenerator.NodeValidationResults; var additionalFileErrors = nodeValidationResults.Where(a => a.ErrorType == ErrorType.AdditionalFile).ToList(); @@ -200,6 +212,8 @@ public async Task SbomParserBasedValidationWorkflowTests_ReturnsSuccessAndValida var otherErrors = nodeValidationResults.Where(a => a.ErrorType == ErrorType.Other).ToList(); Assert.AreEqual(0, otherErrors.Count); + Assert.IsFalse(cc.CapturedStdOut.Contains(CaseSensitiveMessageMarker), "Case-sensitive marker should not have been output"); + configurationMock.VerifyAll(); signValidatorMock.VerifyAll(); fileSystemMock.VerifyAll(); @@ -328,8 +342,18 @@ public async Task SbomParserBasedValidationWorkflowTests_ReturnsSuccessAndValida fileSystemMock.Object, osUtilsMock.Object); - var result = await validator.RunAsync(); - Assert.IsFalse(result); + var cc = new ConsoleCapture(); + + try + { + var result = await validator.RunAsync(); + Assert.IsFalse(result); + } + finally + { + cc.Restore(); + } + var nodeValidationResults = validationResultGenerator.NodeValidationResults; var additionalFileErrors = nodeValidationResults.Where(a => a.ErrorType == ErrorType.AdditionalFile).ToList(); @@ -348,6 +372,8 @@ public async Task SbomParserBasedValidationWorkflowTests_ReturnsSuccessAndValida Assert.AreEqual(1, otherErrors.Count); Assert.AreEqual("./child2/grandchild1/file10", otherErrors.First().Path); + Assert.IsTrue(cc.CapturedStdOut.Contains(CaseSensitiveMessageMarker), "Case-sensitive marker should have been output"); + configurationMock.VerifyAll(); signValidatorMock.VerifyAll(); fileSystemMock.VerifyAll();