Functions/GenXdev.Coding.PowerShell.Modules/Assert-GenXdevTest.ps1
################################################################################ <# .SYNOPSIS Executesunit tests for GenXdev modules, sub-modules, or cmdlets with intelligent debugging and AI-powered error resolution. .DESCRIPTION This function provides a testing framework for GenXdev modules, offering multi-level test execution from entire modules down to individual cmdlets. It integrates PSScriptAnalyzer for static code analysis, Pester for unit testing, and Get-Help validation for documentation compliance. The function includes intelligent error handling with AI-powered resolution capabilities and detailed progress reporting for development workflows. .PARAMETER CmdletName Search pattern to filter cmdlets for testing. Supports wildcards and allows targeting specific cmdlets or groups of cmdlets matching the pattern. .PARAMETER DefinitionMatches Regular expression to match cmdlet definitions during the search process. This allows for advanced filtering based on cmdlet implementation patterns. .PARAMETER ModuleName GenXdev module names to search and test. Must follow the pattern starting with 'GenXdev' followed by optional sub-module components. Supports wildcards for broad module selection. .PARAMETER NoLocal Skip searching in local module paths during cmdlet discovery. When specified, only published module paths will be considered for testing. .PARAMETER OnlyPublished Limit search to published module paths only. This excludes local development modules and focuses on officially published GenXdev modules. .PARAMETER FromScripts Search in script files instead of module files. This allows testing of standalone PowerShell scripts within the GenXdev ecosystem. .PARAMETER IncludeScripts Include the scripts directory in addition to regular modules. This expands the test scope to cover both modular and script-based functionality. .PARAMETER OnlyReturnModuleNames Return only unique module names instead of full cmdlet details. Useful for discovery and inventory operations rather than detailed testing. .PARAMETER ExactMatch Require exact matches for cmdlet names rather than wildcard matching. This provides precise targeting for specific cmdlet testing scenarios. .PARAMETER Verbosity Output detail level for test execution. Controls the amount of information displayed during test runs, from minimal to diagnostic output. .PARAMETER StackTraceVerbosity Stack trace detail level for error reporting. Determines how much call stack information is included when errors occur during testing. .PARAMETER TestFailedAction Action to take when a test fails. Options include interactive prompting, automatic continuation, stopping execution, AI-powered resolution, error logging, or exception throwing for integration scenarios. .PARAMETER AllowLongRunningTests Include unit tests that have long running durations in the test execution. This enables testing including performance and integration tests. .PARAMETER SkipModuleImports Skip importing GenXdev modules before testing. This is useful when modules are already loaded or when testing specific module loading scenarios. .PARAMETER SkipPSAnalyzerTests Skip invoking PSScriptAnalyzer tests during the test execution. This allows focusing solely on functional testing when static analysis is not required. .PARAMETER SkipPesterTests Skip invoking Pester tests during the test execution. This allows focusing solely on static analysis when functional testing is not required. .EXAMPLE Assert-GenXdevTest -ModuleName "GenXdev.AI" Executes all tests for the GenXdev.AI module including PSScriptAnalyzer and Pester tests. .EXAMPLE Assert-GenXdevTest -SubModuleName "GenXdev.Coding.PowerShell.Modules" ` -TestFailedAction SolveWithAI Tests the specified sub-module and uses AI to automatically resolve any failures encountered during testing. .EXAMPLE Assert-GenXdevTest -CmdletName "Get-GenXDevCmdlet" -Verbosity Detailed Tests the specific cmdlet with detailed output showing all test operations and results. .EXAMPLE testcmdlet Assert-GenXdevTest Uses the alias to test the current cmdlet with default settings. #> function Assert-GenXdevTest { [CmdletBinding(DefaultParameterSetName = "ModuleName")] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "Global:AllowLongRunningTests")] [Alias("Assert-GenXdevUnitTest", "rungenxdevtests", "testcmdlet")] param ( ############################################################################### [parameter( Position = 0, Mandatory = $false, ValueFromPipelineByPropertyName = $true, HelpMessage = 'Search pattern to filter cmdlets' )] [ValidateNotNullOrEmpty()] [Alias('Filter', 'CmdLet', 'Cmd', 'FunctionName', 'Name')] [SupportsWildcards()] [string] $CmdletName, ############################################################################### [Parameter( Position = 1, Mandatory = $false, HelpMessage = ('Action to take when a test fails. Options: Ask, ' + 'Continue, Stop, SolveWithAI, Write-Error, Throw') )] [ValidateSet('Ask', 'Continue', 'Stop', 'SolveWithAI', 'Write-Error', 'Throw')] [string] $TestFailedAction = 'Continue', ############################################################################### [parameter( Position = 2, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'Regular expression to match cmdlet definitions' )] [ValidateNotNullOrEmpty()] [string] $DefinitionMatches, ############################################################################### [parameter( Position = 3, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'GenXdev module names to search' )] [ValidateNotNullOrEmpty()] [Alias('Module', 'BaseModuleName', 'SubModuleName')] [ValidatePattern('^(GenXdev|GenXde[v]\*|GenXdev(\.[\w\*\[\]\?]*)+)+$')] [SupportsWildcards()] [string[]] $ModuleName, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Skip searching in local module paths' )] [switch] $NoLocal, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Only search in published module paths' )] [switch] $OnlyPublished, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Search in script files instead of modules' )] [switch] $FromScripts, ############################################################################### [Parameter( ParameterSetName = "ModuleName", Mandatory = $false, HelpMessage = ('Includes the scripts directory in addition to ' + 'regular modules') )] [switch] $IncludeScripts, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Only return unique module names' )] [switch] $OnlyReturnModuleNames, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Require exact matches for cmdlet names' )] [switch] $ExactMatch, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Output detail level' )] [ValidateSet('None', 'Normal', 'Detailed', 'Diagnostic')] [string] $Verbosity = 'Normal', ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Stack trace detail level' )] [ValidateSet('None', 'FirstLine', 'Filtered', 'Full')] [string] $StackTraceVerbosity = 'FirstLine', ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Also selects unit-tests that have long running durations' )] [switch] $AllowLongRunningTests, ############################################################################### [Parameter( ParameterSetName = "ModuleName", Mandatory = $false, HelpMessage = 'Skips importing GenXdev modules before testing' )] [switch] $SkipModuleImports, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Skips invoking PSAnalyzer tests' )] [switch] $SkipPSAnalyzerTests, ############################################################################### [Parameter( Mandatory = $false, HelpMessage = 'Skips invoking Pester tests' )] [switch] $SkipPesterTests ) begin { $originalProgressPreference = $ProgressPreference $ProgressPreference = 'Continue' # store allow long running tests setting in global scope for test access $Global:AllowLongRunningTests = $AllowLongRunningTests -eq $true # ensure pester module is available for test execution GenXdev.FileSystem\EnsurePester # import GenXdev modules if testing modules and imports not skipped if ($ModuleName -and (-not $SkipModuleImports)) { # ensure all GenXdev modules are loaded for testing GenXdev.Helpers\Import-GenXdevModules } # output initialization message for test framework startup Microsoft.PowerShell.Utility\Write-Verbose ( 'Initializing GenXdev test execution framework') # calculate root path for script location discovery $rootPath = GenXdev.FileSystem\Expand-Path "$PSScriptRoot\..\..\..\..\..\" # define script path for script-based testing scenarios $scriptPath = "$rootPath\Scripts" # store current location to restore after test completion $originalLocation = Microsoft.PowerShell.Management\Get-Location # initialize pester configuration with optimized settings for testing $config = Pester\New-PesterConfiguration # configure detailed verbosity when using non-continue failure actions if ((-not $PSBoundParameters.ContainsKey("Verbosity") -and ($TestFailedAction -ne "Continue"))) { $config.Output.Verbosity = 'Detailed' } # apply user-specified or default verbosity setting $config.Output.Verbosity = $Verbosity # configure full stack trace verbosity when not explicitly set if (-not $PSBoundParameters.ContainsKey("StackTraceVerbosity")) { $config.Output.StackTraceVerbosity = 'Full' } # apply user-specified or enhanced stack trace verbosity $config.Output.StackTraceVerbosity = $StackTraceVerbosity # enable pass-through results for programmatic access to test outcomes $config.Run.PassThru = $true # use ANSI rendering for enhanced console output formatting $config.Output.RenderMode = 'Ansi' # disable test result file generation for performance optimization $config.TestResult.Enabled = $false # output configuration confirmation for debugging purposes Microsoft.PowerShell.Utility\Write-Verbose ( ("Test configuration initialized with verbosity: " + "$($config.Output.Verbosity)")) } process { # copy identical parameter values for cmdlet discovery function call $params = GenXdev.Helpers\Copy-IdenticalParamValues ` -BoundParameters $PSBoundParameters ` -FunctionName 'GenXdev.Helpers\Get-GenXdevCmdlet' ` -DefaultValues (Microsoft.PowerShell.Utility\Get-Variable ` -Scope Local ` -ErrorAction SilentlyContinue ) # discover cmdlets matching the specified criteria $cmdlets = GenXdev.Helpers\Get-GenXdevCmdlet @params # verify we have cmdlets to test before proceeding if ($cmdlets.Count -eq 0) { # output warning when no test targets are found Microsoft.PowerShell.Utility\Write-Warning ( 'No test files found for the specified criteria') return } # output discovery results for debugging and progress tracking Microsoft.PowerShell.Utility\Write-Verbose ( "Found $($cmdlets.Count) scripts to test with ScriptAnalyzer") # initialize collection for script analyzer test results [System.Collections.Generic.List[object]] $scriptAnalyzerResults = @() # execute PSScriptAnalyzer tests unless explicitly skipped if (-not $SkipPSAnalyzerTests) { try { # iterate through each discovered cmdlet for analysis foreach ($nextCmdlet in $cmdlets) { # skip internal cmdlets that start with underscore if ($nextCmdlet.Name -like "_*") { continue } Microsoft.PowerShell.Utility\Write-Progress ` -Activity "Analyzing $($nextCmdlet.Name)" ` -CurrentOperation "Processing $($nextCmdlet.Name)" ` -Status "'$((GenXdev.FileSystem\Find-Item ($nextCmdlet.ScriptFilePath) -NoRecurse -RelativeBasePath $rootPath))'" # initialize loop control variables for retry logic $stop = $false $tfa = $TestFailedAction $getHelpExceptionMsg = $null # retry loop for handling test failures and AI resolution while (-not $stop) { try { # extract script file path and function name for testing $scriptFile = $nextCmdlet.ScriptFilePath $fn = $nextCmdlet.Name # perform Get-Help validation tests for documentation try { # attempt to retrieve help for the current cmdlet $null = Microsoft.PowerShell.Core\Get-Help ` -Name $nextCmdlet.Name # clear any previous help exception message on success $getHelpExceptionMsg = $null } catch { # capture help exception message for error handling $getHelpExceptionMsg = $_.Exception.Message # format comprehensive exception message with context $exceptionMsg = ("Follow rules from: " + ".github\copilot-instructions.md !`r`n!`r`n" + "Failed to get help for ${fn}: " + "$($getHelpExceptionMsg)`r`nFix the problem by " + "editing the file, so I can approve your changes.") # handle interactive failure action prompting if ($tfa -eq 'Ask') { $tfatmp = $host.ui.PromptForChoice( 'Make a choice', ("Get-Help failed for ${fn}: " + "$($getHelpExceptionMsg)`r`nWhat to do next?"), @('&Continue', '&Stop', 'Solve with &AI', '&Write-Error', '&Throw'), 0 ) # convert choice index to action string $tfa = switch ($tfatmp) { 0 { 'Continue' } 1 { 'Stop' } 2 { 'SolveWithAI' } 3 { 'Write-Error' } 4 { 'Throw' } } } $doContinue = $false # execute the selected failure action switch ($tfa) { 'Continue' { # log warning and continue with next test Microsoft.PowerShell.Utility\Write-Warning ( ("Get-Help found issues in ${scriptFile}: " + "$getHelpExceptionMsg") ) } 'Stop' { # terminate test execution immediately return } 'SolveWithAI' { # reset action to ask for next iteration $tfa = 'Ask' # invoke AI-powered refactoring to resolve issue GenXdev.Coding\Assert-RefactorFile ` -RefactorSettings ( [GenXdev.Helpers.RefactorSettings] @{ Code = $true PromptKey = "FailedScriptAnalyzerResults" Prompt = $exceptionMsg } ) ` -Path ($scriptFile) $doContinue = $true } 'Write-Error' { # log error and continue processing Microsoft.PowerShell.Utility\Write-Error ( ("Get-Help found issues in ${scriptFile}: " + "$getHelpExceptionMsg") ) } 'Throw' { # create and throw detailed exception $exception = [System.InvalidOperationException]::new( ("Get-Help found issues in ${scriptFile}: " + "$getHelpExceptionMsg") ) $exception.Data.Add('ScriptPath', $scriptFile) $exception.Data.Add('ThrownException', $PSItem) throw $exception } } if ($doContinue) { continue; } } if ([string]::IsNullOrWhiteSpace($scriptFile)) { # output warning when script file path is empty Microsoft.PowerShell.Utility\Write-Warning ( "No script file found for cmdlet: $($nextCmdlet.Name)" ) continue; } # invoke script analyzer on the current script file $analyzerResults = @(GenXdev.Coding\Invoke-GenXdevScriptAnalyzer ` -Path $scriptFile) # process script analyzer results if issues were found if ($analyzerResults.Count -gt 0) { # add analyzer results to the collection for reporting $null = $scriptAnalyzerResults.Add( @{ Path = $scriptFile Results = $analyzerResults } ) # format analyzer results for error reporting $msg = ("Script analysis error during script analyzer " + "tests:`r`n" + "$($scriptAnalyzerResults[$scriptAnalyzerResults.Count-1].Results | Microsoft.PowerShell.Utility\Select-Object -Property RuleName, Line, Message -Unique | Microsoft.PowerShell.Utility\ConvertTo-Json -Depth 5)" ) # handle interactive failure action prompting if ($tfa -eq 'Ask') { $tfatmp = $host.ui.PromptForChoice( 'Make a choice', ("PSScriptAnalyzer detected " + "$($analyzerResults.Count) issues in: $scriptFile "), @('&Continue', '&Stop', 'Solve with &AI', '&Write-Error', '&Throw'), 0 ) # convert choice index to action string $tfa = switch ($tfatmp) { 0 { 'Continue' } 1 { 'Stop' } 2 { 'SolveWithAI' } 3 { 'Write-Error' } 4 { 'Throw' } } } $doContinue = $false; # execute the selected failure action switch ($tfa) { 'Continue' { # log warning and exit retry loop Microsoft.PowerShell.Utility\Write-Warning ( ("PSScriptAnalyzer detected " + "$($analyzerResults.Count) issues in: " + "$scriptFile ") ) $stop = $true $doContinue = $true } 'Stop' { # terminate test execution immediately return } 'SolveWithAI' { # reset action to ask for next iteration $tfa = 'Ask' # invoke AI-powered refactoring to resolve issues GenXdev.Coding\Assert-RefactorFile ` -RefactorSettings ( [GenXdev.Helpers.RefactorSettings] @{ Code = $true PromptKey = "FailedScriptAnalyzerResults" Prompt = $msg } ) ` -Path $scriptFile $doContinue = $true } 'Write-Error' { # log error with issue count Microsoft.PowerShell.Utility\Write-Error ( ("PSScriptAnalyzer detected errors in: " + "$scriptFile " + "$($analyzerResults.Count) issues found") ) } 'Throw' { # create and throw detailed exception $exception = [System.InvalidOperationException]::new( ("PSScriptAnalyzer detected errors in: " + "$scriptFile " + "$($analyzerResults.Count) issues found") ) $exception.Data.Add('ScriptPath', $_) $exception.Data.Add('IssueCount', $analyzerResults.Count) $exception.Data.Add('AnalyzerResults', $analyzerResults) throw $exception } } if ($doContinue) { continue; } } # exit retry loop when no issues are found $stop = $true break } catch [System.InvalidOperationException] { $exc = $_ # handle PSScriptAnalyzer exceptions that we specifically threw if ($exc.Exception.Data.ContainsKey('AnalyzerResults')) { # output structured error result for known analyzer exceptions Microsoft.PowerShell.Utility\Write-Output @{ Success = $false ErrorMessage = ("Unexpected error during script " + "analysis: " + @" $($exc.Exception) $($exc.InvocationInfo.PositionMessage) $($exc.InvocationInfo.Line) $($exc.InvocationInfo.ScriptStackTrace) "@) ScriptAnalyzerResults = $scriptAnalyzerResults } # re-throw our PSScriptAnalyzer exception throw } else { # output structured error result for other exceptions Microsoft.PowerShell.Utility\Write-Output @{ Success = $false ErrorMessage = ("Unexpected error during script " + "analysis: " + @" $($exc.Exception) $($exc.InvocationInfo.PositionMessage) $($exc.InvocationInfo.Line) $($exc.InvocationInfo.ScriptStackTrace) "@) ScriptAnalyzerResults = $scriptAnalyzerResults } # handle the exception based on test failed action switch ($TestFailedAction) { 'Continue' { # log warning with full exception details Microsoft.PowerShell.Utility\Write-Warning ( "Script analysis error: " + @" $($exc.Exception) $($exc.InvocationInfo.PositionMessage) $($exc.InvocationInfo.Line) $($exc.InvocationInfo.ScriptStackTrace) "@) } 'Stop' { # terminate test execution immediately return } 'SolveWithAI' { # perform AI-powered refactoring on current file GenXdev.Coding\Assert-RefactorFile ` -RefactorSettings ( [GenXdev.Helpers.RefactorSettings] @{ Code = $true PromptKey = "FailedScriptAnalyzerResults" Prompt = ("Script analysis error: " + @" $($exc.Exception) $($PSItem.InvocationInfo.PositionMessage) $($exc.InvocationInfo.Line) $($exc.InvocationInfo.ScriptStackTrace) "@) } ) ` -Path $scriptFile # pause for user interaction and reload modules Microsoft.PowerShell.Utility\Read-Host -Prompt "Press Enter to continue" GenXdev.Helpers\Import-GenXdevModules GenXdev.Coding\Assert-GenXdevTest @PSBoundParameters return } 'Write-Error' { # log error with exception message Microsoft.PowerShell.Utility\Write-Error ( "Script analysis error: $($exc.Exception.Message)") } 'Throw' { # re-throw the exception throw $exc } } } } catch { $exc = $_ # output structured error result for unexpected exceptions Microsoft.PowerShell.Utility\Write-Output @{ Success = $false ErrorMessage = ("Unexpected error during script analysis: " + "$($exc.Exception.Message)") ScriptAnalyzerResults = $scriptAnalyzerResults } # handle unexpected exceptions based on test failed action switch ($TestFailedAction) { 'Continue' { # log warning with exception message Microsoft.PowerShell.Utility\Write-Warning ( "Script analysis error: $($exc.Exception.Message)") } 'Stop' { # terminate test execution immediately return } 'SolveWithAI' { # perform AI-powered refactoring on current file GenXdev.Coding\Assert-RefactorFile ` -RefactorSettings ( [GenXdev.Helpers.RefactorSettings] @{ Code = $true PromptKey = "FailedScriptAnalyzerResults" Prompt = ("Script analysis error during " + "script analyzer tests: " + @" $($exc.Exception) $($exc.InvocationInfo.PositionMessage) $($exc.InvocationInfo.Line) $($exc.InvocationInfo.ScriptStackTrace) "@) } ) ` -Path $scriptFile # pause for user interaction and reload modules Microsoft.PowerShell.Utility\Read-Host -Prompt "Press Enter to continue" GenXdev.Helpers\Import-GenXdevModules GenXdev.Coding\Assert-GenXdevTest @PSBoundParameters return } 'Write-Error' { # log error with full exception details Microsoft.PowerShell.Utility\Write-Error ( ("Script analysis error during script " + "analyzer tests: " + @" $($exc.Exception) $($exc.InvocationInfo.PositionMessage) $($exc.InvocationInfo.Line) $($exc.InvocationInfo.ScriptStackTrace) "@) ) } 'Throw' { # re-throw the exception throw $exc } } } } } } finally { # process script analyzer results if issues were found if ($scriptAnalyzerResults.Count -gt 0) { # handle stopping action for script analyzer failures switch ($TestFailedAction) { 'Stop' { # output final failure result with analyzer issues Microsoft.PowerShell.Utility\Write-Output @{ Success = $false ErrorMessage = ("$($scriptAnalyzerResults.Count) " + "script analyzer issues found") ScriptAnalyzerResults = $scriptAnalyzerResults } } } } } } # return early if Pester tests are skipped if ($SkipPesterTests) { # return result indicating PSScriptAnalyzer success and no Pester tests return @{ Success = ($scriptAnalyzerResults.Count -eq 0) TestResults = $null AnalyzerResults = $scriptAnalyzerResults } } Microsoft.PowerShell.Utility\Write-Progress ` -Activity "Analyzing $($nextCmdlet.Name)" ` -Completed ` -Status "Completed" # discover test containers for cmdlets with associated test files $testContainers = @($cmdlets | Microsoft.PowerShell.Core\Where-Object { (-not [string]::IsNullOrWhiteSpace($_.ScriptTestFilePath)) -and (Microsoft.PowerShell.Management\Test-Path ` -LiteralPath $_.ScriptTestFilePath) } | Microsoft.PowerShell.Core\ForEach-Object { # create pester container for each valid test file Pester\New-PesterContainer -Path $_.ScriptTestFilePath } ) # verify we have test containers before proceeding with Pester execution if ($testContainers.Count -eq 0) { # output warning when no Pester test files are found Microsoft.PowerShell.Utility\Write-Warning ( 'No Pester test files found for the specified criteria') return } # output discovery results for debugging and progress tracking Microsoft.PowerShell.Utility\Write-Verbose ( "Found $($testContainers.Count) scripts to test with Pester") # configure pester to run our discovered test containers $config.Run.Container = $testContainers # execute the tests using pester with configured settings Microsoft.PowerShell.Utility\Write-Verbose 'Executing Pester tests' # run pester tests and capture results for processing $testResults = Pester\Invoke-Pester -Configuration $config # handle failed tests with debugging and AI resolution if requested if ($testResults.FailedCount -gt 0) { # initialize test failed action for interactive handling $tfa = $TestFailedAction # handle interactive failure action prompting for Pester failures if ($tfa -eq 'Ask') { $tfatmp = $host.ui.PromptForChoice( 'Make a choice', ("Pester detected $($testResults.FailedCount) failed tests. " + "What to do next?"), @('&Continue', '&Stop', 'Solve with &AI', '&Write-Error', '&Throw'), 0 ) # convert choice index to action string $tfa = switch ($tfatmp) { 0 { 'Continue' } 1 { 'Stop' } 2 { 'SolveWithAI' } 3 { 'Write-Error' } 4 { 'Throw' } } } # execute the selected failure action for Pester test failures switch ($tfa) { 'Throw' { # output structured failure result for throwing exceptions Microsoft.PowerShell.Utility\Write-Output @{ Success = $false ErrorMessage = "$($testResults.FailedCount) test(s) failed" TestResults = $testResults AnalyzerResults = $scriptAnalyzerResults } # create detailed exception with test failure information $exception = [System.InvalidOperationException]::new( ("Found issues in ${scriptFile}: " + "$($analyzerResults.Count) issues found") ) $exception.Data.Add('ScriptPath', $_) $exception.Data.Add('IssueCount', ($scriptAnalyzerResults.Count + $testResult.FailedCount)) $exception.Data.Add('AnalyzerResults', $scriptAnalyzerResults) $exception.Data.Add('TestResults', $testResults) throw $exception } 'SolveWithAI' { # reset action to ask for subsequent iterations $tfa = "Ask" # output progress information for AI-powered debugging Microsoft.PowerShell.Utility\Write-Verbose ( ("Processing $($testResults.FailedCount) failed test(s) " + "for debugging") ) # initialize collection for new test results after fixing [System.Collections.Generic.List[object]] $newResults = @() # iterate through each failed test for AI-powered resolution foreach ($failedTest in $testResults.Failed) { # extract cmdlet name from failed test path for debugging $failedCmdletName = [System.IO.Path]::GetFileNameWithoutExtension( $failedTest.Path).Replace('.Tests', '') # output warning for current failed test Microsoft.PowerShell.Utility\Write-Warning ( "Test failed: $($failedTest.Name) in $failedCmdletName") # determine if test is from scripts directory $isFromScripts = (GenXdev.FileSystem\Expand-Path $failedTest.Path).StartsWith("$scriptPath\") # construct script file path based on test location $scriptFilePath = ($isFromScripts ? (GenXdev.FileSystem\Expand-Path ( "$([IO.Path]::GetDirectoryName($failedTest.Path))" + "\$([IO.Path]::GetFileNameWithoutExtension($failedTest.Path).Replace('.Tests', '')).ps1" )) : (GenXdev.FileSystem\Expand-Path ( "$([IO.Path]::GetDirectoryName($failedTest.Path))" + "\..\..\Functions" + "\$([IO.Path]::GetFileNameWithoutExtension($failedTest.Path).Replace('.Tests', '')).ps1" )) ) # open failed test in VS Code with Copilot integration $failedTest.Path | GenXdev.Coding\VsCode -Copilot # initialize loop control for AI resolution attempts $stopped = $false $ft = $failedTest # retry loop for AI-powered test failure resolution while (-not $stopped) { # invoke AI-powered refactoring to resolve test failure GenXdev.Coding\Assert-RefactorFile ` -RefactorSettings ( [GenXdev.Helpers.RefactorSettings] @{ Code = $true PromptKey = "ResolveFailedTest" Prompt = Prompt ( "Pester test failed for:`r`n" + "$($ft | Microsoft.PowerShell.Utility\ConvertTo-Json ` -Depth 5)" ) } ) ` -Path $scriptFilePath # prompt user for next action after AI resolution attempt switch ($host.ui.PromptForChoice( 'Make a choice', 'What to do next?', @('&Stop', '&Test again', '&Continue'), 1) ) { 0 { # stop entire test execution return } 1 { # re-run tests for the specific cmdlet $results = GenXdev.Coding\Assert-GenXdevTest ` @PSBoundParameters ` -CmdletName $failedCmdletName ` -FromScripts:$isFromScripts ` -TestFailedAction 'Stop' ` -SkipModuleImports # check if tests now pass after AI resolution if ($results.FailedCount -eq 0) { # add successful results to new results collection $results.TestResults | Microsoft.PowerShell.Core\ForEach-Object { $null = $newResults.Add($_) } # exit retry loop for this test $stopped = $true break } else { # update failed test for next retry iteration $ft = $results.Failed[0] } } 2 { # continue with the next failed test $stopped = $true break } } } # update test results if this test was successfully fixed if ($newResults.Failed.Count -eq 0) { # remove the fixed test from failed collection $testResults.Failed = $testResults.Failed | Microsoft.PowerShell.Core\Where-Object { $_ -ne $failedTest } # add new passing results to passed collection $testResults.Passed += $newResults.Passed } } } } # output final test results with success indicators Microsoft.PowerShell.Utility\Write-Output @{ Success = (($testResult.Failed.Count + $scriptAnalyzerResults.Count) -eq 0) ErrorMessage = ("$($testResults.FailedCount) test(s) failed, " + "$($testResults.FailedCount - $testResult.Failed.Count) fixed") TestResults = $testResults AnalyzerResults = $scriptAnalyzerResults } return } # output successful test results when no failures occurred Microsoft.PowerShell.Utility\Write-Output @{ Success = ($scriptAnalyzerResults.Count -eq 0) TestResults = $testResults AnalyzerResults = $scriptAnalyzerResults } } end { Microsoft.PowerShell.Utility\Write-Progress ` -Activity "Analyzing $($nextCmdlet.Name)" ` -Completed ` -Status "Completed" # restore original location after test execution completion Microsoft.PowerShell.Management\Set-Location -LiteralPath $originalLocation $ProgressPreference = $originalProgressPreference } } ################################################################################ |