diff --git a/test/powershell/Language/Scripting/ActionPreference.Tests.ps1 b/test/powershell/Language/Scripting/ActionPreference.Tests.ps1 new file mode 100644 index 0000000000..93675d2e76 --- /dev/null +++ b/test/powershell/Language/Scripting/ActionPreference.Tests.ps1 @@ -0,0 +1,129 @@ +Describe "Tests for (error, warning, etc) action preference" -Tags "CI" { + BeforeAll { + $orgin = $GLOBAL:errorActionPreference + } + + AfterAll { + if ($GLOBAL:errorActionPreference -ne $orgin) + { + $GLOBAL:errorActionPreference = $orgin + } + } + Context 'Setting ErrorActionPreference to stop prevents user from getting the error exception' { + $err = $null + try + { + get-childitem nosuchfile.nosuchextension -ea stop -ev err + } + catch {} + + It '$err.Count' { $err.Count | Should Be 1 } + It '$err[0] should not be $null' { $err[0] | Should Not Be $null } + It '$err[0].GetType().Name' { $err[0].GetType().Name | Should Be ActionPreferenceStopException } + It '$err[0].ErrorRecord' { $err[0].ErrorRecord | Should not BeNullOrEmpty } + It '$err[0].ErrorRecord.Exception.GetType().Name' { $err[0].ErrorRecord.Exception.GetType().Name | Should Be ItemNotFoundException } + } + + It 'ActionPreference Ignore Works' { + $errorCount = $error.Count + Get-Process -Name asdfasdfsadfsadf -ErrorAction Ignore + + $error.Count | Should Be $errorCount + } + + It 'action preference of Ignore cannot be set as a preference variable' { + try { + $GLOBAL:errorActionPreference = "Ignore" + Get-Process -Name asdfasdfasdf + Throw "Exception expected, execution should not have reached here" + } catch { + $_.CategoryInfo.Reason | Should Be NotSupportedException + } finally { + $GLOBAL:errorActionPreference = $orgin + } + + } + + It 'action preference of Suspend cannot be set as a preference variable' { + try { + $GLOBAL:errorActionPreference = "Suspend" + Get-Process -Name asdfasdfasdf + Throw "Exception expected, execution should not have reached here" + } catch { + $_.CategoryInfo.Reason | Should Be ArgumentTransformationMetadataException + } + finally { + $GLOBAL:errorActionPreference = $orgin + } + } + + It 'enum disambiguation works' { + $errorCount = $error.Count + Get-Process -Name asdfasdfsadfsadf -ErrorAction Ig + + $error.Count | Should Be $errorCount + } + + It 'ErrorAction = Suspend works on Workflow' -Skip:$IsCoreCLR { + . .\TestsOnWinFullOnly.ps1 + Run-TestOnWinFull "ActionPreference:ErrorAction=SuspendOnWorkflow" + } + + It 'ErrorAction = Suspend does not work on functions' { + function MyHelperFunction { + [CmdletBinding()] + param() + "Hello" + } + + try + { + MyHelperFunction -ErrorAction Suspend + Throw "Exception expected, execution should not have reached here" + } catch { + $_.FullyQualifiedErrorId | Should Be "ParameterBindingFailed,MyHelperFunction" + } + } + + It 'ErrorAction = Suspend does not work on cmdlets' { + try + { + Get-Process -ErrorAction Suspend + Throw "Exception expected, execution should not have reached here" + } + catch { + $_.FullyQualifiedErrorId | Should Be "ParameterBindingFailed,Microsoft.PowerShell.Commands.GetProcessCommand" + } + } + + It 'WarningAction = Suspend does not work' { + try + { + Get-Process -WarningAction Suspend + Throw "Exception expected, execution should not have reached here" + } + catch { + $_.FullyQualifiedErrorId | Should Be "ParameterBindingFailed,Microsoft.PowerShell.Commands.GetProcessCommand" + } + } + + #issue 2076 + It 'ErrorAction and WarningAction are the only action preferences do not support suspend' -Pending{ + $params = [System.Management.Automation.Internal.CommonParameters].GetProperties().Name | Select-String Action + + $suspendErrors = $null + $num=0 + + $params | % { + $input=@{'InputObject' = 'Test';$_='Suspend'} + + try { + Write-Output @input + } catch { + $_.FullyQualifiedErrorId | Should Be "ParameterBindingFailed,Microsoft.PowerShell.Commands.WriteOutputCommand" + $num++ + } + } + $num | Should Be 2 + } +} diff --git a/test/powershell/Language/Scripting/CheckRestrictedlanguage.Tests.ps1 b/test/powershell/Language/Scripting/CheckRestrictedlanguage.Tests.ps1 new file mode 100644 index 0000000000..877bb6ffb5 --- /dev/null +++ b/test/powershell/Language/Scripting/CheckRestrictedlanguage.Tests.ps1 @@ -0,0 +1,110 @@ +Describe "Test restricted language check method on scriptblocks" -Tags "CI" { + BeforeAll { + set-strictmode -v 2 + function list { + + $l = [System.Collections.Generic.List[String]]::new() + $args | foreach {$l.Add($_)} + , $l + } + } + AfterAll { + Set-StrictMode -Off + } + + It 'Check basic expressions' { + + {{2+2}.CheckRestrictedLanguage($null, $null, $false) } | Should Not Throw # Succeed with no variables + } + + It 'Check default variables' { + + {{ $PSCulture, $PSUICulture, $true, $false, $null}.CheckRestrictedLanguage($null, $null, $false) } | Should Not Throw + } + + It 'Check default variables' { + + try + { + {2+$a}.CheckRestrictedLanguage($null, $null, $false) + Throw "Exception expected, execution should not have reached here" + } + catch + { + $_.FullyQualifiedErrorId | Should Be 'ParseException' + } + + } + + It 'Check union of default + one allowed variables' { + + { { 2 + $a }.CheckRestrictedLanguage($null, (list a), $false) }| Should Not Throw # succeed + } + + It 'Check union of default + two allowed variables' { + + { { $a + $b }.CheckRestrictedLanguage($null, (list a b), $false) } | Should Not Throw # succeed + } + + It 'Check union of default + allowed variables' { + + { { $PSCulture, $PSUICulture, $true, $false, $null, $a, $b}.CheckRestrictedLanguage($null, (list a b), $false) }| Should Not Throw + } + + It 'Check union of default + one disallowed variables' { + + try + { + { $a + $b + $c }.CheckRestrictedLanguage($null, (list a b), $false) # fail + Throw "Exception expected, execution should not have reached here" + } + catch + { + $_.FullyQualifiedErrorId | Should Be 'ParseException' + } + } + + It 'Check union of default + one allowed variable and but not allow environment variable' { + + try + { + { 2 + $a + $env:foo }.CheckRestrictedLanguage($null, (list a), $false) # fail + Throw "Exception expected, execution should not have reached here" + } + catch + { + $_.FullyQualifiedErrorId | Should Be 'ParseException' + } + } + + It 'Check union of default + one allowed variable name and allow environment variable ' { + + {{ 2 + $a + $env:foo }.CheckRestrictedLanguage($null, (list a), $true)} | Should Not Throw # succeed + } + + It 'Check that wildcard allows env even if the flag is set to false' { + + { { 2 + $a + $b + $c + $env:foo }.CheckRestrictedLanguage($null, (list *), $false)} | Should Not Throw # succeed + } + + It 'Check for restricted commands' { + + try + { + {get-date}.CheckRestrictedLangauge($null, $null, $false) + Throw "Exception expected, execution should not have reached here" + } + catch + { + $_.FullyQualifiedErrorId | Should Be 'MethodNotFound' + } + } + + It 'Check for allowed commands and variables' { + + { { get-process | where name -match $pattern | foreach $prop }.CheckRestrictedLanguage( + (list get-process where foreach), + (list prop pattern) + , $false) }| Should Not Throw + } +} diff --git a/test/powershell/Language/Scripting/CmdletDeclaration.Tests.ps1 b/test/powershell/Language/Scripting/CmdletDeclaration.Tests.ps1 new file mode 100644 index 0000000000..586af98193 --- /dev/null +++ b/test/powershell/Language/Scripting/CmdletDeclaration.Tests.ps1 @@ -0,0 +1,121 @@ +Describe "Cmdlet declaration statement" -Tags "CI" { + $testData = @( + @{ Name = 'Verify non-cmdlet formatted names are allowed'; + Script = ' + function foo + { + [CmdletBinding()] + param() + + $a + }' }, + @{ Name = 'Valid cmdlet names case 1'; + Script = ' + function foo + { + [CmdletBinding()] + param() + + $a + }' }, + @{ Name = 'Valid cmdlet names case 2'; + Script = ' + function get-foo + { + [CmdletBinding()] + param() + + $a + }' }, + @{ Name = 'Valid cmdlet names case 3'; + Script = ' + { + [CmdletBinding()] + param() + + $a + }' }, + @{ + Name ='Using parameter annotation in script cmdlets'; + Script = ' + function get-foo + { + param([Parameter(mandatory=$true)]$a) + $a + }'}, + @{ + Name = 'Cmdlet declaration parameter: should process'; + Script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true)] + param([Parameter(mandatory=$true)]$a) + $a + }' }, + @{ + Name = 'Cmdlet declaration parameter: confirm impact'; + Script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="low")] + param([Parameter(mandatory=$true)]$a) + $a + }'}, + @{ + Name = 'Cmdlet declaration parameter: defaultparametersetname'; + Script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="low", defaultparametersetname="set1")] + param([Parameter(mandatory=$true)]$a) + $a + }'}, + @{ + Name = 'cmdlet declaration within as cmdlet'; + Script = ' + function get-foo { + [CmdletBinding()] + param() + + function get-bar + { + param([Parameter(mandatory=$true)]$a) + $a + } + }'} + @{ + Name = 'cmdlet declaration within scriptblock'; + Script = ' + { + param([Parameter(mandatory=$true)]$a) + $a + }'}, + @{ + Name = 'cmdlet declaration within scriptblock 2'; + Script = ' + { + param([Parameter(mandatory=$true)]$a) + $a + }'}, + @{ + Name = 'cmdlet declaration within scriptblock 3'; + Script = ' + { + [CmdletBinding(SupportsShouldProcess=$true)] + param([Parameter(mandatory=$true)]$a) + $a + }'}) + + + It '' -TestCases $testData { + param($Name, $script) + + $syntaxerrors = $null + + $null = [system.management.automation.psparser]::tokenize($script, [ref] $syntaxerrors) + + #Error should not be reported + $syntaxerrors.Count | Should Be 0 + } +} + diff --git a/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 b/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 new file mode 100644 index 0000000000..352820b198 --- /dev/null +++ b/test/powershell/Language/Scripting/CommonParameters.Tests.ps1 @@ -0,0 +1,373 @@ +Describe "Common parameters support for script cmdlets" -Tags "CI" { + BeforeEach { + $rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace() + $rs.open() + $ps = [System.Management.Automation.PowerShell]::Create() + $ps.Runspace = $rs + } + + AfterEach { + $ps.Dispose() + $rs.Dispose() + } + + Context "Debug" { + BeforeAll { + $script = " + function get-foo + { + [CmdletBinding()] + param() + + write-output 'output foo' + write-debug 'debug foo' + }" + } + + It "Debug get-foo" { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should be "output foo" + $ps.Streams.Debug.Count | Should Be 0 + } + + It 'get-foo -debug' { + $command = 'get-foo -debug' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be "output foo" + $ps.Streams.Debug[0].Message | Should Be "debug foo" + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + } + + Context "verbose" { + BeforeAll { + $script = " + function get-foo + { + [CmdletBinding()] + param() + + write-output 'output foo' + write-verbose 'verbose foo' + }" + } + + It 'get-foo' { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be "output foo" + $ps.streams.verbose.Count | Should Be 0 + } + + It 'get-foo -verbose' { + $command = 'get-foo -verbose' + + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be "output foo" + $ps.Streams.verbose[0].Message | Should Be "verbose foo" + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + } + + Context "erroraction" { + BeforeAll { + $script = " + function get-foo + { + [CmdletBinding()] + param() + + write-error 'error foo' + write-output 'output foo' + }" + } + + It 'erroraction' { + + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be "output foo" + $ps.Streams.error[0].ToString() | Should match "error foo" + } + + It 'erroraction continue' { + + $command = 'get-foo -erroraction Continue' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be "output foo" + $ps.Streams.error[0].ToString() | Should match "error foo" + } + + It 'erroraction SilentlyContinue' { + + $command = 'get-foo -erroraction SilentlyContinue' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be "output foo" + $ps.streams.error.count | Should Be 0 + } + + It 'erroraction Stop' { + + $command = 'get-foo -erroraction Stop' + + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + + try + { + $ps.EndInvoke($asyncResult) + Throw "Exception expected, execution should not have reached here" + } + catch { + $_.FullyQualifiedErrorId | Should Be "ActionPreferenceStopException" + } # Exception: "Command execution stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: error foo" + + + # BUG in runspace api. + #$ps.error.count | Should Be 1 + + $ps.InvocationStateInfo.State | Should Be 'Failed' + } + } + + Context "SupportShouldprocess" { + $script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true)] + param() + + if($pscmdlet.shouldprocess("foo", "foo action")) + { + write-output "foo action" + } + }' + + It 'SupportShouldprocess' { + + $command = 'get-foo' + $ps = [system.management.automation.powershell]::Create() + [void] $ps.AddScript($script + $command) + $ps.RunspacePool = $rp + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be 'foo action' + } + + It 'shouldprocess support -whatif' { + + $command = 'get-foo -whatif' + $ps = [system.management.automation.powershell]::Create() + [void] $ps.AddScript($script + $command) + $ps.RunspacePool = $rp + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + + It 'shouldprocess support -confirm under the non-interactive host' { + + $command = 'get-foo -confirm' + [void] $ps.AddScript($script + $command) + + $asyncResult = $ps.BeginInvoke() + $ps.EndInvoke($asyncResult) + + $ps.Streams.Error.Count | Should Be 1 # the host does not implement it. + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + } + + Context 'confirmimpact support: none' { + BeforeAll { + $script = ' + function get-foo + { + [CmdletBinding(supportsshouldprocess=$true, ConfirmImpact="none")] + param() + + if($pscmdlet.shouldprocess("foo", "foo action")) + { + write-output "foo action" + } + }' + } + + It 'get-foo' { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be 'foo action' + } + + It 'get-foo -confirm' { + $command = 'get-foo -confirm' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be 'foo action' + } + } + + Context 'confirmimpact support: low under the non-interactive host' { + BeforeAll { + $script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="low")] + param() + + if($pscmdlet.shouldprocess("foo", "foo action")) + { + write-output "foo action" + } + }' + } + It 'get-foo' { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be 'foo action' + } + + It 'get-foo -confirm' { + $command = 'get-foo -confirm' + + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $ps.EndInvoke($asyncResult) + + $ps.Streams.Error.Count | Should Be 1 # the host does not implement it. + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + } + + Context 'confirmimpact support: Medium under the non-interactive host' { + BeforeAll { + $script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="medium")] + param() + + if($pscmdlet.shouldprocess("foo", "foo action")) + { + write-output "foo action" + } + }' + } + + It 'get-foo' { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $output = $ps.EndInvoke($asyncResult) + + $output[0] | Should Be 'foo action' + } + + It 'get-foo -confirm' { + $command = 'get-foo -confirm' + [void] $ps.AddScript($script + $command) + + $asyncResult = $ps.BeginInvoke() + $ps.EndInvoke($asyncResult) + + $ps.Streams.Error.Count | Should Be 1 # the host does not implement it. + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + } + + + Context 'confirmimpact support: High under the non-interactive host' { + BeforeAll { + $script = ' + function get-foo + { + [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="high")] + param() + + if($pscmdlet.shouldprocess("foo", "foo action")) + { + write-output "foo action" + } + }' + } + + It 'get-foo' { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $ps.EndInvoke($asyncResult) + + $ps.Streams.Error.Count | Should Be 1 # the host does not implement it. + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + + It 'get-foo -confirm' { + $command = 'get-foo -confirm' + [void] $ps.AddScript($script + $command) + $asyncResult = $ps.BeginInvoke() + $ps.EndInvoke($asyncResult) + + $ps.Streams.Error.Count | Should Be 1 # the host does not implement it. + $ps.InvocationStateInfo.State | Should be 'Completed' + } + } + + Context 'ShouldContinue Support under the non-interactive host' { + BeforeAll { + $script = ' + function get-foo + { + [CmdletBinding()] + param() + + if($pscmdlet.shouldcontinue("foo", "foo action")) + { + write-output "foo action" + } + }' + } + + It 'get-foo' { + $command = 'get-foo' + [void] $ps.AddScript($script + $command) + + $asyncResult = $ps.BeginInvoke() + $ps.EndInvoke($asyncResult) + + $ps.Streams.Error.Count | Should Be 1 # the host does not implement it. + $ps.InvocationStateInfo.State | Should Be 'Completed' + } + } +} \ No newline at end of file diff --git a/test/powershell/Language/Scripting/Delegates.Tests.ps1 b/test/powershell/Language/Scripting/Delegates.Tests.ps1 new file mode 100644 index 0000000000..0b4900d94b --- /dev/null +++ b/test/powershell/Language/Scripting/Delegates.Tests.ps1 @@ -0,0 +1,106 @@ +Describe 'Test for conversion b/w script block and delegate' -Tags "CI" { + BeforeAll { + function lineno + { + $myInvocation.ScriptLineNumber + } + + function Generate-ArgumentTypesAndParameters + { + param([int] $num, [ref] $parameters, [ref]$argumentTypes, [bool]$hasReturn = $false) + + For($j = 1; $j -le $num; $j++) + { + $ran = Get-Random -Minimum 1 -Maximum 3 + $type = [Int32] + switch ($ran) + { + 1 { $type = [Int32]; break} + 2 { $type = [string]; break} + 3 { $type = [Hashtable]; break} + } + + $argumentTypes.Value += $type; + + if((-not $hasReturn) -or ($j -lt $num ) ) { + $parameters.Value += Get-Value($type) + } + } + } + + function Get-Value + { + param([type] $t) + + if ($t -eq [Int32]) { 100 } + elseif($t -eq [string]) { 'abc' } + elseif ($t -eq [Hashtable]) {@{a = 'foo'} } + } + } + + #0 arg, no return + It 'System.Action' { + ([System.Action]{ $script:gl=lineno; $args.Length | Should Be 0 }).Invoke() + ($gl + 1) | Should Be (lineno) + } + # multiple args, no return + For($i = 1; $i -le 8; $i++) + { + $str = 'System.Action`{0}' -f $i + Context $str { + $gt = [object].Assembly.GetType($str) + + $parameters = @() + $argumentTypes=@() + Generate-ArgumentTypesAndParameters $i ([ref] $parameters) ([ref] $argumentTypes) + + $ct = $gt.MakeGenericType($argumentTypes) + + $func = { $script:gl=lineno; $args.Length | Should Be $i } -as $ct + $func.DynamicInvoke($parameters) + It '$gl + 2' { ($gl + 2) | Should Be (lineno) } + } + } + + #0 arg with return value + It 'System.Func[Int32]' { + ([System.Func[Int32]]{ $script:gl=lineno; $args.Length }).Invoke() | Should Be 0 + ($gl + 1) | Should Be (lineno) + } + + It 'System.Func[string]' { + ([System.Func[string]]{ $script:gl=lineno; 'hello' }).Invoke() | Should Be 'hello' + ($gl + 1) | Should Be (lineno) + } + + It 'System.Func[hashtable]' { + (([System.Func[hashtable]]{ $script:gl=lineno; @{a = 'foo' }}).Invoke()).a | Should Be 'foo' + ($gl + 1) | Should Be (lineno) + } + + #multiple args, differnt return type + For($i = 2; $i -le 9; $i++) + { + $str = 'System.Func`{0}' -f $i + Context $str { + $gt = [object].Assembly.GetType($str) + + $parameters = @() + $argumentTypes=@() + Generate-ArgumentTypesAndParameters $i ([ref] $parameters) ([ref] $argumentTypes) $true + $v= Get-Value($argumentTypes[$i-1]) + $ct = $gt.MakeGenericType($argumentTypes) + $func = { $script:gl=lineno; $null = ($args.Length | Should Be ($i-1)); $v } -as $ct + $t = $func.DynamicInvoke($parameters) + It '$gl + 2' { ($gl + 2) | Should Be (lineno) } + if ($argumentTypes[$i-1] -eq [Hashtable] ) + { + It '$t.a' { $t.a | Should Be $v.a } + } + else + { + It '$t' { $t | Should Be $v } + } + } + } +} \ No newline at end of file diff --git a/test/powershell/Language/Scripting/ForeachParallel.Tests.ps1 b/test/powershell/Language/Scripting/ForeachParallel.Tests.ps1 new file mode 100644 index 0000000000..163ed36b8f --- /dev/null +++ b/test/powershell/Language/Scripting/ForeachParallel.Tests.ps1 @@ -0,0 +1,39 @@ +Describe "Parallel foreach syntax" -Tags "CI" { + + Context 'Should be able to retrieve AST of parallel foreach, error in regular case' { + $errors = @() + $ast = [System.Management.Automation.Language.Parser]::ParseInput( + 'foreach -parallel ($foo in $bar) {}', [ref] $null, [ref] $errors) + It '$errors.Count' { $errors.Count | Should Be 1 } + It '$ast.EndBlock.Statements[0].Flags' { $ast.EndBlock.Statements[0].Flags | Should Be 'Parallel' } + } + + It 'Should be able to retrieve AST of parallel foreach, works in JobDefinition case' -Skip:$IsCoreCLR { + . .\TestsOnWinFullOnly.ps1 + Run-TestOnWinFull "ForeachParallel:ASTOfParallelForeachOnWorkflow" + } + + Context 'Supports newlines before and after' { + $errors = @() + $ast = [System.Management.Automation.Language.Parser]::ParseInput( + "foreach `n-parallel `n(`$foo in `$bar) {}", [ref] $null, [ref] $null) + It '$errors.Count' { $errors.Count | Should Be 0 } + It '$ast.EndBlock.Statements[0].Flags' { $ast.EndBlock.Statements[0].Flags | Should Be 'Parallel' } + } + + Context 'Generates an error on invalid parameter' { + $errors = @() + $ast = [System.Management.Automation.Language.Parser]::ParseInput( + 'foreach -bogus ($input in $bar) { }', [ref]$null, [ref]$errors) + It '$errors.Count' { $errors.Count | Should Be 1 } + It '$errors[0].ErrorId' { $errors[0].ErrorId | Should Be InvalidForeachFlag } + } + + Context 'Generate an error on -parallel that is not a workflow' { + $errors = @() + $ast = [System.Management.Automation.Language.Parser]::ParseInput( + 'foreach -parallel ($input in $bar) { }', [ref]$null, [ref]$errors) + It '$errors.Count' { $errors.Count | Should Be 1 } + It '$errors[0].ErrorId' { $errors[0].ErrorId | Should Be ParallelNotSupported } + } +} \ No newline at end of file diff --git a/test/powershell/Language/Scripting/TestsOnWinFullOnly.ps1 b/test/powershell/Language/Scripting/TestsOnWinFullOnly.ps1 new file mode 100644 index 0000000000..b6239dd914 --- /dev/null +++ b/test/powershell/Language/Scripting/TestsOnWinFullOnly.ps1 @@ -0,0 +1,30 @@ +function Run-TestOnWinFull +{ + [CmdletBinding()] + param( [string]$name ) + + switch ($name) + { + "ActionPreference:ErrorAction=SuspendOnWorkflow" { + workflow TestErrorActionSuspend { "Hello" } + + $r = TestErrorActionSuspend -ErrorAction Suspend + + $r | Should Be Hello + break; } + + "ForeachParallel:ASTOfParallelForeachOnWorkflow" { + Import-Module PSWorkflow + $errors = @() + $ast = [System.Management.Automation.Language.Parser]::ParseInput( + 'workflow foo { foreach -parallel ($foo in $bar) {} }', [ref] $null, [ref] $errors) + $errors.Count | Should Be 0 + $ast.EndBlock.Statements[0].Body.EndBlock.Statements[0].Flags | Should Be 'Parallel' + break; + } + default { + #do nothing + } + + } +} \ No newline at end of file