new-runtimepoc/Pester.Runtime.ts.ps1

param ([switch] $PassThru)

Get-Item function:wrapper -ErrorAction SilentlyContinue | remove-item


Get-Module Pester.Runtime, P, Pester, Axiom, Stack | Remove-Module
# Import-Module Pester -MinimumVersion 4.4.3

. $PSScriptRoot\Pester.Utility.ps1
Import-Module $PSScriptRoot\Pester.Runtime.psm1 -DisableNameChecking

Import-Module $PSScriptRoot\p.psm1 -DisableNameChecking
Import-Module $PSScriptRoot\..\Dependencies\Axiom\Axiom.psm1 -DisableNameChecking

$global:PesterPreference = @{
    Debug = @{
        ShowFullErrors         = $true
        WriteDebugMessages     = $true
        WriteDebugMessagesFrom = "*Filter*"
    }
}

function Verify-TestPassed {
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        $Actual,
        $StandardOutput
    )

    if (-not $Actual.Passed) {
        throw "Test $($actual.Name) failed with $($actual.ErrorRecord.Count) errors: `n$($actual.ErrorRecord | Format-List -Force * | Out-String)"
    }

    if ($StandardOutput -ne $actual.StandardOutput) {
        throw "Expected standard output '$StandardOutput' but got '$($actual.StandardOutput)'."
    }
}

function Verify-TestFailed {
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        $Actual
    )

    if ($Actual.Passed) {
        throw "Test $($actual.Name) passed but it should have failed."
    }
}




Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

