Skip to content

Fix test issues on PowerShell v3 #555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
316 changes: 162 additions & 154 deletions Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -224,84 +224,167 @@ function Measure-RequiresModules
}
}

<#
.SYNOPSIS
You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script.
.DESCRIPTION
When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script.
To fix a violation of this rule, please store the type name in a variable or using -f operator. For example:
$namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue")
.EXAMPLE
Measure-LongClassName -CommandAst $CommandAst
.INPUTS
[System.Management.Automation.Language.CommandAst]
.OUTPUTS
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
.NOTES
Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition
#>
function Measure-LongClassName
{
[CmdletBinding()]
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
Param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Language.CommandAst]
$CommandAst
)

Process
{
$results = @()

# The StaticParameterBinder help us to find the argument of TypeName.
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]

# Checks New-Object without ComObject parameter command only.
if ($null -ne $CommandAst.GetCommandName())
{
if ($CommandAst.GetCommandName() -ne "new-object")
{
return $results
}
}
else
{
return $results
}

try
{
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
foreach ($sbResult in $sbResults)
{
# TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject.
if ($null -eq $sbResult.BoundParameters["TypeName"].ConstantValue) { continue }

if ($sbResult.BoundParameters["TypeName"].ConstantValue.ToString().Split('.').Length -ge 3)
{
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
$result = New-Object `
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
-ArgumentList $Messages.MeasureLongClassName,$sbResult.BoundParameters["TypeName"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Information,$null

$results += $result
}
}

return $results
}
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}
# The two rules in the following if block use StaticParameterBinder class.
# StaticParameterBinder class was introduced in PSv4.
if ($PSVersionTable.PSVersion -ge [Version]'4.0')
{
<#
.SYNOPSIS
You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script.
.DESCRIPTION
When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script.
To fix a violation of this rule, please store the type name in a variable or using -f operator. For example:
$namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue")
.EXAMPLE
Measure-LongClassName -CommandAst $CommandAst
.INPUTS
[System.Management.Automation.Language.CommandAst]
.OUTPUTS
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
.NOTES
Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition
#>
function Measure-LongClassName
{
[CmdletBinding()]
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
Param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Language.CommandAst]
$CommandAst
)

Process
{
$results = @()

# The StaticParameterBinder help us to find the argument of TypeName.
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]

# Checks New-Object without ComObject parameter command only.
if ($null -ne $CommandAst.GetCommandName())
{
if ($CommandAst.GetCommandName() -ne "new-object")
{
return $results
}
}
else
{
return $results
}

try
{
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
foreach ($sbResult in $sbResults)
{
# TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject.
if ($null -eq $sbResult.BoundParameters["TypeName"].ConstantValue) { continue }

if ($sbResult.BoundParameters["TypeName"].ConstantValue.ToString().Split('.').Length -ge 3)
{
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
$result = New-Object `
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
-ArgumentList $Messages.MeasureLongClassName,$sbResult.BoundParameters["TypeName"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Information,$null

$results += $result
}
}

return $results
}
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}


}
}

<#
.SYNOPSIS
Please do not use COM objects when calling New-Object.
.DESCRIPTION
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.
They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect.
To fix a violation of this rule, please do not use COM objects when calling New-Object.
.EXAMPLE
Measure-ComObject -CommandAst $CommandAst
.INPUTS
[System.Management.Automation.Language.CommandAst]
.OUTPUTS
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
.NOTES
Reference: The Purity Laws, The Community Book of PowerShell Practices.
#>
function Measure-ComObject
{
[CmdletBinding()]
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
Param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Language.CommandAst]
$CommandAst
)

Process
{
$results = @()

# The StaticParameterBinder help us to find the argument of TypeName.
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]

# Checks New-Object without ComObject parameter command only.
if ($null -ne $CommandAst.GetCommandName())
{
if ($CommandAst.GetCommandName() -ne "new-object")
{
return $results
}
}
else
{
return $results
}

