Tests/GenXdev.Coding.PowerShell.Modules/Get-CmdletMetaData.Tests.ps1
|
############################################################################### # Unit tests for Get-CmdletMetaData # Tests per-cmdlet metadata retrieval for C# and .ps1 cmdlets ############################################################################### Pester\Describe 'Get-CmdletMetaData — C# cmdlet (Find-Item)' { Pester\It 'returns a hashtable with all expected top-level keys' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $meta | Pester\Should -Not -BeNullOrEmpty $meta -is [System.Collections.Hashtable] | Pester\Should -Be $true $meta.ContainsKey('Definition') | Pester\Should -Be $true $meta.ContainsKey('Synopsis') | Pester\Should -Be $true $meta.ContainsKey('Description') | Pester\Should -Be $true $meta.ContainsKey('Examples') | Pester\Should -Be $true $meta.ContainsKey('Aliases') | Pester\Should -Be $true $meta.ContainsKey('Parameters') | Pester\Should -Be $true $meta.ContainsKey('OutputType') | Pester\Should -Be $true } Pester\It 'detects cmdlet-level aliases' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $meta.Aliases | Pester\Should -Not -BeNullOrEmpty -Because 'Find-Item has [Alias("l")]' $meta.Aliases | Pester\Should -Contain 'l' } Pester\It 'returns correct Synopsis from [Description] attribute' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $meta.Synopsis | Pester\Should -Not -BeNullOrEmpty $meta.Synopsis | Pester\Should -BeLike '*Search for files*' } Pester\It 'returns correct Description from [Description] attribute' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $meta.Description | Pester\Should -Not -BeNullOrEmpty $meta.Description | Pester\Should -BeLike '*Fast multi-threaded search*' } Pester\It 'returns Examples from [Description] attribute' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $meta.Examples | Pester\Should -Not -BeNullOrEmpty $meta.Examples.Count | Pester\Should -BeGreaterThan 0 } Pester\It 'returns empty OutputType when no [OutputType] attribute on C# class' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' # Find-Item has no [OutputType] attribute on the C# class $meta.OutputType.Count | Pester\Should -Be 0 } Pester\It 'extracts all parameter objects' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $meta.Parameters | Pester\Should -Not -BeNullOrEmpty $meta.Parameters.Count | Pester\Should -BeGreaterThan 5 } Pester\It 'includes ParameterType on every parameter' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' foreach ($p in $meta.Parameters) { $p.PSObject.Properties.Name | Pester\Should -Contain 'ParameterType' $p.ParameterType | Pester\Should -Not -BeNullOrEmpty } } Pester\It 'resolves parameter aliases correctly (Name param)' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $nameParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Name' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $nameParam | Pester\Should -Not -BeNullOrEmpty $nameParam.Aliases | Pester\Should -Contain 'like' $nameParam.Aliases | Pester\Should -Contain 'Path' $nameParam.Aliases | Pester\Should -Contain 'LiteralPath' $nameParam.SupportsWildcards | Pester\Should -Be $true $nameParam.ParameterType | Pester\Should -Be 'System.String[]' } Pester\It 'resolves DefaultValue for C# string[] with initializer (uninitialized instance — field init not available)' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $contentParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Content' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $contentParam | Pester\Should -Not -BeNullOrEmpty # NOTE: C# field initializers like = new string[1] { ".*" } run in # the constructor. FormatterServices.GetUninitializedObject skips # constructors, so field-initialized defaults are $null here. # [DefaultValueAttribute] or SwitchParameter defaults still work. $contentParam.DefaultValue | Pester\Should -Be $null -Because 'Field initializers are not accessible without running the constructor' } Pester\It 'resolves SwitchParameter default to $false' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $dirParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Directory' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $dirParam | Pester\Should -Not -BeNullOrEmpty $dirParam.ParameterType | Pester\Should -Be 'System.Management.Automation.SwitchParameter' $dirParam.DefaultValue | Pester\Should -Be $false } Pester\It 'resolves Position correctly (Name = 0, Content = 1)' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $nameParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Name' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $contentParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Content' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $nameParam.Position | Pester\Should -Be '0' $contentParam.Position | Pester\Should -Be '1' } Pester\It 'resolves Mandatory / ValueFromPipeline correctly' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Item' $inputParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Input' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $inputParam | Pester\Should -Not -BeNullOrEmpty $inputParam.Mandatory | Pester\Should -Be $false $inputParam.ValueFromPipeline | Pester\Should -Be $true $inputParam.ValueFromPipelineByPropertyName | Pester\Should -Be $true } } ############################################################################### Pester\Describe 'Get-CmdletMetaData — .ps1 script cmdlet (Find-Image)' { Pester\It 'returns a hashtable with all expected top-level keys' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta | Pester\Should -Not -BeNullOrEmpty $meta -is [System.Collections.Hashtable] | Pester\Should -Be $true $meta.ContainsKey('Definition') | Pester\Should -Be $true $meta.ContainsKey('Synopsis') | Pester\Should -Be $true $meta.ContainsKey('Description') | Pester\Should -Be $true $meta.ContainsKey('Examples') | Pester\Should -Be $true $meta.ContainsKey('Aliases') | Pester\Should -Be $true $meta.ContainsKey('Parameters') | Pester\Should -Be $true $meta.ContainsKey('OutputType') | Pester\Should -Be $true } Pester\It 'detects function-level aliases from [Alias()]' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta.Aliases | Pester\Should -Not -BeNullOrEmpty $meta.Aliases | Pester\Should -Contain 'findimages' $meta.Aliases | Pester\Should -Contain 'li' } Pester\It 'reads Synopsis from comment-based help' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta.Synopsis | Pester\Should -Not -BeNullOrEmpty $meta.Synopsis | Pester\Should -BeLike '*Searches for image files*' } Pester\It 'reads Description from comment-based help' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta.Description | Pester\Should -Not -BeNullOrEmpty $meta.Description | Pester\Should -BeLike '*Searches for image files*' } Pester\It 'reads Examples from comment-based help' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta.Examples | Pester\Should -Not -BeNullOrEmpty $meta.Examples.Count | Pester\Should -BeGreaterThan 0 } Pester\It 'reads OutputType from [OutputType()] attribute on function' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta.OutputType | Pester\Should -Not -BeNullOrEmpty $meta.OutputType | Pester\Should -Contain 'GenXdev.Helpers.ImageSearchResult' $meta.OutputType | Pester\Should -Contain 'System.String' } Pester\It 'extracts all parameter objects' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $meta.Parameters | Pester\Should -Not -BeNullOrEmpty $meta.Parameters.Count | Pester\Should -BeGreaterThan 5 } Pester\It 'includes ParameterType on every parameter' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' foreach ($p in $meta.Parameters) { $p.PSObject.Properties.Name | Pester\Should -Contain 'ParameterType' $p.ParameterType | Pester\Should -Not -BeNullOrEmpty } } Pester\It 'resolves parameter aliases correctly (Name param)' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $nameParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Name' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $nameParam | Pester\Should -Not -BeNullOrEmpty $nameParam.Aliases | Pester\Should -Contain 'imagespath' $nameParam.Aliases | Pester\Should -Contain 'directories' $nameParam.Aliases | Pester\Should -Contain 'imgdirs' $nameParam.Aliases | Pester\Should -Contain 'imagedirectory' $nameParam.Aliases | Pester\Should -Contain 'ImageDirectories' } Pester\It 'resolves ParameterType correctly (Name is System.String[])' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $nameParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Name' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $nameParam.ParameterType | Pester\Should -Be 'System.String[]' } Pester\It 'resolves DefaultValue from AST expression (Any = @())' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $anyParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Any' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $anyParam | Pester\Should -Not -BeNullOrEmpty $anyParam.DefaultValue | Pester\Should -Be '@()' } Pester\It 'resolves DefaultValue from AST expression (Name = @(''.\''))' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $nameParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Name' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $nameParam.DefaultValue | Pester\Should -Be "@('.\')" } Pester\It 'resolves Position correctly (Any = 0, Name = 1)' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $anyParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Any' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $nameParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Name' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $anyParam.Position | Pester\Should -Be '0' $nameParam.Position | Pester\Should -Be '1' } Pester\It 'resolves Mandatory correctly' { $meta = GenXdev\Get-CmdletMetaData -Name 'Find-Image' $anyParam = $meta.Parameters | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq 'Any' } | Microsoft.PowerShell.Utility\Select-Object -First 1 $anyParam.Mandatory | Pester\Should -Be $false } } ############################################################################### Pester\Describe 'Get-CmdletMetaData — edge cases' { Pester\It 'resolves cmdlet through alias (l -> Find-Item)' { $meta = GenXdev\Get-CmdletMetaData -Name 'l' $meta | Pester\Should -Not -BeNullOrEmpty $meta.Definition | Pester\Should -BeLike 'Find-Item*' } Pester\It 'returns empty synopsis for .ps1 cmdlet with no comment-based help' { # Create a temp function in global scope so Get-Command can find # it. Pester runs in a module scope, so the function must be # globally visible. Microsoft.PowerShell.Management\New-Item -Path 'function:global:Test-NoHelp' -Value { param([string]$Name) Microsoft.PowerShell.Utility\Write-Verbose $Name } -Force -ErrorAction SilentlyContinue | Microsoft.PowerShell.Core\Out-Null try { $meta = GenXdev\Get-CmdletMetaData -Name 'Test-NoHelp' $meta.Synopsis | Pester\Should -Be '' $meta.Description | Pester\Should -Be '' $meta.Examples.Count | Pester\Should -Be 0 $meta.OutputType.Count | Pester\Should -Be 0 $meta.Aliases.Count | Pester\Should -Be 0 } finally { Microsoft.PowerShell.Management\Remove-Item -Path 'function:global:Test-NoHelp' -Force -ErrorAction SilentlyContinue } } } |