i -PassThru:$PassThru {

    & (Get-Module Pester.Runtime) {


        b "tryGetProperty" {
            t "given null it returns null" {
                tryGetProperty $null Name | Verify-Null
            }

            t "given an object that has the property it return the correct value" {
                $p = (Get-Process -Id $Pid)
                tryGetProperty $p Name | Verify-Equal $p.Name
            }
        }

        b "or" {

            t "given a non-null value it returns it" {
                "a" | or "b" | Verify-Equal "a"
            }

            t "given null it returns the default value" {
                $null | or "b" | Verify-Equal "b"
            }
        }

        b "combineNonNull" {
            t "combines values from multiple arrays, skipping nulls and empty arrays, but keeping nulls in the arrays" {
                $r = combineNonNull @(@(1, $null), @(1, 2, 3), $null, $null, 10)
                # expecting: 1, $null, 1, 2, 3, 10
                $r[0] | Verify-Equal 1
                $r[1] | Verify-Null
                $r[2] | Verify-Equal 1
                $r[3] | Verify-Equal 2
                $r[4] | Verify-Equal 3
                $r[5] | Verify-Equal 10
            }
        }

        b "any" {

            t "given a non-null value it returns true" {
                any "b" | Verify-True
            }

            t "given null it returns false" {
                any $null | Verify-False
            }

            t "given empty array it returns false" {
                any @() | Verify-False
            }

            t "given null in array it returns false" {
                any @($null) | Verify-False
            }

            t "given array with value it returns true" {
                any @("b") | Verify-True
            }

            t "given array with multiple values it returns true" {
                any @("b", "c") | Verify-True
            }
        }

        b "Basic" {
            t "Given a scriptblock with 1 test in it, it finds 1 test" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Test "test1" { }
                    }) | % Tests

                @($actual).Length | Verify-Equal 1
                $actual.Name | Verify-Equal "test1"
            }

            t "Given scriptblock with 2 tests in it it finds 2 tests" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Test "test1" { }

                        New-Test "test2" { }
                    }) | % Tests

                @($actual).Length | Verify-Equal 2
                $actual.Name[0] | Verify-Equal "test1"
                $actual.Name[1] | Verify-Equal "test2"
            }
        }

        b "block" {
            t "Given 0 tests it returns block containing no tests" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock { })

                $actual.Tests.Count | Verify-Equal 0
            }

            t "Given 0 tests it returns block containing 0 tests" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Test "test1" {}
                    })

                $actual.Tests.Count | Verify-Equal 1
            }
        }

        b "Find common setup for each test" {
            t "Given block that has test setup for each test it finds it" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-EachTestSetup {setup}
                        New-Test "test1" {}
                    })

                $actual[0].EachTestSetup | Verify-Equal 'setup'
            }
        }

        b "Finding setup for all tests" {
            t "Find setup to run before all tests in the block" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-OneTimeTestSetup {oneTimeSetup}
                        New-Test "test1" {}
                    })

                $actual[0].OneTimeTestSetup | Verify-Equal 'oneTimeSetup'
            }
        }

        b "Finding blocks" {
            t "Find tests in block that is explicitly specified" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Block "block1" {
                            New-Test "test1" {}
                        }
                    })

                $actual.Blocks[0].Tests.Count | Verify-Equal 1
                $actual.Blocks[0].Tests[0].Name | Verify-Equal "test1"
            }

            t "Find tests in blocks that are next to each other" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Block "block1" {
                            New-Test "test1" {}
                        }

                        New-Block "block2" {
                            New-Test "test2" {}
                        }
                    })

                $actual.Blocks.Count | Verify-Equal 2
                $actual.Blocks[0].Tests.Count | Verify-Equal 1
                $actual.Blocks[0].Tests[0].Name | Verify-Equal "test1"
                $actual.Blocks[1].Tests.Count | Verify-Equal 1
                $actual.Blocks[1].Tests[0].Name | Verify-Equal "test2"
            }

            t "Find tests in blocks that are inside of each other" {
                Reset-TestSuiteState
                $actual = Find-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Block "block1" {
                            New-Test "test1" {}
                            New-Block "block2" {
                                New-Test "test2" {}
                            }
                        }
                    })

                $actual.Blocks.Count | Verify-Equal 1
                $actual.Blocks[0].Tests.Count | Verify-Equal 1
                $actual.Blocks[0].Tests[0].Name | Verify-Equal "test1"

                $actual.Blocks[0].Blocks.Count | Verify-Equal 1
                $actual.Blocks[0].Blocks[0].Tests.Count | Verify-Equal 1
                $actual.Blocks[0].Blocks[0].Tests[0].Name | Verify-Equal "test2"
            }
        }

        b "Executing tests" {
            t "Executes 1 test" {
                Reset-TestSuiteState
                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Test "test1" { "a" }
                    })

                $actual.Tests[0].Executed | Verify-True
                $actual.Tests[0].Passed | Verify-True
                $actual.Tests[0].Name | Verify-Equal "test1"
                $actual.Tests[0].StandardOutput | Verify-Equal "a"
            }

            t "Executes 2 tests next to each other" {
                Reset-TestSuiteState
                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Test "test1" { "a" }
                        New-Test "test2" { "b" }
                    })

                $actual.Tests[0].Executed | Verify-True
                $actual.Tests[0].Passed | Verify-True
                $actual.Tests[0].Name | Verify-Equal "test1"
                $actual.Tests[0].StandardOutput | Verify-Equal "a"

                $actual.Tests[1].Executed | Verify-True
                $actual.Tests[1].Passed | Verify-True
                $actual.Tests[1].Name | Verify-Equal "test2"
                $actual.Tests[1].StandardOutput | Verify-Equal "b"
            }

            t "Executes 2 tests in blocks next to each other" {
                Reset-TestSuiteState
                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Block "block1" {
                            New-Test "test1" { "a" }
                        }
                        New-Block "block2" {
                            New-Test "test2" { "b" }
                        }
                    })

                $actual.Blocks[0].Name | Verify-Equal "block1"
                $actual.Blocks[0].Tests[0].Executed | Verify-True
                $actual.Blocks[0].Tests[0].Passed | Verify-True
                $actual.Blocks[0].Tests[0].Name | Verify-Equal "test1"
                $actual.Blocks[0].Tests[0].StandardOutput | Verify-Equal "a"

                $actual.Blocks[1].Name | Verify-Equal "block2"
                $actual.Blocks[1].Tests[0].Executed | Verify-True
                $actual.Blocks[1].Tests[0].Passed | Verify-True
                $actual.Blocks[1].Tests[0].Name | Verify-Equal "test2"
                $actual.Blocks[1].Tests[0].StandardOutput | Verify-Equal "b"
            }

            t "Executes 2 tests deeper in blocks" {
                Reset-TestSuiteState
                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                        New-Block "block1" {
                            New-Test "test1" { "a" }
                            New-Block "block2" {
                                New-Test "test2" { "b" }
                            }
                        }
                    })

                $actual.Blocks[0].Name | Verify-Equal "block1"
                $actual.Blocks[0].Tests[0].Executed | Verify-True
                $actual.Blocks[0].Tests[0].Passed | Verify-True
                $actual.Blocks[0].Tests[0].Name | Verify-Equal "test1"
                $actual.Blocks[0].Tests[0].StandardOutput | Verify-Equal "a"

                $actual.Blocks[0].Blocks[0].Name | Verify-Equal "block2"
                $actual.Blocks[0].Blocks[0].Tests[0].Executed | Verify-True
                $actual.Blocks[0].Blocks[0].Tests[0].Passed | Verify-True
                $actual.Blocks[0].Blocks[0].Tests[0].Name | Verify-Equal "test2"
                $actual.Blocks[0].Blocks[0].Tests[0].StandardOutput | Verify-Equal "b"
            }

            t "Executes container only if it contains anything that should run" {
                $d = @{
                    Call = 0
                }
                Reset-TestSuiteState
                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer @(
                    (New-BlockContainerObject -ScriptBlock {
                            $d.Call++
                            New-Block "block1" {
                                New-Test "test1" { "a" } -Tag "a"
                            }
                        }),
                    (New-BlockContainerObject -ScriptBlock {
                            New-Block "block1" {
                                New-Test "test1" { "a" } -Tag "b"
                            }
                        })
                ) -Filter (New-FilterObject -Tag "b")

                # should add once during discovery
                $d.Call | Verify-Equal 1

                $actual[0].Blocks[0].Tests[0].Name | Verify-Equal "test1"
                $actual[1].Blocks[0].Tests[0].Executed | Verify-True
            }
        }

        b "filtering" {

            # include = true, exclude = false, maybe = $null
            # when the filter is restrictive and the test
            t "Given null filter and a tagged test it includes it" {
                $t = New-TestObject -Name "test1" -Path "p" -Tag a

                $actual = Test-ShouldRun -Item $t -Filter $null
                $actual.Include | Verify-True
            }

            t "Given a test with tag it excludes it when it matches the exclude filter" {
                $t = New-TestObject -Name "test1" -Path "p"  -Tag a

                $f = New-FilterObject -ExcludeTag "a"

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

            t "Given a test without tags it includes it when it does not match exclude filter " {
                $t = New-TestObject -Name "test1" -Path "p"

                $f = New-FilterObject -ExcludeTag "a"

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

            t "Given a test with tags it includes it when it does not match exclude filter " {
                $t = New-TestObject -Name "test1" -Path "p" -Tag "h"

                $f = New-FilterObject -ExcludeTag "a"

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

            t "Given a test with tag it includes it when it matches the tag filter" {
                $t = New-TestObject -Name "test1" -Path "p"  -Tag a

                $f = New-FilterObject -Tag "a"

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

            t "Given a test without tags it returns `$null when it does not match any other filter" {
                $t = New-TestObject -Name "test1" -Path "p"

                $f = New-FilterObject -Tag "a"

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

            t "Given a test without tags it include it when it matches path filter" {
                $t = New-TestObject -Name "test1" -Path "p"

                $f = New-FilterObject -Tag "a" -FullName "p"

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

            t "Given a test with path it includes it when it matches path filter " {
                $t = New-TestObject -Name "test1" -Path "p"

                $f = New-FilterObject -FullName "p"

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

            t "Given a test with path it maybes it when it does not match path filter " {
                $t = New-TestObject -Name "test1" -Path "p"

                $f = New-FilterObject -FullName "r"

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

            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" })

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

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

            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" }

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

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

        b "path filter" {
            t "Given a test with path it includes it when it matches path filter " {
                $t = New-TestObject -Name "test1" -Path "r","p","s"

                $f = New-FilterObject -FullName "*s"
                $actual = Test-ShouldRun -Item $t -Filter $f
                $actual.Include | Verify-True
            }

            t "Given a test with path it maybes it when it does not match path filter " {
                $t = New-TestObject -Name "test1" -Path "r","p","s"

                $f = New-FilterObject -FullName "x"

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

        }
    }

    # outside of module

    b "discover and execute tests" {
        t "discovers and executes one test" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Test "test1" { "a" }
                })

            $actual.Tests[0].Executed | Verify-True
            $actual.Tests[0].Passed | Verify-True
            $actual.Tests[0].Name | Verify-Equal "test1"
            $actual.Tests[0].StandardOutput | Verify-Equal "a"
        }

        t "discovers and executes one failing test" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Test "test1" { throw }
                })

            $actual.Tests[0].Executed | Verify-True
            $actual.Tests[0].Passed | Verify-False
            $actual.Tests[0].Name | Verify-Equal "test1"
        }

        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 }
                    }
                }
            }

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

            # validate the precondition
            $pre.Blocks[0].Tests[0].Executed | Verify-True
            $pre.Blocks[0].Tests[0].Passed | Verify-True
            $pre.Blocks[0].Tests[0].Name | Verify-Equal "test1"
            $pre.Blocks[0].Tests[0].StandardOutput | Verify-Equal "a"

            $pre.Blocks[0].Blocks[0].Tests[0].Executed | Verify-True
            $pre.Blocks[0].Blocks[0].Tests[0].Passed | Verify-False
            $pre.Blocks[0].Blocks[0].Tests[0].Name | Verify-Equal "test2"

            $pre.Blocks[1].Tests[0].Executed | Verify-True
            $pre.Blocks[1].Tests[0].Passed | Verify-False
            $pre.Blocks[1].Tests[0].Name | Verify-Equal "test3"

            # 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.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)

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

            $actual.Length | Verify-Equal 2
            $actual[0].Name | Verify-Equal test2
            $actual[0].Executed | Verify-True
            $actual[0].Passed | Verify-False

            $actual[1].Name | Verify-Equal test3
            $actual[1].Executed | Verify-True
            $actual[1].Passed | Verify-True
        }
    }

    b "executing each setup & teardown on test" {
        t "given a test with setups and teardowns they run in correct scopes" {

            # what I want here is that the test runs in this fashion
            # so that each setup the test body and each teardown all run
            # in the same scope so their variables are accessible and writable.
            # the all setup runs one level up, so it's variables are not writable
            # to keep each test isolated from the other tests
            # block {
            # # . all setup
            # test {
            # # . each setup
            # # . body
            # # . each teardown
            # }

            # test {
            # # . each setup
            # # . body
            # # . each teardown
            # }
            # # . all teardown
            # }

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        New-OneTimeTestSetup {
                            $g = 'one time setup'
                        }
                        New-EachTestSetup {
                            if ($g -ne 'one time setup') { throw "`$g ($g) is not set to 'one time setup' did the one time setup run?"}
                            $g = 'each setup'
                        }

                        New-Test "test1" {
                            if ($g -ne 'each setup') {throw "`$g ($g) is not set to 'each setup' did the each setup run" }
                            $g = 'test'
                        }

                        New-EachTestTeardown {
                            Write-Host "each test teardown"
                            if ($g -ne 'test') {throw "`$g ($g) is not set to 'test' did the test body run? does the body run in the same scope as the setup and teardown?" }
                            $g = 'each teardown'
                        }
                        New-OneTimeTestTeardown {
                            if ($g -eq 'each teardown') { throw "`$g ($g) is set to 'each teardown', is it incorrectly running in the same scope as the each teardown? It should be running one scope above each teardown so tests are isolated from each other." }
                            if ($g -ne 'one time setup') { throw "`$g ($g) is not set to 'one time setup' did the setup run?" }
                            $g
                        }
                    }
                })
            $actual.Blocks[0].StandardOutput | Verify-Equal 'one time setup'
        }

        t "given a test with teardown it executes the teardown right before after the test and has the variables avaliable from the test" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        # if the teardown would run in block without
                        # including the test the $s would remain 'block'
                        # because setting s to test would die within that scope
                        $s = "block"

                        New-Test 'test1' {
                            $s = "test"
                            $g = "setup did not run"
                        }
                        # teardown should run here
                        $s = "teardown run too late"
                        New-EachTestTeardown {
                            $g = $s
                            $g
                        }
                    }
                })

            $actual.Blocks[0].Tests[0].StandardOutput | Verify-Equal "test"
        }
    }

    b "executing all test and teardown" {
        t "given a test with one time setup it executes the setup inside of the block and does not bleed variables to the next block" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        # one time test setup is runs here
                        New-Test 'test1' {
                            if ($g -eq '') { throw "one time setup did not run" }
                            # $g should be one scope below one time setup so this change
                            # should not be visible in the teardown
                            $g = 10

                        }
                        New-OneTimeTestSetup {
                            $g = "from setup"
                        }
                        New-OneTimeTestTeardown {
                            # teardown runs in the scope after the test scope dies so
                            # g should be 'from setup', to which the code after setup set it
                            # set it
                            $g | Verify-Equal "from setup"
                        }
                    }

                    New-Block 'block2' {
                        New-Test 'test1' {
                            $err = { Get-Variable g } | Verify-Throw
                            $err.FullyQualifiedErrorId | Verify-Equal 'VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand'
                        }
                    }
                })

            $actual.Blocks[1].Tests[0].Passed | Verify-True
            $actual.Blocks[0].StandardOutput | Verify-Equal "from setup"
        }

        t "given a test with each time setup it executes the setup inside of the test and does not affect the whole block" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        # one time test setup is runs here
                        New-Test 'test1' {
                            if ($g -eq '') { throw "one time setup did not run" }
                            # $g should be one scope below one time setup so this change
                            # should not be visible in the teardown
                            $g = "changed"

                        }
                        New-EachTestSetup {
                            $g = "from setup"
                        }
                        New-EachTestTeardown {
                            # teardown runs in the scope after the test scope dies so
                            # g should be 'from setup', to which the code after setup set it
                            # set it
                            $g | Verify-Equal "changed"
                        }

                        New-OneTimeTestTeardown {
                            $err = { Get-Variable g } | Verify-Throw
                            $err.FullyQualifiedErrorId | Verify-Equal 'VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand'
                        }
                    }
                })

            $actual.Blocks[0].Passed | Verify-True
            $actual.Blocks[0].Tests[0].Passed | Verify-True
        }

        t "setups and teardowns don't run if there are no tests" {
            $container = [PsCustomObject]@{
                OneTimeSetupRun    = $false
                EachSetupRun       = $false
                EachTeardownRun    = $false
                OneTimeTeardownRun = $false
            }

            $null = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-OneTimeTestSetup {
                        $container.OneTimeSetupRun = $true
                    }

                    New-EachTestSetup {
                        $container.EachSetupRun = $true
                    }

                    New-EachTestTeardown {
                        $container.EachTeardownRun = $true
                    }

                    New-OneTimeTestTeardown {
                        $container.OneTimeTeardownRun = $true
                    }

                    New-Block "block1" {
                        New-Block "block2" {

                        }
                    }
                })

            $container.OneTimeSetupRun | Verify-False
            $container.EachSetupRun | Verify-False
            $container.EachTeardownRun | Verify-False
            $container.OneTimeTeardownRun | Verify-False

        }

        t "one time setups&teardowns run one time and each time setups&teardowns run for every test" {
            $container = [PsCustomObject]@{
                OneTimeSetup    = 0
                EachSetup       = 0
                EachTeardown    = 0
                OneTimeTeardown = 0
            }

            $result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block "block1" {
                        New-OneTimeTestSetup {
                            $container.OneTimeSetup++
                        }

                        New-EachTestSetup {
                            $container.EachSetup++
                        }

                        New-EachTestTeardown {
                            $container.EachTeardown++
                        }

                        New-OneTimeTestTeardown {
                            $container.OneTimeTeardown++
                        }

                        New-Test "test1" {}
                        New-Test "test2" {}
                    }
                })

            # the test should execute but non of the above setups should run
            # those setups are running only for the tests in the current block

            $result.Blocks[0].Tests[0].Executed | Verify-True

            $container.OneTimeSetup | Verify-Equal 1
            $container.EachSetup | Verify-Equal 2
            $container.EachTeardown | Verify-Equal 2
            $container.OneTimeTeardown | Verify-Equal 1

        }

        t "error in one container during Run phase does not prevent the next container from running" {
            $result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer @(
                New-BlockContainerObject -ScriptBlock {
                    New-OneTimeTestSetup {
                        throw
                    }
                    New-Block "block1" {
                        New-Test "test1" {}
                    }
                }
                New-BlockContainerObject -ScriptBlock {
                    New-Block "block2" {
                        New-Test "test2" {}
                    }
                })

            $result.Blocks[0].Passed | Verify-False
            $result.Blocks[0].Executed | Verify-False
            $result.Blocks[0].Tests[0].Executed | Verify-False

            $result.Blocks[1].Executed | Verify-True
            $result.Blocks[1].Tests[0].Executed | Verify-True
        }
    }

    b "Not running tests by tags" {
        t "tests can be not run based on tags" {
            $result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Test "test1" -Tag run {}
                    New-Test "test2" {}
                }) -Filter (New-FilterObject -Tag 'Run')

            $result.Tests[0].Executed | Verify-True
            $result.Tests[1].Executed | Verify-False
        }

        t "blocks can be excluded based on tags" {
            $result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block "block1" -Tag DoNotRun {
                        New-Test "test1" {}
                    }
                }) -Filter (New-FilterObject -ExcludeTag 'DoNotRun')

            $result.Blocks[0].Tests[0].Executed | Verify-False
        }

        t "continues to second block even if the first block is excluded" {
            Reset-TestSuiteState
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block "block1" -Tag "DoNotRun" {
                        New-Test "test1" { "a" }
                    }
                    New-Block "block2" {
                        New-Test "test2" { "b" }
                    }
                }) -Filter (New-FilterObject -ExcludeTag 'DoNotRun')

            $actual.Blocks[0].Name | Verify-Equal "block1"
            $actual.Blocks[0].Tests[0].Executed | Verify-False

            $actual.Blocks[1].Name | Verify-Equal "block2"
            $actual.Blocks[1].Tests[0].Executed | Verify-True
            $actual.Blocks[1].Tests[0].Passed | Verify-True
        }

        t "continues to second test even if the first test is excluded" {
            Reset-TestSuiteState
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block "block1" {
                        New-Test "test1" { "a" } -Tag "DoNotRun"
                        New-Test "test2" { "b" }
                    }
                }) -Filter (New-FilterObject -ExcludeTag 'DoNotRun')

            $actual.Blocks[0].Name | Verify-Equal "block1"
            $actual.Blocks[0].Tests[0].Executed | Verify-False

            $actual.Blocks[0].Tests[1].Name | Verify-Equal "test2"
            $actual.Blocks[0].Tests[1].Executed | Verify-True
            $actual.Blocks[0].Tests[1].Passed | Verify-True
        }
    }

    b "Not running tests by -Skip" {
        t "skippping single test will set its result correctly" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                New-Block "block1" {
                    New-Test "test1" { "a" } -Skip
                }
            })

            $actual.Blocks[0].Tests[0].Skip | Verify-True
            $actual.Blocks[0].Tests[0].Executed | Verify-True
            $actual.Blocks[0].Tests[0].Passed | Verify-True
            $actual.Blocks[0].Tests[0].Skipped | Verify-True
            $actual.SkippedCount | Verify-Equal 1
        }

        t "skippping block will skip all tests in it" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                New-Block "skipped block" -Skip {
                    New-Test "test1" { "a" }
                }
            })

            $actual.Blocks[0].Skip | Verify-True
            $actual.Blocks[0].Tests[0].Skip | Verify-True
        }

        t "skippping block will skip child blocks in it" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                New-Block "skipped block" -Skip {
                    New-Block "skipped block" -Skip {
                        New-Test "test1" { "a" }
                    }
                }
            })

            $actual.Blocks[0].Skip | Verify-True
            $actual.Blocks[0].Blocks[0].Skip | Verify-True
            $actual.Blocks[0].Blocks[0].Tests[0].Skip | Verify-True
        }

        t "skipping a block will skip block setup and teardows" {
            $container = @{
                OneTimeTestSetup = 0
                OneTimeTestTeardown = 0
                EachTestSetup = 0
                EachTestTeardown = 0
                TestRun = 0
            }

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                New-Block "parent block" {
                    New-Block "parent block" -Skip {
                        # putting this in child block because each test setup is not supported in root block
                        New-OneTimeTestSetup -ScriptBlock { $container.OneTimeTestSetup++ }
                        New-OneTimeTestTeardown -ScriptBlock { $container.OneTimeTestTeardown++ }

                        New-EachTestSetup -ScriptBlock { $container.EachTestSetup++ }
                        New-EachTestTeardown -ScriptBlock { $container.EachTestTeardown++ }

                        New-Test "test1" {
                            $container.TestRun++
                            "a"
                        }
                    }
                }
            })

            # $actual.Blocks[0].Skip | Verify-True
            $actual.Blocks[0].ErrorRecord.Count | Verify-Equal 0
            $container.TestRun | Verify-Equal 0
            $container.OneTimeTestSetup | Verify-Equal 0
            $container.OneTimeTestTeardown | Verify-Equal 0
            $container.EachTestSetup | Verify-Equal 0
            $container.EachTestTeardown | Verify-Equal 0
        }

        t "skipping all items in a block will skip the parent block" {
            # this is not implemented, but is a possible feature
            # which could be implemented together with "if any test is explicitly unskipped in child
            # then the block should run, this will be needed for running tests explicitly by path I think
            # it also should be taken into consideration whether or not adding a lazySkip is a good idea and how it would
            # affect implementation of this. Right now skipping the block goes from parent down, and skipping all items in a block
            # will not prevent the parent block setups from running

        # $container = @{
        # OneTimeTestSetup = 0
        # OneTimeTestTeardown = 0
        # EachTestSetup = 0
        # EachTestTeardown = 0
        # TestRun = 0
        # }

        # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
        # New-Block "parent block" {
        # New-Block "parent block" {
        # # putting this in child block because each test setup is not supported in root block
        # New-OneTimeTestSetup -ScriptBlock { $container.OneTimeTestSetup++ }
        # New-OneTimeTestTeardown -ScriptBlock { $container.OneTimeTestTeardown++ }

        # New-EachTestSetup -ScriptBlock { $container.EachTestSetup++ }
        # New-EachTestTeardown -ScriptBlock { $container.EachTestTeardown++ }

        # New-Test "test1" -Skip {
        # $container.TestRun++
        # "a"
        # }

        # New-Test "test2" -Skip {
        # $container.TestRun++
        # "a"
        # }
        # }
        # }
        # })

        # # $actual.Blocks[0].Skip | Verify-True
        # $actual.Blocks[0].ErrorRecord.Count | Verify-Equal 0
        # $container.TestRun | Verify-Equal 0
        # $container.OneTimeTestSetup | Verify-Equal 0
        # $container.OneTimeTestTeardown | Verify-Equal 0
        # $container.EachTestSetup | Verify-Equal 0
        # $container.EachTestTeardown | Verify-Equal 0
        }
    }

    b "Block teardown and setup" {
        t "setups&teardowns run only once" {
            $container = [PSCustomObject] @{
                OneTimeTestSetup    = 0
                EachTestSetup       = 0
                EachTestTeardown    = 0
                OneTimeTestTeardown = 0
            }

            $null = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        New-OneTimeTestSetup { $container.OneTimeTestSetup++ }
                        New-EachTestSetup { $container.EachTestSetup++ }
                        New-Test "test1" {}
                        New-EachTestTeardown {
                            $container.EachTestTeardown++ }
                        New-OneTimeTestTeardown { $container.OneTimeTestTeardown++ }
                    }
                })

            $container.OneTimeTestSetup | Verify-Equal 1
            $container.EachTestSetup | Verify-Equal 1

            $container.EachTestTeardown | Verify-Equal 1
            $container.OneTimeTestTeardown | Verify-Equal 1
        }

        t "block setups&teardowns run only when there are some tests to run in the block" {
            $container = [PSCustomObject]@{
                OneTimeBlockSetup1    = 0
                EachBlockSetup1       = 0
                EachBlockTeardown1    = 0
                OneTimeBlockTeardown1 = 0
            }
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {

                    # New-OneTimeBlockSetup { $container.OneTimeBlockSetup1++}
                    New-EachBlockSetup {
                        $container.EachBlockSetup1++
                    }

                    New-Block 'block1' {
                        New-Test "test1" {
                            "here"
                        }
                    }

                    New-Block 'no test block' {

                    }

                    New-Block 'no running tests' {
                        New-Test "do not run test" -Tag "DoNotRun" {
                        }
                    }

                    New-EachBlockTeardown {
                        $container.EachBlockTeardown1++
                    }
                   # New-OneTimeBlockTeardown { $container.OneTimeBlockTeardown1++ }
                }) -Filter (New-FilterObject -ExcludeTag DoNotRun)

            # $container.OneTimeBlockSetup1 | Verify-Equal 1
            $container.EachBlockSetup1 | Verify-Equal 1
            $container.EachBlockTeardown1 | Verify-Equal 1
            # $container.OneTimeBlockTeardown1 | Verify-Equal 1
        }
    }

    b "plugins" {
        t "Given a plugin it is used in the run" {
            $container = [PSCustomObject] @{
                OneTimeBlockSetup    = 0
                EachBlockSetup       = 0
                OneTimeTestSetup     = 0
                EachTestSetup        = 0
                EachTestTeardown     = 0
                OneTimeTestTeardown  = 0
                EachBlockTeardown    = 0
                OneTimeBlockTeardown = 0
            }
            $p = New-PluginObject -Name "CountCalls" `
                -OneTimeBlockSetupStart { $container.OneTimeBlockSetup++ } `
                -EachBlockSetupStart { $container.EachBlockSetup++ } `
                -OneTimeTestSetupStart { $container.OneTimeTestSetup++ } `
                -EachTestSetupStart { $container.EachTestSetup++ } `
                -EachTestTeardownEnd { $container.EachTestTeardown++ } `
                -OneTimeTestTeardownEnd { $container.OneTimeTestTeardown++ } `
                -EachBlockTeardownEnd { $container.EachBlockTeardown++ } `
                -OneTimeBlockTeardownEnd { $container.OneTimeBlockTeardown++ }

            $null = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        New-Test "test1" {}
                        New-Test "test2" {}
                    }

                    New-Block 'block2' {
                        New-Test "test3" {}
                    }
                }) -Plugin $p

            $container.OneTimeBlockSetup | Verify-Equal 1
            $container.EachBlockSetup | Verify-Equal 2

            $container.OneTimeTestSetup | Verify-Equal 2
            $container.EachTestSetup | Verify-Equal 3

            $container.EachTestTeardown | Verify-Equal 3
            $container.OneTimeTestTeardown | Verify-Equal 2

            $container.EachBlockTeardown | Verify-Equal 2
            $container.OneTimeBlockTeardown | Verify-Equal 1
        }

        t "Given multiple plugins the teardowns are called in opposite order than the setups" {
            $container = [PSCustomObject] @{
                OneTimeBlockSetup    = ""
                EachBlockSetup       = ""
                OneTimeTestSetup     = ""
                EachTestSetup        = ""
                EachTestTeardown     = ""
                OneTimeTestTeardown  = ""
                EachBlockTeardown    = ""
                OneTimeBlockTeardown = ""
            }
            $p = @(
                New-PluginObject -Name "a" `
                -OneTimeBlockSetupStart { $container.OneTimeBlockSetup += "a" } `
                -EachBlockSetupStart { $container.EachBlockSetup += "a" } `
                -OneTimeTestSetupStart { $container.OneTimeTestSetup += "a" } `
                -EachTestSetupStart { $container.EachTestSetup += "a" } `
                -EachTestTeardownEnd { $container.EachTestTeardown += "a" } `
                -OneTimeTestTeardownEnd { $container.OneTimeTestTeardown += "a" } `
                -EachBlockTeardownEnd { $container.EachBlockTeardown += "a" } `
                -OneTimeBlockTeardownEnd { $container.OneTimeBlockTeardown += "a" }

                New-PluginObject -Name "b" `
                -OneTimeBlockSetupStart { $container.OneTimeBlockSetup += "b" } `
                -EachBlockSetupStart { $container.EachBlockSetup += "b" } `
                -OneTimeTestSetupStart { $container.OneTimeTestSetup += "b" } `
                -EachTestSetupStart { $container.EachTestSetup += "b" } `
                -EachTestTeardownEnd { $container.EachTestTeardown += "b" } `
                -OneTimeTestTeardownEnd { $container.OneTimeTestTeardown += "b" } `
                -EachBlockTeardownEnd { $container.EachBlockTeardown += "b" } `
                -OneTimeBlockTeardownEnd { $container.OneTimeBlockTeardown += "b" }
            )

            $null = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block 'block1' {
                        New-Test "test1" {}
                        New-Test "test2" {}
                    }

                    New-Block 'block2' {
                        New-Test "test3" {}
                    }
                }) -Plugin $p

            $container.OneTimeBlockSetup | Verify-Equal "ab"
            $container.EachBlockSetup | Verify-Equal "abab"

            $container.OneTimeTestSetup | Verify-Equal "abab"
            $container.EachTestSetup | Verify-Equal "ababab"

            $container.EachTestTeardown | Verify-Equal "bababa"
            $container.OneTimeTestTeardown | Verify-Equal "baba"

            $container.EachBlockTeardown | Verify-Equal "baba"
            $container.OneTimeBlockTeardown | Verify-Equal "ba"
        }

        t "Plugin has access to test info" {
            $container = [PSCustomObject]@{
                Test = $null
            }
            $p = New-PluginObject -Name "readContext" `
                -EachTestTeardownEnd { param($context) $container.Test = $context.Test }

            $null = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Test "test1" {}
                }) -Plugin $p

            $container.Test.Name | Verify-Equal "test1"
            $container.Test.Passed | Verify-True
        }

        t "Plugin has access to block info" {

            $container = [PSCustomObject]@{
                Block = $null
            }

            $p = New-PluginObject -Name "readContext" `
                -EachBlockSetupStart { param($context)
                $container.Block = $context.Block }

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-Test "test1" {}
                    }
                }) -Plugin $p

            $container.Block.Name | Verify-Equal "block1"
        }
    }

    b "test data" {
        t "test can access data provided in -Data as variables" {
            $container = @{
                Value1 = $null
            }

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-Test "test1" {
                            $container.Value1 = $Value1
                        } -Data @{ Value1 = 1 }
                    }
                }
            )

            $container.Value1 | Verify-Equal 1
        }

        t "test can access data provided in -Data as parameters" {
            $container = @{
                Value1 = $null
            }

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-Test "test1" {
                            param ($Value1)
                            $container.Value1 = $Value1
                        } -Data @{ Value1 = 1 }
                    }
                }
            )

            $container.Value1 | Verify-Equal 1
        }

        t "test result contains data provided in -Data" {

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-Test "test1" {

                        } -Data @{ Value1 = 1 }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Data.Value1 | Verify-Equal 1
        }

        t "tests do not share data" {

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-Test "test1" {

                        } -Data @{ Value1 = 1 }

                        New-Test "test1" {
                            if (Test-Path "variable:Value1") {
                                throw 'variable $Value1 should not be defined in this test,
                            because it leaks from the previous test'

                            }
                        } -Data @{ Value2 = 2 }
                        if (Test-Path "variable:Value1") {
                            throw 'variable $Value1 should not be defined in this block,
                            because it leaks from the previous test'

                        }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Data.Value1 | Verify-Equal 1
        }
    }
    b "New-ParametrizedTest" {
        t "New-ParameterizedTest takes data and generates as many tests as there are hashtables" {
            $data = @(
                @{ Value = 1 }
                @{ Value = 2 }
            )

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-ParametrizedTest "test" {

                        } -Data $data
                    }
                }
            )

            $actual.Blocks[0].Tests.Count | Verify-Equal 2
        }

        # #is the Id still needed? does this test have any value?
        # t "Each parametrized test has unique id and they both successfully execute and have the correct data" {
        # $data = @(
        # @{ Value = 1 }
        # @{ Value = 2 }
        # )

        # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
        # New-BlockContainerObject -ScriptBlock {
        # New-Block -Name "block1" {
        # New-ParametrizedTest "test" {

        # } -Data $data
        # }
        # }
        # )

        # $actual.Blocks[0].Tests[0].Id | Verify-Equal 0
        # $actual.Blocks[0].Tests[1].Id | Verify-Equal 1

        # $actual.Blocks[0].Tests[0].Executed | Verify-True
        # $actual.Blocks[0].Tests[1].Executed | Verify-True

        # $actual.Blocks[0].Tests[0].Passed | Verify-True
        # $actual.Blocks[0].Tests[1].Passed | Verify-True

        # $actual.Blocks[0].Tests[0].Data.Value | Verify-Equal 1
        # $actual.Blocks[0].Tests[1].Data.Value | Verify-Equal 2

        # }
    }

    b "running from files" {
        t "given a path to file with tests it can execute it" {
            $tempPath = [IO.Path]::GetTempPath() + "/" + ([Guid]::NewGuid().Guid) + ".Tests.ps1"
            try {
                $c = {
                    New-Block "block1" {
                        New-Test "test1" {
                            throw "I fail"
                        }
                    }
                }

                $c | Set-Content -Encoding UTF8 -Path $tempPath

                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -Path $tempPath)

                $actual.Blocks[0].Tests[0].Passed | Verify-False
            }
            finally {
                if (Test-Path $tempPath) {
                    Remove-Item $tempPath -Force
                }
            }
        }

        t "given a path to multiple files with tests it can execute it" {
            $tempPath = [IO.Path]::GetTempPath() + "/" + ([Guid]::NewGuid().Guid) + ".Tests.ps1"
            try {
                $c = {
                    New-Block "block1" {
                        New-Test "test1" {
                            throw "I fail"
                        }
                    }
                }

                $c | Set-Content -Encoding UTF8 -Path $tempPath

                $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (New-BlockContainerObject -Path $tempPath), (New-BlockContainerObject -Path $tempPath)

                $actual.Blocks[0].Tests[0].Passed | Verify-False
                $actual.Blocks[1].Tests[0].Passed | Verify-False
            }
            finally {
                if (Test-Path $tempPath) {
                    Remove-Item $tempPath -Force
                }
            }
        }
    }

    b "running parent each setups and teardowns" {
        t "adding each test setup runs it before each test in that block and in any child blocks" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-EachTestSetup {
                            "me"
                        }

                        New-Test "test 1" { }

                        New-Block -Name "block2" {
                            New-Test "test 2" { }
                        }
                    }

                    New-Block -Name "block3" {
                        New-Test "test 3" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].StandardOutput | Verify-Equal "me"
            $actual.Blocks[0].Blocks[0].Tests[0].StandardOutput | Verify-Equal "me"
            $actual.Blocks[1].Tests[0].StandardOutput | Verify-Null
        }

        t "adding multiple each test setups runs them in parent first, child last order " {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-EachTestSetup {
                            "parent"
                        }

                        New-Test "test 1" { }

                        New-Block -Name "block2" {
                            New-EachTestSetup {
                                "child"
                            }
                            New-Test "test 2" { }
                        }
                    }

                    New-Block -Name "block3" {
                        New-Test "test 3" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].StandardOutput -join "->" | Verify-Equal "parent"
            $actual.Blocks[0].Blocks[0].Tests[0].StandardOutput -join "->" | Verify-Equal "parent->child"
            $actual.Blocks[1].Tests[0].StandardOutput | Verify-Null
        }

        t "adding each test teardown runs it after each test in that block and in any child blocks" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-EachTestTeardown {
                            "me"
                        }

                        New-Test "test 1" { }

                        New-Block -Name "block2" {
                            New-Test "test 2" { }
                        }
                    }

                    New-Block -Name "block3" {
                        New-Test "test 3" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].StandardOutput | Verify-Equal "me"
            $actual.Blocks[0].Blocks[0].Tests[0].StandardOutput | Verify-Equal "me"
            $actual.Blocks[1].Tests[0].StandardOutput | Verify-Null
        }

        t "adding multiple each test teardowns runs them in child first, parent last order " {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-Block -Name "block1" {
                        New-EachTestTeardown {
                            "parent"
                        }

                        New-Test "test 1" { }

                        New-Block -Name "block2" {
                            New-EachTestTeardown {
                                "child"
                            }
                            New-Test "test 2" { }
                        }
                    }

                    New-Block -Name "block3" {
                        New-Test "test 3" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].StandardOutput -join "->" | Verify-Equal "parent"
            $actual.Blocks[0].Blocks[0].Tests[0].StandardOutput -join "->" | Verify-Equal "child->parent"
            $actual.Blocks[1].Tests[0].StandardOutput | Verify-Null
        }
    }

    b "failing one time block test setups and teardowns" {
        t "failing in onetime setup will fail the block and everything below" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {

                    New-Block -Name "block1" {
                        New-OneTimeTestSetup {
                            throw "error1"
                        }

                        New-Test "test 1" { }

                        New-Block -Name "block2" {
                            New-Test "test 2" { }
                        }
                    }

                    New-Block -Name "block3" {
                        New-Test "test 3" { }
                    }
                }
            )

            # everything in that first block should have
            # been running but all the inner things did not run
            # and failed
            $actual.Blocks[0].First | Verify-True
            $actual.Blocks[0].Passed | Verify-False
            $actual.Blocks[0].ShouldRun | Verify-True
            $actual.Blocks[0].Executed | Verify-True

            $actual.Blocks[0].Tests[0].Passed | Verify-False
            $actual.Blocks[0].Tests[0].ShouldRun | Verify-True
            $actual.Blocks[0].Tests[0].Executed | Verify-False

            $actual.Blocks[0].Blocks[0].Passed | Verify-False
            $actual.Blocks[0].Blocks[0].ShouldRun | Verify-True
            $actual.Blocks[0].Blocks[0].Executed | Verify-False

            $actual.Blocks[0].Blocks[0].Tests[0].Passed | Verify-False
            $actual.Blocks[0].Blocks[0].Tests[0].ShouldRun | Verify-True
            $actual.Blocks[0].Blocks[0].Tests[0].Executed | Verify-False


            # only the first block failed, but the second passed
            $actual.Blocks[1].Passed | Verify-True
            $actual.Blocks[1].ShouldRun | Verify-True
            $actual.Blocks[1].Executed | Verify-True

            $actual.Blocks[1].Tests[0].Passed | Verify-True
            $actual.Blocks[1].Tests[0].ShouldRun | Verify-True
            $actual.Blocks[1].Tests[0].Executed | Verify-True
        }

        t "failing in onetime block teardown will fail the block" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {

                    New-Block -Name "block1" {
                        New-OneTimeTestTeardown {
                            throw "error1"
                        }

                        New-Test "test 1" { }

                        New-Block -Name "block2" {
                            New-Test "test 2" { }
                        }
                    }

                    New-Block -Name "block3" {
                        New-Test "test 3" { }
                    }
                }
            )

            # the tests passed but, the block itself failed
            $actual.Blocks[0].Passed | Verify-False
            $actual.Blocks[0].ShouldRun | Verify-True
            $actual.Blocks[0].Executed | Verify-True

            $actual.Blocks[0].Tests[0].Passed | Verify-True
            $actual.Blocks[0].Tests[0].ShouldRun | Verify-True
            $actual.Blocks[0].Tests[0].Executed | Verify-True

            $actual.Blocks[0].Blocks[0].Passed | Verify-True
            $actual.Blocks[0].Blocks[0].ShouldRun | Verify-True
            $actual.Blocks[0].Blocks[0].Executed | Verify-True

            $actual.Blocks[0].Blocks[0].Tests[0].Passed | Verify-True
            $actual.Blocks[0].Blocks[0].Tests[0].ShouldRun | Verify-True
            $actual.Blocks[0].Blocks[0].Tests[0].Executed | Verify-True

            $actual.Blocks[1].Tests[0].Passed | Verify-True

            # ...but the last block
            $actual.Blocks[1].Last | Verify-True
            $actual.Blocks[1].Passed | Verify-True
        }
    }

    # focus is removed and will be replaced by pins
    # b "focus" {
    # t "focusing one test in group will run only it" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # New-Block -Name "block1" {

    # New-Test "test 1" { }

    # New-Block -Name "block2" {
    # New-Test "test 2" { }
    # }
    # }

    # New-Block -Name "block3" {
    # New-Test -Focus "test 3" { }
    # }
    # }
    # )

    # $testsToRun = @($actual | View-Flat | where { $_.ShouldRun })
    # $testsToRun.Count | Verify-Equal 1
    # $testsToRun[0].Name | Verify-Equal "test 3"
    # }

    # t "focusing one block in group will run only tests in it" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # New-Block -Focus -Name "block1" {

    # New-Test "test 1" { }

    # New-Block -Name "block2" {
    # New-Test "test 2" { }
    # }
    # }

    # New-Block -Name "block3" {
    # New-Test "test 3" { }
    # }
    # }
    # )

    # $testsToRun = $actual | View-Flat | where { $_.ShouldRun }
    # $testsToRun.Count | Verify-Equal 2
    # $testsToRun[0].Name | Verify-Equal "test 1"
    # $testsToRun[1].Name | Verify-Equal "test 2"
    # }
    # }

    # # do these tests still have value? Is the Id needed, or it is useless with the new new runtime?
    # b "generating tests" {
    # t "generating tests without external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # New-Block -Name "block1" {
    # foreach ($notUsed in 1..3) {
    # New-Test "test 1" { } # no -Id here
    # }
    # }
    # }
    # )


    # $actual.Blocks[0].ErrorRecord | Verify-Null
    # $actual.Blocks[0].Tests[2].Id | Verify-Equal 2
    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 3
    # }

    # t "generating paremetrized tests without external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # New-Block -Name "block1" {
    # foreach ($notUsed in 1..3) {
    # New-ParametrizedTest "test 1" -Data @{ Value = "a" } { }
    # }
    # }
    # }
    # )

    # $actual.Blocks[0].ErrorRecord | Verify-Null
    # $actual.Blocks[0].Tests[2].Id | Verify-Equal "2"
    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 3
    # }

    # t "generating multiple tests from one foreach without external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # New-Block -Name "block1" {
    # foreach ($notUsed in 1..3) {
    # New-Test "test 1" { } # no -Id here
    # New-Test "test 2" { } # no -Id here
    # }
    # }
    # }
    # )

    # $actual.Blocks[0].ErrorRecord | Verify-Null

    # $actual.Blocks[0].Tests[2].Name | Verify-Equal "test 1"
    # $actual.Blocks[0].Tests[2].Id | Verify-Equal 1

    # $actual.Blocks[0].Tests[3].Name | Verify-Equal "test 2"
    # $actual.Blocks[0].Tests[3].Id | Verify-Equal 1

    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 6
    # }

    # t "generating tests with external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # New-Block -Name "block1" {
    # foreach ($id in 80..82) {
    # New-Test "test 1" { } -Id $id
    # }
    # }
    # }
    # )

    # $actual.Blocks[0].ErrorRecord | Verify-Null
    # $actual.Blocks[0].Tests[2].Id | Verify-Equal 82
    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 3
    # }
    # }

    # # do these tests still have value? Is the Id needed, or it is useless with the new new runtime?
    # b "generating blocks" {
    # t "generating blocks without external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {
    # foreach ($notUsed in 1..3) {
    # New-Block -Name "block1" {
    # New-Test "test 1" { }
    # } # no -Id here
    # }
    # }
    # )


    # $actual.Blocks[1].ErrorRecord | Verify-Null
    # $actual.Blocks[1].Id | Verify-Equal 1
    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 3
    # }

    # t "generating multiple blocks from one foreach without external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # foreach ($notUsed in 1..3) {
    # New-Block -Name "block1" {
    # New-Test "test 1" { }
    # } # no -Id here

    # New-Block -Name "block2" {
    # New-Test "test 2" { }
    # } # no -Id here
    # }
    # }
    # )

    # $actual.Blocks[0].ErrorRecord | Verify-Null
    # $actual.Blocks[0].Id | Verify-Equal 0 # block1-0

    # $actual.Blocks[1].ErrorRecord | Verify-Null
    # $actual.Blocks[1].Id | Verify-Equal 0 # block2-0

    # $actual.Blocks[2].ErrorRecord | Verify-Null
    # $actual.Blocks[2].Id | Verify-Equal 1 # block1-1

    # $actual.Blocks[3].ErrorRecord | Verify-Null
    # $actual.Blocks[3].Id | Verify-Equal 1 # block2-1

    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 6
    # }

    # t "generating blocks with external id" {
    # $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
    # New-BlockContainerObject -ScriptBlock {

    # foreach ($id in 80..82) {
    # New-Block -Name "block1" {
    # New-Test "test 1" { }
    # } -Id $id
    # }
    # }
    # )

    # $actual.Blocks[0].ErrorRecord | Verify-Null
    # $actual.Blocks[2].Id | Verify-Equal 82
    # $passedTests = @($actual | View-Flat | where { $_.Passed })
    # $passedTests.Count | Verify-Equal 3
    # }
    # }

    b "expandable variables in names" {
        t "can run tests that have expandable variable in their name" {
            # this should cause no problems, the test name is the same during
            # discovery and run, so they can easily match

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    $v = 1
                    New-Block -Name "b1" {
                        New-Test "$v" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Passed | Verify-True
        }

        t "can run tests that have expandable variable in their name that changes values between discovery and run" {

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    $v = (Get-Date).Ticks
                    New-Block -Name "b1" {
                        New-Test "$v" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Passed | Verify-True
        }

        t "can run blocks that have expandable variable in their name" {
            # this should cause no problems, the block name is the same during
            # discovery and run, so they can easily match

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    $v = 1
                    New-Block -Name "$v" {
                        New-Test "t1" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Passed | Verify-True
        }

        t "can run blocks that have expandable variable in their name that changes value between discovery and run" {

            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    $v = (Get-Date).Ticks
                    New-Block -Name "$v" {
                        New-Test "t1" { }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Passed | Verify-True
        }
    }

    b "expanding values in names of parametrized tests" {
        t "strings expand in the name" {
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    $v = 1
                    New-Block -Name "b1" {
                        New-ParametrizedTest "Hello <name>." -Data @{ Name = "Jakub" } {
                            $true
                        }
                    }
                }
            )

            $actual.Blocks[0].Tests[0].Name | Verify-Equal  "Hello <name>."
            $actual.Blocks[0].Tests[0].ExpandedName | Verify-Equal  "Hello Jakub."
        }
    }

    b "timing" {

        t "total time is roughly the same as time measured externally" {
            $container = @{
                # Test = $null
                # Block = $null
                Total = $null
                Result = $null
            }

            $container.Total = Measure-Command {
                $container.Result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                    New-BlockContainerObject -ScriptBlock {
                        New-Block -Name "b1" {
                            New-Test "t1" {
                                $true | Verify-False
                            }
                        }
                    })
            }
            # some of the code is commented out here because before changing the runtime to the new-new runtime
            # I was able to measure the block and the test execution time and so if I come up with a way again
            # I don't want to write the same code one more time
            $actual = $container.Result
            $testReported = $actual.Blocks[0].Tests[0].Duration + $actual.Blocks[0].Tests[0].FrameworkDuration
            #$testDifference = $container.Test - $testReported
            Write-Host Reported test duration $actual.Blocks[0].Tests[0].Duration.TotalMilliseconds
            Write-Host Reported test overhead $actual.Blocks[0].Tests[0].FrameworkDuration.TotalMilliseconds
            Write-Host Reported test total $testReported.TotalMilliseconds
            #Write-Host Measured test total $container.Test.TotalMilliseconds
            #Write-Host Test difference $testDifference.TotalMilliseconds
            # the difference here is actually <1ms but let's make this less finicky
           # $testDifference.TotalMilliseconds -lt 5 | Verify-True

            # so the block non aggregated time is mostly correct (to get the total time we need to add total blockduration + total test duration), but the overhead is accounted twice because we have only one timer running so the child overhead is included in the child and the parent ( that is the FrameworkDuration on Block is actually Aggregated framework duration),
            $blockReported =  $actual.Blocks[0].Duration + $actual.Blocks[0].FrameworkDuration
            #$blockDifference = $container.Block - $blockReported
            Write-Host Reported block duration $actual.Blocks[0].Duration.TotalMilliseconds
            Write-Host Reported block overhead $actual.Blocks[0].FrameworkDuration.TotalMilliseconds
            Write-Host Reported block total $blockReported.TotalMilliseconds
            #Write-Host Measured block total $container.Block.TotalMilliseconds
            #Write-Host Block difference $blockDifference.TotalMilliseconds

            # the difference here is actually <1ms but let's make this less finicky
            #$blockDifference.TotalMilliseconds -lt 5 | Verify-True

            $totalReported = $actual.Duration + $actual.FrameworkDuration + $actual.DiscoveryDuration
            $totalDifference = $container.Total - $totalReported
            Write-Host Reported total duration $actual.Duration.TotalMilliseconds
            Write-Host Reported total overhead $actual.FrameworkDuration.TotalMilliseconds
            Write-Host Reported total $totalReported.TotalMilliseconds
            Write-Host Measured total $container.Total.TotalMilliseconds
            Write-Host Total difference $totalDifference.TotalMilliseconds

            # the difference here is because of the code that is running after all tests have been discovered
            # such as figuring out if there are focused tests, setting filters and determining which tests to run
            # this needs to be done over all blocks at the same time because of the focused tests
            # the difference here is actually <10ms but let's make this less finicky
            $totalDifference.TotalMilliseconds -lt 100 | Verify-True
        }


        t "total time is roughly the same as time measured externally (measured on a second test)" {
            # this is the same as above, if I add one time setups then the framework time should grow
            # but not the user code time
            $container = @{
                Test = $null
                Block = $null
                Total = $null
                Result = $null
            }

            $container.Total = Measure-Command {
                $container.Result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                    New-BlockContainerObject -ScriptBlock {
                        New-Block "b1" {
                        }

                        New-Block -Name "b2" {
                            New-Test "t1" { $true }
                            New-Test "t2" {
                                $true | Verify-False
                            }
                        }
                    }
                )
            }

            $actual = $container.Result
            $testReported = $actual.Blocks[1].Tests[1].Duration + $actual.Blocks[1].Tests[1].FrameworkDuration
            # $testDifference = $container.Test - $testReported
            Write-Host Reported test duration $actual.Blocks[1].Tests[1].Duration.TotalMilliseconds
            Write-Host Reported test overhead $actual.Blocks[1].Tests[1].FrameworkDuration.TotalMilliseconds
            Write-Host Reported test total $testReported.TotalMilliseconds
            # Write-Host Measured test total $container.Test.TotalMilliseconds
            # Write-Host Test difference $testDifference.TotalMilliseconds
            # the difference here is actually <1ms but let's make this less finicky
            # $testDifference.TotalMilliseconds -lt 5 | Verify-True

            # so the block non aggregated time is mostly correct (to get the total time we need to add total blockduration + total test duration), but the overhead is accounted twice because we have only one timer running so the child overhead is included in the child and the parent ( that is the FrameworkDuration on Block is actually Aggregated framework duration),
            $blockReported =  $actual.Blocks[1].Duration + $actual.Blocks[1].FrameworkDuration
            # $blockDifference = $container.Block - $blockReported
            Write-Host Reported block duration $actual.Blocks[1].Duration.TotalMilliseconds ms
            Write-Host Reported block overhead $actual.Blocks[1].FrameworkDuration.TotalMilliseconds ms
            Write-Host Reported block total $blockReported.TotalMilliseconds ms
            # Write-Host Measured block total $container.Block.TotalMilliseconds ms
            # Write-Host Block difference $blockDifference.TotalMilliseconds ms

            # the difference here is actually <1ms but let's make this less finicky
            # $blockDifference.TotalMilliseconds -lt 5 | Verify-True

            $totalReported = $actual.Duration + $actual.FrameworkDuration + $actual.DiscoveryDuration
            $totalDifference = $container.Total - $totalReported
            Write-Host Reported total duration $actual.Duration.TotalMilliseconds ms
            Write-Host Reported total overhead $actual.FrameworkDuration.TotalMilliseconds ms
            Write-Host Reported total $totalReported.TotalMilliseconds ms
            Write-Host Measured total $container.Total.TotalMilliseconds ms
            Write-Host Total difference $totalDifference.TotalMilliseconds ms

            # the difference here is because of the code that is running after all tests have been discovered
            # such as figuring out if there are focused tests, setting filters and determining which tests to run
            # this needs to be done over all blocks at the same time because of the focused tests
            # the difference here is actually <10ms but let's make this less finicky
            $totalDifference.TotalMilliseconds -lt 100 | Verify-True
        }

        t "total time is roughly the same as time measured externally (on many tests)" {
            # this is the same as above, if I add one time setups then the framework time should grow
            # but not the user code time
            $container = @{
                Test = $null
                Block = $null
                Total = $null
                Result = $null
            }

            $cs = 1..2
            $bs = 1..10
            $ts = 1..10

            $container.Total = Measure-Command {
                $container.Result = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer $(
                    foreach ($c in $cs) {
                        New-BlockContainerObject -ScriptBlock {
                            foreach ($b in $bs) {
                                New-Block -Name "b$b" {
                                    foreach ($t in $ts) {
                                        New-Test "b$b-t$t" {
                                            $true | Verify-True
                                        }
                                    }
                                }
                            }
                        }
                    }
                )
            }

            $actual = $container.Result


            $actualDuration = $actual.Duration | % { $t = [timespan]::zero } { $t += $_ } { $t }
            $actualFrameworkDuration = $actual.FrameworkDuration | % { $t = [timespan]::zero } { $t += $_ } { $t }
            $actualDiscoveryDuration = $actual.DiscoveryDuration | % { $t = [timespan]::zero } { $t += $_ } { $t }
            $totalReported = $actualDuration + $actualFrameworkDuration + $actualDiscoveryDuration
            $totalDifference = $container.Total - $totalReported
            $testCount = $cs.Count * $bs.Count * $ts.Count
            Write-Host Test count $testCount
            Write-Host Per test $([int]($container.Total.TotalMilliseconds / $testCount)) ms
            Write-Host Per test without discovery $([int](($actualDuration + $actualFrameworkDuration).TotalMilliseconds / $testCount)) ms
            Write-Host Reported discovery duration $actualDiscoveryDuration.TotalMilliseconds ms
            Write-Host Reported total duration $actualDuration.TotalMilliseconds ms
            Write-Host Reported total overhead $actualFrameworkDuration.TotalMilliseconds ms
            Write-Host Reported total $totalReported.TotalMilliseconds ms
            Write-Host Measured total $container.Total.TotalMilliseconds ms
            Write-Host Total difference $totalDifference.TotalMilliseconds ms


            # the difference here is because of the code that is running after all tests have been discovered
            # such as figuring out if there are focused tests, setting filters and determining which tests to run
            # this needs to be done over all blocks at the same time because of the focused tests
            # the difference here is actually <10ms but let's make this less finicky
            $totalDifference.TotalMilliseconds -lt 100 | Verify-True

            # TODO: revisit the difference on many tests, it is still missing some parts of the common discovery processing I guess (replicates on 10k tests)
        }
    }

    b "Setup and Teardown on root block" {
        t "OneTimeTestSetup is invoked when placed in the script root" {
            # the one time test setup that is placed in the top level block should
            # be invoked before the first inner block runs and should be scoped to the
            # outside of the block so the setup is shared with other blocks
            # that follow the first block
            $container = @{
                OneTimeTestSetup = 0
                ValueInTestInFirstBlock = ''
                ValueInTestInSecondBlock = ''
            }
            $actual = Invoke-Test -SessionState $ExecutionContext.SessionState -BlockContainer (
                New-BlockContainerObject -ScriptBlock {
                    New-OneTimeTestSetup {
                        $container.OneTimeTestSetup++
                        $outside = "outside"
                    }

                    New-Block -Name "b1" {
                        New-Test "t1" {
                            $true
                            $container.ValueInTestInFirstBlock = $outside
                        }
                    }

                    New-Block -name "b2" {
                        New-Test "b2" {
                            $true
                            $container.ValueInTestInSecondBlock = $outside
                        }
                    }

                }
            )

            $container.OneTimeTestSetup | Verify-Equal 1
            $container.ValueInTestInFirstBlock | Verify-Equal "outside"
            $container.ValueInTestInSecondBlock | Verify-Equal "outside"
        }
    }
}