try
{
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
foreach ($sbResult in $sbResults)
{
if ($sbResults.BoundParameters.ContainsKey("ComObject"))
{
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
$result = New-Object `
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
-ArgumentList $Messages.MeasureComObject,$sbResult.BoundParameters["ComObject"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null

$results += $result
}
}

return $results
}
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}


}
}

} # end if ($PSVersionTable.PSVersion -ge [Version]'4.0')


}
}

<#
.SYNOPSIS
Do not use deprecated WMI class in your script.
Expand Down Expand Up @@ -357,81 +440,6 @@ function Measure-DeprecatedWMIClass
}
}

<#
.SYNOPSIS
Please do not use COM objects when calling New-Object.
.DESCRIPTION
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.
They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect.
To fix a violation of this rule, please do not use COM objects when calling New-Object.
.EXAMPLE
Measure-ComObject -CommandAst $CommandAst
.INPUTS
[System.Management.Automation.Language.CommandAst]
.OUTPUTS
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
.NOTES
Reference: The Purity Laws, The Community Book of PowerShell Practices.
#>
function Measure-ComObject
{
[CmdletBinding()]
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
Param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Language.CommandAst]
$CommandAst
)

Process
{
$results = @()

# The StaticParameterBinder help us to find the argument of TypeName.
$spBinder = [System.Management.Automation.Language.StaticParameterBinder]

# Checks New-Object without ComObject parameter command only.
if ($null -ne $CommandAst.GetCommandName())
{
if ($CommandAst.GetCommandName() -ne "new-object")
{
return $results
}
}
else
{
return $results
}

try
{
[System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true)
foreach ($sbResult in $sbResults)
{
if ($sbResults.BoundParameters.ContainsKey("ComObject"))
{
# $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent.
$result = New-Object `
-Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
-ArgumentList $Messages.MeasureComObject,$sbResult.BoundParameters["ComObject"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null

$results += $result
}
}

return $results
}
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}


}
}

<#
.SYNOPSIS
Adds end-of-line comment after closing curly bracket for deeply nested structures.
Expand Down Expand Up @@ -498,8 +506,8 @@ function Measure-CurlyBracket
foreach ($ast in $asts)
{
# Checks nesting structures
$nestingASTs = $asts.Where({($PSItem.Extent.StartLineNumber -gt $ast.Extent.StartLineNumber) -and
($PSItem.Extent.EndLineNumber -lt $ast.Extent.EndLineNumber)})
$nestingASTs = $asts | Where-Object {($PSItem.Extent.StartLineNumber -gt $ast.Extent.StartLineNumber) -and
($PSItem.Extent.EndLineNumber -lt $ast.Extent.EndLineNumber)}

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

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

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

foreach ($questionVariable in $questionVariables)
{
Expand Down
12 changes: 9 additions & 3 deletions Tests/Engine/GetScriptAnalyzerRule.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,26 @@ Describe "Test RuleExtension" {
$community = "CommunityAnalyzerRules"
$measureRequired = "Measure-RequiresModules"
Context "When used correctly" {

$expectedNumCommunityRules = 10
if ($PSVersionTable.PSVersion -ge [Version]'4.0')
{
$expectedNumCommunityRules = 12
}
It "with the module folder path" {
$ruleExtension = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\CommunityAnalyzerRules | Where-Object {$_.SourceName -eq $community}
$ruleExtension.Count | Should Be 12
$ruleExtension.Count | Should Be $expectedNumCommunityRules
}

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

}

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

It "with Name of a built-in rules" {
Expand Down
5 changes: 3 additions & 2 deletions Tests/Rules/UseToExportFieldsInManifest.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ Describe "UseManifestExportFields" {
# if more than two elements contain wildcard we can show only the first one as of now.
$results = Run-PSScriptAnalyzerRule $testManifestBadFunctionsWildcardInArrayPath
$results.Count | Should be 2
$results.Where({$_.Message -match "FunctionsToExport"}).Extent.Text | Should be "'Get-*'"
$results.Where({$_.Message -match "CmdletsToExport"}).Extent.Text | Should be "'Update-*'"
($results | Where-Object {$_.Message -match "FunctionsToExport"}).Extent.Text | Should be "'Get-*'"
($results | Where-Object {$_.Message -match "CmdletsToExport"}).Extent.Text | Should be "'Update-*'"

}


Expand Down
Loading