Skip to content

Commit

Permalink
Add support for excluding functions with [ExcludeFromCodeCoverageAttr…
Browse files Browse the repository at this point in the history
…ibute()] attribute
  • Loading branch information
benjaminfuchs committed Dec 21, 2024
1 parent 62823f5 commit 99eb66a
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 75 deletions.
83 changes: 75 additions & 8 deletions src/functions/Coverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -286,28 +286,95 @@ function Get-CommandsInFile {

if ($PSVersionTable.PSVersion.Major -ge 5) {
# In PowerShell 5.0, dynamic keywords for DSC configurations are represented by the DynamicKeywordStatementAst
# class. They still trigger breakpoints, but are not a child class of CommandBaseAst anymore.
# class. They still trigger breakpoints, but are not a child class of CommandBaseAst anymore.

# ReturnStatementAst is excluded as it's not behaving consistent.
# "return" is not hit in 5.1 but fixed in a later version. Using "return 123" we get hit on 123 but not return.
# See https://github.com/pester/Pester/issues/1465#issuecomment-604323645
$predicate = {
$args[0] -is [System.Management.Automation.Language.DynamicKeywordStatementAst] -or
$args[0] -is [System.Management.Automation.Language.CommandBaseAst] -or
$args[0] -is [System.Management.Automation.Language.BreakStatementAst] -or
$args[0] -is [System.Management.Automation.Language.ContinueStatementAst] -or
$args[0] -is [System.Management.Automation.Language.ExitStatementAst] -or
$args[0] -is [System.Management.Automation.Language.ThrowStatementAst]
if ($args[0] -is [System.Management.Automation.Language.DynamicKeywordStatementAst] -or
$args[0] -is [System.Management.Automation.Language.CommandBaseAst] -or
$args[0] -is [System.Management.Automation.Language.BreakStatementAst] -or
$args[0] -is [System.Management.Automation.Language.ContinueStatementAst] -or
$args[0] -is [System.Management.Automation.Language.ExitStatementAst] -or
$args[0] -is [System.Management.Automation.Language.ThrowStatementAst]) {
if (-not (IsExcludedByAttribute -Ast $args[0])) {
return $true
}
}
}
}
else {
$predicate = { $args[0] -is [System.Management.Automation.Language.CommandBaseAst] }
$predicate = {
if ($args[0] -is [System.Management.Automation.Language.CommandBaseAst]) {
if (-not (IsExcludedByAttribute -Ast $args[0])) {
return $true
}
}
}
}

$searchNestedScriptBlocks = $true
$ast.FindAll($predicate, $searchNestedScriptBlocks)
}

function IsExcludedByAttribute {
param (
[System.Management.Automation.Language.Ast] $Ast
)

$functionParents = @()
for ($parent = $Ast.Parent; $null -ne $parent; $parent = $parent.Parent) {
if ($parent -is [System.Management.Automation.Language.FunctionDefinitionAst]) {
$functionParents += $parent
}
}

$parentsAttributeNames = @()
foreach ($functionParent in $functionParents) {
$paramBlock = $functionParent.Body.ParamBlock
if ($paramBlock -and $paramBlock.Attributes) {
$parentsAttributeNames += $paramBlock.Attributes.TypeName.FullName
}
}

foreach ($parentsAttributeName in $parentsAttributeNames) {
if ($parentsAttributeName.EndsWith('ExcludeFromCodeCoverageAttribute')) {
$namespaces = Get-NamespacesFromScript -Ast $Ast
if ($namespaces) {
foreach ($namespace in $namespaces) {
if ("$namespace.$parentsAttributeName" -eq 'System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute') {
return $true
}
}
}
}
}

return $false
}

function Get-NamespacesFromScript {
param (
[System.Management.Automation.Language.Ast] $Ast
)

while ($null -ne $Ast.Parent) {
$Ast = $Ast.Parent
}

$usingStatements = $Ast.FindAll({
param ($node) $node -is [System.Management.Automation.Language.UsingStatementAst] -and $node.UsingStatementKind -eq 'Namespace'
}, $true)

$namespaces = @()
foreach ($usingStatement in $usingStatements) {
$namespaces += $usingStatement.Name.Value
}

return $namespaces
}

function Test-CoverageOverlapsCommand {
param ([object] $CoverageInfo, [System.Management.Automation.Language.Ast] $Command)

Expand Down
Loading

0 comments on commit 99eb66a

Please sign in to comment.