Cap Format-Nicely2 recursion depth to avoid call depth overflow#2830
Merged
Conversation
Failing asserts format the actual value with Format-Nicely2, which recurses through every property and collection element. Deeply nested or self-referential objects (such as SMO stub types, or DirectoryInfo whose Parent/Root point back up the tree) recursed until PowerShell threw "The script failed due to call depth overflow", which hid the real assertion result. Thread a Depth counter through the recursive formatters (Format-Collection2/Object2/Hashtable2/Dictionary2 and Format-Nicely2) and stop expanding once past a fixed depth, printing the value's type instead. Scalars are still fully formatted; only the recursing container/object branches are guarded. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
43ba24b to
1518c56
Compare
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.
Problem
When an assertion fails, Pester formats the actual value for the error message with
Format-Nicely2(src/Format2.ps1).Format-Nicely2→Format-Object2recurses through every property of an object by callingFormat-Nicely2again per property (and likewiseFormat-Collection2/Format-Hashtable2/Format-Dictionary2per element).For deeply nested or self-referential objects this recurses until PowerShell throws:
which hides the real assertion result. This happens with SQL Server Management Objects (SMO) stub types (reported in #2828) and, previously, with
DirectoryInfowhoseParent/Rootpoint back up the tree (#2474, partially mitigated by a hard-coded property map).Fix
Thread an
[int]$Depthparameter through the four recursive formatters andFormat-Nicely2. Each recursive call increments the depth; once past a fixed maximum depth of10Format-Nicely2stops expanding and prints the value's short type instead (e.g.[PSObject]), which is enough for a diagnostic message and cannot recurse further. The limit is a hard-coded constant, not a configurable script variable.The guard sits after the scalar branches (null/bool/string/type/number/scriptblock, which never recurse) and before the container/object branches (which do), so simple values are always fully formatted. Behavior for normally‑nested values is unchanged — the depth default of
0makes every existing single‑level call identical to before.Example, before vs after, for a self‑referential object:
The script failed due to call depth overflow.Expected value to have type [string], but got [PSObject] PSObject{Name='x'; Self=PSObject{…; Self=[PSObject]}}.Tests
tst/Format2.Tests.ps1: a self-referential object is truncated with a type marker instead of overflowing; values nested past the max depth are cut off.tst/functions/assert/General/Should-HaveType.Tests.ps1: a self-referential actual value now yields a normal assertion failure rather than a call-depth overflow.989 assert/format tests pass; the custom build analyzer is clean on the changed file.
Fix #2828