PowerShell/test/powershell/Language/Scripting/ParameterBinding.Tests.ps1
bergmeister ffd39b2853 PSScriptAnalyzer fixes by category (#4261)
- Fix PSScriptAnalyzer warnings of type PSAvoidUsingCmdletAliases for 'ForEach-Object' (alias is '%' or 'foreach')
- Fix PSScriptAnalyzer warnings of type PSAvoidUsingCmdletAliases for 'Where-Object' (alias is '?' or 'where')
- Fix PSScriptAnalyzer warnings of type PSAvoidUsingCmdletAliases for 'Select-Object' (alias is 'select')
- Fix PSScriptAnalyzer warnings of type PSPossibleIncorrectComparisonWithNull. Essentially, $null has to be on the left-hand side when using it for comparison.
- A Test in ParameterBinding.Tests.ps1 needed adapting as this test used to rely on the wrong null comparison
- Replace a subset of tests of kind '($object -eq $null) | Should Be $true' with '$object | Should Be $null'
2017-07-21 21:03:49 -07:00

526 lines
16 KiB
PowerShell
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Describe "Tests for parameter binding" -Tags "CI" {
Context 'Test of Mandatory parameters' {
BeforeAll {
$f = "function get-foo { param([Parameter(mandatory=`$true)] `$a) `$a };"
}
It 'Mandatory parameters used in non-interactive host' {
$rs = [system.management.automation.runspaces.runspacefactory]::CreateRunspace()
$rs.open()
$ps = [System.Management.Automation.PowerShell]::Create()
$ps.Runspace = $rs
try
{
[void] $ps.AddScript($f + "get-foo")
$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'
} finally {
$ps.Dispose()
$rs.Dispose()
}
}
It 'Mandatory parameters used in interactive host' {
$th = New-TestHost
$rs = [system.management.automation.runspaces.runspacefactory]::Createrunspace($th)
$rs.open()
$ps = [System.Management.Automation.PowerShell]::Create()
$ps.Runspace = $rs
try
{
$ps.AddScript($f + "get-foo").invoke()
$prompt = $th.ui.streams.prompt[0]
$prompt | should Not BeNullOrEmpty
$result = $prompt.split(":")
$result[0] | Should Match 'get-foo'
$result[-1] | should be 'a'
} finally {
$rs.Close()
$rs.Dispose()
$ps.Dispose()
}
}
}
It 'Test of positional parameters' {
function get-foo
{
[CmdletBinding()]
param($a)
$a
}
get-foo a | Should Be a
get-foo -a b | Should Be b
}
It 'Positional parameters when only one position specified: position = 1' {
function get-foo
{
param([Parameter(position=1)] $a )
$a
}
get-foo b | Should Be b
}
It 'Positional parameters when only position specified: position = 2' {
function get-foo
{
param([Parameter(position=2)] $a )
$a
}
get-foo b | Should Be b
}
It 'Multiple positional parameters case 1' {
function get-foo
{
param( [Parameter(position=1)] $a,
[Parameter(position=2)] $b )
$a; $b
}
( get-foo c d ) -join ',' | Should Be 'c,d'
( get-foo -a c d ) -join ',' | Should Be 'c,d'
( get-foo -a c -b d ) -join ',' | Should Be 'c,d'
( get-foo -b d c ) -join ',' | Should Be 'c,d'
( get-foo c -b d ) -join ',' | Should Be 'c,d'
}
It 'Multiple positional parameters case 2: the parameters are put in different order?' {
function get-foo
{
# the parameters are purposefully out of order.
param( [Parameter(position=2)] $a,
[Parameter(position=1)] $b )
$a; $b
}
(get-foo c d) -join ',' | Should Be 'd,c'
}
It 'Value from pipeline' {
function get-foo
{
param( [Parameter(valuefrompipeline=$true)] $a )
process
{
if($a % 2 -eq 0)
{
$a
}
}
}
(1..10 | get-foo) -join ',' | Should Be '2,4,6,8,10'
}
It 'Value from pipeline by property name' {
function get-foo
{
param( [Parameter(valuefrompipelinebypropertyname=$true)] $foo )
process
{
if($foo % 2 -eq 0)
{
$foo
}
}
}
$b = 1..10 | select-object @{name='foo'; expression={$_ * 10}} | get-foo
$b -join ',' | Should Be '10,20,30,40,50,60,70,80,90,100'
}
It 'Value from remaining arguments' {
function get-foo
{
param(
[Parameter(position=1)] $a,
[Parameter(valuefromremainingarguments=$true)] $foo
)
$foo
}
( get-foo a b c d ) -join ',' | Should Be 'b,c,d'
( get-foo a b -a c d ) -join ',' | Should Be 'a,b,d'
( get-foo a b -a c -q d ) -join ',' | Should Be 'a,b,-q,d'
}
It 'Multiple parameter sets with Value from remaining arguments' {
function get-foo
{
param( [Parameter(parametersetname='set1',position=1)] $a,
[Parameter(parametersetname='set2',position=1)] $b,
[parameter(valuefromremainingarguments=$true)] $foo )
$foo
}
{ get-foo -a a -b b c d } | ShouldBeErrorId 'AmbiguousParameterSet,get-foo'
( get-foo -a a b c d ) -join ',' | Should Be 'b,c,d'
( get-foo -b b a c d ) -join ',' | Should Be 'a,c,d'
}
It 'Default parameter set with value from remaining arguments case 1' {
function get-foo
{
[CmdletBinding(DefaultParameterSetName="set1")]
param( [Parameter(parametersetname="set1", position=1)] $a,
[Parameter(parametersetname="set2", position=1)] $b,
[parameter(valuefromremainingarguments=$true)] $foo )
$a,$b,$foo
}
$x,$y,$z=get-foo a b c d
$x | Should Be a
$y | Should Be $null
$z -join ',' | Should Be 'b,c,d'
}
It 'Default parameter set with value from remaining argument case 2' {
function get-foo
{
[CmdletBinding(DefaultParameterSetName="set2")]
param( [Parameter(parametersetname="set1", position = 1)] $a,
[Parameter(parametersetname="set2", position = 1)] $b,
[parameter(valuefromremainingarguments=$true)] $foo )
$a,$b,$foo
}
$x,$y,$z=get-foo a b c d
$x | Should Be $null
$y | Should Be 'a'
$z -join ',' | Should Be 'b,c,d'
}
It 'Alias are specified for parameters' {
function get-foo
{
param( [Parameter(mandatory=$true)][alias("foo", "bar")] $a )
$a
}
get-foo -foo b | Should Be 'b'
}
It 'Invoking with script block' {
$foo = . { param([Parameter(position=2)] $a, [Parameter(position=1)]$b); $a; $b} a b
$foo[0] | Should Be b
}
It 'Normal functions' {
function foo ($a, $b) {$b, $a}
( foo a b ) -join ',' | Should Be 'b,a'
}
It 'Null is not Allowed when AllowNull attribute is not set' {
function get-foo
{
param( [Parameter(mandatory=$true)] $a )
$a
}
{ get-foo -a $null } | ShouldBeErrorId 'ParameterArgumentValidationErrorNullNotAllowed,get-foo'
}
It 'Null is allowed when Allownull attribute is set' {
function get-foo
{
param( [Parameter(mandatory=$true)][allownull()] $a )
$a
}
(get-foo -a $null) | Should Be $null
}
It 'Empty string is not allowed AllowEmptyString Attribute is not set' {
function get-foo
{
param( [Parameter(mandatory=$true)][string] $a )
$a
}
{ get-foo -a '' } | ShouldBeErrorID 'ParameterArgumentValidationErrorEmptyStringNotAllowed,get-foo'
}
It 'Empty string is allowed when AllowEmptyString Attribute is set' {
function get-foo
{
param( [Parameter(mandatory=$true)][allowemptystring()][string] $a )
$a
}
get-foo -a '' | Should Be ''
}
It 'Empty collection is not allowed when AllowEmptyCollection it not set' {
function get-foo
{
param( [Parameter(mandatory=$true)][string[]] $a )
$a
}
{ get-foo -a @() } | ShouldBeErrorId 'ParameterArgumentValidationErrorEmptyArrayNotAllowed,get-foo'
}
It 'Empty collection is allowed when allowEmptyCollection is set' {
function get-foo
{
param( [Parameter(mandatory=$true)][allowemptycollection()][string[]] $a )
$a
}
get-foo -a @() | Should Be $null
}
It 'Unspecified non-mandatory bool should not cause exception' {
function get-foo
{
param([Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)] $a,
[System.Boolean] $b)
$a
}
42 | get-foo | Should be 42
}
It 'Parameter binding failure on Parameter1 should not cause parameter binding failure on Length' {
function get-foo
{
param( [Parameter(ValueFromPipeline = $true)] [int] $Parameter1 = 10,
[Parameter(ValueFromPipelineByPropertyName = $true)] [int] $Length = 100 )
process { $Length }
}
'abc' | get-foo | Should Be 3
}
It 'Binding array of string to array of bool should fail (cmdletbinding)' {
function get-foo
{
[cmdletbinding()]
param ([bool[]] $Parameter )
$Parameter
}
{ get-foo 'a','b' } | ShouldBeErrorId 'ParameterArgumentTransformationError,get-foo'
}
It "Binding array of string to array of bool should succeed" {
function get-foo
{
param ([bool[]] $Parameter)
$Parameter
}
$x = get-foo 'a','b'
$x[0] | Should be $true
$x[1] | Should be $true
}
Context 'Default value conversion tests' {
It 'Parameter default value is converted correctly to the proper type when nothing is set on parameter' {
function get-fooa
{
param( [System.Reflection.MemberTypes] $memberTypes = $([Enum]::GetNames("System.Reflection.MemberTypes") -join ",") )
$memberTypes | Should BeOfType System.Reflection.MemberTypes
}
get-fooa
}
It "Parameter default value is converted correctly to the proper type when CmdletBinding is set on param" {
function get-foob
{
[CmdletBinding()]
param( [System.Reflection.MemberTypes] $memberTypes = $([Enum]::GetNames("System.Reflection.MemberTypes") -join ",") )
$memberTypes | Should BeOfType System.Reflection.MemberTypes
}
get-foob
}
It "No default value specified should not cause error when parameter attribute is set on the parameter" {
function get-fooc
{
param( [Parameter()] [System.Reflection.MemberTypes] $memberTypes )
$memberTypes | Should Be $null
}
get-fooc
}
It "No default value specified should not cause error when nothing is set on parameter" {
function get-food
{
param( [System.Reflection.MemberTypes] $memberTypes )
$memberTypes | Should Be $null
}
get-food
}
It "Validation attributes should not run on default values when nothing is set on the parameter" {
function get-fooe
{
param([ValidateRange(1,42)] $p = 55)
$p
}
get-fooe| Should Be 55
}
It "Validation attributes should not run on default values when CmdletBinding is set on the parameter" {
function get-foof
{
[CmdletBinding()]
param([ValidateRange(1,42)] $p = 55)
$p
}
get-foof| Should Be 55
}
It "Validation attributes should not run on default values" {
function get-foog
{
param([ValidateRange(1,42)] $p)
$p
}
{ get-foog } | Should not throw
}
It "Validation attributes should not run on default values when CmdletBinding is set" {
function get-fooh
{
[CmdletBinding()]
param([ValidateRange(1,42)] $p)
$p
}
{ get-fooh } | Should not throw
}
It "ValidateScript can use custom ErrorMessage" {
function get-fooi {
[CmdletBinding()]
param([ValidateScript({$_ -gt 2}, ErrorMessage = "Item '{0}' failed '{1}' validation")] $p)
$p
}
$errMsg = ''
try
{
get-fooi -p 2
}
catch
{
$errMsg = $_.Exception.Message
}
$errMsg | Should Be "Cannot validate argument on parameter 'p'. Item '2' failed '`$_ -gt 2' validation"
}
It "ValidatePattern can use custom ErrorMessage" {
function get-fooj
{
[CmdletBinding()]
param([ValidatePattern("\s+", ErrorMessage = "Item '{0}' failed '{1}' regex")] $p)
$p
}
$errMsg = ''
try
{
get-fooj -p 2
}
catch
{
$errMsg = $_.Exception.Message
}
$errMsg | Should Be "Cannot validate argument on parameter 'p'. Item '2' failed '\s+' regex"
}
It "ValidateSet can use custom ErrorMessage" {
function get-fook
{
param([ValidateSet('A', 'B', 'C', IgnoreCase=$false, ErrorMessage="Item '{0}' is not in '{1}'")] $p)
}
$errMsg = ''
try
{
get-fook -p 2
}
catch
{
$errMsg = $_.Exception.Message
}
$set = 'A','B','C' -join [Globalization.CultureInfo]::CurrentUICulture.TextInfo.ListSeparator
$errMsg | Should Be "Cannot validate argument on parameter 'p'. Item '2' is not in '$set'"
}
}
#known issue 2069
It 'Some conversions should be attempted before trying to encode a collection' -skip:$IsCoreCLR {
try {
$null = [Test.Language.ParameterBinding.MyClass]
}
catch {
add-type -PassThru -TypeDefinition @'
using System.Management.Automation;
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.IO;
namespace Test.Language.ParameterBinding {
public class MyClass : Collection<string>
{
public MyClass() {}
public MyClass(Hashtable h) {}
}
[Cmdlet("Get", "TestCmdlet")]
public class MyCmdlet : PSCmdlet {
[Parameter]
public MyClass MyParameter
{
get { return myParameter; }
set { myParameter = value; }
}
private MyClass myParameter;
protected override void ProcessRecord()
{
WriteObject((myParameter == null) ? "<null>" : "hashtable");
}
}
}
'@ | ForEach-Object {$_.assembly} | Import-module
}
Get-TestCmdlet -MyParameter @{ a = 42 } | Should Be 'hashtable'
}
It 'Parameter pasing is consuming enumerators' {
$a = 1..4
$b = $a.getenumerator()
$null = $b.MoveNext()
$null = $b.current
& { } $b
#The position of the enumerator shouldn't be modified
$b.current |Should Be 1
}
}