Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/Format2.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,13 @@ function Format-Nicely2 ($Value, [switch]$Pretty, [int]$Depth = 0) {
return Format-Type2 -Value $Value
}

if (Is-DecimalNumber -Value $Value) {
# Inlined Is-DecimalNumber / Is-ScriptBlock to avoid a function call per formatted value on this
# hot dispatch path (used for every <template> name expansion). The helpers stay defined for other callers.
if ($Value -is [float] -or $Value -is [single] -or $Value -is [double] -or $Value -is [decimal]) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is-DecimalNumber is only used here and Format.ps1. Maybe update both?

return Format-Number2 -Value $Value
}

if (Is-ScriptBlock -Value $Value) {
if ($Value -is [ScriptBlock]) {
return Format-ScriptBlock2 -Value $Value
}

Expand All @@ -142,11 +144,15 @@ function Format-Nicely2 ($Value, [switch]$Pretty, [int]$Depth = 0) {
return Get-ShortType2 -Value $Value
}

if (Is-Collection -Value $Value) {
# Inlined Is-Collection (same LanguagePrimitives::GetEnumerator check the helper runs).
if ($null -ne [System.Management.Automation.LanguagePrimitives]::GetEnumerator($Value)) {
return Format-Collection2 -Value $Value -Pretty:$Pretty -Depth $Depth
}

if (Is-Value -Value $Value) {
# Inlined Is-Value. The helper's leading `$Value = $($Value)` (which unwraps single-element and empty
# collections) is intentionally dropped: any collection was already handled by the Is-Collection branch
# above, so here $Value is never a collection and the unwrap is a no-op.
if ($Value -is [ValueType] -or $Value -is [string] -or $Value -is [scriptblock]) {
return $Value
}

Expand Down
4 changes: 2 additions & 2 deletions src/Main.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ function Invoke-Pester {
}

foreach ($c in $rspecResult.Containers) {
Fold-Container -Container $c -OnTest { param($t) Add-RSpecTestObjectProperties $t }
Add-RSpecTestObjectPropertiesToContainer $c
$foldedContainers.Add($c)
}
}
Expand Down Expand Up @@ -931,7 +931,7 @@ function Invoke-Pester {
}

foreach ($c in $rspecContainers) {
Fold-Container -Container $c -OnTest { param($t) Add-RSpecTestObjectProperties $t }
Add-RSpecTestObjectPropertiesToContainer $c
}
}

Expand Down
88 changes: 41 additions & 47 deletions src/Pester.RSpec.ps1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious so I can learn, what's the big benefit here besides clearer names? We skip maybe 1-2 light function calls, but all the scriptblocks are reference types and passed on from the initial call.

Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,24 @@ function Add-RSpecBlockObjectProperties ($BlockObject) {
}
}

function Add-RSpecTestObjectPropertiesToContainer ($Container) {
# Direct walk over the container tree instead of Fold-Container. It visits every test in the
# same pre-order (tests of a block before its child blocks), but without the fold's per-item
# scriptblock dispatch and per-block advanced-function recursion.
foreach ($b in $Container.Blocks) {
Add-RSpecTestObjectPropertiesToBlock $b
}
}

function Add-RSpecTestObjectPropertiesToBlock ($Block) {
foreach ($t in $Block.Tests) {
Add-RSpecTestObjectProperties $t
}
foreach ($b in $Block.Blocks) {
Add-RSpecTestObjectPropertiesToBlock $b
}
}

function PostProcess-RspecTestRun ($TestRun, [switch] $Parallel, [TimeSpan] $RunDuration) {
$discoveryOnly = $PesterPreference.Run.SkipRun.Value

Expand Down Expand Up @@ -507,56 +525,32 @@ function Remove-RSpecNonPublicProperties ($run) {
# 'Duration'
# )

Fold-Run $run -OnRun {
param($i)
# $ps = $i.PsObject.Properties.Name
# foreach ($p in $ps) {
# if ($p -like 'Plugin*') {
# $i.PsObject.Properties.Remove($p)
# }
# }
# Direct walk over the run tree instead of Fold-Run; same visit of every block and test,
# without the fold's per-item scriptblock dispatch. Containers need no cleanup.
foreach ($r in $run) {
$r.PluginConfiguration = $null
$r.PluginData = $null
$r.Plugins = $null

$i.PluginConfiguration = $null
$i.PluginData = $null
$i.Plugins = $null
foreach ($c in $r.Containers) {
foreach ($b in $c.Blocks) {
Remove-RSpecNonPublicPropertiesFromBlock $b
}
}
}
}

} -OnContainer {
param($i)
# $ps = $i.PsObject.Properties.Name
# foreach ($p in $ps) {
# if ($p -like 'Own*') {
# $i.PsObject.Properties.Remove($p)
# }
# }

# $i.FrameworkData = $null
# $i.PluginConfiguration = $null
# $i.PluginData = $null
# $i.Plugins = $null
function Remove-RSpecNonPublicPropertiesFromBlock ($Block) {
$Block.FrameworkData = $null
$Block.PluginData = $null

} -OnBlock {
param($i)
# $ps = $i.PsObject.Properties.Name
# foreach ($p in $ps) {
# if ($p -eq 'FrameworkData' -or $p -like 'Own*' -or $p -like 'Plugin*') {
# $i.PsObject.Properties.Remove($p)
# }
# }

$i.FrameworkData = $null
$i.PluginData = $null

} -OnTest {
param($i)
# $ps = $i.PsObject.Properties.Name
# foreach ($p in $ps) {
# if ($p -eq 'FrameworkData' -or $p -like 'Plugin*') {
# $i.PsObject.Properties.Remove($p)
# }
# }

$i.FrameworkData = $null
$i.PluginData = $null
foreach ($t in $Block.Tests) {
$t.FrameworkData = $null
$t.PluginData = $null
}

foreach ($b in $Block.Blocks) {
Remove-RSpecNonPublicPropertiesFromBlock $b
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/functions/Output.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,12 @@ function Get-WriteScreenPlugin ($Verbosity) {
$p.DiscoveryEnd = {
param ($Context)

$discoveredTests = @(View-Flat -Block $Context.BlockContainers)
# flattening the tree costs time proportional to the number of discovered tests, and the
# result is only read by the two guarded blocks below, so skip it in the default run
# (Normal verbosity, not discovery-only) where neither guard can be entered
$discoveredTests = if ($PesterPreference.Run.SkipRun.Value -or $PesterPreference.Output.Verbosity.Value -in 'Detailed', 'Diagnostic') {
@(View-Flat -Block $Context.BlockContainers)
}

if ($PesterPreference.Run.SkipRun.Value) {
# Only announce the discovery result on screen when we are not going to run
Expand Down
Loading