diff --git a/src/DemaConsulting.NuGet.CacheTool/Validation.cs b/src/DemaConsulting.NuGet.CacheTool/Validation.cs index d0968de..598fee1 100644 --- a/src/DemaConsulting.NuGet.CacheTool/Validation.cs +++ b/src/DemaConsulting.NuGet.CacheTool/Validation.cs @@ -101,65 +101,22 @@ private static void PrintValidationHeader(Context context) /// The test results collection. private static void RunVersionTest(Context context, DemaConsulting.TestResults.TestResults testResults) { - var startTime = DateTime.UtcNow; - var test = CreateTestResult("NuGetCache_VersionDisplay"); - - try - { - using var tempDir = new TemporaryDirectory(); - var logFile = PathHelpers.SafePathCombine(tempDir.DirectoryPath, "version-test.log"); - - // Build command line arguments - var args = new List - { - "--silent", - "--log", logFile, - "--version" - }; - - // Run the program - int exitCode; - using (var testContext = Context.Create([.. args])) - { - Program.Run(testContext); - exitCode = testContext.ExitCode; - } - - // Check if execution succeeded - if (exitCode == 0) + RunValidationTest( + context, + testResults, + "NuGetCache_VersionDisplay", + "Version Display Test", + ["--version"], + logContent => { - // Read log content - var logContent = File.ReadAllText(logFile); - // Verify version string is in log (version contains dots like 0.0.0) - if (!string.IsNullOrWhiteSpace(logContent) && - logContent.Split('.').Length >= 3) - { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed; - context.WriteLine($"✓ Version Display Test - PASSED"); - } - else + if (!string.IsNullOrWhiteSpace(logContent) && logContent.Split('.').Length >= 3) { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; - test.ErrorMessage = "Version string not found in log"; - context.WriteError($"✗ Version Display Test - FAILED: Version string not found in log"); + return null; } - } - else - { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; - test.ErrorMessage = $"Program exited with code {exitCode}"; - context.WriteError($"✗ Version Display Test - FAILED: Exit code {exitCode}"); - } - } - // Generic catch is justified here as this is a test framework - any exception should be - // recorded as a test failure to ensure robust test execution and reporting. - catch (Exception ex) - { - HandleTestException(test, context, "Version Display Test", ex); - } - FinalizeTestResult(test, startTime, testResults); + return "Version string not found in log"; + }); } /// @@ -169,64 +126,22 @@ private static void RunVersionTest(Context context, DemaConsulting.TestResults.T /// The test results collection. private static void RunHelpTest(Context context, DemaConsulting.TestResults.TestResults testResults) { - var startTime = DateTime.UtcNow; - var test = CreateTestResult("NuGetCache_HelpDisplay"); - - try - { - using var tempDir = new TemporaryDirectory(); - var logFile = PathHelpers.SafePathCombine(tempDir.DirectoryPath, "help-test.log"); - - // Build command line arguments - var args = new List + RunValidationTest( + context, + testResults, + "NuGetCache_HelpDisplay", + "Help Display Test", + ["--help"], + logContent => { - "--silent", - "--log", logFile, - "--help" - }; - - // Run the program - int exitCode; - using (var testContext = Context.Create([.. args])) - { - Program.Run(testContext); - exitCode = testContext.ExitCode; - } - - // Check if execution succeeded - if (exitCode == 0) - { - // Read log content - var logContent = File.ReadAllText(logFile); - // Verify help text is in log if (logContent.Contains("Usage:") && logContent.Contains("Options:")) { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed; - context.WriteLine($"✓ Help Display Test - PASSED"); - } - else - { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; - test.ErrorMessage = "Help text not found in log"; - context.WriteError($"✗ Help Display Test - FAILED: Help text not found in log"); + return null; } - } - else - { - test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; - test.ErrorMessage = $"Program exited with code {exitCode}"; - context.WriteError($"✗ Help Display Test - FAILED: Exit code {exitCode}"); - } - } - // Generic catch is justified here as this is a test framework - any exception should be - // recorded as a test failure to ensure robust test execution and reporting. - catch (Exception ex) - { - HandleTestException(test, context, "Help Display Test", ex); - } - FinalizeTestResult(test, startTime, testResults); + return "Help text not found in log"; + }); } /// @@ -235,22 +150,56 @@ private static void RunHelpTest(Context context, DemaConsulting.TestResults.Test /// The context for output. /// The test results collection. private static void RunCachePackageTest(Context context, DemaConsulting.TestResults.TestResults testResults) + { + RunValidationTest( + context, + testResults, + "NuGetCache_CachePackage", + "Cache Package Test", + ["DemaConsulting.NuGet.Caching:0.1.0"], + logContent => + { + // Verify that a non-empty path was written to the log + if (!string.IsNullOrWhiteSpace(logContent)) + { + return null; + } + + return "Package path not found in log"; + }); + } + + /// + /// Runs a validation test with common test execution logic. + /// + /// The context for output. + /// The test results collection. + /// The name of the test. + /// The display name for console output. + /// Additional command-line arguments for the test. + /// + /// Function to validate test results. Receives log content and returns null on + /// success or an error message on failure. + /// + private static void RunValidationTest( + Context context, + DemaConsulting.TestResults.TestResults testResults, + string testName, + string displayName, + string[] additionalArgs, + Func validator) { var startTime = DateTime.UtcNow; - var test = CreateTestResult("NuGetCache_CachePackage"); + var test = CreateTestResult(testName); try { using var tempDir = new TemporaryDirectory(); - var logFile = PathHelpers.SafePathCombine(tempDir.DirectoryPath, "cache-package-test.log"); + var logFile = PathHelpers.SafePathCombine(tempDir.DirectoryPath, $"{testName}.log"); - // Build command line arguments to cache a known package - var args = new List - { - "--silent", - "--log", logFile, - "DemaConsulting.NuGet.Caching:0.1.0" - }; + // Build command line arguments: always use --silent and --log for consistent capture + var args = new List { "--silent", "--log", logFile }; + args.AddRange(additionalArgs); // Run the program int exitCode; @@ -263,34 +212,34 @@ private static void RunCachePackageTest(Context context, DemaConsulting.TestResu // Check if execution succeeded if (exitCode == 0) { - // Read log content to verify a path was written + // Read log content and invoke the validator var logContent = File.ReadAllText(logFile); + var errorMessage = validator(logContent); - // Verify that a non-empty path was written to the log - if (!string.IsNullOrWhiteSpace(logContent)) + if (errorMessage == null) { test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed; - context.WriteLine($"✓ Cache Package Test - PASSED"); + context.WriteLine($"✓ {displayName} - PASSED"); } else { test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; - test.ErrorMessage = "Package path not found in log"; - context.WriteError($"✗ Cache Package Test - FAILED: Package path not found in log"); + test.ErrorMessage = errorMessage; + context.WriteError($"✗ {displayName} - FAILED: {errorMessage}"); } } else { test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; test.ErrorMessage = $"Program exited with code {exitCode}"; - context.WriteError($"✗ Cache Package Test - FAILED: Exit code {exitCode}"); + context.WriteError($"✗ {displayName} - FAILED: Exit code {exitCode}"); } } // Generic catch is justified here as this is a test framework - any exception should be // recorded as a test failure to ensure robust test execution and reporting. catch (Exception ex) { - HandleTestException(test, context, "Cache Package Test", ex); + HandleTestException(test, context, displayName, ex); } FinalizeTestResult(test, startTime, testResults); diff --git a/test/DemaConsulting.NuGet.CacheTool.Tests/ContextTests.cs b/test/DemaConsulting.NuGet.CacheTool.Tests/ContextTests.cs index f112e95..0bcecb5 100644 --- a/test/DemaConsulting.NuGet.CacheTool.Tests/ContextTests.cs +++ b/test/DemaConsulting.NuGet.CacheTool.Tests/ContextTests.cs @@ -270,4 +270,80 @@ public void Context_WriteLine_Silent_DoesNotWriteToConsole() Console.SetOut(originalOut); } } + + /// + /// Test WriteError sets exit code to 1. + /// + [TestMethod] + public void Context_WriteError_SetsErrorExitCode() + { + // Arrange + var originalOut = Console.Out; + try + { + using var outWriter = new StringWriter(); + Console.SetOut(outWriter); + using var context = Context.Create([]); + + // Act + Assert.AreEqual(0, context.ExitCode); + context.WriteError("Test error"); + + // Assert + Assert.AreEqual(1, context.ExitCode); + } + finally + { + Console.SetOut(originalOut); + } + } + + /// + /// Test WriteError writes message to console when not silent. + /// + [TestMethod] + public void Context_WriteError_NotSilent_WritesToConsole() + { + // Arrange + var originalOut = Console.Out; + try + { + using var outWriter = new StringWriter(); + Console.SetOut(outWriter); + using var context = Context.Create([]); + + // Act + context.WriteError("Test error message"); + + // Assert + var output = outWriter.ToString(); + Assert.Contains("Test error message", output); + } + finally + { + Console.SetOut(originalOut); + } + } + + /// + /// Test creating a context with --log flag but no value throws ArgumentException. + /// + [TestMethod] + public void Context_Create_LogFlag_WithoutValue_ThrowsArgumentException() + { + // Act & Assert + var exception = Assert.Throws(() => Context.Create(["--log"])); + Assert.Contains("--log", exception.Message); + } + + /// + /// Test creating a context with --results flag but no value throws ArgumentException. + /// + [TestMethod] + public void Context_Create_ResultsFlag_WithoutValue_ThrowsArgumentException() + { + // Act & Assert + var exception = Assert.Throws(() => Context.Create(["--results"])); + Assert.Contains("--results", exception.Message); + } } diff --git a/test/DemaConsulting.NuGet.CacheTool.Tests/IntegrationTests.cs b/test/DemaConsulting.NuGet.CacheTool.Tests/IntegrationTests.cs index 4a9299a..3ea0437 100644 --- a/test/DemaConsulting.NuGet.CacheTool.Tests/IntegrationTests.cs +++ b/test/DemaConsulting.NuGet.CacheTool.Tests/IntegrationTests.cs @@ -139,6 +139,45 @@ public void IntegrationTest_ValidateWithResults_GeneratesTrxFile() } } + /// + /// Test that validate with results flag generates JUnit XML file. + /// + [TestMethod] + public void IntegrationTest_ValidateWithResults_GeneratesJUnitFile() + { + // Arrange + var resultsFile = Path.GetTempFileName(); + resultsFile = Path.ChangeExtension(resultsFile, ".xml"); + + try + { + // Act + var exitCode = Runner.Run( + out var _, + "dotnet", + _dllPath, + "--validate", + "--results", + resultsFile); + + // Assert + Assert.AreEqual(0, exitCode); + Assert.IsTrue(File.Exists(resultsFile), "JUnit results file was not created"); + + var content = File.ReadAllText(resultsFile); + Assert.Contains(" /// Test that silent flag suppresses output. /// diff --git a/test/DemaConsulting.NuGet.CacheTool.Tests/ProgramTests.cs b/test/DemaConsulting.NuGet.CacheTool.Tests/ProgramTests.cs index 9115ec6..6aec070 100644 --- a/test/DemaConsulting.NuGet.CacheTool.Tests/ProgramTests.cs +++ b/test/DemaConsulting.NuGet.CacheTool.Tests/ProgramTests.cs @@ -161,4 +161,30 @@ public void Program_Version_ReturnsNonEmptyString() // Assert Assert.IsFalse(string.IsNullOrWhiteSpace(version)); } + + /// + /// Test that Run with validate flag and unsupported results format sets error exit code. + /// + [TestMethod] + public void Program_Run_WithValidateAndUnsupportedResultsFormat_SetsErrorExitCode() + { + // Arrange + var originalOut = Console.Out; + try + { + using var outWriter = new StringWriter(); + Console.SetOut(outWriter); + using var context = Context.Create(["--validate", "--silent", "--results", "output.json"]); + + // Act + Program.Run(context); + + // Assert - unsupported format should cause an error + Assert.AreEqual(1, context.ExitCode); + } + finally + { + Console.SetOut(originalOut); + } + } }