Skip to content

Commit

Permalink
Added Filter.ExcludeLine option (#2016)
Browse files Browse the repository at this point in the history
* Added ExcludeLine option to FilterConfiguration

* Added ExcludeLine to New-FilterObject

* Added code to do excluding

* Set Explicit to true

* Added tests

* Modifying test names
  • Loading branch information
ArmaanMcleod committed Jun 27, 2021
1 parent ad2899c commit a5bdc2f
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/Main.ps1
Expand Up @@ -1015,6 +1015,7 @@ function Invoke-Pester {
-Tag $PesterPreference.Filter.Tag.Value `
-ExcludeTag $PesterPreference.Filter.ExcludeTag.Value `
-Line $PesterPreference.Filter.Line.Value `
-ExcludeLine $PesterPreference.Filter.ExcludeLine.Value `
-FullName $PesterPreference.Filter.FullName.Value

$containers = @()
Expand Down
3 changes: 3 additions & 0 deletions src/Pester.RSpec.ps1
Expand Up @@ -322,6 +322,9 @@ function New-PesterConfiguration {
Line: Filter by file and scriptblock start line, useful to run parsed tests programatically to avoid problems with expanded names. Example: 'C:\tests\file1.Tests.ps1:37'
Default value: @()
ExcludeLine: Exclude by file and scriptblock start line, takes precedence over Line.
Default value: @()
FullName: Full name of test with -like wildcards, joined by dot. Example: '*.describe Get-Item.test1'
Default value: @()
Expand Down
29 changes: 24 additions & 5 deletions src/Pester.Runtime.ps1
Expand Up @@ -1721,6 +1721,23 @@ function Test-ShouldRun {
}
}

$excludeLineFilter = $Filter.ExcludeLine

$line = "$(if ($Item.ScriptBlock.File) { $Item.ScriptBlock.File } else { $Item.ScriptBlock.Id }):$($Item.StartLine)" -replace '\\', '/'
if ($excludeLineFilter -and 0 -ne $excludeLineFilter.Count) {
foreach ($l in $excludeLineFilter -replace '\\', '/') {
if ($l -eq $line) {
if ($PesterPreference.Debug.WriteDebugMessages.Value) {
Write-PesterDebugMessage -Scope Filter "($fullDottedPath) $($Item.ItemType) is excluded, because its path:line '$line' matches line filter '$excludeLineFilter'."
Write-PesterDebugMessage -Scope Filter "($fullDottedPath) $($Item.ItemType) is explicitly excluded, because it matched line filter, and will run even if -Skip is specified on it. Any skipped children will still be skipped."
}
$result.Exclude = $true
$result.Explicit = $true
return $result
}
}
}

# - place exclude filters above this line and include below this line

$lineFilter = $Filter.Line
Expand Down Expand Up @@ -2286,14 +2303,16 @@ function New-FilterObject {
[String[]] $FullName,
[String[]] $Tag,
[String[]] $ExcludeTag,
[String[]] $Line
[String[]] $Line,
[String[]] $ExcludeLine
)

[PSCustomObject] @{
FullName = $FullName
Tag = $Tag
ExcludeTag = $ExcludeTag
Line = $Line
FullName = $FullName
Tag = $Tag
ExcludeTag = $ExcludeTag
Line = $Line
ExcludeLine = $ExcludeLine
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/csharp/Pester/FilterConfiguration.cs
Expand Up @@ -24,6 +24,7 @@ public class FilterConfiguration : ConfigurationSection
private StringArrayOption _tag;
private StringArrayOption _excludeTag;
private StringArrayOption _line;
private StringArrayOption _excludeLine;
private StringArrayOption _fullName;

public static FilterConfiguration Default { get { return new FilterConfiguration(); } }
Expand All @@ -39,6 +40,7 @@ public FilterConfiguration(IDictionary configuration) : this()
Tag = configuration.GetArrayOrNull<string>("Tag") ?? Tag;
ExcludeTag = configuration.GetArrayOrNull<string>("ExcludeTag") ?? ExcludeTag;
Line = configuration.GetArrayOrNull<string>("Line") ?? Line;
ExcludeLine = configuration.GetArrayOrNull<string>("ExcludeLine") ?? ExcludeLine;
FullName = configuration.GetArrayOrNull<string>("FullName") ?? FullName;
}
}
Expand All @@ -47,6 +49,7 @@ public FilterConfiguration() : base("Filter configuration")
Tag = new StringArrayOption("Tags of Describe, Context or It to be run.", new string[0]);
ExcludeTag = new StringArrayOption("Tags of Describe, Context or It to be excluded from the run.", new string[0]);
Line = new StringArrayOption(@"Filter by file and scriptblock start line, useful to run parsed tests programatically to avoid problems with expanded names. Example: 'C:\tests\file1.Tests.ps1:37'", new string[0]);
ExcludeLine = new StringArrayOption("Exclude by file and scriptblock start line, takes precedence over Line.", new string[0]);
FullName = new StringArrayOption("Full name of test with -like wildcards, joined by dot. Example: '*.describe Get-Item.test1'", new string[0]);
}

