Skip to content

Add -DefaultValueType to Should -HaveParameter#2898

Draft
nohwnd wants to merge 4 commits into
mainfrom
nohwnd-have-parameter-default-value-type
Draft

Add -DefaultValueType to Should -HaveParameter#2898
nohwnd wants to merge 4 commits into
mainfrom
nohwnd-have-parameter-default-value-type

Conversation

@nohwnd

@nohwnd nohwnd commented Jul 17, 2026

Copy link
Copy Markdown
Member

Fix #1888

Adds -DefaultValueType to both Should -HaveParameter and the assert-style Should-HaveParameter.

The issue wants to tell an expression default apart from a string literal that has the same -DefaultValue text. The catch is that the two are the same type: (Get-DefaultPath) returns a path string and '(Get-DefaultPath)' is a string, so a type alone cannot separate them. The real difference is that one is a computed expression and the other is a literal.

So -DefaultValueType takes a real .NET type, given as a [type] or a type name the same way -Type is given, matched against the type of a literal default. For a computed default whose type is not known until it runs, you pass the special value Expression:

function Connect-Thing {
    param(
        [string] $Url      = (Get-DefaultUrl),    # expression, evaluated at call time
        [string] $Fallback = '(Get-DefaultUrl)',  # literal string that looks identical
        [int]    $Retries  = 3,
        [bool]   $Force    = $false
    )
}

$cmd = Get-Command Connect-Thing
$cmd | Should -HaveParameter Retries -DefaultValueType ([int])       # or -DefaultValueType int
$cmd | Should -HaveParameter Force   -DefaultValueType ([bool])
$cmd | Should -HaveParameter Fallback -DefaultValueType String       # literal string

# The #1888 distinction, same -DefaultValue string, different kind of default:
$cmd | Should -HaveParameter Url      -DefaultValue '(Get-DefaultUrl)' -DefaultValueType Expression
$cmd | Should -HaveParameter Fallback -DefaultValue '(Get-DefaultUrl)' -DefaultValueType String

Notes:

  • The type can be a [type] (([bool])) or a type name string (bool, int, string, datetime), same as -Type. An unknown type name throws, and points you at -DefaultValueType Expression.
  • Expression covers any computed default whose type is not statically known, e.g. (Get-Date), [datetime]::Now, $someVariable. You cannot assert a concrete type for those, because the type is only known once the code runs.
  • $true/$false are [bool], a number is [int]/[double], { ... } is [scriptblock], @{ } is [hashtable]. A $null default has no type. An interpolated string like "$x bar" is [string].
  • Failure messages read as, for example, the default value to be of type [System.Int32], but the default value was of type [System.String], or the default value to be an expression, but the default value was of type [System.String].

HaveParameter.ps1 and Should-HaveParameter.ps1 plus tests for both. All existing -HaveParameter behavior is unchanged. test.ps1 for the affected files: 202 passed, no new analyzer findings.

Surface the parameter default value's expression kind (the AST node type of
the default value) so assertions can distinguish an expression default like
$Path = (Get-DefaultPath) from a string-literal default like
$Path = '(Get-DefaultPath)', which share the same -DefaultValue string.

The new -DefaultValueType parameter is added to both the legacy
Should -HaveParameter operator and the assert-style Should-HaveParameter, and
is matched case-insensitively with an optional trailing 'Ast'.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@nohwnd nohwnd added this to the 6.1.0 milestone Jul 17, 2026
@nohwnd
nohwnd marked this pull request as draft July 17, 2026 21:01
@nohwnd

nohwnd commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

doubt that people want to write StringConstantExpressionAst as the expected type of the parameter. need to iterate

nohwnd and others added 3 commits July 18, 2026 22:17
The first version required the raw AST node type, like ParenExpressionAst
or StringConstantExpressionAst, which you cannot know without reading the
PowerShell parser internals. Use a ValidateSet of friendly kinds instead:
String, InterpolatedString, Number, Variable, Expression, ScriptBlock,
Array, Hashtable, and map each to the AST type(s) internally.

This gives tab completion on Should-HaveParameter and a clear error that
lists the valid kinds when you pass something wrong, instead of a confusing
assertion failure. Failure messages show the friendly kind on both sides
now. $true, $false and $null are Variable, and the help says so.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
$true is Boolean now, not Variable. A default has a real type when the
parser can type it statically, so report that: Boolean, Null, Number,
String, ScriptBlock, Array, Hashtable. A computed default like (Get-Date)
or [datetime]::Now has no static type, PowerShell reports it as
System.Object, so it stays Expression, which is also what tells it apart
from a literal string default. Interpolated strings are String, a bare
$var is Expression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The two things #1888 wants to tell apart, (Get-DefaultPath) and
'(Get-DefaultPath)', are the same type, so a type alone cannot separate
them. The real difference is that one is a computed expression and one is a
literal.

So -DefaultValueType now takes a real .NET type, as a [type] or a type name
the same way -Type does, matched against the type of a literal default
($Force = $false is [bool], $Retries = 3 is [int]). For a computed default
like (Get-Date) whose type is not known until it runs, pass the special
value Expression. Expression vs a concrete type is what distinguishes the
two cases from the issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Should -HaveParameter should check DefaultParameterType

1 participant