Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Assert assertions to Pester #2428

Draft
wants to merge 46 commits into
base: dev/6.x.x
Choose a base branch
from
Draft

Add Assert assertions to Pester #2428

wants to merge 46 commits into from

Conversation

nohwnd
Copy link
Member

@nohwnd nohwnd commented Apr 2, 2024

Fix #1423

PR Summary

This PR adds assertions from Assert module to Pester, to serve as a base for future assertions and to live side-by-side with the existing Should assertions that are based on parameter sets.

PR Checklist

  • PR has meaningful title
  • Summary describes changes
  • PR is ready to be merged
    • If not, use the arrow next to Create Pull Request to mark it as a draft. PR can be marked Ready for review when it's ready.
  • Tests are added/update (if required)
  • Documentation is updated/added (if required)

Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

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

PSScriptAnalyzer found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@fflaten
Copy link
Collaborator

fflaten commented Apr 2, 2024

We should probably decide on #2381 soon, so these assertions can either implement it - or not. 🙂

@nohwnd nohwnd changed the base branch from main to dev/6.x.x April 10, 2024 19:15
@nohwnd
Copy link
Member Author

nohwnd commented Apr 21, 2024

/azp run

Copy link
Contributor

Azure Pipelines could not run because the pipeline triggers exclude this branch/path.

Comment on lines 11 to 18
[Parameter(Position = 0, ParameterSetName = "Fluent")]
$Time,

[Parameter(Position = 1, ParameterSetName = "Fluent")]
[switch] $Ago,

[Parameter(Position = 1, ParameterSetName = "Fluent")]
[switch] $FromNow,
Copy link
Collaborator

@fflaten fflaten Apr 23, 2024

Choose a reason for hiding this comment

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

Suggested change
[Parameter(Position = 0, ParameterSetName = "Fluent")]
$Time,
[Parameter(Position = 1, ParameterSetName = "Fluent")]
[switch] $Ago,
[Parameter(Position = 1, ParameterSetName = "Fluent")]
[switch] $FromNow,
[Parameter(Position = 0, ParameterSetName = "Ago")]
[Parameter(Position = 0, ParameterSetName = "FromNow")]
$Time,
[Parameter(Mandatory, Position = 1, ParameterSetName = "Ago")]
[switch] $Ago,
[Parameter(Mandatory, Position = 1, ParameterSetName = "FromNow")]
[switch] $FromNow,

Split parameter sets so you can avoid throw for conflicting switches later on?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was thinking about that, but that gives some generic "cannot figure out parameter set" error, no?

Copy link
Collaborator

@fflaten fflaten Apr 23, 2024

Choose a reason for hiding this comment

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

If you call Assert-After -Time 1s -Ago -FromNow or Assert-After -Time 1s, yes.

However tab completion will hide Ago/FromNow when the other is already used. Docs and syntax in get-help will also be clearer about the incompatibility

Copy link
Collaborator

@fflaten fflaten Apr 24, 2024

Choose a reason for hiding this comment

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

Maybe just skip the -Ago/FromNow and add support for negative value in string pattern? It simplifies the syntax and is self-documenting besides the Fluent-pattern. E.g.

Assert-After [-Now] [-Actual] <Object> [<CommonParameters>]
Assert-After [-TimeSpanFromNow] <timespan> [-Actual] <Object> [<CommonParameters>]
Assert-After [-TimePatternFromNow] <string> [-Actual] <Object> [<CommonParameters>]
Assert-After [-Expected] <datetime> [-Actual] <Object> [<CommonParameters>]

I'm a little conflicted with the string syntax in general. I really appreciate the readability and efficiency for very simple timespans and I'm fine with keeping it. However, it is proprietary and currently doesn't support for negative values and multiple units (see below).

TimeSpan itself has a string pattern that is applicable everywhere in PowerShell. PowerShell is all about learning things once, so we should promote the native ways when possible.