# SIG # Begin signature block
# MIIcVgYJKoZIhvcNAQcCoIIcRzCCHEMCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU7c+8Ff0uvXP7tO4sXxiN26+r
# w6uggheFMIIFDjCCA/agAwIBAgIQCIQ1OU/QbU6rESO7M78utDANBgkqhkiG9w0B
# AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz
# c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDEzMTAwMDAwMFoXDTIxMDEw
# NTEyMDAwMFowSzELMAkGA1UEBhMCQ1oxDjAMBgNVBAcTBVByYWhhMRUwEwYDVQQK
# DAxKYWt1YiBKYXJlxaExFTATBgNVBAMMDEpha3ViIEphcmXFoTCCASIwDQYJKoZI
# hvcNAQEBBQADggEPADCCAQoCggEBALYF0cDtFUyYgraHpHdObGJM9dxjfRr0WaPN
# kVZcEHdPXk4bVCPZLSca3Byybx745CpB3oejDHEbohLSTrbunoSA9utpwxVQSutt
# /H1onVexiJgwGJ6xoQgR17FGLBGiIHgyPhFJhba9yENh0dqargLWllsg070WE2yb
# gz3m659gmfuCuSZOhQ2nCHvOjEocTiI67mZlHvN7axg+pCgdEJrtIyvhHPqXeE2j
# cdMrfmYY1lq2FBpELEW1imYlu5BnaJd/5IT7WjHL3LWx5Su9FkY5RwrA6+X78+j+
# vKv00JtDjM0dT+4A/m65jXSywxa4YoGDqQ5n+BwDMQlWCzfu37sCAwEAAaOCAcUw
# ggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBRE
# 05R/U5mVzc4vKq4rvKyyPm12EzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
# KwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQu
# Y29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRp
# Z2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwGA1UdIARFMEMwNwYJ
# YIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv
# bS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0
# dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZCaHR0cDovL2NhY2Vy
# dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRENvZGVTaWduaW5n
# Q0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBADAk7PRuDcdl
# lPZQSfZ1Y0jeItmEWPMNcAL0LQaa6M5Slrznjxv1ZiseT9SMWTxOQylfPvpOSo1x
# xV3kD7qf7tf2EuicKkV6dBgGiHb0riWZ3+wMA6C8IK3cGesJ4jgpTtYEzbh88pxT
# g2MSzpRnwyXHhrgcKSps1z34JmmmHP1lncxNC6DTM6yEUwE7XiDD2xNoeLITgdTQ
# jjMMT6nDJe8+xL0Zyh32OPIyrG7qPjG6MmEjzlCaWsE/trVo7I9CSOjwpp8721Hj
# q/tIHzPFg1C3dYmDh8Kbmr21dHWBLYQF4P8lq8u8AYDa6H7xvkx7G0i2jglAA4YK
# i1V8AlyTwRkwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3
# DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAX
# BgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3Vy
# ZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ
# RCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl
# +YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQz
# UHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNx
# PqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqr
# hPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItq
# cyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/
# AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEF
# BQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBD
# BggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2Ny
# bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDig
# NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYc
# aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4E
# FgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGL
# p6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0c
# LToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9x
# jmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpx
# KAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUI
# QjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhiz
# gZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggZq
# MIIFUqADAgECAhADAZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUAMGIxCzAJ
# BgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
# aWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMTAe
# Fw0xNDEwMjIwMDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYTAlVTMREw
# DwYDVQQKEwhEaWdpQ2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0YW1wIFJl
# c3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNkXfx8s+CC
# NeDg9sYq5kl1O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85vZu7dy4Xp
# X6X51Id0iEQ7Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmejvmGfrvP9
# Enh1DqZbFP1FI46GRFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFyGGi5uHzu
# 5uc0LzF3gTAfuzYBje8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjHyQYuRhDI
# jegEYNu8c3T6Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr7GJCkawC
# wO+k8IkRj3cCAwEAAaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E
# AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIwggGh
# BglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy
# dC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAA
# bwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMA
# dABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgA
# ZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgA
# ZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4A
# dAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAA
# YQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIA
# ZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwDFTAf
# BgNVHSMEGDAWgBQVABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQUYVpNJLZJ
# Mp1KKnkag0v0HonByn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSGMmh0dHA6
# Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEuY3JsMHcG
# CCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu
# Y29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln
# aUNlcnRBc3N1cmVkSURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAnSV+GzNN
# siaBXJuGziMgD4CH5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA+94GAYw3
# +puxnSR+/iCkV61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n4hFBpr1i
# 2fAnPTgdKG86Ugnw7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OPQ6dxnSHd
# FMoVXZJB2vkPgdGZdA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xIJ2bIo4sK
# HOWV2q7ELlmgYd3a822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g9BQKOhvj
# jz3Kr2qNe9zYRDCCBs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhswDQYJKoZI
# hvcNAQEFBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNz
# dXJlZCBJRCBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAwMFow
# YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJRCBD
# QS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnKwkKVpYBz
# QHDSnlZUXKnE0kEGj8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InECtqvy15r
# 7a2wcTHrzzpADEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH6zY/2DDD
# /6b3+6LNb3Mj/qxWBZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77blUjE7h6z
# 8rwMK5nQxl0SQoHhg26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnxTPKvmPv2
# zkBdXPao8S+v7Iki8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2KkPzIUYJX9
# BwSiCQIDAQABo4IDejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0MDIGCCsG
# AQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCDCC
# AdIGA1UdIASCAckwggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYBBQUHAgEW
# Lmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0w
# ggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgA
# aQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQA
# ZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcA
# aQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwA
# eQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkA
# YwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEA
# cgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIA
# eQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1UdEwEB/wQI
# MAYBAf8CAQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
# cC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgw
# OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
# RFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdp
# Q2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZB+0e36K+
# Vw0rZwLNMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3
# DQEBBQUAA4IBAQBGUD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/sdR90OPKy
# XGGinJXDUOSCuSPRujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZVann4+er
# Ys37iy2QwsDStZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQlc+Qqq8+c
# dkvtX8JLFuRLcEwAiR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dFzdaD7eeS
# DY2xaYxP+1ngIw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsYGk38KiGt
# STGDR5V3cdyxG0tLHBCcdxTBnU8vWpUIKRAmMYIEOzCCBDcCAQEwgYYwcjELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENv
# ZGUgU2lnbmluZyBDQQIQCIQ1OU/QbU6rESO7M78utDAJBgUrDgMCGgUAoHgwGAYK
# KwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIB
# BDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQU
# NjzB7R2qiiQbv8D9bUB+rQkYVgUwDQYJKoZIhvcNAQEBBQAEggEAsfFhhXzNpwIf
# lxvu1n0oAH2ifzpE0jOBty4yjlg0hBXs0e1Hjw5IVwouf7PDN4ck/ILt6l3jmTdB
# A82jZekgjWEnO6LeKRrAltT9THt0y8pxvziGw7kDJLrq82Ts1Irhg48Kt3NS+U0O
# 9YaMKa9bYChLg9S4ncZscxMkJLWsaIlDGKyOdYT+cnY9nCVdvlmNPWlOGY96xsFa
# IdhuKKT+C1DBj6rdYlHXUaHDtNjFCpnoBj1NDFwbUfj7k6thsZkASJzVBCzTp2vq
# h/hmTrsDkptHOXvXdmBRDb1HQNeWIxD6vOLGnqqvkXBD0cIX88bTmHbu1NKoY+R+
# lyio3qPA9KGCAg8wggILBgkqhkiG9w0BCQYxggH8MIIB+AIBATB2MGIxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMQIQAwGa
# Ajr/WLFr1tXq5hfwZjAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3
# DQEHATAcBgkqhkiG9w0BCQUxDxcNMjAwNDE0MTgzOTI0WjAjBgkqhkiG9w0BCQQx
# FgQUBUgV6Qq9khmONajxgEPo5CK0nSowDQYJKoZIhvcNAQEBBQAEggEATtNJRoyX
# ty1E6Vaynn7Orjueux+tz1rIHd87WQz5G7kc27Yr3HXjCwjVIr9ITYhRmryn8lXB
# vV3fgOaD9wB4khqVlPB+h7kmx1M2KX6TKmGMeWOtYI7uG4IUYl5eoKs9hboHxfk/
# q9z1XGu1n/7aiElaPokBpkM/OBszZRPRQsyFM96vM7eFQD29GcvgM5/xTEoBl2i8
# 0XtYD6BQGNcJhqXfSTwqoh8oF40wkEh1CS8yxrJQ1ZqY/D+B60UFZi6SRDHDzRBp
# JGBf+p1LnmcQoQuH9td7uq3zd1obYSSCN3oFdv1W7VzyFVwKk7D+GJkl/f83O/uQ
# VxDIkMpcgG8T+A==
# SIG # End signature block