diff --git a/test/powershell/Language/Scripting/HashtableToPSCustomObjectConversion.Tests.ps1 b/test/powershell/Language/Scripting/HashtableToPSCustomObjectConversion.Tests.ps1 new file mode 100644 index 00000000000..2832fe2fa3b --- /dev/null +++ b/test/powershell/Language/Scripting/HashtableToPSCustomObjectConversion.Tests.ps1 @@ -0,0 +1,133 @@ +Describe "Tests for hashtable to PSCustomObject conversion" -Tags "CI" { + BeforeAll { + class SampleClass5 { + [int]$a + [int]$b + SampleClass5([int]$x) { $this.a = $x } + SampleClass5([hashtable]$h) { $this.a = 100; $this.b = 100 } + } + } + + $testdata = @( + @{ Name = 'New-Object cmdlet should accept empty hashtable or $null as Property argument'; + Cmd = "new-object psobject -property `$null"; + ExpectedType = 'System.Management.automation.psobject' + }, + @{ Name = 'Hashtable conversion to PSCustomObject succeeds (Insertion Order is not retained)'; + Cmd = "[pscustomobject][hashtable]`@{one=1;two=2}"; + ExpectedType = 'System.Management.automation.psobject' + }, + @{ Name = 'Hashtable(Stored in a variable) conversion to PSCustomObject succeeds (Insertion Order is not retained)'; + Cmd = "`$ht = @{one=1;two=2};[pscustomobject]`$ht"; + ExpectedType = 'System.Management.automation.psobject' + } + ) + + It 'Type Validation: ' -TestCases:$testdata { + param ($Name, $Cmd, $ExpectedType) + Invoke-expression $Cmd -OutVariable a + $a = Get-Variable -Name a -ValueOnly + $a | should BeOfType $ExpectedType + } + + It 'Hashtable conversion to PSCustomObject retains insertion order of hashtable keys when passed a hashliteral' { + + $x = [pscustomobject]@{one=1;two=2} + $x | should BeOfType "System.Management.automation.psobject" + + $p = 0 + # Checks if the first property is One + $x.psobject.Properties | foreach-object ` + { + if ($p -eq 0) + { + $p++; + $_.Name | Should Be 'one' + } + } + } + + It 'Conversion of Ordered hashtable to PSCustomObject should succeed' { + + $x = [pscustomobject][ordered]@{one=1;two=2} + $x | should BeOfType "System.Management.automation.psobject" + + $p = 0 + # Checks if the first property is One + $x.psobject.Properties | foreach-object ` + { + if ($p -eq 0) + { + $p++; + $_.Name | Should Be 'one' + } + } + } + + $testdata1 = @( + @{ Name = 'Creating an object of an existing type from hashtable should throw error when setting non-existent properties'; + Cmd = "[System.MAnagement.Automation.Host.Coordinates]`@{blah=10;Y=5 }"; + ErrorID = 'ObjectCreationError'; + InnerException = $true + }, + @{ Name = 'Creating an object of an existing type from hashtable should throw error when setting incompatible values for properties'; + Cmd = "[System.MAnagement.Automation.Host.Coordinates]`@{X='foo';Y=5}"; + ErrorID = 'ObjectCreationError'; + InnerException = $true + }, + @{ Name = 'Conversion from PSCustomObject to hashtable should fail'; + Cmd = "[hashtable][pscustomobject]`@{one=1;two=2}"; + ErrorID ='InvalidCastConstructorException'; + InnerException = $true + }, + @{ + Name = 'New-Object cmdlet should throw terminating errors when user specifies a non-existent property or tries to assign incompatible values'; + Cmd = "New-Object -TypeName System.MAnagement.Automation.Host.Coordinates -Property `@{xx=10;y=5}"; + ErrorID ='InvalidOperationException,Microsoft.PowerShell.Commands.NewObjectCommand' + } + ) + + It '' -TestCases:$testData1 { + param ($Name, $Cmd, $ErrorID, $InnerException) + try + { + Invoke-Expression $Cmd + Throw "Exception expected, execution should not have reached here" + } catch { + + if($InnerException) + { + $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should Be $ErrorID + } + else { + $_.FullyQualifiedErrorId | Should Be $ErrorID + } + } + } + + + It 'Creating an object of an existing type from hashtable should succeed' { + $result = [System.Management.Automation.Host.Coordinates]@{X=10;Y=33} + $result.X | should be 10 + } + + It 'Creating an object of an existing type from hashtable should call the constructor taking a hashtable if such a constructor exists in the type' { + + $x = [SampleClass5]@{a=10;b=5} + $x.a | Should Be '100' + } + + It 'Add a new type name to PSTypeNames property' { + + $obj = [PSCustomObject] @{pstypename = 'Mytype'} + $obj.PSTypeNames[0] | Should Be 'Mytype' + } + + It 'Add an existing type name to PSTypeNames property' { + + $obj = [PSCustomObject] @{pstypename = 'System.Object'} + $obj.PSTypeNames.Count | Should Be 3 + $obj.PSTypeNames[0] | Should Be 'System.Object' + } +} + diff --git a/test/powershell/Language/Scripting/OutErrorVariable.Tests.ps1 b/test/powershell/Language/Scripting/OutErrorVariable.Tests.ps1 new file mode 100644 index 00000000000..f85291e8b29 --- /dev/null +++ b/test/powershell/Language/Scripting/OutErrorVariable.Tests.ps1 @@ -0,0 +1,386 @@ +Describe "Tests OutVariable only" -Tags "CI" { + BeforeAll { + + function get-foo1 + { + [CmdletBinding()] + param() + + "foo" + } + + function get-foo2 + { + [CmdletBinding()] + param() + + $pscmdlet.writeobject("foo") + } + + function get-bar + { + [CmdletBinding()] + param() + + "bar" + get-foo1 -outVariable script:a + } + } + + $testdata = @( + @{ Name = 'Updating OutVariable Case 1: pipe string'; + Command = "get-foo1"; + OutVariable = 'a'; + Expected = 'foo' + }, + @{ Name = 'Updating OutVariable Case 2: $pscmdlet.writeobject'; + Command = "get-foo2"; + OutVariable = 'a'; + Expected = 'foo' + }, + @{ Name = 'Appending OutVariable Case 1: pipe string'; + Command = "get-foo1"; + OutVariable = 'a'; + PreSet = 'a','b'; + Expected = @("a", "b", "foo") + }, + @{ Name = 'Appending OutVariable Case 2: $pscmdlet.writeobject'; + Command = "get-foo2"; + OutVariable = 'a'; + PreSet = 'a','b'; + Expected = @("a", "b", "foo") + } + ) + + It 'Test: ' -TestCases $testdata { + param ( $Name, $Command, $OutVariable, $PreSet, $Expected ) + if($PreSet -ne $null) + { + Set-Variable -Name $OutVariable -Value $PreSet + & $Command -OutVariable +$OutVariable > $null + } + else + { + & $Command -OutVariable $OutVariable > $null + } + $a = Get-Variable -ValueOnly $OutVariable + $a | Should Be $Expected + } + + It 'Nested OutVariable' { + + get-bar -outVariable b > $null + $script:a | Should Be 'foo' + $b | Should Be @("bar", "foo") + } +} + +Describe "Test ErrorVariable only" -Tags "CI" { + BeforeAll { + function get-foo1 + { + [CmdletBinding()] + param() + + write-error "foo" + } + + function get-foo2 + { + [CmdletBinding()] + param() + + $pscmdlet.WriteError($script:foo[0]) + } + + function get-bar + { + [CmdletBinding()] + param() + + write-error "bar" + get-foo1 -errorVariable script:a + } + } + + $testdata1 = @( + @{ Name = 'Updating ErrorVariable Case 1: write-error'; + Command = "get-foo1"; + ErrorVariable = 'a'; + Expected = 'foo' + }, + @{ Name = 'Updating ErrorVariable Case 2: $pscmdlet.WriteError'; + Command = "get-foo1"; + ErrorVariable = 'a'; + Expected = 'foo' + }, + @{ Name = 'Appending ErrorVariable Case 1: pipe string'; + Command = "get-foo1"; + ErrorVariable = 'a'; + PreSet = @('a','b'); + Expected = @("a", "b", "foo") + } + ) + + It '' -TestCases $testdata1 { + param ( $Name, $Command, $ErrorVariable, $PreSet, $Expected ) + if($PreSet -ne $null) + { + Set-Variable -Name $ErrorVariable -Value $PreSet + & $Command -ErrorVariable +$ErrorVariable 2> $null + } + else + { + & $Command -ErrorVariable $ErrorVariable 2> $null + + } + $a = (Get-Variable -ValueOnly $ErrorVariable) | % {$_.ToString()} + $a | should be $Expected + } + + It 'Appending ErrorVariable Case 2: $pscmdlet.writeerror' { + write-error "foo" -errorVariable script:foo 2> $null + $a = 'a','b' + + get-foo2 -errorVariable +a 2> $null + + $a.count | Should Be 3 + $a| % {$_.ToString()} | Should Be @('a', 'b', 'foo') + } + + It 'Nested ErrorVariable' { + + get-bar -errorVariable b 2> $null + + $script:a | Should be 'foo' + $b | Should be @("bar","foo") + } + + It 'Nested ErrorVariable with redirection' { + + get-bar -errorVariable b 2>&1 > $null + + $script:a | Should be 'foo' + $b | Should be @("bar", "foo") + } + +} + +Describe "Update both OutVariable and ErrorVariable" -Tags "CI" { + BeforeAll { + + function get-foo + { + [CmdletBinding()] + param() + + write-output "foo-output" + write-error "foo-error" + } + + function get-foo1 + { + [CmdletBinding()] + param() + + write-error "foo" + } + + function get-foo2 + { + [CmdletBinding()] + param() + + $pscmdlet.WriteError($script:foo[0]) + } + + function get-bar + { + [CmdletBinding()] + param() + + write-error "bar" + get-foo1 -errorVariable script:a + } + + function get-foo3 + { + [CmdletBinding()] + param() + + "foo-output-0" + write-output "foo-output-1" + write-error "foo-error" + } + + function get-bar2 + { + [CmdletBinding()] + param() + + "bar-output-0" + write-output "bar-output-1" + write-error "bar-error" + get-foo3 -OutVariable script:foo_out -errorVariable script:foo_err + } + } + + It 'Update OutVariable and ErrorVariable' { + + get-foo3 -OutVariable out -errorVariable err 2> $null > $null + + $out | Should be @("foo-output-0", "foo-output-1") + $err | Should be "foo-error" + } + + It 'Update OutVariable and ErrorVariable' { + + get-bar2 -OutVariable script:bar_out -errorVariable script:bar_err 2> $null > $null + + $foo_out | Should be @("foo-output-0", "foo-output-1") + $foo_err | Should be 'foo-error' + + $bar_out | Should be @("bar-output-0", "bar-output-1", "foo-output-0", "foo-output-1") + $bar_err | Should be @("bar-error", "foo-error") + } + + It 'Verify that exceptions are added to the ErrorVariable' { + function get-foo4 + { + [CmdletBinding()] + param() + + write-error "foo-error" + + try + { + throw "foo-exception" + } + catch + {} + } + + get-foo4 -errorVariable err 2> $null + + $err | Should be @("foo-error", "foo-exception") + } + + It 'Error variable in multi-command pipeline' { + function get-foo5 + { + [CmdletBinding()] + param([Parameter(ValueFromPipeline = $true)][string] $foo) + + process + { + write-output $foo + write-error $foo + } + } + + (get-foo5 "foo-message" -ev foo_err1 -ov foo_out1 | get-foo5 -ev foo_err2 -ov foo_out2 | get-foo5 -ev foo_err3 -ov foo_out3) 2>&1 > $null + + $foo_out1 | Should be "foo-message" + $foo_out2 | Should be "foo-message" + $foo_out3 | Should be "foo-message" + $foo_err1 | Should be "foo-message" + $foo_err2 | Should be "foo-message" + $foo_err3 | Should be "foo-message" + } + + Context 'Error variable in multi-command pipeline (with native cmdlet)' { + + (get-foo -ev foo_err | get-item -ev get_item_err ) 2>&1 > $null + + $foo_err | Should Be "foo-error" + + It '$get_item_err.count' { $get_item_err.count | Should Be 1 } + It '$get_item_err[0].exception' { $get_item_err[0].exception.GetType() | Should Be 'System.Management.Automation.ItemNotFoundException' } + } + + It 'Multi-command pipeline with nested commands' { + + function get-bar3 + { + [CmdletBinding()] + param([Parameter(ValueFromPipeline = $true)][string] $i) + + write-error 'bar-error' + write-output 'bar-output' + get-foo + } + + (get-foo -errorVariable foo_err | get-bar3 -errorVariable bar_err) 2>&1 > $null + + $foo_err | Should be 'foo-error' + $bar_err | Should be @("bar-error", "foo-error") + } + + It 'multi-command pipeline with nested commands' { + + function get-foo6 + { + [CmdletBinding()] + param([Parameter(ValueFromPipeline = $true)][string] $i) + + write-error "foo-error" + write-output $i + } + + function get-bar4 + { + [CmdletBinding()] + param([Parameter(ValueFromPipeline = $true)][string] $i) + + write-error "bar-error" + get-foo6 "foo-output" -errorVariable script:foo_err1 | get-foo6 -errorVariable script:foo_err2 + } + + get-bar4 -errorVariable script:bar_err 2>&1 > $null + + $script:foo_err1 | Should be "foo-error" + $script:foo_err2 | Should be "foo-error" + $script:bar_err | Should be @("bar-error", "foo-error") + } + + It 'Nested output variables' { + function get-foo7 + { + [CmdletBinding()] + param([Parameter(ValueFromPipeline = $true)][string] $output) + + $output + write-error "foo-error" + } + + function get-bar5 + { + [CmdletBinding()] + param() + + "bar-output" + write-error "bar-error" + get-foo7 "foo-output" -ev script:foo_err1 -ov script:foo_out1 | get-foo7 -ev script:foo_err2 -ov script:foo_out2 + get-foo7 "foo-output" -ev script:foo_err3 -ov script:foo_out3 | get-foo7 -ev script:foo_err4 -ov script:foo_out4 + } + + + get-bar5 -ev script:bar_err -ov script:bar_out 2>&1 > $null + + $script:foo_out1 | Should be "foo-output" + $script:foo_err1 | Should be "foo-error" + + $script:foo_out2 | Should be "foo-output" + $script:foo_err2 | Should be "foo-error" + + $script:foo_out3 | Should be "foo-output" + $script:foo_err3 | Should be "foo-error" + + $script:foo_out4 | Should be "foo-output" + $script:foo_err4 | Should be "foo-error" + + $script:bar_out | Should be @("bar-output", "foo-output", "foo-output") + $script:bar_err | Should be @("bar-error", "foo-error", "foo-error") + } +} +