From 40e34f5bc33eafa190188d619cea5ad235bfe011 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 11 Jun 2026 18:16:32 +0200 Subject: [PATCH] Should-BeAfter/BeBefore: make positional DateTime work The doc example `(Get-Date).AddDays(1) | Should-BeAfter (Get-Date)` errored with "Cannot bind positional parameters because no names were given." The `Fluent` and `Expected` parameter sets both declared a position-0 parameter (`$Time` and `$Expected`), so a `DateTime` at position 0 matched both sets and PowerShell could not pick one. Split the `Fluent` parameter set into `FluentAgo` and `FluentFromNow`, each requiring its mandatory switch. With `-Ago`/`-FromNow` no longer optional within their set, neither fluent set is satisfiable from just a positional `[DateTime]`, so the `Expected` set wins unambiguously. Side effects: - `Should-BeAfter 10minutes -Ago -FromNow` now fails at binding (no parameter set can be resolved) instead of the runtime check. - The runtime "you must provide -Ago or -FromNow" check is gone, since binding enforces it. Added doc-style positional tests on both `Should-BeAfter` and `Should-BeBefore`. Verified the full Pester suite: 2171 passed, 0 failed. Follow-up to #2707. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/functions/assert/Time/Should-BeAfter.ps1 | 31 +++++++++---------- src/functions/assert/Time/Should-BeBefore.ps1 | 31 +++++++++---------- .../assert/Time/Should-BeAfter.Tests.ps1 | 4 +++ .../assert/Time/Should-BeBefore.Tests.ps1 | 4 +++ 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/functions/assert/Time/Should-BeAfter.ps1 b/src/functions/assert/Time/Should-BeAfter.ps1 index 9c0b2ab3f..19891f3a5 100644 --- a/src/functions/assert/Time/Should-BeAfter.ps1 +++ b/src/functions/assert/Time/Should-BeAfter.ps1 @@ -67,16 +67,17 @@ [Parameter(Position = 2, ValueFromPipeline = $true)] $Actual, - [Parameter(Position = 0, ParameterSetName = "Now")] + [Parameter(ParameterSetName = "Now")] [switch] $Now, - [Parameter(Position = 0, ParameterSetName = "Fluent")] - $Time, + [Parameter(Position = 0, ParameterSetName = "FluentAgo")] + [Parameter(Position = 0, ParameterSetName = "FluentFromNow")] + [String] $Time, - [Parameter(Position = 1, ParameterSetName = "Fluent")] + [Parameter(Mandatory, ParameterSetName = "FluentAgo")] [switch] $Ago, - [Parameter(Position = 1, ParameterSetName = "Fluent")] + [Parameter(Mandatory, ParameterSetName = "FluentFromNow")] [switch] $FromNow, [Parameter(Position = 0, ParameterSetName = "Expected")] @@ -92,21 +93,17 @@ $Now = $Now $currentTime = [datetime]::UtcNow.ToLocalTime() - if ($PSCmdlet.ParameterSetName -eq "Expected") { - # do nothing we already have expected value - } - elseif ($PSCmdlet.ParameterSetName -eq "Now") { - $Expected = $currentTime - } - else { - if ($Ago -and $FromNow -or (-not $Ago -and -not $FromNow)) { - throw "You must provide either -Ago or -FromNow switch, but not both or none." + switch ($PSCmdlet.ParameterSetName) { + "Expected" { + # do nothing we already have expected value } - - if ($Ago) { + "Now" { + $Expected = $currentTime + } + "FluentAgo" { $Expected = $currentTime - (Get-TimeSpanFromStringWithUnit -Value $Time) } - else { + "FluentFromNow" { $Expected = $currentTime + (Get-TimeSpanFromStringWithUnit -Value $Time) } } diff --git a/src/functions/assert/Time/Should-BeBefore.ps1 b/src/functions/assert/Time/Should-BeBefore.ps1 index d96be8eb2..ce7b128cc 100644 --- a/src/functions/assert/Time/Should-BeBefore.ps1 +++ b/src/functions/assert/Time/Should-BeBefore.ps1 @@ -67,16 +67,17 @@ [Parameter(Position = 2, ValueFromPipeline = $true)] $Actual, - [Parameter(Position = 0, ParameterSetName = "Now")] + [Parameter(ParameterSetName = "Now")] [switch] $Now, - [Parameter(Position = 0, ParameterSetName = "Fluent")] - $Time, + [Parameter(Position = 0, ParameterSetName = "FluentAgo")] + [Parameter(Position = 0, ParameterSetName = "FluentFromNow")] + [String] $Time, - [Parameter(Position = 1, ParameterSetName = "Fluent")] + [Parameter(Mandatory, ParameterSetName = "FluentAgo")] [switch] $Ago, - [Parameter(Position = 1, ParameterSetName = "Fluent")] + [Parameter(Mandatory, ParameterSetName = "FluentFromNow")] [switch] $FromNow, [Parameter(Position = 0, ParameterSetName = "Expected")] @@ -92,21 +93,17 @@ $Now = $Now $currentTime = [datetime]::UtcNow.ToLocalTime() - if ($PSCmdlet.ParameterSetName -eq "Expected") { - # do nothing we already have expected value - } - elseif ($PSCmdlet.ParameterSetName -eq "Now") { - $Expected = $currentTime - } - else { - if ($Ago -and $FromNow -or (-not $Ago -and -not $FromNow)) { - throw "You must provide either -Ago or -FromNow switch, but not both or none." + switch ($PSCmdlet.ParameterSetName) { + "Expected" { + # do nothing we already have expected value } - - if ($Ago) { + "Now" { + $Expected = $currentTime + } + "FluentAgo" { $Expected = $currentTime - (Get-TimeSpanFromStringWithUnit -Value $Time) } - else { + "FluentFromNow" { $Expected = $currentTime + (Get-TimeSpanFromStringWithUnit -Value $Time) } } diff --git a/tst/functions/assert/Time/Should-BeAfter.Tests.ps1 b/tst/functions/assert/Time/Should-BeAfter.Tests.ps1 index 9266eaa76..e4d9c719b 100644 --- a/tst/functions/assert/Time/Should-BeAfter.Tests.ps1 +++ b/tst/functions/assert/Time/Should-BeAfter.Tests.ps1 @@ -23,6 +23,10 @@ Describe "Should-BeAfter" { [DateTime]::Now.Add([timespan]::FromMinutes(20)) | Should-BeAfter } + It "Does not throw when actual date is before expected date using positional DateTime" { + [DateTime]::Now.AddDays(1) | Should-BeAfter ([DateTime]::Now) + } + It "Throws when actual date is before expected date" -ForEach @( @{ Actual = [DateTime]::Now.AddDays(-1); Expected = [DateTime]::Now } ) { diff --git a/tst/functions/assert/Time/Should-BeBefore.Tests.ps1 b/tst/functions/assert/Time/Should-BeBefore.Tests.ps1 index 7b714b4d8..2ed904e7d 100644 --- a/tst/functions/assert/Time/Should-BeBefore.Tests.ps1 +++ b/tst/functions/assert/Time/Should-BeBefore.Tests.ps1 @@ -23,6 +23,10 @@ Describe "Should-BeBefore" { [DateTime]::Now.Add([timespan]::FromMinutes(-20)) | Should-BeBefore } + It "Does not throw when actual date is before expected date using positional DateTime" { + [DateTime]::Now.AddDays(-1) | Should-BeBefore ([DateTime]::Now) + } + It "Throws when actual date is after expected date" -ForEach @( @{ Actual = [DateTime]::Now.AddDays(1); Expected = [DateTime]::Now } ) {