-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make module compatible with PS2 (#39)
Make the module compatible with Windows PowerShell 2. The problems are anottated in the code so we can remove them when migrating to newer version of PowerShell.
- Loading branch information
Showing
19 changed files
with
464 additions
and
241 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
function New-PSObject ([hashtable]$Property) { | ||
New-Object -Type PSObject -Property $Property | ||
} | ||
|
||
function Invoke-WithContext { | ||
param( | ||
[Parameter(Mandatory = $true )] | ||
[ScriptBlock] $ScriptBlock, | ||
[Parameter(Mandatory = $true)] | ||
[hashtable] $Variables) | ||
|
||
# this functions is a psv2 compatible version of | ||
# ScriptBlock InvokeWithContext that is not available | ||
# in that version of PowerShell | ||
|
||
# this is what the code below does | ||
# which in effect sets the context without detaching the | ||
# scriptblock from the original scope | ||
# & { | ||
# # context | ||
# $a = 10 | ||
# $b = 20 | ||
# # invoking our original scriptblock | ||
# & $sb | ||
# } | ||
|
||
# a similar solution was $SessionState.PSVariable.Set('a', 10) | ||
# but that sets the variable for all "scopes" in the current | ||
# scope so the value persist after the original has run which | ||
# is not correct, | ||
|
||
$scriptBlockWithContext = { | ||
param($context) | ||
|
||
foreach ($pair in $context.Variables.GetEnumerator()) { | ||
New-Variable -Name $pair.Key -Value $pair.Value | ||
} | ||
|
||
# this cleans up the variable from the session | ||
# the subexpression outputs the value of the variable | ||
# and then deletes the variable, so the value is still passed | ||
# but the variable no longer exists when the scriptblock executes | ||
& $($context.ScriptBlock; Remove-Variable -Name 'context' -Scope Local) | ||
} | ||
|
||
$flags = [System.Reflection.BindingFlags]'Instance,NonPublic' | ||
$SessionState = $ScriptBlock.GetType().GetProperty("SessionState", $flags).GetValue($ScriptBlock, $null) | ||
$SessionStateInternal = $SessionState.GetType().GetProperty('Internal', $flags).GetValue($SessionState, $null) | ||
|
||
# attach the original session state to the wrapper scriptblock | ||
# making it invoke in the same scope as $ScriptBlock | ||
$scriptBlockWithContext.GetType().GetProperty('SessionStateInternal', $flags).SetValue($scriptBlockWithContext, $SessionStateInternal, $null) | ||
|
||
& $scriptBlockWithContext @{ ScriptBlock = $ScriptBlock; Variables = $Variables } | ||
} | ||
|
||
function Test-NullOrWhiteSpace ($Value) { | ||
# psv2 compatibility, on newer .net we would simply use | ||
# [string]::isnullorwhitespace | ||
$null -eq $Value -or $Value -match "^\s*$" | ||
} | ||
|
||
function Get-Type ($InputObject) { | ||
try { | ||
$ErrorActionPreference = 'Stop' | ||
# normally this would not ever throw | ||
# but in psv2 when datatable is deserialized then | ||
# [Deserialized.System.Data.DataTable] does not contain | ||
# .GetType() | ||
$InputObject.GetType() | ||
} | ||
catch [Exception] { | ||
return [Object] | ||
} | ||
|
||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
$here = $MyInvocation.MyCommand.Path | Split-Path | ||
Import-Module -Force $here/../../Axiom/src/Axiom.psm1 -DisableNameChecking | ||
. $here/../src/Compatibility.ps1 | ||
|
||
Describe "New-PSObject" { | ||
It "Creates a new object of type PSCustomObject" { | ||
$hashtable = @{ | ||
Name = 'Jakub' | ||
} | ||
|
||
$object = New-PSObject $hashtable | ||
$object | Verify-Type ([PSCustomObject]) | ||
} | ||
|
||
It "Creates a new PSObject with the properties populated" { | ||
$hashtable = @{ | ||
Name = 'Jakub' | ||
} | ||
|
||
$object = New-PSObject $hashtable | ||
$object.Name | Verify-Equal $hashtable.Name | ||
} | ||
} | ||
|
||
Describe "Test-NullOrWhiteSpace" { | ||
It "Returns `$true for `$null or whitespace" -TestCases @( | ||
@{ Value = $null } | ||
@{ Value = " " } | ||
@{ Value = " " } | ||
@{ Value = "`t" } | ||
@{ Value = "`r" } | ||
@{ Value = "`n" } | ||
@{ Value = " `t `r `n" } | ||
) { | ||
param($Value) | ||
Test-NullOrWhiteSpace $Value | Verify-True | ||
} | ||
|
||
It "Returns `$false for '<value>'" -TestCases @( | ||
@{ Value = "a" } | ||
@{ Value = " abc" } | ||
@{ Value = "`tabc`t" } | ||
) { | ||
param ($Value) | ||
Test-NullOrWhiteSpace $Value | Verify-False | ||
} | ||
} | ||
|
||
Describe "Invoke-WithContext" { | ||
BeforeAll { | ||
Get-Module "Test-Module" | Remove-Module | ||
$body = { | ||
$a = "in test module" | ||
$context = "context" | ||
|
||
# all of these are functions returning scriptblocks | ||
# so we can test that they remain bounded to the state of | ||
# this module | ||
function sb1 { { "-$a-" } } | ||
function sb2 { { "-$a- -$b-" } } | ||
function sb3 { { "-$context- -$a-" } } | ||
} | ||
New-Module -Name "Test-Module" -ScriptBlock $body | Import-Module | ||
} | ||
|
||
AfterAll { | ||
Get-Module "Test-Module" | Remove-Module | ||
} | ||
|
||
It "Keeps the scriptblock attached to the original scope" { | ||
# we define variable $a here and in the module, and we must | ||
# resolve $a to the value in the module, not to the local value | ||
# or null | ||
$a = 100 | ||
Invoke-WithContext -ScriptBlock (sb1) -Variables @{} | | ||
Verify-Equal "-in test module-" | ||
} | ||
|
||
It "Injects variable `$b into the scope while keeping `$a attached to the module scope" { | ||
Invoke-WithContext -ScriptBlock (sb2) -Variables @{ b = 'injected' } | | ||
Verify-Equal "-in test module- -injected-" | ||
} | ||
|
||
It "Does not conflict with `$Context variable that is used internally" { | ||
# internally we wrap the call in something like | ||
# & { | ||
# param($context) | ||
# & $context.ScriptBlock | ||
# } | ||
# and we need to make sure that the `$context variable | ||
# will not be seen by the original scriptblock to avoid | ||
# naming conflicts | ||
Invoke-WithContext -ScriptBlock (sb3) -Variables @{} | | ||
Verify-Equal "-context- -in test module-" | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
$typeDefinition = Get-Content $PSScriptRoot/AssertionException.cs | Out-String | ||
$here = $MyInvocation.MyCommand.Path | Split-Path | ||
$typeDefinition = Get-Content $here/AssertionException.cs | Out-String | ||
Add-Type -TypeDefinition $typeDefinition -WarningAction SilentlyContinue |
Oops, something went wrong.