1
+ <#
2
+ . NOTES
3
+ The original test this is based upon was written by June Blender.
4
+ After several rounds of modifications it stands now as it is, but the honor remains hers.
5
+
6
+ Thank you June, for all you have done!
7
+
8
+ . DESCRIPTION
9
+ This test evaluates the help for all commands in a module.
10
+
11
+ . PARAMETER SkipTest
12
+ Disables this test.
13
+
14
+ . PARAMETER CommandPath
15
+ List of paths under which the script files are stored.
16
+ This test assumes that all functions have their own file that is named after themselves.
17
+ These paths are used to search for commands that should exist and be tested.
18
+ Will search recursively and accepts wildcards, make sure only functions are found
19
+
20
+ . PARAMETER ModuleName
21
+ Name of the module to be tested.
22
+ The module must already be imported
23
+
24
+ . PARAMETER ExceptionsFile
25
+ File in which exceptions and adjustments are configured.
26
+ In it there should be two arrays and a hashtable defined:
27
+ $global:FunctionHelpTestExceptions
28
+ $global:HelpTestEnumeratedArrays
29
+ $global:HelpTestSkipParameterType
30
+ These can be used to tweak the tests slightly in cases of need.
31
+ See the example file for explanations on each of these usage and effect.
32
+ #>
33
+ [CmdletBinding ()]
34
+ Param (
35
+ [switch ]
36
+ $SkipTest ,
37
+
38
+ [string []]
39
+ $CommandPath = @ (" $PSScriptRoot \..\..\functions" , " $PSScriptRoot \..\..\internal\functions" ),
40
+
41
+ [string ]
42
+ $ModuleName = " PSModuleDevelopment" ,
43
+
44
+ [string ]
45
+ $ExceptionsFile = " $PSScriptRoot \Help.Exceptions.ps1"
46
+ )
47
+ if ($SkipTest ) { return }
48
+ . $ExceptionsFile
49
+
50
+ $includedNames = (Get-ChildItem $CommandPath - Recurse - File | Where-Object Name -like " *.ps1" ).BaseName
51
+ $commands = Get-Command - Module (Get-Module $ModuleName ) - CommandType Cmdlet, Function, Workflow | Where-Object Name -in $includedNames
52
+
53
+ # # When testing help, remember that help is cached at the beginning of each session.
54
+ # # To test, restart session.
55
+
56
+
57
+ foreach ($command in $commands ) {
58
+ $commandName = $command.Name
59
+
60
+ # Skip all functions that are on the exclusions list
61
+ if ($global :FunctionHelpTestExceptions -contains $commandName ) { continue }
62
+
63
+ # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets
64
+ $Help = Get-Help $commandName - ErrorAction SilentlyContinue
65
+ $testhelperrors = 0
66
+ $testhelpall = 0
67
+ Describe " Test help for $commandName " {
68
+
69
+ $testhelpall += 1
70
+ if ($Help.Synopsis -like ' *`[`<CommonParameters`>`]*' ) {
71
+ # If help is not found, synopsis in auto-generated help is the syntax diagram
72
+ It " should not be auto-generated" {
73
+ $Help.Synopsis | Should Not BeLike ' *`[`<CommonParameters`>`]*'
74
+ }
75
+ $testhelperrors += 1
76
+ }
77
+
78
+ $testhelpall += 1
79
+ if ([String ]::IsNullOrEmpty($Help.Description.Text )) {
80
+ # Should be a description for every function
81
+ It " gets description for $commandName " {
82
+ $Help.Description | Should Not BeNullOrEmpty
83
+ }
84
+ $testhelperrors += 1
85
+ }
86
+
87
+ $testhelpall += 1
88
+ if ([String ]::IsNullOrEmpty(($Help.Examples.Example | Select-Object - First 1 ).Code)) {
89
+ # Should be at least one example
90
+ It " gets example code from $commandName " {
91
+ ($Help.Examples.Example | Select-Object - First 1 ).Code | Should Not BeNullOrEmpty
92
+ }
93
+ $testhelperrors += 1
94
+ }
95
+
96
+ $testhelpall += 1
97
+ if ([String ]::IsNullOrEmpty(($Help.Examples.Example.Remarks | Select-Object - First 1 ).Text)) {
98
+ # Should be at least one example description
99
+ It " gets example help from $commandName " {
100
+ ($Help.Examples.Example.Remarks | Select-Object - First 1 ).Text | Should Not BeNullOrEmpty
101
+ }
102
+ $testhelperrors += 1
103
+ }
104
+
105
+ if ($testhelperrors -eq 0 ) {
106
+ It " Ran silently $testhelpall tests" {
107
+ $testhelperrors | Should be 0
108
+ }
109
+ }
110
+
111
+ $testparamsall = 0
112
+ $testparamserrors = 0
113
+ Context " Test parameter help for $commandName " {
114
+
115
+ $Common = ' Debug' , ' ErrorAction' , ' ErrorVariable' , ' InformationAction' , ' InformationVariable' , ' OutBuffer' , ' OutVariable' ,
116
+ ' PipelineVariable' , ' Verbose' , ' WarningAction' , ' WarningVariable'
117
+
118
+ $parameters = $command.ParameterSets.Parameters | Sort-Object - Property Name - Unique | Where-Object Name -notin $common
119
+ $parameterNames = $parameters.Name
120
+ $HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object - Unique
121
+ foreach ($parameter in $parameters ) {
122
+ $parameterName = $parameter.Name
123
+ $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName
124
+
125
+ $testparamsall += 1
126
+ if ([String ]::IsNullOrEmpty($parameterHelp.Description.Text )) {
127
+ # Should be a description for every parameter
128
+ It " gets help for parameter: $parameterName : in $commandName " {
129
+ $parameterHelp.Description.Text | Should Not BeNullOrEmpty
130
+ }
131
+ $testparamserrors += 1
132
+ }
133
+
134
+ $testparamsall += 1
135
+ $codeMandatory = $parameter.IsMandatory.toString ()
136
+ if ($parameterHelp.Required -ne $codeMandatory ) {
137
+ # Required value in Help should match IsMandatory property of parameter
138
+ It " help for $parameterName parameter in $commandName has correct Mandatory value" {
139
+ $parameterHelp.Required | Should Be $codeMandatory
140
+ }
141
+ $testparamserrors += 1
142
+ }
143
+
144
+ if ($HelpTestSkipParameterType [$commandName ] -contains $parameterName ) { continue }
145
+
146
+ $codeType = $parameter.ParameterType.Name
147
+
148
+ $testparamsall += 1
149
+ if ($parameter.ParameterType.IsEnum ) {
150
+ # Enumerations often have issues with the typename not being reliably available
151
+ $names = $parameter.ParameterType ::GetNames($parameter.ParameterType )
152
+ if ($parameterHelp.parameterValueGroup.parameterValue -ne $names ) {
153
+ # Parameter type in Help should match code
154
+ It " help for $commandName has correct parameter type for $parameterName " {
155
+ $parameterHelp.parameterValueGroup.parameterValue | Should be $names
156
+ }
157
+ $testparamserrors += 1
158
+ }
159
+ }
160
+ elseif ($parameter.ParameterType.FullName -in $HelpTestEnumeratedArrays ) {
161
+ # Enumerations often have issues with the typename not being reliably available
162
+ $names = [Enum ]::GetNames($parameter.ParameterType.DeclaredMembers [0 ].ReturnType)
163
+ if ($parameterHelp.parameterValueGroup.parameterValue -ne $names ) {
164
+ # Parameter type in Help should match code
165
+ It " help for $commandName has correct parameter type for $parameterName " {
166
+ $parameterHelp.parameterValueGroup.parameterValue | Should be $names
167
+ }
168
+ $testparamserrors += 1
169
+ }
170
+ }
171
+ else {
172
+ # To avoid calling Trim method on a null object.
173
+ $helpType = if ($parameterHelp.parameterValue ) { $parameterHelp.parameterValue.Trim () }
174
+ if ($helpType -ne $codeType ) {
175
+ # Parameter type in Help should match code
176
+ It " help for $commandName has correct parameter type for $parameterName " {
177
+ $helpType | Should be $codeType
178
+ }
179
+ $testparamserrors += 1
180
+ }
181
+ }
182
+ }
183
+ foreach ($helpParm in $HelpParameterNames ) {
184
+ $testparamsall += 1
185
+ if ($helpParm -notin $parameterNames ) {
186
+ # Shouldn't find extra parameters in help.
187
+ It " finds help parameter in code: $helpParm " {
188
+ $helpParm -in $parameterNames | Should Be $true
189
+ }
190
+ $testparamserrors += 1
191
+ }
192
+ }
193
+ if ($testparamserrors -eq 0 ) {
194
+ It " Ran silently $testparamsall tests" {
195
+ $testparamserrors | Should be 0
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
0 commit comments