From 11bd992988b44b48ccf41a181b56e693eaf7677f Mon Sep 17 00:00:00 2001 From: Dave Wyatt Date: Mon, 7 Dec 2015 15:32:30 -0500 Subject: [PATCH 1/2] Adding new test for module-qualified mock calls --- Functions/Mock.Tests.ps1 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Functions/Mock.Tests.ps1 b/Functions/Mock.Tests.ps1 index 91354320b..4c3bd6c61 100644 --- a/Functions/Mock.Tests.ps1 +++ b/Functions/Mock.Tests.ps1 @@ -1458,3 +1458,26 @@ Describe 'Mocking a function taking input from pipeline' { } } } + +Describe 'Mocking module-qualified calls' { + It 'Mock alias should not exist before the mock is defined' { + 'alias:\Microsoft.PowerShell.Management\Get-Content' | Should Not Exist + } + + Context 'Scope Boundary' { + $mockFile = 'TestDrive:\TestFile' + $mockResult = 'Mocked' + + Mock Get-Content { return $mockResult } -ParameterFilter { $Path -eq $mockFile } + Setup -File TestFile -Content 'The actual file' + + It 'Calls the mock properly even if the call is module-qualified' { + $result = Microsoft.PowerShell.Management\Get-Content -Path $mockFile + $result | Should Be $mockResult + } + } + + It 'Removes the alias after the mock goes out of scope' { + 'alias:\Microsoft.PowerShell.Management\Get-Content' | Should Not Exist + } +} From 344aee669706bfdb2c686af12b52a6b65f43d7aa Mon Sep 17 00:00:00 2001 From: Dave Wyatt Date: Mon, 7 Dec 2015 15:34:49 -0500 Subject: [PATCH 2/2] Adding support for mocks to module-qualified command calls --- Functions/Assertions/Be.ps1 | 8 +- Functions/Assertions/Contain.ps1 | 2 +- Functions/Assertions/ContainExactly.ps1 | 2 +- Functions/Assertions/Exist.ps1 | 2 +- Functions/Assertions/Should.ps1 | 6 +- Functions/Context.ps1 | 4 +- Functions/Coverage.ps1 | 44 ++++----- Functions/Describe.ps1 | 12 +-- Functions/In.ps1 | 4 +- Functions/InModuleScope.ps1 | 12 +-- Functions/It.ps1 | 10 +- Functions/Mock.Tests.ps1 | 32 ++++--- Functions/Mock.ps1 | 74 ++++++++++----- Functions/New-Fixture.ps1 | 15 +-- Functions/PesterState.ps1 | 49 +++++----- Functions/SetupTeardown.ps1 | 34 +++---- Functions/TestDrive.ps1 | 61 ++++++------ Functions/TestResults.ps1 | 24 ++--- Pester.psm1 | 117 ++++++++++++++++++------ 19 files changed, 313 insertions(+), 199 deletions(-) diff --git a/Functions/Assertions/Be.ps1 b/Functions/Assertions/Be.ps1 index 0feac3e6e..ea24739cd 100644 --- a/Functions/Assertions/Be.ps1 +++ b/Functions/Assertions/Be.ps1 @@ -60,7 +60,7 @@ function Get-CompareStringMessage { $expectedLength = $expected.Length $actualLength = $actual.Length - $maxLength = $expectedLength,$actualLength | Sort -Descending | select -First 1 + $maxLength = $expectedLength,$actualLength | & $SafeCommands['Sort-Object'] -Descending | & $SafeCommands['Select-Object'] -First 1 $differenceIndex = $null for ($i = 0; $i -lt $maxLength -and ($null -eq $differenceIndex); ++$i){ @@ -94,9 +94,9 @@ function Get-CompareStringMessage { { #count all the special characters before the difference $specialCharacterOffset = ($actual[0..($differenceIndex-1)] | - Where {"`n","`r","`t","`b","`0" -contains $_} | - Measure-Object | - select -ExpandProperty Count) + & $SafeCommands['Where-Object'] {"`n","`r","`t","`b","`0" -contains $_} | + & $SafeCommands['Measure-Object'] | + & $SafeCommands['Select-Object'] -ExpandProperty Count) } '-'*($differenceIndex+$specialCharacterOffset+11)+'^' diff --git a/Functions/Assertions/Contain.ps1 b/Functions/Assertions/Contain.ps1 index e57f12d23..491411e6f 100644 --- a/Functions/Assertions/Contain.ps1 +++ b/Functions/Assertions/Contain.ps1 @@ -1,6 +1,6 @@ function PesterContain($file, $contentExpecation) { - return ((Get-Content -Encoding UTF8 $file) -match $contentExpecation) + return ((& $SafeCommands['Get-Content'] -Encoding UTF8 $file) -match $contentExpecation) } function PesterContainFailureMessage($file, $contentExpecation) { diff --git a/Functions/Assertions/ContainExactly.ps1 b/Functions/Assertions/ContainExactly.ps1 index c313b5dc3..4d5f4f754 100644 --- a/Functions/Assertions/ContainExactly.ps1 +++ b/Functions/Assertions/ContainExactly.ps1 @@ -1,5 +1,5 @@ function PesterContainExactly($file, $contentExpecation) { - return ((Get-Content -Encoding UTF8 $file) -cmatch $contentExpecation) + return ((& $SafeCommands['Get-Content'] -Encoding UTF8 $file) -cmatch $contentExpecation) } function PesterContainExactlyFailureMessage($file, $contentExpecation) { diff --git a/Functions/Assertions/Exist.ps1 b/Functions/Assertions/Exist.ps1 index 17658c93e..88e034a11 100644 --- a/Functions/Assertions/Exist.ps1 +++ b/Functions/Assertions/Exist.ps1 @@ -1,6 +1,6 @@ function PesterExist($value) { - Test-Path $value + & $SafeCommands['Test-Path'] $value } function PesterExistFailureMessage($value) { diff --git a/Functions/Assertions/Should.ps1 b/Functions/Assertions/Should.ps1 index 30c7cd712..5ce2a485c 100644 --- a/Functions/Assertions/Should.ps1 +++ b/Functions/Assertions/Should.ps1 @@ -34,7 +34,7 @@ function Parse-ShouldArgs([array] $shouldArgs) { function Get-TestResult($shouldArgs, $value) { $assertionMethod = $shouldArgs.AssertionMethod - $command = Get-Command $assertionMethod -ErrorAction $script:IgnoreErrorPreference + $command = Get-Command $assertionMethod -CommandType Function -ErrorAction $script:IgnoreErrorPreference if ($null -eq $command) { @@ -60,12 +60,12 @@ function Get-FailureMessage($shouldArgs, $value) { return (& $failureMessageFunction $value $shouldArgs.ExpectedValue) } function New-ShouldErrorRecord ([string] $Message, [string] $File, [string] $Line, [string] $LineText) { - $exception = New-Object Exception $Message + $exception = & $SafeCommands['New-Object'] Exception $Message $errorID = 'PesterAssertionFailed' $errorCategory = [Management.Automation.ErrorCategory]::InvalidResult # we use ErrorRecord.TargetObject to pass structured information about the error to a reporting system. $targetObject = @{Message = $Message; File = $File; Line = $Line; LineText = $LineText} - $errorRecord = New-Object Management.Automation.ErrorRecord $exception, $errorID, $errorCategory, $targetObject + $errorRecord = & $SafeCommands['New-Object'] Management.Automation.ErrorRecord $exception, $errorID, $errorCategory, $targetObject return $errorRecord } diff --git a/Functions/Context.ps1 b/Functions/Context.ps1 index b575d720e..15944fc73 100644 --- a/Functions/Context.ps1 +++ b/Functions/Context.ps1 @@ -68,7 +68,7 @@ about_TestDrive } catch { - $firstStackTraceLine = $_.InvocationInfo.PositionMessage.Trim() -split '\r?\n' | Select-Object -First 1 + $firstStackTraceLine = $_.InvocationInfo.PositionMessage.Trim() -split '\r?\n' | & $SafeCommands['Select-Object'] -First 1 $Pester.AddTestResult('Error occurred in Context block', "Failed", $null, $_.Exception.Message, $firstStackTraceLine, $null, $null, $_) $Pester.TestResult[-1] | Write-PesterResult } @@ -78,7 +78,7 @@ about_TestDrive } Clear-SetupAndTeardown - Clear-TestDrive -Exclude ($TestDriveContent | select -ExpandProperty FullName) + Clear-TestDrive -Exclude ($TestDriveContent | & $SafeCommands['Select-Object'] -ExpandProperty FullName) Exit-MockScope $Pester.LeaveContext() } diff --git a/Functions/Coverage.ps1 b/Functions/Coverage.ps1 index 2e4872ee5..855a7426e 100644 --- a/Functions/Coverage.ps1 +++ b/Functions/Coverage.ps1 @@ -6,7 +6,7 @@ if ($PSVersionTable.PSVersion.Major -le 2) function Enter-CoverageAnalysis { param ( $CodeCoverage ) - if ($CodeCoverage) { Write-Error 'Code coverage analysis requires PowerShell 3.0 or later.' } + if ($CodeCoverage) { & $SafeCommands['Write-Error'] 'Code coverage analysis requires PowerShell 3.0 or later.' } } return @@ -33,12 +33,12 @@ function Exit-CoverageAnalysis { param ([object] $PesterState) - Set-StrictMode -Off + & $SafeCommands['Set-StrictMode'] -Off $breakpoints = @($PesterState.CommandCoverage.Breakpoint) -ne $null if ($breakpoints.Count -gt 0) { - Remove-PSBreakpoint -Breakpoint $breakpoints + & $SafeCommands['Remove-PSBreakpoint'] -Breakpoint $breakpoints } } @@ -116,25 +116,25 @@ function Resolve-CoverageInfo try { - $resolvedPaths = Resolve-Path -Path $path -ErrorAction Stop + $resolvedPaths = & $SafeCommands['Resolve-Path'] -Path $path -ErrorAction Stop } catch { - Write-Error "Could not resolve coverage path '$path': $($_.Exception.Message)" + & $SafeCommands['Write-Error'] "Could not resolve coverage path '$path': $($_.Exception.Message)" return } $filePaths = foreach ($resolvedPath in $resolvedPaths) { - $item = Get-Item -LiteralPath $resolvedPath + $item = & $SafeCommands['Get-Item'] -LiteralPath $resolvedPath if ($item -is [System.IO.FileInfo] -and ('.ps1','.psm1') -contains $item.Extension) { $item.FullName } elseif (-not $item.PsIsContainer) { - Write-Warning "CodeCoverage path '$path' resolved to a non-PowerShell file '$($item.FullName)'; this path will not be part of the coverage report." + & $SafeCommands['Write-Warning'] "CodeCoverage path '$path' resolved to a non-PowerShell file '$($item.FullName)'; this path will not be part of the coverage report." } } @@ -158,10 +158,10 @@ function Get-CoverageBreakpoints [object[]] $CoverageInfo ) - $fileGroups = @($CoverageInfo | Group-Object -Property Path) + $fileGroups = @($CoverageInfo | & $SafeCommands['Group-Object'] -Property Path) foreach ($fileGroup in $fileGroups) { - Write-Verbose "Initializing code coverage analysis for file '$($fileGroup.Name)'" + & $SafeCommands['Write-Verbose'] "Initializing code coverage analysis for file '$($fileGroup.Name)'" $totalCommands = 0 $analyzedCommands = 0 @@ -181,7 +181,7 @@ function Get-CoverageBreakpoints } } - Write-Verbose "Analyzing $analyzedCommands of $totalCommands commands in file '$($fileGroup.Name)' for code coverage" + & $SafeCommands['Write-Verbose'] "Analyzing $analyzedCommands of $totalCommands commands in file '$($fileGroup.Name)' for code coverage" } } @@ -279,7 +279,7 @@ function New-CoverageBreakpoint Action = { } } - $breakpoint = Set-PSBreakpoint @params + $breakpoint = & $SafeCommands['Set-PSBreakpoint'] @params [pscustomobject] @{ File = $Command.Extent.File @@ -454,7 +454,7 @@ function Get-KeyValuePairText [System.Management.Automation.Language.Ast] $ChildAst ) - Set-StrictMode -Off + & $SafeCommands['Set-StrictMode'] -Off foreach ($keyValuePair in $HashtableAst.KeyValuePairs) { @@ -471,13 +471,13 @@ function Get-KeyValuePairText function Get-CoverageMissedCommands { param ([object[]] $CommandCoverage) - $CommandCoverage | Where-Object { $_.Breakpoint.HitCount -eq 0 } + $CommandCoverage | & $SafeCommands['Where-Object'] { $_.Breakpoint.HitCount -eq 0 } } function Get-CoverageHitCommands { param ([object[]] $CommandCoverage) - $CommandCoverage | Where-Object { $_.Breakpoint.HitCount -gt 0 } + $CommandCoverage | & $SafeCommands['Where-Object'] { $_.Breakpoint.HitCount -gt 0 } } function Get-CoverageReport @@ -486,9 +486,9 @@ function Get-CoverageReport $totalCommandCount = $PesterState.CommandCoverage.Count - $missedCommands = @(Get-CoverageMissedCommands -CommandCoverage $PesterState.CommandCoverage | Select-Object File, Line, Function, Command) - $hitCommands = @(Get-CoverageHitCommands -CommandCoverage $PesterState.CommandCoverage | Select-Object File, Line, Function, Command) - $analyzedFiles = @($PesterState.CommandCoverage | Select-Object -ExpandProperty File -Unique) + $missedCommands = @(Get-CoverageMissedCommands -CommandCoverage $PesterState.CommandCoverage | & $SafeCommands['Select-Object'] File, Line, Function, Command) + $hitCommands = @(Get-CoverageHitCommands -CommandCoverage $PesterState.CommandCoverage | & $SafeCommands['Select-Object'] File, Line, Function, Command) + $analyzedFiles = @($PesterState.CommandCoverage | & $SafeCommands['Select-Object'] -ExpandProperty File -Unique) $fileCount = $analyzedFiles.Count $executedCommandCount = $totalCommandCount - $missedCommands.Count @@ -522,7 +522,7 @@ function Show-CoverageReport if ($fileCount -gt 1) { $filePlural = 's' } $commonParent = Get-CommonParentPath -Path $CoverageReport.AnalyzedFiles - $report = $CoverageReport.MissedCommands | Select-Object -Property @( + $report = $CoverageReport.MissedCommands | & $SafeCommands['Select-Object'] -Property @( @{ Name = 'File'; Expression = { Get-RelativePath -Path $_.File -RelativeTo $commonParent } } 'Function' 'Line' @@ -537,7 +537,7 @@ function Show-CoverageReport { Write-Screen '' Write-Screen 'Missed commands:' - $report | Format-Table -AutoSize | Out-String | Write-Screen + $report | & $SafeCommands['Format-Table'] -AutoSize | & $SafeCommands['Out-String'] | Write-Screen } } @@ -545,11 +545,11 @@ function Get-CommonParentPath { param ([string[]] $Path) - $pathsToTest = @( $Path | Select-Object -Unique ) + $pathsToTest = @( $Path | & $SafeCommands['Select-Object'] -Unique ) if ($pathsToTest.Count -gt 0) { - $parentPath = Split-Path -Path $pathsToTest[0] -Parent + $parentPath = & $SafeCommands['Split-Path'] -Path $pathsToTest[0] -Parent while ($parentPath.Length -gt 0) { @@ -561,7 +561,7 @@ function Get-CommonParentPath } else { - $parentPath = Split-Path -Path $parentPath -Parent + $parentPath = & $SafeCommands['Split-Path'] -Path $parentPath -Parent } } } diff --git a/Functions/Describe.ps1 b/Functions/Describe.ps1 index 884d3361d..6d6451498 100644 --- a/Functions/Describe.ps1 +++ b/Functions/Describe.ps1 @@ -65,22 +65,22 @@ about_TestDrive [ScriptBlock] $Fixture = $(Throw "No test script block is provided. (Have you put the open curly brace on the next line?)") ) - if ($null -eq (Get-Variable -Name Pester -ValueOnly -ErrorAction $script:IgnoreErrorPreference)) + if ($null -eq (& $SafeCommands['Get-Variable'] -Name Pester -ValueOnly -ErrorAction $script:IgnoreErrorPreference)) { # User has executed a test script directly instead of calling Invoke-Pester - $Pester = New-PesterState -Path (Resolve-Path .) -TestNameFilter $null -TagFilter @() -SessionState $PSCmdlet.SessionState + $Pester = New-PesterState -Path (& $SafeCommands['Resolve-Path'] .) -TestNameFilter $null -TagFilter @() -SessionState $PSCmdlet.SessionState $script:mockTable = @{} } - if($Pester.TestNameFilter-and -not ($Pester.TestNameFilter | Where-Object { $Name -like $_ })) + if($Pester.TestNameFilter-and -not ($Pester.TestNameFilter | & $SafeCommands['Where-Object'] { $Name -like $_ })) { #skip this test return } #TODO add test to test tags functionality - if($Pester.TagFilter -and @(Compare-Object $Tags $Pester.TagFilter -IncludeEqual -ExcludeDifferent).count -eq 0) {return} - if($Pester.ExcludeTagFilter -and @(Compare-Object $Tags $Pester.ExcludeTagFilter -IncludeEqual -ExcludeDifferent).count -gt 0) {return} + if($Pester.TagFilter -and @(& $SafeCommands['Compare-Object'] $Tags $Pester.TagFilter -IncludeEqual -ExcludeDifferent).count -eq 0) {return} + if($Pester.ExcludeTagFilter -and @(& $SafeCommands['Compare-Object'] $Tags $Pester.ExcludeTagFilter -IncludeEqual -ExcludeDifferent).count -gt 0) {return} $Pester.EnterDescribe($Name) @@ -102,7 +102,7 @@ about_TestDrive } catch { - $firstStackTraceLine = $_.InvocationInfo.PositionMessage.Trim() -split '\r?\n' | Select-Object -First 1 + $firstStackTraceLine = $_.InvocationInfo.PositionMessage.Trim() -split '\r?\n' | & $SafeCommands['Select-Object'] -First 1 $Pester.AddTestResult('Error occurred in Describe block', "Failed", $null, $_.Exception.Message, $firstStackTraceLine, $null, $null, $_) $Pester.TestResult[-1] | Write-PesterResult } diff --git a/Functions/In.ps1 b/Functions/In.ps1 index 3ddf8835b..b7552a1ad 100644 --- a/Functions/In.ps1 +++ b/Functions/In.ps1 @@ -24,12 +24,12 @@ param( Assert-DescribeInProgress -CommandName In $old_pwd = $pwd - pushd $path + & $SafeCommands['Push-Location'] $path $pwd = $path try { & $execute } finally { - popd + & $SafeCommands['Pop-Location'] $pwd = $old_pwd } } diff --git a/Functions/InModuleScope.ps1 b/Functions/InModuleScope.ps1 index 925858af8..120696e12 100644 --- a/Functions/InModuleScope.ps1 +++ b/Functions/InModuleScope.ps1 @@ -61,10 +61,10 @@ function InModuleScope $ScriptBlock ) - if ($null -eq (Get-Variable -Name Pester -ValueOnly -ErrorAction $script:IgnoreErrorPreference)) + if ($null -eq (& $SafeCommands['Get-Variable'] -Name Pester -ValueOnly -ErrorAction $script:IgnoreErrorPreference)) { # User has executed a test script directly instead of calling Invoke-Pester - $Pester = New-PesterState -Path (Resolve-Path .) -TestNameFilter $null -TagFilter @() -ExcludeTagFilter @() -SessionState $PSCmdlet.SessionState + $Pester = New-PesterState -Path (& $SafeCommands['Resolve-Path'] .) -TestNameFilter $null -TagFilter @() -ExcludeTagFilter @() -SessionState $PSCmdlet.SessionState $script:mockTable = @{} } @@ -101,14 +101,14 @@ function Get-ScriptModule try { - $modules = @(Get-Module -Name $ModuleName -All -ErrorAction Stop) + $modules = @(& $SafeCommands['Get-Module'] -Name $ModuleName -All -ErrorAction Stop) } catch { throw "No module named '$ModuleName' is currently loaded." } - $scriptModules = @($modules | Where-Object { $_.ModuleType -eq 'Script' }) + $scriptModules = @($modules | & $SafeCommands['Where-Object'] { $_.ModuleType -eq 'Script' }) if ($scriptModules.Count -gt 1) { @@ -119,8 +119,8 @@ function Get-ScriptModule { $actualTypes = @( $modules | - Where-Object { $_.ModuleType -ne 'Script' } | - Select-Object -ExpandProperty ModuleType -Unique + & $SafeCommands['Where-Object'] { $_.ModuleType -ne 'Script' } | + & $SafeCommands['Select-Object'] -ExpandProperty ModuleType -Unique ) $actualTypes = $actualTypes -join ', ' diff --git a/Functions/It.ps1 b/Functions/It.ps1 index d759bc022..31bd253b3 100644 --- a/Functions/It.ps1 +++ b/Functions/It.ps1 @@ -241,7 +241,7 @@ function Invoke-Test } else { - Write-Progress -Activity "Running test '$Name'" -Status Processing + & $SafeCommands['Write-Progress'] -Activity "Running test '$Name'" -Status Processing $errorRecord = $null try @@ -277,7 +277,7 @@ function Invoke-Test $result = Get-PesterResult -ErrorRecord $errorRecord $orderedParameters = Get-OrderedParameterDictionary -ScriptBlock $ScriptBlock -Dictionary $Parameters $Pester.AddTestResult( $result.name, $result.Result, $null, $result.FailureMessage, $result.StackTrace, $ParameterizedSuiteName, $orderedParameters, $result.ErrorRecord ) - Write-Progress -Activity "Running test '$Name'" -Completed -Status Processing + & $SafeCommands['Write-Progress'] -Activity "Running test '$Name'" -Completed -Status Processing } if ($null -ne $OutputScriptBlock) @@ -364,7 +364,7 @@ function Get-OrderedParameterDictionary $parameters = Get-ParameterDictionary -ScriptBlock $ScriptBlock - $orderedDictionary = New-Object System.Collections.Specialized.OrderedDictionary + $orderedDictionary = & $SafeCommands['New-Object'] System.Collections.Specialized.OrderedDictionary foreach ($parameterName in $parameters.Keys) { @@ -390,13 +390,13 @@ function Get-ParameterDictionary try { - Set-Content function:\$guid $ScriptBlock + & $SafeCommands['Set-Content'] function:\$guid $ScriptBlock $metadata = [System.Management.Automation.CommandMetadata](Get-Command -Name $guid -CommandType Function) return $metadata.Parameters } finally { - if (Test-Path function:\$guid) { Remove-Item function:\$guid } + if (& $SafeCommands['Test-Path'] function:\$guid) { & $SafeCommands['Remove-Item'] function:\$guid } } } diff --git a/Functions/Mock.Tests.ps1 b/Functions/Mock.Tests.ps1 index 4c3bd6c61..26140627f 100644 --- a/Functions/Mock.Tests.ps1 +++ b/Functions/Mock.Tests.ps1 @@ -859,6 +859,9 @@ Describe 'Dot Source Test' { } It "Doesn't call the mock with any other parameters" { + InModuleScope Pester { + $global:calls = $mockTable['||Test-Path'].CallHistory + } Assert-MockCalled Test-Path -Exactly 0 -ParameterFilter { $Path -ne 'Test' } } } @@ -1461,23 +1464,30 @@ Describe 'Mocking a function taking input from pipeline' { Describe 'Mocking module-qualified calls' { It 'Mock alias should not exist before the mock is defined' { - 'alias:\Microsoft.PowerShell.Management\Get-Content' | Should Not Exist + $alias = Get-Alias -Name 'Microsoft.PowerShell.Management\Get-Content' -ErrorAction SilentlyContinue + $alias | Should Be $null } - Context 'Scope Boundary' { - $mockFile = 'TestDrive:\TestFile' - $mockResult = 'Mocked' + $mockFile = 'TestDrive:\TestFile' + $mockResult = 'Mocked' - Mock Get-Content { return $mockResult } -ParameterFilter { $Path -eq $mockFile } - Setup -File TestFile -Content 'The actual file' + Mock Get-Content { return $mockResult } -ParameterFilter { $Path -eq $mockFile } + Setup -File TestFile -Content 'The actual file' - It 'Calls the mock properly even if the call is module-qualified' { - $result = Microsoft.PowerShell.Management\Get-Content -Path $mockFile - $result | Should Be $mockResult - } + It 'Creates the alias while the mock is in effect' { + $alias = Get-Alias -Name 'Microsoft.PowerShell.Management\Get-Content' -ErrorAction SilentlyContinue + $alias | Should Not Be $null } + It 'Calls the mock properly even if the call is module-qualified' { + $result = Microsoft.PowerShell.Management\Get-Content -Path $mockFile + $result | Should Be $mockResult + } +} + +Describe 'After a mock goes out of scope' { It 'Removes the alias after the mock goes out of scope' { - 'alias:\Microsoft.PowerShell.Management\Get-Content' | Should Not Exist + $alias = Get-Alias -Name 'Microsoft.PowerShell.Management\Get-Content' -ErrorAction SilentlyContinue + $alias | Should Be $null } } diff --git a/Functions/Mock.ps1 b/Functions/Mock.ps1 index efff3c7d2..9a3dc1533 100644 --- a/Functions/Mock.ps1 +++ b/Functions/Mock.ps1 @@ -212,9 +212,9 @@ about_Mocking # Some versions of powershell may include dynamic parameters here # We will filter them out and add them at the end to be # compatible with both earlier and later versions - $dynamicParams = $metadata.Parameters.Values | ? {$_.IsDynamic} + $dynamicParams = $metadata.Parameters.Values | & $SafeCommands['Where-Object'] {$_.IsDynamic} if($dynamicParams -ne $null) { - $dynamicparams | % { $null = $metadata.Parameters.Remove($_.name) } + $dynamicparams | & $SafeCommands['ForEach-Object'] { $null = $metadata.Parameters.Remove($_.name) } } $cmdletBinding = [Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($metadata) @@ -264,7 +264,7 @@ about_Mocking } } - $newContent = Microsoft.PowerShell.Management\Get-Content function:\MockPrototype + $newContent = & $SafeCommands['Get-Content'] function:\MockPrototype $newContent = $newContent -replace '#FUNCTIONNAME#', $CommandName $newContent = $newContent -replace '#MODULENAME#', $ModuleName @@ -300,6 +300,7 @@ about_Mocking CallHistory = @() DynamicParamScriptBlock = $dynamicParamScriptBlock FunctionScope = '' + Alias = $null } $mockTable["$ModuleName||$CommandName"] = $mock @@ -323,13 +324,25 @@ about_Mocking $scriptBlock = { $ExecutionContext.InvokeProvider.Item.Set("Function:\script:$($args[0])", $args[1], $true, $true) } $null = Invoke-InMockScope -SessionState $mock.SessionState -ScriptBlock $scriptBlock -ArgumentList $CommandName, $mockScript + + if ($mock.OriginalCommand.ModuleName) + { + $mock.Alias = "$($mock.OriginalCommand.ModuleName)\$($CommandName)" + + $scriptBlock = { + $setAlias = Get-Command -Name Set-Alias -CommandType Cmdlet -Module Microsoft.PowerShell.Utility + & $setAlias -Name $args[0] -Value $args[1] -Scope Script + } + + $null = Invoke-InMockScope -SessionState $mock.SessionState -ScriptBlock $scriptBlock -ArgumentList $mock.Alias, $CommandName + } } $mock.Blocks = @( - $mock.Blocks | Where-Object { $_.Filter.ToString() -eq '$True' } + $mock.Blocks | & $SafeCommands['Where-Object'] { $_.Filter.ToString() -eq '$True' } if ($block.Filter.ToString() -eq '$True') { $block } - $mock.Blocks | Where-Object { $_.Filter.ToString() -ne '$True' } + $mock.Blocks | & $SafeCommands['Where-Object'] { $_.Filter.ToString() -ne '$True' } if ($block.Filter.ToString() -ne '$True') { $block } ) } @@ -370,8 +383,12 @@ This will not throw an exception because the mock was invoked. Assert-DescribeInProgress -CommandName Assert-VerifiableMocks $unVerified=@{} - $mockTable.Keys | % { - $m=$_; $mockTable[$m].blocks | ? { $_.Verifiable } | % { $unVerified[$m]=$_ } + $mockTable.Keys | & $SafeCommands['ForEach-Object'] { + $m=$_; + + $mockTable[$m].blocks | + & $SafeCommands['Where-Object'] { $_.Verifiable } | + & $SafeCommands['ForEach-Object'] { $unVerified[$m]=$_ } } if($unVerified.Count -gt 0) { foreach($mock in $unVerified.Keys){ @@ -586,8 +603,8 @@ param( } } - $matchingCalls = New-Object System.Collections.ArrayList - $nonMatchingCalls = New-Object System.Collections.ArrayList + $matchingCalls = & $SafeCommands['New-Object'] System.Collections.ArrayList + $nonMatchingCalls = & $SafeCommands['New-Object'] System.Collections.ArrayList foreach ($historyEntry in $mock.CallHistory) { @@ -655,7 +672,8 @@ function Exit-MockScope { { param ( [string] $CommandName, - [string] $Scope + [string] $Scope, + [string] $Alias ) $ExecutionContext.InvokeProvider.Item.Remove("Function:\$CommandName", $false, $true, $true) @@ -663,6 +681,11 @@ function Exit-MockScope { { $ExecutionContext.InvokeProvider.Item.Rename("Function:\PesterIsMocking_$CommandName", "$Scope$CommandName", $true) } + + if ($Alias -and $ExecutionContext.InvokeProvider.Item.Exists("Alias:$Alias", $true, $true)) + { + $ExecutionContext.InvokeProvider.Item.Remove("Alias:$Alias", $false, $true, $true) + } } $mockKeys = [string[]]$mockTable.Keys @@ -670,11 +693,11 @@ function Exit-MockScope { foreach ($mockKey in $mockKeys) { $mock = $mockTable[$mockKey] - $mock.Blocks = @($mock.Blocks | Where {$_.Scope -ne $currentScope}) + $mock.Blocks = @($mock.Blocks | & $SafeCommands['Where-Object'] {$_.Scope -ne $currentScope}) if ($null -eq $parentScope) { - $null = Invoke-InMockScope -SessionState $mock.SessionState -ScriptBlock $scriptBlock -ArgumentList $mock.CommandName, $mock.FunctionScope + $null = Invoke-InMockScope -SessionState $mock.SessionState -ScriptBlock $scriptBlock -ArgumentList $mock.CommandName, $mock.FunctionScope, $mock.Alias $mockTable.Remove($mockKey) } else @@ -691,9 +714,12 @@ function Validate-Command([string]$CommandName, [string]$ModuleName) { $module = $null $origCommand = $null - $commandInfo = New-Object psobject -Property @{ Command = $null; Scope = '' } + $commandInfo = & $SafeCommands['New-Object'] psobject -Property @{ Command = $null; Scope = '' } $scriptBlock = { + $getContentCommand = Get-Command Get-Content -Module Microsoft.PowerShell.Management -CommandType Cmdlet + $newObjectCommand = Get-Command New-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet + $command = $ExecutionContext.InvokeCommand.GetCommand($args[0], 'All') while ($null -ne $command -and $command.CommandType -eq [System.Management.Automation.CommandTypes]::Alias) { @@ -707,12 +733,12 @@ function Validate-Command([string]$CommandName, [string]$ModuleName) { if ($null -ne $command -and $command.CommandType -eq 'Function') { if ($ExecutionContext.InvokeProvider.Item.Exists("function:\global:$($command.Name)") -and - (Microsoft.PowerShell.Management\Get-Content "function:\global:$($command.Name)" -ErrorAction Stop) -eq $command.ScriptBlock) + (& $getContentCommand "function:\global:$($command.Name)" -ErrorAction Stop) -eq $command.ScriptBlock) { $properties['Scope'] = 'global:' } elseif ($ExecutionContext.InvokeProvider.Item.Exists("function:\script:$($command.Name)") -and - (Microsoft.PowerShell.Management\Get-Content "function:\script:$($command.Name)" -ErrorAction Stop) -eq $command.ScriptBlock) + (& $getContentCommand "function:\script:$($command.Name)" -ErrorAction Stop) -eq $command.ScriptBlock) { $properties['Scope'] = 'script:' } @@ -722,7 +748,7 @@ function Validate-Command([string]$CommandName, [string]$ModuleName) { } } - return New-Object psobject -Property $properties + return & $newObjectCommand psobject -Property $properties } if ($ModuleName) { @@ -764,10 +790,12 @@ function MockPrototype { [string] ${ignore preference} = 'SilentlyContinue' } - [object] ${a r g s} = Get-Variable -Name args -ValueOnly -Scope Local -ErrorAction ${ignore preference} + ${get Variable Command} = Get-Command -Name Get-Variable -Module Microsoft.PowerShell.Utility -CommandType Cmdlet + + [object] ${a r g s} = & ${get Variable Command} -Name args -ValueOnly -Scope Local -ErrorAction ${ignore preference} if ($null -eq ${a r g s}) { ${a r g s} = @() } - ${p s cmdlet} = Get-Variable -Name PSCmdlet -ValueOnly -Scope Local -ErrorAction ${ignore preference} + ${p s cmdlet} = & ${get Variable Command} -Name PSCmdlet -ValueOnly -Scope Local -ErrorAction ${ignore preference} ${session state} = if (${p s cmdlet}) { ${p s cmdlet}.SessionState } @@ -816,7 +844,7 @@ function Invoke-Mock { { Begin { - $mock.InputObjects = New-Object System.Collections.ArrayList + $mock.InputObjects = & $SafeCommands['New-Object'] System.Collections.ArrayList $mock.ShouldExecuteOriginalCommand = $false $mock.BeginBoundParameters = $BoundParameters.Clone() $mock.BeginArgumentList = $ArgumentList @@ -1143,7 +1171,7 @@ function Set-DynamicParameterVariables { if ($ExecutionContext.SessionState -eq $SessionState) { - Set-Variable -Scope 1 -Name $variableName -Value $keyValuePair.Value -Force -Confirm:$false -WhatIf:$false + & $SafeCommands['Set-Variable'] -Scope 1 -Name $variableName -Value $keyValuePair.Value -Force -Confirm:$false -WhatIf:$false } else { @@ -1175,8 +1203,8 @@ function Get-DynamicParamBlock if ($null -ne $ScriptBlock.Ast.Body.DynamicParamBlock) { $statements = $ScriptBlock.Ast.Body.DynamicParamBlock.Statements | - Select-Object -ExpandProperty Extent | - Select-Object -ExpandProperty Text + & $SafeCommands['Select-Object'] -ExpandProperty Extent | + & $SafeCommands['Select-Object'] -ExpandProperty Text return $statements -join "`r`n" } @@ -1246,7 +1274,7 @@ function Get-DynamicParametersForCmdlet $PSCmdlet.ThrowTerminatingError($_) } - $cmdlet = Microsoft.PowerShell.Utility\New-Object $command.ImplementingType.FullName + $cmdlet = & $SafeCommands['New-Object'] $command.ImplementingType.FullName if ($cmdlet -isnot [System.Management.Automation.IDynamicParameters]) { return diff --git a/Functions/New-Fixture.ps1 b/Functions/New-Fixture.ps1 index ca2244cad..3a06b48d3 100644 --- a/Functions/New-Fixture.ps1 +++ b/Functions/New-Fixture.ps1 @@ -88,17 +88,20 @@ Describe "#name#" { } function Create-File ($Path,$Name,$Content) { - if (-not (Test-Path -Path $Path)) { - New-Item -ItemType Directory -Path $Path | Out-Null + if (-not (& $SafeCommands['Test-Path'] -Path $Path)) { + & $SafeCommands['New-Item'] -ItemType Directory -Path $Path | & $SafeCommands['Out-Null'] } - $FullPath = Join-Path -Path $Path -ChildPath $Name - if (-not (Test-Path -Path $FullPath)) { - Set-Content -Path $FullPath -Value $Content -Encoding UTF8 - Get-Item -Path $FullPath + $FullPath = & $SafeCommands['Join-Path'] -Path $Path -ChildPath $Name + if (-not (& $SafeCommands['Test-Path'] -Path $FullPath)) { + & $SafeCommands['Set-Content'] -Path $FullPath -Value $Content -Encoding UTF8 + & $SafeCommands['Get-Item'] -Path $FullPath } else { + # This is deliberately not sent through $SafeCommands, because our own tests rely on + # mocking Write-Warning, and it's not really the end of the world if this call happens to + # be screwed up in an edge case. Write-Warning "Skipping the file '$FullPath', because it already exists." } } diff --git a/Functions/PesterState.ps1 b/Functions/PesterState.ps1 index c4633c9a7..dd8911abb 100644 --- a/Functions/PesterState.ps1 +++ b/Functions/PesterState.ps1 @@ -11,7 +11,7 @@ function New-PesterState if ($null -eq $SessionState) { $SessionState = $ExecutionContext.SessionState } - New-Module -Name Pester -AsCustomObject -ScriptBlock { + & $SafeCommands['New-Module'] -Name Pester -AsCustomObject -ScriptBlock { param ( [String[]]$_tagFilter, [String[]]$_excludeTagFilter, @@ -50,11 +50,18 @@ function New-PesterState $script:PendingCount = 0 $script:InconclusiveCount = 0 + $script:SafeCommands = @{} + + $script:SafeCommands['New-Object'] = Get-Command -Name New-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet + $script:SafeCommands['Select-Object'] = Get-Command -Name Select-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet + $script:SafeCommands['Export-ModuleMember'] = Get-Command -Name Export-ModuleMember -Module Microsoft.PowerShell.Core -CommandType Cmdlet + $script:SafeCommands['Add-Member'] = Get-Command -Name Add-Member -Module Microsoft.PowerShell.Utility -CommandType Cmdlet + function EnterDescribe([string]$Name) { if ($CurrentDescribe) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "You already are in Describe, you cannot enter Describe twice" + throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in Describe, you cannot enter Describe twice" } $script:CurrentDescribe = $Name } @@ -62,7 +69,7 @@ function New-PesterState function LeaveDescribe { if ( $CurrentContext ) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "Cannot leave Describe before leaving Context" + throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot leave Describe before leaving Context" } $script:CurrentDescribe = $null @@ -72,17 +79,17 @@ function New-PesterState { if ( -not $CurrentDescribe ) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "Cannot enter Context before entering Describe" + throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot enter Context before entering Describe" } if ( $CurrentContext ) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "You already are in Context, you cannot enter Context twice" + throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in Context, you cannot enter Context twice" } if ($CurrentTest) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "You already are in It, you cannot enter Context inside It" + throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in It, you cannot enter Context inside It" } $script:CurrentContext = $Name @@ -92,7 +99,7 @@ function New-PesterState { if ($CurrentTest) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "Cannot leave Context before leaving It" + throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot leave Context before leaving It" } $script:CurrentContext = $null @@ -102,12 +109,12 @@ function New-PesterState { if (-not $script:CurrentDescribe) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "Cannot enter It before entering Describe" + throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot enter It before entering Describe" } if ( $CurrentTest ) { - throw Microsoft.PowerShell.Utility\New-Object InvalidOperationException "You already are in It, you cannot enter It twice" + throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in It, you cannot enter It twice" } $script:CurrentTest = $Name @@ -167,7 +174,7 @@ function New-PesterState Inconclusive { $script:InconclusiveCount++; break; } } - $Script:TestResult += Microsoft.PowerShell.Utility\New-Object -TypeName PsObject -Property @{ + $Script:TestResult += & $SafeCommands['New-Object'] -TypeName PsObject -Property @{ Describe = $CurrentDescribe Context = $CurrentContext Name = $Name @@ -179,7 +186,7 @@ function New-PesterState ErrorRecord = $ErrorRecord ParameterizedSuiteName = $ParameterizedSuiteName Parameters = $Parameters - } | Microsoft.PowerShell.Utility\Select-Object Describe, Context, Name, Result, Passed, Time, FailureMessage, StackTrace, ErrorRecord, ParameterizedSuiteName, Parameters + } | & $SafeCommands['Select-Object'] Describe, Context, Name, Result, Passed, Time, FailureMessage, StackTrace, ErrorRecord, ParameterizedSuiteName, Parameters } $ExportedVariables = "TagFilter", @@ -213,15 +220,15 @@ function New-PesterState "LeaveTest", "AddTestResult" - Export-ModuleMember -Variable $ExportedVariables -function $ExportedFunctions + & $SafeCommands['Export-ModuleMember'] -Variable $ExportedVariables -function $ExportedFunctions } -ArgumentList $TagFilter, $ExcludeTagFilter, $TestNameFilter, $SessionState, $Strict, $Quiet | - Add-Member -MemberType ScriptProperty -Name Scope -Value { + & $SafeCommands['Add-Member'] -MemberType ScriptProperty -Name Scope -Value { if ($this.CurrentTest) { 'It' } elseif ($this.CurrentContext) { 'Context' } elseif ($this.CurrentDescribe) { 'Describe' } else { $null } } -Passthru | - Add-Member -MemberType ScriptProperty -Name ParentScope -Value { + & $SafeCommands['Add-Member'] -MemberType ScriptProperty -Name ParentScope -Value { $parentScope = $null $scope = $this.Scope @@ -284,8 +291,8 @@ function Write-PesterResult "$margin[-] $output $humanTime" | Write-Screen -OutputType Failed $TestResult.ErrorRecord | ConvertTo-FailureLines | - % {$_.Message + $_.Trace} | - % { Write-Screen -OutputType Failed $($_ -replace '(?m)^',$error_margin) } + & $SafeCommands['ForEach-Object'] {$_.Message + $_.Trace} | + & $SafeCommands['ForEach-Object'] { Write-Screen -OutputType Failed $($_ -replace '(?m)^',$error_margin) } } Skipped { "$margin[!] $output $humanTime" | Write-Screen -OutputType Skipped @@ -342,7 +349,7 @@ function ConvertTo-FailureLines $lines.Message += "$($ErrorRecord.TargetObject.Line)`: $($ErrorRecord.TargetObject.LineText)".Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) } - if ( -not ($ErrorRecord | Get-Member -Name ScriptStackTrace) ) + if ( -not ($ErrorRecord | & $SafeCommands['Get-Member'] -Name ScriptStackTrace) ) { if ($ErrorRecord.FullyQualifiedErrorID -eq 'PesterAssertionFailed') { @@ -368,8 +375,8 @@ function ConvertTo-FailureLines $count ++ } $lines.Trace += $traceLines | - Select-Object -First $count | - ? { + & $SafeCommands['Select-Object'] -First $count | + & $SafeCommands['Where-Object'] { $_ -notmatch '^at Should, .*\\Functions\\Assertions\\Should.ps1: line [0-9]*$' -and $_ -notmatch '^at Assert-MockCalled, .*\\Functions\\Mock.ps1: line [0-9]*$' } @@ -413,8 +420,8 @@ function Write-Screen { if ($Quiet) { return } #make the bound parameters compatible with Write-Host - if ($PSBoundParameters.ContainsKey('Quiet')) { $PSBoundParameters.Remove('Quiet') | Out-Null } - if ($PSBoundParameters.ContainsKey('OutputType')) { $PSBoundParameters.Remove('OutputType') | Out-Null} + if ($PSBoundParameters.ContainsKey('Quiet')) { $PSBoundParameters.Remove('Quiet') | & $SafeCommands['Out-Null'] } + if ($PSBoundParameters.ContainsKey('OutputType')) { $PSBoundParameters.Remove('OutputType') | & $SafeCommands['Out-Null'] } if ($OutputType -ne "Standard") { diff --git a/Functions/SetupTeardown.ps1 b/Functions/SetupTeardown.ps1 index 774ed7b01..c791f532e 100644 --- a/Functions/SetupTeardown.ps1 +++ b/Functions/SetupTeardown.ps1 @@ -76,17 +76,17 @@ function AfterAll function Clear-SetupAndTeardown { - $pester.BeforeEach = @( $pester.BeforeEach | Where-Object { $_.Scope -ne $pester.Scope } ) - $pester.AfterEach = @( $pester.AfterEach | Where-Object { $_.Scope -ne $pester.Scope } ) - $pester.BeforeAll = @( $pester.BeforeAll | Where-Object { $_.Scope -ne $pester.Scope } ) - $pester.AfterAll = @( $pester.AfterAll | Where-Object { $_.Scope -ne $pester.Scope } ) + $pester.BeforeEach = @( $pester.BeforeEach | & $SafeCommands['Where-Object'] { $_.Scope -ne $pester.Scope } ) + $pester.AfterEach = @( $pester.AfterEach | & $SafeCommands['Where-Object'] { $_.Scope -ne $pester.Scope } ) + $pester.BeforeAll = @( $pester.BeforeAll | & $SafeCommands['Where-Object'] { $_.Scope -ne $pester.Scope } ) + $pester.AfterAll = @( $pester.AfterAll | & $SafeCommands['Where-Object'] { $_.Scope -ne $pester.Scope } ) } function Invoke-TestCaseSetupBlocks { $orderedSetupBlocks = @( - $pester.BeforeEach | Where-Object { $_.Scope -eq 'Describe' } | Select-Object -ExpandProperty ScriptBlock - $pester.BeforeEach | Where-Object { $_.Scope -eq 'Context' } | Select-Object -ExpandProperty ScriptBlock + $pester.BeforeEach | & $SafeCommands['Where-Object'] { $_.Scope -eq 'Describe' } | & $SafeCommands['Select-Object'] -ExpandProperty ScriptBlock + $pester.BeforeEach | & $SafeCommands['Where-Object'] { $_.Scope -eq 'Context' } | & $SafeCommands['Select-Object'] -ExpandProperty ScriptBlock ) Invoke-Blocks -ScriptBlock $orderedSetupBlocks @@ -95,8 +95,8 @@ function Invoke-TestCaseSetupBlocks function Invoke-TestCaseTeardownBlocks { $orderedTeardownBlocks = @( - $pester.AfterEach | Where-Object { $_.Scope -eq 'Context' } | Select-Object -ExpandProperty ScriptBlock - $pester.AfterEach | Where-Object { $_.Scope -eq 'Describe' } | Select-Object -ExpandProperty ScriptBlock + $pester.AfterEach | & $SafeCommands['Where-Object'] { $_.Scope -eq 'Context' } | & $SafeCommands['Select-Object'] -ExpandProperty ScriptBlock + $pester.AfterEach | & $SafeCommands['Where-Object'] { $_.Scope -eq 'Describe' } | & $SafeCommands['Select-Object'] -ExpandProperty ScriptBlock ) Invoke-Blocks -ScriptBlock $orderedTeardownBlocks @@ -107,8 +107,8 @@ function Invoke-TestGroupSetupBlocks param ([string] $Scope) $scriptBlocks = $pester.BeforeAll | - Where-Object { $_.Scope -eq $Scope } | - Select-Object -ExpandProperty ScriptBlock + & $SafeCommands['Where-Object'] { $_.Scope -eq $Scope } | + & $SafeCommands['Select-Object'] -ExpandProperty ScriptBlock Invoke-Blocks -ScriptBlock $scriptBlocks } @@ -118,8 +118,8 @@ function Invoke-TestGroupTeardownBlocks param ([string] $Scope) $scriptBlocks = $pester.AfterAll | - Where-Object { $_.Scope -eq $Scope } | - Select-Object -ExpandProperty ScriptBlock + & $SafeCommands['Where-Object'] { $_.Scope -eq $Scope } | + & $SafeCommands['Select-Object'] -ExpandProperty ScriptBlock Invoke-Blocks -ScriptBlock $scriptBlocks } @@ -298,7 +298,7 @@ function Get-GroupStartTokenForCommand return $CommandIndex + 1 } -Add-Type -TypeDefinition @' +& $SafeCommands['Add-Type'] -TypeDefinition @' namespace Pester { using System; @@ -416,7 +416,7 @@ function Add-BeforeEach ScriptBlock = $ScriptBlock } - $pester.BeforeEach += @(New-Object psobject -Property $props) + $pester.BeforeEach += @(& $SafeCommands['New-Object'] psobject -Property $props) } function Add-AfterEach @@ -433,7 +433,7 @@ function Add-AfterEach ScriptBlock = $ScriptBlock } - $pester.AfterEach += @(New-Object psobject -Property $props) + $pester.AfterEach += @(& $SafeCommands['New-Object'] psobject -Property $props) } function Add-BeforeAll @@ -450,7 +450,7 @@ function Add-BeforeAll ScriptBlock = $ScriptBlock } - $pester.BeforeAll += @(New-Object psobject -Property $props) + $pester.BeforeAll += @(& $SafeCommands['New-Object'] psobject -Property $props) } function Add-AfterAll @@ -467,5 +467,5 @@ function Add-AfterAll ScriptBlock = $ScriptBlock } - $pester.AfterAll += @(New-Object psobject -Property $props) + $pester.AfterAll += @(& $SafeCommands['New-Object'] psobject -Property $props) } diff --git a/Functions/TestDrive.ps1 b/Functions/TestDrive.ps1 index 97d5e562d..bd4c03f8d 100644 --- a/Functions/TestDrive.ps1 +++ b/Functions/TestDrive.ps1 @@ -3,46 +3,46 @@ function New-TestDrive ([Switch]$PassThru) { $Path = New-RandomTempDirectory $DriveName = "TestDrive" - if (-not (Microsoft.PowerShell.Management\Test-Path -Path $Path)) + if (-not (& $SafeCommands['Test-Path'] -Path $Path)) { - New-Item -ItemType Container -Path $Path | Out-Null + & $SafeCommands['New-Item'] -ItemType Container -Path $Path | & $SafeCommands['Out-Null'] } #setup the test drive - if ( -not (Test-Path "${DriveName}:\") ) + if ( -not (& $SafeCommands['Test-Path'] "${DriveName}:\") ) { - New-PSDrive -Name $DriveName -PSProvider FileSystem -Root $Path -Scope Global -Description "Pester test drive" | Out-Null + & $SafeCommands['New-PSDrive'] -Name $DriveName -PSProvider FileSystem -Root $Path -Scope Global -Description "Pester test drive" | & $SafeCommands['Out-Null'] } #publish the global TestDrive variable used in few places within the module - if (-not (Test-Path "Variable:Global:DriveName")) + if (-not (& $SafeCommands['Test-Path'] "Variable:Global:DriveName")) { - New-Variable -Name $DriveName -Scope Global -Value $Path + & $SafeCommands['New-Variable'] -Name $DriveName -Scope Global -Value $Path } - if ( $PassThru ) { Get-PSDrive -Name $DriveName } + if ( $PassThru ) { & $SafeCommands['Get-PSDrive'] -Name $DriveName } } function Clear-TestDrive ([String[]]$Exclude) { - $Path = (Microsoft.PowerShell.Management\Get-PSDrive -Name TestDrive).Root - if (Microsoft.PowerShell.Management\Test-Path -Path $Path ) + $Path = (& $SafeCommands['Get-PSDrive'] -Name TestDrive).Root + if (& $SafeCommands['Test-Path'] -Path $Path ) { #Get-ChildItem -Exclude did not seem to work with full paths - Microsoft.PowerShell.Management\Get-ChildItem -Recurse -Path $Path | - Microsoft.PowerShell.Utility\Sort-Object -Descending -Property "FullName" | - Microsoft.PowerShell.Core\Where-Object { $Exclude -NotContains $_.FullName } | - Microsoft.PowerShell.Management\Remove-Item -Force -Recurse + & $SafeCommands['Get-ChildItem'] -Recurse -Path $Path | + & $SafeCommands['Sort-Object'] -Descending -Property "FullName" | + & $SafeCommands['Where-Object'] { $Exclude -NotContains $_.FullName } | + & $SafeCommands['Remove-Item'] -Force -Recurse } } function New-RandomTempDirectory { do { - $Path = Join-Path -Path $env:TEMP -ChildPath ([Guid]::NewGuid()) - } until (-not ( Microsoft.PowerShell.Management\Test-Path -Path $Path )) + $Path = & $SafeCommands['Join-Path'] -Path $env:TEMP -ChildPath ([Guid]::NewGuid()) + } until (-not (& $SafeCommands['Test-Path'] -Path $Path )) - New-Item -ItemType Container -Path $Path + & $SafeCommands['New-Item'] -ItemType Container -Path $Path } function Get-TestDriveItem { @@ -50,42 +50,42 @@ function Get-TestDriveItem { param( [string]$Path ) Assert-DescribeInProgress -CommandName Get-TestDriveItem - Get-Item $(Join-Path $TestDrive $Path ) + & $SafeCommands['Get-Item'] $(& $SafeCommands['Join-Path'] $TestDrive $Path ) } function Get-TestDriveChildItem { - $Path = (Microsoft.PowerShell.Management\Get-PSDrive -Name TestDrive).Root - if (Microsoft.PowerShell.Management\Test-Path -Path $Path ) + $Path = (& $SafeCommands['Get-PSDrive'] -Name TestDrive).Root + if (& $SafeCommands['Test-Path'] -Path $Path ) { - Microsoft.PowerShell.Management\Get-ChildItem -Recurse -Path $Path + & $SafeCommands['Get-ChildItem'] -Recurse -Path $Path } } function Remove-TestDrive { $DriveName = "TestDrive" - $Drive = Get-PSDrive -Name $DriveName -ErrorAction $script:IgnoreErrorPreference + $Drive = & $SafeCommands['Get-PSDrive'] -Name $DriveName -ErrorAction $script:IgnoreErrorPreference $Path = ($Drive).Root if ($pwd -like "$DriveName*" ) { #will staying in the test drive cause issues? #TODO review this - Write-Warning -Message "Your current path is set to ${pwd}:. You should leave ${DriveName}:\ before leaving Describe." + & $SafeCommands['Write-Warning'] -Message "Your current path is set to ${pwd}:. You should leave ${DriveName}:\ before leaving Describe." } if ( $Drive ) { - $Drive | Remove-PSDrive -Force -ErrorAction $script:IgnoreErrorPreference + $Drive | & $SafeCommands['Remove-PSDrive'] -Force -ErrorAction $script:IgnoreErrorPreference } - if (Microsoft.PowerShell.Management\Test-Path -Path $Path) + if (& $SafeCommands['Test-Path'] -Path $Path) { - Microsoft.PowerShell.Management\Remove-Item -Path $Path -Force -Recurse + & $SafeCommands['Remove-Item'] -Path $Path -Force -Recurse } - if (Get-Variable -Name $DriveName -Scope Global -ErrorAction $script:IgnoreErrorPreference) { - Remove-Variable -Scope Global -Name $DriveName -Force + if (& $SafeCommands['Get-Variable'] -Name $DriveName -Scope Global -ErrorAction $script:IgnoreErrorPreference) { + & $SafeCommands['Remove-Variable'] -Scope Global -Name $DriveName -Force } } @@ -101,13 +101,14 @@ function Setup { Assert-DescribeInProgress -CommandName Setup - $TestDriveName = Get-PSDrive TestDrive | Select -ExpandProperty Root + $TestDriveName = & $SafeCommands['Get-PSDrive'] TestDrive | + & $SafeCommands['Select-Object'] -ExpandProperty Root if ($Dir) { - $item = New-Item -Name $Path -Path "${TestDriveName}\" -Type Container -Force + $item = & $SafeCommands['New-Item'] -Name $Path -Path "${TestDriveName}\" -Type Container -Force } if ($File) { - $item = $Content | New-Item -Name $Path -Path "${TestDriveName}\" -Type File -Force + $item = $Content | & $SafeCommands['New-Item'] -Name $Path -Path "${TestDriveName}\" -Type File -Force } if($PassThru) { diff --git a/Functions/TestResults.ps1 b/Functions/TestResults.ps1 index 38efdf34c..b2836e6db 100644 --- a/Functions/TestResults.ps1 +++ b/Functions/TestResults.ps1 @@ -13,7 +13,7 @@ function Get-HumanTime($Seconds) { function GetFullPath ([string]$Path) { if (-not [System.IO.Path]::IsPathRooted($Path)) { - $Path = Join-Path $ExecutionContext.SessionState.Path.CurrentFileSystemLocation $Path + $Path = & $SafeCommands['Join-Path'] $ExecutionContext.SessionState.Path.CurrentFileSystemLocation $Path } return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) @@ -55,7 +55,7 @@ function Export-NUnitReport { $Path = GetFullPath -Path $Path - $settings = New-Object -TypeName Xml.XmlWriterSettings -Property @{ + $settings = & $SafeCommands['New-Object'] -TypeName Xml.XmlWriterSettings -Property @{ Indent = $true NewLineOnAttributes = $false } @@ -109,9 +109,9 @@ function Write-NUnitTestResultAttributes($PesterState, [System.Xml.XmlWriter] $X $XmlWriter.WriteAttributeString('ignored', $PesterState.SkippedCount) $XmlWriter.WriteAttributeString('skipped', '0') $XmlWriter.WriteAttributeString('invalid', '0') - $date = Get-Date - $XmlWriter.WriteAttributeString('date', (Get-Date -Date $date -Format 'yyyy-MM-dd')) - $XmlWriter.WriteAttributeString('time', (Get-Date -Date $date -Format 'HH:mm:ss')) + $date = & $SafeCommands['Get-Date'] + $XmlWriter.WriteAttributeString('date', (& $SafeCommands['Get-Date'] -Date $date -Format 'yyyy-MM-dd')) + $XmlWriter.WriteAttributeString('time', (& $SafeCommands['Get-Date'] -Date $date -Format 'HH:mm:ss')) } function Write-NUnitTestResultChildNodes($PesterState, [System.Xml.XmlWriter] $XmlWriter, [switch] $LegacyFormat) @@ -173,7 +173,7 @@ function Write-NUnitGlobalTestSuiteAttributes($PesterState, [System.Xml.XmlWrite function Write-NUnitDescribeElements($PesterState, [System.Xml.XmlWriter] $XmlWriter, [switch] $LegacyFormat) { - $Describes = $PesterState.TestResult | Group-Object -Property Describe + $Describes = $PesterState.TestResult | & $SafeCommands['Group-Object'] -Property Describe if ($null -ne $Describes) { foreach ($currentDescribe in $Describes) @@ -272,7 +272,7 @@ function Write-NUnitTestSuiteAttributes($TestSuiteInfo, [System.Xml.XmlWriter] $ function Write-NUnitDescribeChildElements([object[]] $TestResults, [System.Xml.XmlWriter] $XmlWriter, [switch] $LegacyFormat, [string] $DescribeName) { - $suites = $TestResults | Group-Object -Property ParameterizedSuiteName + $suites = $TestResults | & $SafeCommands['Group-Object'] -Property ParameterizedSuiteName foreach ($suite in $suites) { @@ -409,12 +409,12 @@ function Write-NUnitTestCaseAttributes($TestResult, [System.Xml.XmlWriter] $XmlW } } function Get-RunTimeEnvironment() { - $osSystemInformation = (Get-WmiObject Win32_OperatingSystem) + $osSystemInformation = (& $SafeCommands['Get-WmiObject'] Win32_OperatingSystem) @{ 'nunit-version' = '2.5.8.0' 'os-version' = $osSystemInformation.Version platform = $osSystemInformation.Name - cwd = (Get-Location).Path #run path + cwd = (& $SafeCommands['Get-Location']).Path #run path 'machine-name' = $env:ComputerName user = $env:Username 'user-domain' = $env:userDomain @@ -440,8 +440,8 @@ function Get-GroupResult ($InputObject) { #I am not sure about the result precedence, and can't find any good source #TODO: Confirm this is the correct order of precedence - if ($InputObject | Where {$_.Result -eq 'Failed'}) { return 'Failure' } - if ($InputObject | Where {$_.Result -eq 'Skipped'}) { return 'Ignored' } - if ($InputObject | Where {$_.Result -eq 'Pending' -or $_.Result -eq 'Inconclusive'}) { return 'Inconclusive' } + if ($InputObject | & $SafeCommands['Where-Object'] {$_.Result -eq 'Failed'}) { return 'Failure' } + if ($InputObject | & $SafeCommands['Where-Object'] {$_.Result -eq 'Skipped'}) { return 'Ignored' } + if ($InputObject | & $SafeCommands['Where-Object'] {$_.Result -eq 'Pending' -or $_.Result -eq 'Inconclusive'}) { return 'Inconclusive' } return 'Success' } diff --git a/Pester.psm1 b/Pester.psm1 index f6bfb9db7..a4d3f9026 100644 --- a/Pester.psm1 +++ b/Pester.psm1 @@ -5,18 +5,80 @@ if ($PSVersionTable.PSVersion.Major -ge 3) { $script:IgnoreErrorPreference = 'Ignore' + $outNullModule = 'Microsoft.PowerShell.Core' } else { $script:IgnoreErrorPreference = 'SilentlyContinue' + $outNullModule = 'Microsoft.PowerShell.Utility' } -$moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path +$script:SafeCommands = @{ + 'Add-Member' = Get-Command -Name Add-Member -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Add-Type' = Get-Command -Name Add-Type -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Compare-Object' = Get-Command -Name Compare-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Export-ModuleMember' = Get-Command -Name Export-ModuleMember -Module Microsoft.PowerShell.Core -CommandType Cmdlet -ErrorAction Stop + 'ForEach-Object' = Get-Command -Name ForEach-Object -Module Microsoft.PowerShell.Core -CommandType Cmdlet -ErrorAction Stop + 'Format-Table' = Get-Command -Name Format-Table -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Get-ChildItem' = Get-Command -Name Get-ChildItem -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Get-Content' = Get-Command -Name Get-Content -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Get-Date' = Get-Command -Name Get-Date -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Get-Item' = Get-Command -Name Get-Item -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Get-Location' = Get-Command -Name Get-Location -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Get-Member' = Get-Command -Name Get-Member -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Get-Module' = Get-Command -Name Get-Module -Module Microsoft.PowerShell.Core -CommandType Cmdlet -ErrorAction Stop + 'Get-PSDrive' = Get-Command -Name Get-PSDrive -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Get-Variable' = Get-Command -Name Get-Variable -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Get-WmiObject' = Get-Command -Name Get-WmiObject -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Group-Object' = Get-Command -Name Group-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Join-Path' = Get-Command -Name Join-Path -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Measure-Object' = Get-Command -Name Measure-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'New-Item' = Get-Command -Name New-Item -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'New-Module' = Get-Command -Name New-Module -Module Microsoft.PowerShell.Core -CommandType Cmdlet -ErrorAction Stop + 'New-Object' = Get-Command -Name New-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'New-PSDrive' = Get-Command -Name New-PSDrive -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'New-Variable' = Get-Command -Name New-Variable -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Out-Null' = Get-Command -Name Out-Null -Module $outNullModule -CommandType Cmdlet -ErrorAction Stop + 'Pop-Location' = Get-Command -Name Pop-Location -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Push-Location' = Get-Command -Name Push-Location -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Remove-Item' = Get-Command -Name Remove-Item -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Remove-PSBreakpoint' = Get-Command -Name Remove-PSBreakpoint -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Remove-PSDrive' = Get-Command -Name Remove-PSDrive -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Remove-Variable' = Get-Command -Name Remove-Variable -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Resolve-Path' = Get-Command -Name Resolve-Path -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Select-Object' = Get-Command -Name Select-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Set-Content' = Get-Command -Name Set-Content -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Set-PSBreakpoint' = Get-Command -Name Set-PSBreakpoint -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Set-StrictMode' = Get-Command -Name Set-StrictMode -Module Microsoft.PowerShell.Core -CommandType Cmdlet -ErrorAction Stop + 'Set-Variable' = Get-Command -Name Set-Variable -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Sort-Object' = Get-Command -Name Sort-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Split-Path' = Get-Command -Name Split-Path -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Start-Sleep' = Get-Command -Name Start-Sleep -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Test-Path' = Get-Command -Name Test-Path -Module Microsoft.PowerShell.Management -CommandType Cmdlet -ErrorAction Stop + 'Where-Object' = Get-Command -Name Where-Object -Module Microsoft.PowerShell.Core -CommandType Cmdlet -ErrorAction Stop + 'Write-Error' = Get-Command -Name Write-Error -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Write-Progress' = Get-Command -Name Write-Progress -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Write-Verbose' = Get-Command -Name Write-Verbose -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop + 'Write-Warning' = Get-Command -Name Write-Warning -Module Microsoft.PowerShell.Utility -CommandType Cmdlet -ErrorAction Stop +} + +# little sanity check to make sure we don't blow up a system with a typo up there +# (not that I've EVER done that by, for example, mapping New-Item to Remove-Item...) + +foreach ($keyValuePair in $script:SafeCommands.GetEnumerator()) +{ + if ($keyValuePair.Key -ne $keyValuePair.Value.Name) + { + throw "SafeCommands entry for $($keyValuePair.Key) does not hold a reference to the proper command." + } +} + +$moduleRoot = & $script:SafeCommands['Split-Path'] -Path $MyInvocation.MyCommand.Path "$moduleRoot\Functions\*.ps1", "$moduleRoot\Functions\Assertions\*.ps1" | -Resolve-Path | -Where-Object { -not ($_.ProviderPath.ToLower().Contains(".tests.")) } | -ForEach-Object { . $_.ProviderPath } +& $script:SafeCommands['Resolve-Path'] | +& $script:SafeCommands['Where-Object'] { -not ($_.ProviderPath.ToLower().Contains(".tests.")) } | +& $script:SafeCommands['ForEach-Object'] { . $_.ProviderPath } function Invoke-Pester { <# @@ -172,9 +234,9 @@ about_pester if ($PSBoundParameters.ContainsKey('OutputXml')) { - Write-Warning 'The -OutputXml parameter has been deprecated; please use the new -OutputFile and -OutputFormat parameters instead. To get the same type of export that the -OutputXml parameter currently provides, use an -OutputFormat of "LegacyNUnitXml".' + & $script:SafeCommands['Write-Warning'] 'The -OutputXml parameter has been deprecated; please use the new -OutputFile and -OutputFormat parameters instead. To get the same type of export that the -OutputXml parameter currently provides, use an -OutputFormat of "LegacyNUnitXml".' - Start-Sleep -Seconds 2 + & $script:SafeCommands['Start-Sleep'] -Seconds 2 $OutputFile = $OutputXml $OutputFormat = 'LegacyNUnitXml' @@ -214,7 +276,7 @@ about_pester } catch { - $firstStackTraceLine = $_.ScriptStackTrace -split '\r?\n' | Select-Object -First 1 + $firstStackTraceLine = $_.ScriptStackTrace -split '\r?\n' | & $script:SafeCommands['Select-Object'] -First 1 $pester.AddTestResult("Error occurred in test script '$($testScript.Path)'", "Failed", $null, $_.Exception.Message, $firstStackTraceLine, $null, $null, $_) $pester.TestResult[-1] | Write-PesterResult } @@ -225,7 +287,7 @@ about_pester Show-CoverageReport -CoverageReport $coverageReport Exit-CoverageAnalysis -PesterState $pester - if(Get-Variable -Name OutputFile -ValueOnly -ErrorAction $script:IgnoreErrorPreference) { + if(& $script:SafeCommands['Get-Variable'] -Name OutputFile -ValueOnly -ErrorAction $script:IgnoreErrorPreference) { Export-PesterResults -PesterState $pester -Path $OutputFile -Format $OutputFormat } @@ -240,7 +302,7 @@ about_pester } ) - $pester | Select -Property $properties + $pester | & $script:SafeCommands['Select-Object'] -Property $properties } if ($EnableExit) { Exit-WithCode -FailedCount $pester.FailedCount } @@ -277,17 +339,17 @@ function ResolveTestScripts } if ($unresolvedPath -notmatch '[\*\?\[\]]' -and - (Test-Path -LiteralPath $unresolvedPath -PathType Leaf) -and - (Get-Item -LiteralPath $unresolvedPath) -is [System.IO.FileInfo]) + (& $script:SafeCommands['Test-Path'] -LiteralPath $unresolvedPath -PathType Leaf) -and + (& $script:SafeCommands['Get-Item'] -LiteralPath $unresolvedPath) -is [System.IO.FileInfo]) { $extension = [System.IO.Path]::GetExtension($unresolvedPath) if ($extension -ne '.ps1') { - Write-Error "Script path '$unresolvedPath' is not a ps1 file." + & $script:SafeCommands['Write-Error'] "Script path '$unresolvedPath' is not a ps1 file." } else { - New-Object psobject -Property @{ + & $script:SafeCommands['New-Object'] psobject -Property @{ Path = $unresolvedPath Arguments = $arguments Parameters = $parameters @@ -298,14 +360,14 @@ function ResolveTestScripts { # 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 @{ + & $script:SafeCommands['Resolve-Path'] -Path $unresolvedPath | + & $script:SafeCommands['Where-Object'] { $_.Provider.Name -eq 'FileSystem' } | + & $script:SafeCommands['Select-Object'] -ExpandProperty ProviderPath | + & $script:SafeCommands['Get-ChildItem'] -Include *.Tests.ps1 -Recurse | + & $script:SafeCommands['Where-Object'] { -not $_.PSIsContainer } | + & $script:SafeCommands['Select-Object'] -ExpandProperty FullName -Unique | + & $script:SafeCommands['ForEach-Object'] { + & $script:SafeCommands['New-Object'] psobject -Property @{ Path = $_ Arguments = $arguments Parameters = $parameters @@ -373,12 +435,15 @@ function Get-ScriptBlockScope } $snippetsDirectoryPath = "$PSScriptRoot\Snippets" -if ((Test-Path -Path Variable:\psise) -and ($null -ne $psISE) -and ($PSVersionTable.PSVersion.Major -ge 3) -and (Test-Path $snippetsDirectoryPath)) +if ((& $script:SafeCommands['Test-Path'] -Path Variable:\psise) -and + ($null -ne $psISE) -and + ($PSVersionTable.PSVersion.Major -ge 3) -and + (& $script:SafeCommands['Test-Path'] $snippetsDirectoryPath)) { Import-IseSnippet -Path $snippetsDirectoryPath } -Export-ModuleMember Describe, Context, It, In, Mock, Assert-VerifiableMocks, Assert-MockCalled, Set-TestInconclusive -Export-ModuleMember New-Fixture, Get-TestDriveItem, Should, Invoke-Pester, Setup, InModuleScope, Invoke-Mock -Export-ModuleMember BeforeEach, AfterEach, BeforeAll, AfterAll -Export-ModuleMember Get-MockDynamicParameters, Set-DynamicParameterVariables +& $script:SafeCommands['Export-ModuleMember'] Describe, Context, It, In, Mock, Assert-VerifiableMocks, Assert-MockCalled, Set-TestInconclusive +& $script:SafeCommands['Export-ModuleMember'] New-Fixture, Get-TestDriveItem, Should, Invoke-Pester, Setup, InModuleScope, Invoke-Mock +& $script:SafeCommands['Export-ModuleMember'] BeforeEach, AfterEach, BeforeAll, AfterAll +& $script:SafeCommands['Export-ModuleMember'] Get-MockDynamicParameters, Set-DynamicParameterVariables