Skip to content

Commit

Permalink
Fix line-based filter for tests with multiline testcases (#1664)
Browse files Browse the repository at this point in the history
Allow LineFilter use the Describe / Context / It position instead of the `{` position of the associated scriptblock. This way we have easier time figuring out the correct line number to pass even in cases where the `{` is on a different line. Typically when TestCases are provided.

```powershell
Describe "d1" `
{
    Context "c1" `
    {
        It "User with guard" `
        {
            1 | Should -Be 2
        }
    }
}
```
  • Loading branch information
fflaten committed Sep 3, 2020
1 parent 95121da commit 459a4b7
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 32 deletions.
10 changes: 8 additions & 2 deletions src/Pester.Runtime.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ function New-Block {
[String] $Name,
[Parameter(Mandatory = $true)]
[ScriptBlock] $ScriptBlock,
[int] $StartLine,
[String[]] $Tag = @(),
[HashTable] $FrameworkData = @{ },
[Switch] $Focus,
Expand Down Expand Up @@ -184,6 +185,7 @@ function New-Block {
$block.Path = $Path
$block.Tag = $Tag
$block.ScriptBlock = $ScriptBlock
$block.StartLine = $StartLine
$block.FrameworkData = $FrameworkData
$block.Focus = $Focus
$block.Id = $Id
Expand Down Expand Up @@ -369,6 +371,7 @@ function New-Test {
[String] $Name,
[Parameter(Mandatory = $true, Position = 1)]
[ScriptBlock] $ScriptBlock,
[int] $StartLine,
[String[]] $Tag = @(),
[System.Collections.IDictionary] $Data = @{ },
[String] $Id,
Expand Down Expand Up @@ -397,6 +400,7 @@ function New-Test {
$test.ScriptBlock = $ScriptBlock
$test.Name = $Name
$test.Path = $path
$test.StartLine = $StartLine
$test.Tag = $Tag
$test.Focus = $Focus
$test.Skip = $Skip
Expand Down Expand Up @@ -1550,7 +1554,8 @@ function Test-ShouldRun {
# the test even if it is marked as skipped run this include as first so we figure it out
# in one place and check if parent was included after this one to short circuit the other
# filters in case parent already knows that it will run
$line = "$(if ($Item.ScriptBlock.File) { $Item.ScriptBlock.File } else { $Item.ScriptBlock.Id }):$($Item.ScriptBlock.StartPosition.StartLine)" -replace '\\', '/'

$line = "$(if ($Item.ScriptBlock.File) { $Item.ScriptBlock.File } else { $Item.ScriptBlock.Id }):$($Item.StartLine)" -replace '\\', '/'
if ($lineFilter -and 0 -ne $lineFilter.Count) {
$anyIncludeFilters = $true
foreach ($l in $lineFilter -replace '\\', '/') {
Expand Down Expand Up @@ -2344,6 +2349,7 @@ function New-ParametrizedTest () {
[String] $Name,
[Parameter(Mandatory = $true, Position = 1)]
[ScriptBlock] $ScriptBlock,
[int] $StartLine,
[String[]] $Tag = @(),
# do not use [hashtable[]] because that throws away the order if user uses [ordered] hashtable
[System.Collections.IDictionary[]] $Data = @{ },
Expand All @@ -2360,7 +2366,7 @@ function New-ParametrizedTest () {
$id = $ScriptBlock.StartPosition.StartLine
foreach ($d in $Data) {
# $innerId = if (-not $hasExternalId) { $null } else { "$Id-$(($counter++))" }
New-Test -Id $id -Name $Name -Tag $Tag -ScriptBlock $ScriptBlock -Data $d -Focus:$Focus -Skip:$Skip
New-Test -Id $id -Name $Name -Tag $Tag -ScriptBlock $ScriptBlock -StartLine $StartLine -Data $d -Focus:$Focus -Skip:$Skip
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/csharp/Pester/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public Block()
public TimeSpan OwnDuration { get; set; }

public ScriptBlock ScriptBlock { get; set; }
public int StartLine { get; set; }
public Hashtable FrameworkData { get; set; } = new Hashtable();
public Hashtable PluginData { get; set; } = new Hashtable();

Expand All @@ -88,6 +89,7 @@ public Block()
public int OwnPendingCount { get; set; }
public int OwnNotRunCount { get; set; }
public int OwnInconclusiveCount { get; set; }

public override string ToString()
{
return ToStringConverter.BlockToString(this);
Expand Down
2 changes: 2 additions & 0 deletions src/csharp/Pester/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public Test()
public bool Explicit { get; set; }
public bool ShouldRun { get; set; }

public int StartLine { get; set; }

public bool Executed { get; set; }
public DateTime? ExecutedAt { get; set; }
public bool Passed { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/functions/Context.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ https://pester.dev/docs/usage/testdrive
}

if ($ExecutionContext.SessionState.PSVariable.Get("invokedViaInvokePester")) {
New-Block -Name $Name -ScriptBlock $Fixture -Tag $Tag -FrameworkData @{ CommandUsed = "Context" } -Focus:$Focus -Skip:$Skip
New-Block -Name $Name -ScriptBlock $Fixture -StartLine $MyInvocation.ScriptLineNumber -Tag $Tag -FrameworkData @{ CommandUsed = "Context" } -Focus:$Focus -Skip:$Skip
}
else {
if ($invokedInteractively) {
Expand Down
2 changes: 1 addition & 1 deletion src/functions/Describe.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ about_TestDrive


if ($ExecutionContext.SessionState.PSVariable.Get('invokedViaInvokePester')) {
New-Block -Name $Name -ScriptBlock $Fixture -Tag $Tag -FrameworkData @{ CommandUsed = 'Describe' } -Focus:$Focus -Skip:$Skip
New-Block -Name $Name -ScriptBlock $Fixture -StartLine $MyInvocation.ScriptLineNumber -Tag $Tag -FrameworkData @{ CommandUsed = 'Describe' } -Focus:$Focus -Skip:$Skip
}
else {
Invoke-Interactively -CommandUsed 'Describe' -ScriptName $PSCmdlet.MyInvocation.ScriptName -SessionState $PSCmdlet.SessionState -BoundParameters $PSCmdlet.MyInvocation.BoundParameters
Expand Down
4 changes: 2 additions & 2 deletions src/functions/It.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ about_should
}

if (any $TestCases) {
New-ParametrizedTest -Name $Name -ScriptBlock $Test -Data $TestCases -Tag $Tag -Focus:$Focus -Skip:$Skip
New-ParametrizedTest -Name $Name -ScriptBlock $Test -StartLine $MyInvocation.ScriptLineNumber -Data $TestCases -Tag $Tag -Focus:$Focus -Skip:$Skip
}
else {
New-Test -Name $Name -ScriptBlock $Test -Tag $Tag -Focus:$Focus -Skip:$Skip
New-Test -Name $Name -ScriptBlock $Test -StartLine $MyInvocation.ScriptLineNumber -Tag $Tag -Focus:$Focus -Skip:$Skip
}
}
4 changes: 2 additions & 2 deletions src/functions/Output.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ function Get-WriteScreenPlugin ($Verbosity) {
$text = $ReportStrings.$commandUsed -f $block.Name

if ($PesterPreference.Debug.ShowNavigationMarkers.Value) {
$text += ", $($block.ScriptBlock.File):$($block.ScriptBlock.StartPosition.StartLine)"
$text += ", $($block.ScriptBlock.File):$($block.StartLine)"
}

if (0 -eq $level -and -not $block.First) {
Expand Down Expand Up @@ -587,7 +587,7 @@ function Get-WriteScreenPlugin ($Verbosity) {
$humanTime = "$(Get-HumanTime ($_test.Duration)) ($(Get-HumanTime $_test.UserDuration)|$(Get-HumanTime $_test.FrameworkDuration))"

if ($PesterPreference.Debug.ShowNavigationMarkers.Value) {
$out += ", $($_test.ScriptBlock.File):$($_Test.ScriptBlock.StartPosition.StartLine)"
$out += ", $($_test.ScriptBlock.File):$($_Test.StartLine)"
}

$result = $_test.Result
Expand Down
32 changes: 29 additions & 3 deletions tst/Pester.RSpec.Configuration.ts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ i -PassThru:$PassThru {
'slow' -notin $runTags | Verify-True
}

t "Filtering test based on line" {
t "Filtering test based on line of It" {
$c = [PesterConfiguration]@{
Run = @{
Path = "$PSScriptRoot/testProjects/BasicTests"
Expand All @@ -333,7 +333,7 @@ i -PassThru:$PassThru {
$tests[0].Name | Verify-Equal "fails"
}

t "Filtering test based on line" {
t "Filtering tests based on line of Describe" {
$c = [PesterConfiguration]@{
Run = @{
Path = "$PSScriptRoot/testProjects/BasicTests"
Expand All @@ -350,9 +350,35 @@ i -PassThru:$PassThru {
$r = Invoke-Pester -Configuration $c
$tests = @($r.Containers.Blocks.Tests | where { $_.ShouldRun })

$tests.Count | Verify-Equal 2
$tests.Count | Verify-Equal 4
$tests[0].Name | Verify-Equal "passing"
$tests[1].Name | Verify-Equal "fails"
$tests[2].Name | Verify-Equal "passing with testcases"
$tests[3].Name | Verify-Equal "passing with testcases"
}

t "Filtering test with testcases based on line of It" {
$c = [PesterConfiguration]@{
Run = @{
Path = "$PSScriptRoot/testProjects/BasicTests"
PassThru = $true
}
Filter = @{
Line = "$PSScriptRoot/testProjects/BasicTests/folder1/file1.Tests.ps1:12"
}
Output = @{
Verbosity = 'None'
}
}

$r = Invoke-Pester -Configuration $c
$tests = @($r.Containers.Blocks.Tests | where { $_.ShouldRun })

$tests.Count | Verify-Equal 2
$tests[0].Name | Verify-Equal "passing with testcases"
$tests[0].Data.Value | Verify-Equal 1
$tests[1].Name | Verify-Equal "passing with testcases"
$tests[1].Data.Value | Verify-Equal 2
}

t "Filtering test based on name will find the test" {
Expand Down
31 changes: 10 additions & 21 deletions tst/Pester.Runtime.ts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ i -PassThru:$PassThru {
[System.Collections.IDictionary] $Data,
[String] $Id,
[ScriptBlock] $ScriptBlock,
[int] $StartLine,
[Switch] $Focus,
[Switch] $Skip
)
Expand All @@ -72,6 +73,7 @@ i -PassThru:$PassThru {
$t.Name = $Name
$t.Path = $Path
$t.Tag = $Tag
$t.StartLine = $StartLine
$t.Focus = [Bool]$Focus
$t.Skip = [Bool]$Skip
$t.Data = $Data
Expand Down Expand Up @@ -467,7 +469,7 @@ i -PassThru:$PassThru {
}

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

$f = New-FilterObject -Line "$($sb.File):$($sb.StartPosition.StartLine)"

Expand All @@ -476,7 +478,7 @@ i -PassThru:$PassThru {
}

t "Given a test with file path and line number it maybes it when it does not match the lines filter" {
$t = New-TestObject -Name "test1" -ScriptBlock { "test" }
$t = New-TestObject -Name "test1" -ScriptBlock { "test" } -StartLine 1

$f = New-FilterObject -Line "C:\file.tests.ps1:10"

Expand Down Expand Up @@ -537,25 +539,11 @@ i -PassThru:$PassThru {
}

t "re-runs failing tests" {
$sb = {
New-Block "block1" {
New-Test "test1" { "a" }
New-Block "block2" {
New-Test "test2" {
throw
}
}
}

New-Block "block3" {
New-Test "test3" {
if (-not $willPass) { throw }
}
}
}
# Tests stored in file to make StartLine predictable as it's needed for New-Block/-Test parameter for filtering to work
$testFile = "$PSScriptRoot/testProjects/RerunFailed.tests.ps1"

$willPass = $false
$pre = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)
$pre = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -Path $testFile)

# validate the precondition
$pre.Blocks[0].Tests[0].Executed | Verify-True
Expand All @@ -574,13 +562,14 @@ i -PassThru:$PassThru {
# here I have the failed tests, I need to accumulate paths
# on them and use them for filtering the run in the next run
# I should probably re-do the navigation to make it see how deep # I am in the scope, I have som Scopes prototype in the Mock imho
$lines = $pre | Where-Failed | % { "$($_.ScriptBlock.File):$($_.ScriptBlock.StartPosition.StartLine)" }

$lines = $pre | Where-Failed | % { "$($_.ScriptBlock.File):$($_.StartLine)" }
$lines.Length | Verify-Equal 2

Write-Host "`n`n`n"
# set the test3 to pass this time so we have some difference
$willPass = $true
$result = Invoke-Test -SessionState $ExecutionContext.SessionState -Filter (New-FilterObject -Line $lines ) -BlockContainer (New-BlockContainerObject -ScriptBlock $sb)
$result = Invoke-Test -SessionState $ExecutionContext.SessionState -Filter (New-FilterObject -Line $lines ) -BlockContainer (New-BlockContainerObject -Path $testFile)

$actual = @($result | View-Flat | where { $_.Executed })

Expand Down
7 changes: 7 additions & 0 deletions tst/testProjects/BasicTests/folder1/file1.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,11 @@ Describe "describe state tests" {
It "fails" {
1 | Should -Be 2
}

It "passing with testcases" -TestCases @(
@{Value = 1}
@{Value = 2}
) {
1 | Should -Be 1
}
}
16 changes: 16 additions & 0 deletions tst/testProjects/RerunFailed.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Set-StrictMode -Version Latest

New-Block "rerun block1" -StartLine 3 {
New-Test "test1" -StartLine 4 { "a" }
New-Block "rerun block2" -StartLine 5 {
New-Test "test2" -StartLine 6 {
throw
}
}
}

New-Block "rerun block3" -StartLine 12 {
New-Test "test3" -StartLine 13 {
if (-not $willPass) { throw }
}
}

0 comments on commit 459a4b7

Please sign in to comment.