Private/Measure-Koan.ps1
using namespace System.Management.Automation using namespace System.Management.Automation.Language function Measure-Koan { <# .SYNOPSIS Counts the number of koans in the provided ExternalScriptInfo objects. .DESCRIPTION Traverses the AST of the script blocks taken from the Get-Command output of the koan files to find all of the 'It' blocks in order to count the total number of Pester tests present in the file. When provided with a piped list of ExternalScriptInfo objects, sums the entire collection's 'It' blocks and returns a single integer sum. .PARAMETER KoanInfo Takes an array of ExternalScriptInfo objects (as provided from Get-Command when passed the path to an external .ps1 script file). .EXAMPLE Get-Command .\KoanDirectory\*\*.ps1 | Measure-Koan 422 .NOTES Measure-Koan is NOT designed to handle dynamic -TestCases values. It will handle simple counts of directly attached -TestCases hashtables only if they do not contain variables, pipelines, and other dynamic expressions. Handling dynamic scripts with pipelines and variables is beyond scope and will not be handled; we'd essentially end up reimplementing the PS parser. If it can't be got with .GetSafeValue() we simply aren't working with it. Author: Joel Sallow Module: PSKoans .LINK https://github.com/vexx32/PSKoans #> [CmdletBinding()] [OutputType([int])] param( [Parameter(Position = 0, Mandatory, ValueFromPipeline)] [ValidateNotNull()] [CommandInfo[]] $KoanInfo ) begin { $KoanCount = 0 } process { Write-Verbose "Parsing koan files from [$($KoanInfo.Name -join '], [')]" # Find all Pester 'It' commands $ItCommands = $KoanInfo.ScriptBlock.Ast.FindAll( { param($Item) $Item -is [CommandAst] -and $Item.GetCommandName() -eq 'It' }, $true ) # Find the -TestCases parameters $TestCasesParameters = $ItCommands.CommandElements | Where-Object { $_ -is [CommandParameterAst] -and $_.ParameterName -eq 'TestCases' } if ($TestCasesParameters) { # Get the right CommandElements indexes for their arguments $Indexes = $TestCasesParameters.ForEach{$ItCommands.CommandElements.IndexOf($_) + 1} # Get value of the argument for each -TestCases $ParameterArgument = $ItCommands.CommandElements[$Indexes] try { $TestCaseCount = $ParameterArgument.SafeGetValue().Count } catch { # We aren't parsing complex or variable expressions, so exit here (violently) $ParseException = [ParseException]::new( "Unable to parse unsafe expression in Koan -TestCase syntax.", $_.Exception ) $ErrorRecord = [ErrorRecord]::new( $ParseException, "KoanAstParseError", [ErrorCategory]::ParserError, $ParameterValues.PipelineElements.Extent.Text ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } $KoanCount += $TestCaseCount + $ItCommands.Count - $TestCasesParameters.Count } end { Write-Verbose "Total Koans: $KoanCount" $KoanCount } } |