Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make InModuleScope-parameters available as variables in scriptblock #1957

Merged
merged 8 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 41 additions & 19 deletions src/functions/InModuleScope.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,48 @@
)

$module = Get-ScriptModule -ModuleName $ModuleName -ErrorAction Stop
$sessionState = Set-SessionStateHint -PassThru -Hint "Module - $($module.Name)" -SessionState $module.SessionState

# TODO: could this simply be $PSCmdlet.SessionState? Because the original scope we are moving from
# is the scope in which this command is running, right?
# $originalState = $Pester.SessionState
# $originalScriptBlockScope = Get-ScriptBlockScope -ScriptBlock $ScriptBlock

# try {
# $sessionState = Set-SessionStateHint -PassThru -Hint "Module - $($module.Name)" -SessionState $module.SessionState
# $Pester.SessionState = $sessionState
# Set-ScriptBlockScope -ScriptBlock $ScriptBlock -SessionState $sessionState

# do {
# Write-ScriptBlockInvocationHint -Hint "InModuleScope" -ScriptBlock $ScriptBlock
& $module $ScriptBlock @Parameters @ArgumentList
# } until ($true)
# }
# finally {
# $Pester.SessionState = $originalState
# Set-ScriptBlockScope -ScriptBlock $ScriptBlock -SessionStateInternal $originalScriptBlockScope
# }
$wrapper = {
param (
[Parameter(Mandatory = $true)]
[scriptblock]
${Script Block},
fflaten marked this conversation as resolved.
Show resolved Hide resolved

[hashtable]
$___Parameters___ = @{ },

[object[]]
$___ArgumentList___ = @(),

[System.Management.Automation.SessionState]
${Session State},

${Set Dynamic Parameter Variable}
)

# This script block is used to create variables for provided parameters that
# the real scriptblock can inherit. Makes defining a param-block optional.

& ${Set Dynamic Parameter Variable} -SessionState ${Session State} -Parameters $___Parameters___

# define this in the current scope to be used instead of $PSBoundParameter if needed
# $PesterBoundParameters = if ($null -ne $___Parameters___) { $___Parameters___ } else { @{} }
& ${Script Block} @___Parameters___ @___ArgumentList___
fflaten marked this conversation as resolved.
Show resolved Hide resolved
}

Set-ScriptBlockScope -ScriptBlock $ScriptBlock -SessionState $sessionState
Set-ScriptBlockScope -ScriptBlock $wrapper -SessionState $sessionState
$splat = @{
fflaten marked this conversation as resolved.
Show resolved Hide resolved
'Script Block' = $ScriptBlock
'___ArgumentList___' = $ArgumentList
'___Parameters___' = $Parameters
'Session State' = $sessionState
'Set Dynamic Parameter Variable' = $SafeCommands['Set-DynamicParameterVariable']
fflaten marked this conversation as resolved.
Show resolved Hide resolved
}

Write-ScriptBlockInvocationHint -Hint "InModuleScope" -ScriptBlock $ScriptBlock
fflaten marked this conversation as resolved.
Show resolved Hide resolved
& $wrapper @splat
}

function Get-ScriptModule {
Expand Down
51 changes: 45 additions & 6 deletions tst/functions/InModuleScope.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ Describe "Get-ScriptModule behavior" {
}

Describe 'InModuleScope parameter binding' {
# do not put this into BeforeAll this needs to be imported before calling InModuleScope
# that is below, because it requires the module to be loaded

Get-Module TestModule2 | Remove-Module
New-Module -Name TestModule2 { } | Import-Module -Force
BeforeAll {
Get-Module TestModule2 | Remove-Module
New-Module -Name TestModule2 { } | Import-Module -Force
}

It 'Works with parameters while using advanced function/script' {
# https://github.com/pester/Pester/issues/1809
Expand Down Expand Up @@ -134,9 +134,48 @@ Describe 'InModuleScope parameter binding' {
InModuleScope -ModuleName TestModule2 -Parameters $inModuleScopeParameters -ScriptBlock $sb -ArgumentList $myArgs | Should -Be @($inModuleScopeParameters.SomeParam, $myArgs.Count)
}

It 'Automatically imports parameters as variables in module scope' {
# https://github.com/pester/Pester/issues/1603
$inModuleScopeParameters = @{
SomeParam2 = 'MyValue'
}

$sb = {
"$SomeParam2"
}

$sb2 = {
# Should return nothing. Making sure dynamic variable isn't persisted in module state.
"$SomeParam2"
}

InModuleScope -ModuleName TestModule2 -ScriptBlock $sb -Parameters $inModuleScopeParameters | Should -Be $inModuleScopeParameters.SomeParam2
InModuleScope -ModuleName TestModule2 -ScriptBlock $sb2 | Should -BeNullOrEmpty
}

AfterAll {
Remove-Module TestModule2 -Force
}
}

Describe "Using variables within module scope" {
BeforeAll {
Get-Module TestModule2 | Remove-Module
New-Module -Name TestModule2 { } | Import-Module -Force
}

It 'Only script-scoped variables should persist across InModuleScope calls' {
$setup = {
$script:myVar = 'bar'
$myVar2 = 'bar'
}
InModuleScope -ModuleName TestModule2 -ScriptBlock $setup

InModuleScope -ModuleName TestModule2 -ScriptBlock { $script:myVar } | Should -Be 'bar'
InModuleScope -ModuleName TestModule2 -ScriptBlock { $myVar2 } | Should -BeNullOrEmpty
}

AfterAll {
# keep this in AfterAll so we remove the module after tests are invoked
# and not while the tests are discovered
Remove-Module TestModule2 -Force
}
}