Skip to content

Commit 8f9ad83

Browse files
author
Kapil Borle
committed
Merge pull request #555 from PowerShell/kapilmb/FixPSv3Tests
Fix test issues on PowerShell v3
2 parents 6eb2735 + a5b211f commit 8f9ad83

File tree

4 files changed

+175
-159
lines changed

4 files changed

+175
-159
lines changed

Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1

Lines changed: 162 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -224,84 +224,167 @@ function Measure-RequiresModules
224224
}
225225
}
226226

227-
<#
228-
.SYNOPSIS
229-
You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script.
230-
.DESCRIPTION
231-
When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script.
232-
To fix a violation of this rule, please store the type name in a variable or using -f operator. For example:
233-
$namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue")
234-
.EXAMPLE
235-
Measure-LongClassName -CommandAst $CommandAst
236-
.INPUTS
237-
[System.Management.Automation.Language.CommandAst]
238-
.OUTPUTS
239-
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
240-
.NOTES
241-
Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition
242-
#>
243-
function Measure-LongClassName
244-
{
245-
[CmdletBinding()]
246-
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
247-
Param
248-
(
249-
[Parameter(Mandatory = $true)]
250-
[ValidateNotNullOrEmpty()]
251-
[System.Management.Automation.Language.CommandAst]
252-
$CommandAst
253-
)
254-
255-
Process
256-
{
257-
$results = @()
258227

259-
# The StaticParameterBinder help us to find the argument of TypeName.
260-
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]
261-
262-
# Checks New-Object without ComObject parameter command only.
263-
if ($null -ne $CommandAst.GetCommandName())
264-
{
265-
if ($CommandAst.GetCommandName() -ne "new-object")
266-
{
267-
return $results
268-
}
269-
}
270-
else
271-
{
272-
return $results
273-
}
274-
275-
try
276-
{
277-
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
278-
foreach ($sbResult in $sbResults)
279-
{
280-
# TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject.
281-
if ($null -eq $sbResult.BoundParameters["TypeName"].ConstantValue) { continue }
282-
283-
if ($sbResult.BoundParameters["TypeName"].ConstantValue.ToString().Split('.').Length -ge 3)
284-
{
285-
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
286-
$result = New-Object `
287-
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
288-
-ArgumentList $Messages.MeasureLongClassName,$sbResult.BoundParameters["TypeName"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Information,$null
289-
290-
$results += $result
291-
}
292-
}
293-
294-
return $results
295-
}
296-
catch
297-
{
298-
$PSCmdlet.ThrowTerminatingError($PSItem)
299-
}
228+
# The two rules in the following if block use StaticParameterBinder class.
229+
# StaticParameterBinder class was introduced in PSv4.
230+
if ($PSVersionTable.PSVersion -ge [Version]'4.0')
231+
{
232+
<#
233+
.SYNOPSIS
234+
You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script.
235+
.DESCRIPTION
236+
When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script.
237+
To fix a violation of this rule, please store the type name in a variable or using -f operator. For example:
238+
$namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue")
239+
.EXAMPLE
240+
Measure-LongClassName -CommandAst $CommandAst
241+
.INPUTS
242+
[System.Management.Automation.Language.CommandAst]
243+
.OUTPUTS
244+
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
245+
.NOTES
246+
Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition
247+
#>
248+
function Measure-LongClassName
249+
{
250+
[CmdletBinding()]
251+
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
252+
Param
253+
(
254+
[Parameter(Mandatory = $true)]
255+
[ValidateNotNullOrEmpty()]
256+
[System.Management.Automation.Language.CommandAst]
257+
$CommandAst
258+
)
259+
260+
Process
261+
{
262+
$results = @()
263+
264+
# The StaticParameterBinder help us to find the argument of TypeName.
265+
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]
266+
267+
# Checks New-Object without ComObject parameter command only.
268+
if ($null -ne $CommandAst.GetCommandName())
269+
{
270+
if ($CommandAst.GetCommandName() -ne "new-object")
271+
{
272+
return $results
273+
}
274+
}
275+
else
276+
{
277+
return $results
278+
}
279+
280+
try
281+
{
282+
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
283+
foreach ($sbResult in $sbResults)
284+
{
285+
# TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject.
286+
if ($null -eq $sbResult.BoundParameters["TypeName"].ConstantValue) { continue }
287+
288+
if ($sbResult.BoundParameters["TypeName"].ConstantValue.ToString().Split('.').Length -ge 3)
289+
{
290+
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
291+
$result = New-Object `
292+
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
293+
-ArgumentList $Messages.MeasureLongClassName,$sbResult.BoundParameters["TypeName"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Information,$null
294+
295+
$results += $result
296+
}
297+
}
298+
299+
return $results
300+
}
301+
catch
302+
{
303+
$PSCmdlet.ThrowTerminatingError($PSItem)
304+
}
305+
306+
307+
}
308+
}
309+
310+
<#
311+
.SYNOPSIS
312+
Please do not use COM objects when calling New-Object.
313+
.DESCRIPTION
314+
If you can't use just PowerShell, use .NET, external commands or COM objects, in that order of preference. COM objects are rarely well-documented, making them harder for someone else to research and understand.
315+
They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect.
316+
To fix a violation of this rule, please do not use COM objects when calling New-Object.
317+
.EXAMPLE
318+
Measure-ComObject -CommandAst $CommandAst
319+
.INPUTS
320+
[System.Management.Automation.Language.CommandAst]
321+
.OUTPUTS
322+
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
323+
.NOTES
324+
Reference: The Purity Laws, The Community Book of PowerShell Practices.
325+
#>
326+
function Measure-ComObject
327+
{
328+
[CmdletBinding()]
329+
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
330+
Param
331+
(
332+
[Parameter(Mandatory = $true)]
333+
[ValidateNotNullOrEmpty()]
334+
[System.Management.Automation.Language.CommandAst]
335+
$CommandAst
336+
)
337+
338+
Process
339+
{
340+
$results = @()
341+
342+
# The StaticParameterBinder help us to find the argument of TypeName.
343+
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]
344+
345+
# Checks New-Object without ComObject parameter command only.
346+
if ($null -ne $CommandAst.GetCommandName())
347+
{
348+
if ($CommandAst.GetCommandName() -ne "new-object")
349+
{
350+
return $results
351+
}
352+
}
353+
else
354+
{
355+
return $results
356+
}
357+
358+
try
359+
{
360+
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
361+
foreach ($sbResult in $sbResults)
362+
{
363+
if ($sbResults.BoundParameters.ContainsKey("ComObject"))
364+
{
365+
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
366+
$result = New-Object `
367+
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
368+
-ArgumentList $Messages.MeasureComObject,$sbResult.BoundParameters["ComObject"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null
369+
370+
$results += $result
371+
}
372+
}
373+
374+
return $results
375+
}
376+
catch
377+
{
378+
$PSCmdlet.ThrowTerminatingError($PSItem)
379+
}
380+
381+
382+
}
383+
}
384+
385+
} # end if ($PSVersionTable.PSVersion -ge [Version]'4.0')
300386

301387

302-
}
303-
}
304-
305388
<#
306389
.SYNOPSIS
307390
Do not use deprecated WMI class in your script.
@@ -357,81 +440,6 @@ function Measure-DeprecatedWMIClass
357440
}
358441
}
359442

360-
<#
361-
.SYNOPSIS
362-
Please do not use COM objects when calling New-Object.
363-
.DESCRIPTION
364-
If you can't use just PowerShell, use .NET, external commands or COM objects, in that order of preference. COM objects are rarely well-documented, making them harder for someone else to research and understand.
365-
They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect.
366-
To fix a violation of this rule, please do not use COM objects when calling New-Object.
367-
.EXAMPLE
368-
Measure-ComObject -CommandAst $CommandAst
369-
.INPUTS
370-
[System.Management.Automation.Language.CommandAst]
371-
.OUTPUTS
372-
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
373-
.NOTES
374-
Reference: The Purity Laws, The Community Book of PowerShell Practices.
375-
#>
376-
function Measure-ComObject
377-
{
378-
[CmdletBinding()]
379-
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
380-
Param
381-
(
382-
[Parameter(Mandatory = $true)]
383-
[ValidateNotNullOrEmpty()]
384-
[System.Management.Automation.Language.CommandAst]
385-
$CommandAst
386-
)
387-
388-
Process
389-
{
390-
$results = @()
391-
392-
# The StaticParameterBinder help us to find the argument of TypeName.
393-
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]
394-
395-
# Checks New-Object without ComObject parameter command only.
396-
if ($null -ne $CommandAst.GetCommandName())
397-
{
398-
if ($CommandAst.GetCommandName() -ne "new-object")
399-
{
400-
return $results
401-
}
402-
}
403-
else
404-
{
405-
return $results
406-
}
407-
408-
try
409-
{
410-
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
411-
foreach ($sbResult in $sbResults)
412-
{
413-
if ($sbResults.BoundParameters.ContainsKey("ComObject"))
414-
{
415-
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
416-
$result = New-Object `
417-
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
418-
-ArgumentList $Messages.MeasureComObject,$sbResult.BoundParameters["ComObject"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null
419-
420-
$results += $result
421-
}
422-
}
423-
424-
return $results
425-
}
426-
catch
427-
{
428-
$PSCmdlet.ThrowTerminatingError($PSItem)
429-
}
430-
431-
432-
}
433-
}
434-
435443
<#
436444
.SYNOPSIS
437445
Adds end-of-line comment after closing curly bracket for deeply nested structures.
@@ -498,8 +506,8 @@ function Measure-CurlyBracket
498506
foreach ($ast in $asts)
499507
{
500508
# Checks nesting structures
501-
$nestingASTs = $asts.Where({($PSItem.Extent.StartLineNumber -gt $ast.Extent.StartLineNumber) -and
502-
($PSItem.Extent.EndLineNumber -lt $ast.Extent.EndLineNumber)})
509+
$nestingASTs = $asts | Where-Object {($PSItem.Extent.StartLineNumber -gt $ast.Extent.StartLineNumber) -and
510+
($PSItem.Extent.EndLineNumber -lt $ast.Extent.EndLineNumber)}
503511

504512
# If one AST have end-of-line comments, we should skip it.
505513
[bool]$needComment = $ast.Extent.EndScriptPosition.Line.Trim().EndsWith("}")
@@ -629,7 +637,7 @@ function Measure-Backtick
629637
try
630638
{
631639
# Finds LineContinuation tokens
632-
$lcTokens = $Token.Where({$PSItem.Kind -eq [System.Management.Automation.Language.TokenKind]::LineContinuation})
640+
$lcTokens = $Token | Where-Object {$PSItem.Kind -eq [System.Management.Automation.Language.TokenKind]::LineContinuation}
633641

634642
foreach ($lcToken in $lcTokens)
635643
{
@@ -830,7 +838,7 @@ function Measure-QuestionVariable
830838
$sbAst = [System.Management.Automation.Language.Parser]::ParseInput($ScriptBlockAst, [ref]$tokens, [ref]$errors)
831839

832840
# Gets question variables
833-
$questionVariables = $tokens.Where({$PSItem.Name -eq '?'})
841+
$questionVariables = $tokens | Where-Object {$PSItem.Name -eq '?'}
834842

835843
foreach ($questionVariable in $questionVariables)
836844
{

Tests/Engine/GetScriptAnalyzerRule.tests.ps1

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,26 @@ Describe "Test RuleExtension" {
8383
$community = "CommunityAnalyzerRules"
8484
$measureRequired = "Measure-RequiresModules"
8585
Context "When used correctly" {
86+
87+
$expectedNumCommunityRules = 10
88+
if ($PSVersionTable.PSVersion -ge [Version]'4.0')
89+
{
90+
$expectedNumCommunityRules = 12
91+
}
8692
It "with the module folder path" {
8793
$ruleExtension = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\CommunityAnalyzerRules | Where-Object {$_.SourceName -eq $community}
88-
$ruleExtension.Count | Should Be 12
94+
$ruleExtension.Count | Should Be $expectedNumCommunityRules
8995
}
9096

9197
It "with the psd1 path" {
9298
$ruleExtension = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\CommunityAnalyzerRules\CommunityAnalyzerRules.psd1 | Where-Object {$_.SourceName -eq $community}
93-
$ruleExtension.Count | Should Be 12
99+
$ruleExtension.Count | Should Be $expectedNumCommunityRules
94100

95101
}
96102

97103
It "with the psm1 path" {
98104
$ruleExtension = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\CommunityAnalyzerRules\CommunityAnalyzerRules.psm1 | Where-Object {$_.SourceName -eq $community}
99-
$ruleExtension.Count | Should Be 12
105+
$ruleExtension.Count | Should Be $expectedNumCommunityRules
100106
}
101107

102108
It "with Name of a built-in rules" {

Tests/Rules/UseToExportFieldsInManifest.tests.ps1

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ Describe "UseManifestExportFields" {
6363
# if more than two elements contain wildcard we can show only the first one as of now.
6464
$results = Run-PSScriptAnalyzerRule $testManifestBadFunctionsWildcardInArrayPath
6565
$results.Count | Should be 2
66-
$results.Where({$_.Message -match "FunctionsToExport"}).Extent.Text | Should be "'Get-*'"
67-
$results.Where({$_.Message -match "CmdletsToExport"}).Extent.Text | Should be "'Update-*'"
66+
($results | Where-Object {$_.Message -match "FunctionsToExport"}).Extent.Text | Should be "'Get-*'"
67+
($results | Where-Object {$_.Message -match "CmdletsToExport"}).Extent.Text | Should be "'Update-*'"
68+
6869
}
6970

7071

0 commit comments

Comments
 (0)