Skip to content

Commit

Permalink
-Path updates
Browse files Browse the repository at this point in the history
This is a first crack at resolving issues pester#270 and pester#271 .  I haven't written any tests around this new code yet, but it does successfully run all of Pester's existing tests (except for those looking specifically for the -Path parameter on New-PesterState; that's been removed since nothing but Invoke-Pester was actually looking at it.)
  • Loading branch information
dlwyatt committed Jan 27, 2015
1 parent 30a9689 commit 94821ab
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 73 deletions.
10 changes: 0 additions & 10 deletions Functions/Coverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,6 @@ function Get-CoverageInfoFromDictionary
return New-CoverageInfo -Path $path -StartLine $startLine -EndLine $endLine -Function $function
}

function Get-DictionaryValueFromFirstKeyFound
{
param ([System.Collections.IDictionary] $Dictionary, [object[]] $Key)

foreach ($keyToTry in $Key)
{
if ($Dictionary.Contains($keyToTry)) { return $Dictionary[$keyToTry] }
}
}

function Convert-UnknownValueToInt
{
param ([object] $Value, [int] $DefaultValue = 0)
Expand Down
55 changes: 13 additions & 42 deletions Functions/PesterState.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,32 @@ Set-StrictMode -Version Latest

InModuleScope Pester {
Describe "New-PesterState" {
it "Path is mandatory parameter" {
(get-command New-PesterState ).Parameters.Path.ParameterSets.__AllParameterSets.IsMandatory | Should Be $true
}

Context "Path parameter is set" {
it "sets the path property" {
$p = new-pesterstate -path "path"
$p.Path | should be "path"
}
}

Context "Path and TestNameFilter parameter is set" {
$p = new-pesterstate -path "path" -TestNameFilter "filter"

it "sets the path property" {
$p.Path | should be "path"
}
Context "TestNameFilter parameter is set" {
$p = new-pesterstate -TestNameFilter "filter"

it "sets the TestNameFilter property" {
$p.TestNameFilter | should be "filter"
}

}
Context "Path and TagFilter parameter are set" {
$p = new-pesterstate -path "path" -TagFilter "tag","tag2"

it "sets the path property" {
$p.Path | should be "path"
}
Context "TagFilter parameter is set" {
$p = new-pesterstate -TagFilter "tag","tag2"

it "sets the TestNameFilter property" {
$p.TagFilter | should be ("tag","tag2")
}
}
Context "Path and ExcludeTagFilter parameter are set" {
$p = new-pesterstate -path "path" -ExcludeTagFilter "tag3", "tag"

it "sets the path property" {
$p.Path | should be "path"
}
Context "ExcludeTagFilter parameter is set" {
$p = new-pesterstate -ExcludeTagFilter "tag3", "tag"

it "sets the ExcludeTagFilter property" {
$p.ExcludeTagFilter | should be ("tag3", "tag")
}
}
Context "Path, TagFilter and ExcludeTagFilter parameter are set" {
$p = new-pesterstate -path "path" -TagFilter "tag","tag2" -ExcludeTagFilter "tag3"

it "sets the path property" {
$p.Path | should be "path"
}

Context "TagFilter and ExcludeTagFilter parameter are set" {
$p = new-pesterstate -TagFilter "tag","tag2" -ExcludeTagFilter "tag3"

it "sets the TestNameFilter property" {
$p.TagFilter | should be ("tag","tag2")
Expand All @@ -62,12 +37,8 @@ InModuleScope Pester {
$p.ExcludeTagFilter | should be ("tag3")
}
}
Context "Path TestNameFilter and TagFilter parameter is set" {
$p = new-pesterstate -path "path" -TagFilter "tag","tag2" -testnamefilter "filter"

it "sets the path property" {
$p.Path | should be "path"
}
Context "TestNameFilter and TagFilter parameter is set" {
$p = new-pesterstate -TagFilter "tag","tag2" -testnamefilter "filter"

it "sets the TestNameFilter property" {
$p.TagFilter | should be ("tag","tag2")
Expand All @@ -81,7 +52,7 @@ InModuleScope Pester {
}

Describe "Pester state object" {
$p = New-PesterState -Path "Local"
$p = New-PesterState

Context "entering describe" {
It "enters describe" {
Expand Down Expand Up @@ -254,7 +225,7 @@ InModuleScope Pester {
}

Context "Path and TestNameFilter parameter is set" {
$strict = New-PesterState -path "path" -Strict
$strict = New-PesterState -Strict

It "Keeps Passed state" {
$strict.AddTestResult("test","Passed")
Expand Down
9 changes: 2 additions & 7 deletions Functions/PesterState.ps1
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
function New-PesterState
{
param (
[Parameter(Mandatory=$true)]
[String]$Path,
[String[]]$TagFilter,
[String[]]$ExcludeTagFilter,
[String[]]$TestNameFilter,
Expand All @@ -15,7 +13,6 @@ function New-PesterState

New-Module -Name Pester -AsCustomObject -ScriptBlock {
param (
[String]$_path,
[String[]]$_tagFilter,
[String[]]$_excludeTagFilter,
[String[]]$_testNameFilter,
Expand All @@ -25,7 +22,6 @@ function New-PesterState
)

#public read-only
$Path = $_path
$TagFilter = $_tagFilter
$ExcludeTagFilter = $_excludeTagFilter
$TestNameFilter = $_testNameFilter
Expand Down Expand Up @@ -182,8 +178,7 @@ function New-PesterState
} | Microsoft.PowerShell.Utility\Select-Object Describe, Context, Name, Result, Passed, Time, FailureMessage, StackTrace, ParameterizedSuiteName, Parameters
}

$ExportedVariables = "Path",
"TagFilter",
$ExportedVariables = "TagFilter",
"ExcludeTagFilter",
"TestNameFilter",
"TestResult",
Expand Down Expand Up @@ -214,7 +209,7 @@ function New-PesterState
"AddTestResult"

Export-ModuleMember -Variable $ExportedVariables -function $ExportedFunctions
} -ArgumentList $Path, $TagFilter, $ExcludeTagFilter, $TestNameFilter, $SessionState, $Strict, $Quiet |
} -ArgumentList $TagFilter, $ExcludeTagFilter, $TestNameFilter, $SessionState, $Strict, $Quiet |
Add-Member -MemberType ScriptProperty -Name Scope -Value {
if ($this.CurrentTest) { 'It' }
elseif ($this.CurrentContext) { 'Context' }
Expand Down
111 changes: 97 additions & 14 deletions Pester.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,15 @@ about_pester
param(
[Parameter(Position=0,Mandatory=0)]
[Alias('relative_path')]
[string]$Path = ".",
[object[]]$Path = '.',

[Parameter(Position=1,Mandatory=0)]
[Alias("Name")]
[string[]]$TestName,

[Parameter(Position=2,Mandatory=0)]
[switch]$EnableExit,

[Parameter(Position=3,Mandatory=0, ParameterSetName = 'LegacyOutputXml')]
[string]$OutputXml,

Expand All @@ -143,6 +146,7 @@ about_pester
[switch]$PassThru,

[object[]] $CodeCoverage = @(),

[Switch]$Strict,

[Parameter(Mandatory = $true, ParameterSetName = 'NewOutputSet')]
Expand All @@ -151,6 +155,7 @@ about_pester
[Parameter(Mandatory = $true, ParameterSetName = 'NewOutputSet')]
[ValidateSet('LegacyNUnitXml', 'NUnitXml')]
[string] $OutputFormat,

[Switch]$Quiet
)

Expand All @@ -166,30 +171,35 @@ about_pester

$script:mockTable = @{}

$pester = New-PesterState -Path (Resolve-Path $Path) -TestNameFilter $TestName -TagFilter ($Tag -split "\s") -ExcludeTagFilter ($ExcludeTag -split "\s") -SessionState $PSCmdlet.SessionState -Strict:$Strict -Quiet:$Quiet
$pester = New-PesterState -TestNameFilter $TestName -TagFilter ($Tag -split "\s") -ExcludeTagFilter ($ExcludeTag -split "\s") -SessionState $PSCmdlet.SessionState -Strict:$Strict -Quiet:$Quiet
Enter-CoverageAnalysis -CodeCoverage $CodeCoverage -PesterState $pester

$message = "Executing all tests in '$($pester.Path)'"
if ($TestName) { $message += " matching test name '$TestName'" }
$invokeTestScript = {
param (
[Parameter(Position = 0)]
[string] $Path,

Write-Screen $message
[object[]] $Arguments = @(),
[System.Collections.IDictionary] $Parameters = @{}
)

& $Path @Parameters @Arguments
}

$scriptBlock = { & $args[0] }
Set-ScriptBlockScope -ScriptBlock $scriptBlock -SessionState $PSCmdlet.SessionState
Set-ScriptBlockScope -ScriptBlock $invokeTestScript -SessionState $PSCmdlet.SessionState

Get-ChildItem $pester.Path -Filter "*.Tests.ps1" -Recurse |
where { -not $_.PSIsContainer } |
foreach {
$testFile = $_
$testScripts = ResolveTestScripts $Path

foreach ($testScript in $testScripts)
{
try
{
& $scriptBlock $testFile.PSPath
& $invokeTestScript -Path $testScript.Path -Arguments $testScript.Arguments -Parameters $testScript.Parameters
}
catch
{
$firstStackTraceLine = $_.ScriptStackTrace -split '\r?\n' | Select-Object -First 1
$pester.AddTestResult("Error occurred in test script '$($testFile.FullName)'", "Failed", $null, $_.Exception.Message, $firstStackTraceLine)
$pester.AddTestResult("Error occurred in test script '$($testScript.Path)'", "Failed", $null, $_.Exception.Message, $firstStackTraceLine)
$pester.TestResult[-1] | Write-PesterResult
}
}
Expand All @@ -199,7 +209,6 @@ about_pester
Show-CoverageReport -CoverageReport $coverageReport
Exit-CoverageAnalysis -PesterState $pester


if($OutputFile) {
Export-PesterResults -PesterState $pester -Path $OutputFile -Format $OutputFormat
}
Expand All @@ -221,6 +230,80 @@ about_pester
if ($EnableExit) { Exit-WithCode -FailedCount $pester.FailedCount }
}

function ResolveTestScripts
{
param ([object[]] $Path)

$resolvedScriptInfo = @(
foreach ($object in $Path)
{
if ($object -is [System.Collections.IDictionary])
{
$unresolvedPath = Get-DictionaryValueFromFirstKeyFound -Dictionary $object -Key 'Path', 'p'
$arguments = Get-DictionaryValueFromFirstKeyFound -Dictionary $object -Key 'Arguments', 'args', 'a'
$parameters = Get-DictionaryValueFromFirstKeyFound -Dictionary $object -Key 'Parameters', 'params'

if ($unresolvedPath -notmatch '\S')
{
throw 'When passing hashtables to the -Path parameter, the Path key is mandatory.'
}
}
else
{
$unresolvedPath = [string] $object
$arguments = @()
$parameters = @{}
}

if ($unresolvedPath -notmatch '[\*\?\[\]]' -and
(Test-Path -LiteralPath $unresolvedPath -PathType Leaf) -and
(Get-Item -LiteralPath $unresolvedPath) -is [System.IO.FileInfo])
{
New-Object psobject -Property @{
Path = $unresolvedPath
Arguments = $arguments
Parameters = $parameters
}
}
else
{
# World's longest pipeline?

Resolve-Path -Path $unresolvedPath |
Where-Object { $_.Provider.Name -eq 'FileSystem' } |
Select-Object -ExpandProperty ProviderPath |
Get-ChildItem -Include *.Tests.ps1 -Recurse |
Where-Object { -not $_.PSIsContainer } |
Select-Object -ExpandProperty FullName -Unique |
ForEach-Object {
New-Object psobject -Property @{
Path = $_
Arguments = $arguments
Parameters = $parameters
}
}
}
}
)

# Here, we have the option of trying to weed out duplicate file paths that also contain identical
# Parameters / Arguments. However, we already make sure that each object in $Path didn't produce
# any duplicate file paths, and if the caller happens to pass in a set of parameters that produce
# dupes, maybe that's not our problem. For now, just return what we found.

$resolvedScriptInfo
}

function Get-DictionaryValueFromFirstKeyFound
{
param ([System.Collections.IDictionary] $Dictionary, [object[]] $Key)

foreach ($keyToTry in $Key)
{
if ($Dictionary.Contains($keyToTry)) { return $Dictionary[$keyToTry] }
}
}

function Set-ScriptBlockScope
{
[CmdletBinding()]
Expand Down

0 comments on commit 94821ab

Please sign in to comment.