'1:15:10' -> '1h15m10s' # currently not supported in Fluent, would be 4510s
'-1.0:0:0' -> '-1d' # Fluent syntax is nicer

Copy link
Member Author

Choose a reason for hiding this comment

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

I was not sure if I am going too deep with the syntax. I agree on switching to different parameter sets. Your point about negative, multiple units and learning syntax once is all valid. But does it need to be that complicated?

What I was envisioning here is that the text syntax is used for more general use cases, like:

  • I fetched all data, and user provided 1 week filter, so no item should be older than a week.
  • I just created a user, make sure it is not older than 30 seconds.
  • I run my code, make sure it completes within 1 second.

Usually when I need a super precise time, I am just converting it from some other event that already has some timespan or a date, instead of relating it to now, so that syntax would not be usable there.

But I will think about it. I probably also need to capture the $currentTime in begin { } block, so it starts before the command. So e.g. if there is a user that is exactly 1 week old we don't fail.

Copy link
Collaborator

@fflaten fflaten Apr 24, 2024

Choose a reason for hiding this comment

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

What I was envisioning here is that the text syntax is used for more general use cases

I agree with your vision here. I do believe the parameter sets I suggested in the previous comment + supporting negative values in the Fluent-pattern would be a balanced solution. 🙂

  • Short and simple for most use cases with Fluent
  • Advanced with datetime or timespan. Timespan is not really required, but should stay as long as Fluent is there
  • No switches as they clutter what a - could provide
  • No ambiguous object-parameters.

Alternative with two string parameters without negative values:

Assert-After [-Now] [-Actual] <Object> [<CommonParameters>]
Assert-After [-Ago] <string> [-Actual] <Object> [<CommonParameters>]
Assert-After [-FromNow] <string> [-Actual] <Object> [<CommonParameters>]
Assert-After [-TimeSpanFromNow] <timespan> [-Actual] <Object> [<CommonParameters>]
Assert-After [-Expected] <datetime> [-Actual] <Object> [<CommonParameters>]

Copy link
Member Author

Choose a reason for hiding this comment

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

It’s also seems that it would be useful to provide a date time and timespan in the string format to be able to provide a $now. E.g. when you run a command and need to ensure the items you grabbed are not a week old since before the command started, and not since after the command finished.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure I follow. Assert-After -Ago "1w"?

Copy link
Member Author

Choose a reason for hiding this comment

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

$now = datetime.now
$files = Get-ReportsButNotOlderThan1Week
… | Should-BeAfter -Time $now -Ago 1w

so if the get-reports… command takes 30 seconds to finish and the oldest report is exactly one week old the assertion wont fail

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah okay. That's the "advanced" case I expected Should-BeAfter -Expected $now.AddDays(-7) to solve.

But I see your point, the datetime reference could easily be a parameter for timespan and string sets :)

@@ -32,13 +35,15 @@
.NOTES
Tests are excluded with Tags VersionChecks, StyleRules, Help.
#>
[CmdletBinding()]
Copy link
Collaborator

@fflaten fflaten Apr 23, 2024

Choose a reason for hiding this comment

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

This disabled remaining arguments which is why the -PassThru suddenly broke CI as the parameter doesn't exist.

@nohwnd
Copy link
Member Author

nohwnd commented Apr 24, 2024

This PR is getting too much, will start refactoring the existing assertions towards common pattern (to make them more similar to the current Should -* assertions), instead of adding new ones.

  • rename all files to Should-*
  • rename all test files to should-*, and use Should-Assertions in the tests instead of Assert- to make sure we export them. Get rid of inpestermodulescope
  • review messages so they look similar to existing assertions
  • write help
  • make type specific assertions require that type (e.g. should-*string needs string input)
  • Fix assertion for collections
  • Make sure that assertions throw for no input?

@nohwnd nohwnd modified the milestones: 6.0.0, Better Should Apr 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Way forward for Should?
2 participants