Expand Down Expand Up @@ -97,6 +100,22 @@ public StringArrayOption Line
}
}

public StringArrayOption ExcludeLine
{
get { return _excludeLine; }
set
{
if (_excludeLine == null)
{
_excludeLine = value;
}
else
{
_excludeLine = new StringArrayOption(_excludeLine, value?.Value);
}
}
}

public StringArrayOption FullName
{
get { return _fullName; }
Expand Down
257 changes: 257 additions & 0 deletions tst/Pester.Runtime.ts.ps1
Expand Up @@ -476,6 +476,263 @@ i -PassThru:$PassThru {
$actual.Include | Verify-False
$actual.Exclude | Verify-False
}

t "Given a test with file path and line number it excludes it when it matches the ExcludeLine filter" {
$t = New-TestObject -Name "test1" -ScriptBlock ($sb = { "test" }) -StartLine $sb.StartPosition.StartLine

$excludeLines = "$($sb.File):$($sb.StartPosition.StartLine)"

$f = New-FilterObject -ExcludeLine $excludeLines

$actual = Test-ShouldRun -Item $t -Filter $f
$actual.Include | Verify-False
$actual.Exclude | Verify-True
}

t "Given a test with file path and line number it overrides the Line filter when it matches the ExcludeLine filter" {
$t = New-TestObject -Name "test1" -ScriptBlock ($sb = { "test" }) -StartLine $sb.StartPosition.StartLine

$includeLines = "$($sb.File):$($sb.StartPosition.StartLine)"
$excludeLines = "$($sb.File):$($sb.StartPosition.StartLine)"

$f = New-FilterObject -Line $includeLines -ExcludeLine $excludeLines

$actual = Test-ShouldRun -Item $t -Filter $f
$actual.Include | Verify-False
$actual.Exclude | Verify-True
}

t "Given two tests with file paths and line numbers it excludes both they match the ExcludeLine filter" {
$sb = {
New-Block "block1" {
New-Test "test1" { "a" }
New-Test "test2" { "b" }
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$test1 = $actual.Blocks[0].Tests[0]
$test2 = $actual.Blocks[0].Tests[1]

$excludeLines = "$($sb.File):$($test1.ScriptBlock.StartPosition.StartLine)", "$($sb.File):$($test2.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $test1 -Filter $f
$actual1.Include | Verify-False
$actual1.Exclude | Verify-True

$actual2 = Test-ShouldRun -Item $test2 -Filter $f
$actual2.Include | Verify-False
$actual2.Exclude | Verify-True
}

t "Given two tests with file paths and line numbers it includes the first one from Line filter and excludes second one from ExcludeLine filter" {
$sb = {
New-Block "block1" {
New-Test "test1" { "a" }
New-Test "test2" { "b" }
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$test1 = $actual.Blocks[0].Tests[0]
$test2 = $actual.Blocks[0].Tests[1]

$includeLines = "$($sb.File):$($test1.ScriptBlock.StartPosition.StartLine)"
$excludeLines = "$($sb.File):$($test2.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -Line $includeLines -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $test1 -Filter $f
$actual1.Include | Verify-True
$actual1.Exclude | Verify-False

$actual2 = Test-ShouldRun -Item $test2 -Filter $f
$actual2.Include | Verify-False
$actual2.Exclude | Verify-True
}

t "Given multiple tests with file paths and line numbers it includes the lines that match the Line filter and excludes when overriden with the ExcludeLine filter" {
$sb = {
New-Block "block1" {
New-Test "test1" { "a" }
New-Test "test2" { "b" }
New-Test "test3" { "c" }
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$test1 = $actual.Blocks[0].Tests[0]
$test2 = $actual.Blocks[0].Tests[1]
$test3 = $actual.Blocks[0].Tests[2]

$includeLines = "$($sb.File):$($test1.ScriptBlock.StartPosition.StartLine)", "$($sb.File):$($test2.ScriptBlock.StartPosition.StartLine)", "$($sb.File):$($test3.ScriptBlock.StartPosition.StartLine)"
$excludeLines = "$($sb.File):$($test3.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -Line $includeLines -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $test1 -Filter $f
$actual1.Include | Verify-True
$actual1.Exclude | Verify-False

$actual2 = Test-ShouldRun -Item $test2 -Filter $f
$actual2.Include | Verify-True
$actual2.Exclude | Verify-False

$actual3 = Test-ShouldRun -Item $test3 -Filter $f
$actual3.Include | Verify-False
$actual3.Exclude | Verify-True
}

t "Given multiple tests with file paths and line numbers it excludes selected tests inside a block" {
$sb = {
New-Block "block1" {
New-Test "test1" { "a" }
New-Test "test2" { "b" }
New-Test "test3" { "c" }
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$block1 = $actual.Blocks[0]
$test1 = $block1.Tests[0]
$test2 = $block1.Tests[1]
$test3 = $block1.Tests[2]

$includeLines = "$($sb.File):$($block1.ScriptBlock.StartPosition.StartLine)"
$excludeLines = "$($sb.File):$($test2.ScriptBlock.StartPosition.StartLine)", "$($sb.File):$($test3.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -Line $includeLines -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $block1 -Filter $f
$actual1.Include | Verify-True
$actual1.Exclude | Verify-False

$actual2 = Test-ShouldRun -Item $test1 -Filter $f
$actual2.Include | Verify-True
$actual2.Exclude | Verify-False

$actual3 = Test-ShouldRun -Item $test2 -Filter $f
$actual3.Include | Verify-False
$actual3.Exclude | Verify-True

$actual4 = Test-ShouldRun -Item $test3 -Filter $f
$actual4.Include | Verify-False
$actual4.Exclude | Verify-True
}

t "Given multiple tests with file paths and line numbers it excludes block" {
$sb = {
New-Block "block1" {
New-Test "test1" { "a" }
New-Test "test2" { "b" }
New-Test "test3" { "c" }
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$block1 = $actual.Blocks[0]

$excludeLines = "$($sb.File):$($block1.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $block1 -Filter $f
$actual1.Include | Verify-False
$actual1.Exclude | Verify-True
}

t "Given multiple tests with file paths and line numbers it excludes nested blocks" {
$sb = {
# Describe
New-Block "block1" {
New-Test "test1" { "a" }

# Context
New-Block "block2" {
New-Test "test2" { "b" }
New-Test "test3" { "c" }
}
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$block1 = $actual.Blocks[0]
$test1 = $block1.Tests[0]
$block2 = $actual.Blocks[0].Blocks[0]

$includeLines = "$($sb.File):$($block1.ScriptBlock.StartPosition.StartLine)"
$excludeLines = "$($sb.File):$($block2.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -Line $includeLines -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $block1 -Filter $f
$actual1.Include | Verify-True
$actual1.Exclude | Verify-False

$actual2 = Test-ShouldRun -Item $test1 -Filter $f
$actual2.Include | Verify-True
$actual2.Exclude | Verify-False

$actual3 = Test-ShouldRun -Item $block2 -Filter $f
$actual3.Include | Verify-False
$actual3.Exclude | Verify-True
}

t "Given multiple tests with file paths and line numbers it includes nested blocks but excludes selected tests within blocks" {
$sb = {
# Describe
New-Block "block1" {
New-Test "test1" { "a" }

# Context
New-Block "block2" {
New-Test "test2" { "b" }
New-Test "test3" { "c" }
}
}
}

$actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)

$block1 = $actual.Blocks[0]
$test1 = $block1.Tests[0]
$block2 = $actual.Blocks[0].Blocks[0]
$test2 = $block2.Tests[0]
$test3 = $block2.Tests[1]

$includeLines = "$($sb.File):$($block1.ScriptBlock.StartPosition.StartLine)", "$($sb.File):$($block2.ScriptBlock.StartPosition.StartLine)", "$($sb.File):$($test2.ScriptBlock.StartPosition.StartLine)"
$excludeLines = "$($sb.File):$($test2.ScriptBlock.StartPosition.StartLine)"

$f = New-FilterObject -Line $includeLines -ExcludeLine $excludeLines

$actual1 = Test-ShouldRun -Item $block1 -Filter $f
$actual1.Include | Verify-True
$actual1.Exclude | Verify-False

$actual2 = Test-ShouldRun -Item $test1 -Filter $f
$actual2.Include | Verify-True
$actual2.Exclude | Verify-False

$actual3 = Test-ShouldRun -Item $block2 -Filter $f
$actual3.Include | Verify-True
$actual3.Exclude | Verify-False

$actual4 = Test-ShouldRun -Item $test2 -Filter $f
$actual4.Include | Verify-False
$actual4.Exclude | Verify-True

$actual5 = Test-ShouldRun -Item $test3 -Filter $f
$actual5.Include | Verify-True
$actual5.Exclude | Verify-False
}
}

b "path filter" {
Expand Down

0 comments on commit a5bdc2f

Please sign in to comment.