Add -End switch to Mock for pipeline aggregation - #2947
Draft
nohwnd wants to merge 1 commit into
Draft
Conversation
Mocking a command that consumes the pipeline and returns once from its end block did not work. The mock runs MockWith once per piped item, so a command that returns a single object returned one object per input instead, and Should -Invoke counted one call per item. Add -End to Mock. With it the process block only collects the pipeline, and MockWith runs once from the end block over all the input. The collected input is piped into MockWith, so it is available as $input and MockWith can have its own begin/process/end blocks. Should -Invoke counts one call per pipeline, and the parameter filter sees the whole collected input bound to the pipeline parameter, so you can assert on all of it at once. All mocks for one command must be the same type. Mixing an -End mock and a per-call mock for the same command would put two different granularities in the call history and Should -Invoke could not count it, so it is rejected at definition time. This keeps the change additive, per-call mocks behave exactly as before.
| $Hook, | ||
| [string[]]$RemoveParameterType, | ||
| [string[]]$RemoveParameterValidation | ||
| [string[]]$RemoveParameterValidation, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix #2154
Mocking a command that takes pipeline input and returns once from its end block never
worked.
MockWithruns once per piped item, so a command that aggregates the pipelineand returns a single object returns one object per input instead, and
Should -Invokecounts one call per item.
The change
Add
-EndtoMock. With it the process block only collects the pipeline, andMockWithruns once from the end block over all the input.
Mock inner { "FOO" } -End @(outer).Count # 1The collected input is piped into
MockWith, so it is there as$inputandMockWithcanhave its own
begin/process/endblocks, just like the real command.Should -Invokecounts one call per pipeline, and the parameter filter sees the wholecollected input bound to the pipeline parameter, so you can assert on all of it at once.
Mock inner { "FOO" } -End $null = outer Should -Invoke inner -Times 1 -Exactly Should -Invoke inner -Times 1 -Exactly -ParameterFilter { $InputObject -contains 2 }Design
The idea: one mock type per command.
MockWithper item and records one call per item.-Endmock collects the pipeline and records one call per pipeline.All mocks for a single command must be the same type. Mixing the two would put two different
granularities in the call history and
Should -Invokecould not count it coherently, so it isrejected at definition time. That is what keeps
Should -Invokea plain counter, it does nothave to know about the two types, it just counts the history entries. Per-call mocks behave
exactly as before,
-Endis purely additive.Because the type carries the granularity, the filter naturally sees the aggregate for an
-Endmock, so there is no separate
-EndParameterFilter.Verification
262 existing Mock tests still pass, plus 16 new ones in
Mock.EndBlock.Tests.ps1(output shape,per-pipeline counting, filter over the aggregate,
-Verifiable, module scope, the homogeneityguard). Built inline and ran on PS 7.5.
Open questions, @fflaten LMK before I polish
-Endbecause that is what we said, but it reads a bit odd as a bareswitch (
Mock inner { } -End).-Aggregate/-PipelineEnd/-OnEndare alternatives.-Endmock and achild-scope per-call mock for the same command would slip through the definition-time check.
Do we care, or add a resolution-time guard too?
pwsh, see Can't mock a function that takes pipeline input #2154 powercode comment)has no
ValueFromPipelineparameter, so nothing binds by name for the filter. The input isstill collected and piped into
MockWith, but you cannot assert on it by parameter name.Probably fine for v1, but worth calling out.
Mock.Tests.ps1instead of a separate file?🤖