11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4+ using WinApp . Cli . Services ;
45using WinApp . Cli . Tools ;
56
67namespace WinApp . Cli . Tests ;
@@ -159,7 +160,7 @@ public async Task RunBuildToolAsync_WithValidTool_ReturnsOutput()
159160 File . WriteAllText ( fakeToolPath , "@echo Hello from fake tool" ) ;
160161
161162 // Act
162- var ( stdout , stderr ) = await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "echo.cmd" ) , "" , TestContext . CancellationToken ) ;
163+ var ( stdout , stderr ) = await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "echo.cmd" ) , "" , true , TestContext . CancellationToken ) ;
163164
164165 // Assert
165166 Assert . Contains ( "Hello from fake tool" , stdout ) ;
@@ -175,7 +176,7 @@ public async Task RunBuildToolAsync_WithNonExistentTool_ThrowsFileNotFoundExcept
175176 // Act & Assert
176177 await Assert . ThrowsExactlyAsync < FileNotFoundException > ( async ( ) =>
177178 {
178- await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "nonexistent.exe" ) , "" , TestContext . CancellationToken ) ;
179+ await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "nonexistent.exe" ) , "" , true , TestContext . CancellationToken ) ;
179180 } ) ;
180181 }
181182
@@ -322,7 +323,7 @@ public async Task RunBuildToolAsync_WithNoExistingPackage_AutoInstallsAndRuns()
322323 {
323324 // Create a simple batch command that outputs something
324325 // This will either succeed (if BuildTools installs successfully) or throw an exception
325- await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "echo.cmd" ) , "test" , TestContext . CancellationToken ) ;
326+ await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "echo.cmd" ) , "test" , true , TestContext . CancellationToken ) ;
326327
327328 // If we reach here, the auto-installation worked - test passes
328329 }
@@ -349,10 +350,71 @@ public async Task RunBuildToolAsync_WithExistingTool_RunsDirectly()
349350 File . WriteAllText ( batchFile , "@echo Hello from test tool" ) ;
350351
351352 // Act
352- var ( stdout , stderr ) = await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "test.cmd" ) , "" , TestContext . CancellationToken ) ;
353+ var ( stdout , stderr ) = await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "test.cmd" ) , "" , true , TestContext . CancellationToken ) ;
353354
354355 // Assert
355356 Assert . Contains ( "Hello from test tool" , stdout ) ;
356357 Assert . AreEqual ( string . Empty , stderr . Trim ( ) ) ;
357358 }
358359}
360+
361+ /// <summary>
362+ /// Tests for BuildToolsService with non-verbose logging to test PrintErrorText behavior
363+ /// </summary>
364+ [ TestClass ]
365+ [ DoNotParallelize ]
366+ public class BuildToolsServicePrintErrorsTests ( ) : BaseCommandTests ( configPaths : true , verboseLogging : false )
367+ {
368+ [ TestMethod ]
369+ public async Task RunBuildToolAsync_WithPrintErrorsTrue_WritesErrorOutput ( )
370+ {
371+ // Arrange - Create a batch file that fails with exit code 1 and writes to stderr
372+ var packagesDir = Path . Combine ( _testCacheDirectory . FullName , "packages" ) ;
373+ var buildToolsPackageDir = Path . Combine ( packagesDir , "Microsoft.Windows.SDK.BuildTools.10.0.26100.1" ) ;
374+ var binDir = Path . Combine ( buildToolsPackageDir , "bin" , "10.0.26100.0" , "x64" ) ;
375+ Directory . CreateDirectory ( binDir ) ;
376+
377+ var failingTool = Path . Combine ( binDir , "failing.cmd" ) ;
378+ File . WriteAllText ( failingTool , "@echo Error message to stderr 1>&2\r \n @exit /b 1" ) ;
379+
380+ // Act: Run with printErrors=true - error SHOULD be printed via PrintErrorText
381+ var exception = await Assert . ThrowsExactlyAsync < BuildToolsService . InvalidBuildToolException > ( async ( ) =>
382+ {
383+ await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "failing.cmd" ) , "" , printErrors : true , TestContext . CancellationToken ) ;
384+ } ) ;
385+
386+ // Verify the exception captures the error info
387+ Assert . Contains ( "Error message to stderr" , exception . Stderr ) ;
388+
389+ // Verify that error-level log output occurred when printErrors=true
390+ // (PrintErrorText uses LogError which goes to stderr)
391+ var stdErrOutput = ConsoleStdErr . ToString ( ) ;
392+ Assert . Contains ( "Error message to stderr" , stdErrOutput , "Error output should be printed when printErrors is true" ) ;
393+ }
394+
395+ [ TestMethod ]
396+ public async Task RunBuildToolAsync_WithPrintErrorsFalse_DoesNotWriteErrorOutput ( )
397+ {
398+ // Arrange - Create a batch file that fails with exit code 1 and writes to stderr
399+ var packagesDir = Path . Combine ( _testCacheDirectory . FullName , "packages" ) ;
400+ var buildToolsPackageDir = Path . Combine ( packagesDir , "Microsoft.Windows.SDK.BuildTools.10.0.26100.1" ) ;
401+ var binDir = Path . Combine ( buildToolsPackageDir , "bin" , "10.0.26100.0" , "x64" ) ;
402+ Directory . CreateDirectory ( binDir ) ;
403+
404+ var failingTool = Path . Combine ( binDir , "failing.cmd" ) ;
405+ File . WriteAllText ( failingTool , "@echo Error message to stderr 1>&2\r \n @exit /b 1" ) ;
406+
407+ // Act: Run with printErrors=false - error should NOT be printed via PrintErrorText
408+ var exception = await Assert . ThrowsExactlyAsync < BuildToolsService . InvalidBuildToolException > ( async ( ) =>
409+ {
410+ await _buildToolsService . RunBuildToolAsync ( new GenericTool ( "failing.cmd" ) , "" , printErrors : false , TestContext . CancellationToken ) ;
411+ } ) ;
412+
413+ // Verify the exception still captures the error info
414+ Assert . Contains ( "Error message to stderr" , exception . Stderr ) ;
415+
416+ // Verify that NO error-level log output occurred when printErrors=false
417+ var stdErrOutput = ConsoleStdErr . ToString ( ) ;
418+ Assert . DoesNotContain ( "Error message to stderr" , stdErrOutput , "Error output should NOT be printed when printErrors is false" ) ;
419+ }
420+ }
0 commit comments