private/ASTFunctions.ps1
Function Get-ASTFromInput { [CmdletBinding()] param( [Parameter(Mandatory)]$Content ) $ast = [System.Management.Automation.Language.Parser]::ParseInput($Content,[ref]$null,[ref]$Null) return $ast } Function Get-TestNameAndTestBlock { [OutputType([String])] param( [Parameter()] [String]$Content ) $ast = Get-ASTFromInput -Content $Content $commandAST = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst]}, $true) $output = @() # fetch all the Describe blocks using AST $describeASTs = $commandAST | Where-Object -FilterScript {$PSItem.GetCommandName() -eq 'Describe'} if ($describeASTs) { # iterate over each Describe block, this means that PSRemotely allows usage of multiple Describe # block within a Node block. foreach ($describeAST in $describeASTs) { $ScriptBlock = [scriptblock]::create("$($describeAST.Extent.Text)") #$TestNameElement = $describeAST.CommandElements | Select-Object -First 2 | Where-Object -FilterScript {$PSitem.Value -ne 'Describe'} $ParametersPassedToDescribe = Get-ParametersPassedToDSLKeyword -FunctionInfo $(Get-Command -Module Pester -Name Describe) -ScriptBlock $ScriptBlock # since there is a limitation while generating parameters from the proxy command # we need to explicitly check that the name and fixture are not empty here if (-not $ParametersPassedToDescribe['name'] -or (-not $ParametersPassedToDescribe['Fixture'])) { throw 'Name or Fixture missing in the Describe block' } $output += @{ $ParametersPassedToDescribe['Name'] = $($describeAST.Extent.Text) } } # end foreach block Write-Output -InputObject $output } else { throw 'Describe block not found in the Test Body.' } } Function Get-ParametersPassedToDSLKeyword { <# This function is a magic function. Specify it a module's DSL keyword function metadata along with the actual usage of the DSL and it will return the PSBoundParameters being passed to the original DSL keyword. This was written in order to determine the test names of the Describe block wrapped inside PSRemotely DSL. Since these test names are later used while dropping individual .Tests.ps1 files on the PSRemotely node(s). #> [cmdletbinding()] param( # Supply the script info object, output of Get-Command -Name <DeploymentScript>.ps1 [Parameter(Mandatory)] [System.Management.Automation.FunctionInfo]$FunctionInfo, [Parameter(Mandatory)] [ScriptBlock]$ScriptBlock ) TRY { $Metadata = [System.Management.Automation.CommandMetadata]::New($FunctionInfo) $CmdletBinding = [System.Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($Metadata) $Parameters = [System.Management.Automation.ProxyCommand]::GetParamBlock($Metadata) # bad formatting due to usage of here-string $FunctionBody = @" $CmdletBinding param( $Parameters ) `$returnHashtable = `$PSBoundParameters `$returnHashtable "@ $DummyFunction = [scriptblock]::Create($FunctionBody) $Null = New-Item -Path Function:\ -Name pSRemotelyDescribeOverride -Value $DummyFunction -Force # create a temporary override for the Pester's Describe keyword $null = New-Alias -Name Describe -Value pSRemotelyDescribeOverride -Force # Now invoke the scriptblock $ParametersHash = & $ScriptBlock Write-Output -InputObject $ParametersHash } CATCH { Write-Warning -Message "$($PSItem.Exception)" $PSCmdlet.ThrowTerminatingError($PSItem) } FINALLY { # Clean up the alias Remove-Item -Path Alias:\Describe -Force -ErrorAction SilentlyContinue } } |