Skip to content

Commit de4018a

Browse files
test(help): pin the directive character class and the last-run-above rule
A scoped review of the help-detector fix found two behaviours the fixture set asserts but does not discriminate: mutating either survives every assertion in the file, so a regression in either would land green. The character class. The existing 'dotword-prose-voids-block' fixture is documented as pinning `\w` against `[A-Za-z]`, and does not -- `.NET` is pure ASCII, so both patterns match it identically and what that fixture actually pins is the argument group. Add 'digit-dotword-voids-block', whose `.EXAMPLE` body opens with `.5 is a fraction ...`: directive-shaped to `\w` alone. Measured on pwsh 7.6.5 and WinPS 5.1, Get-Help renders auto-generated syntax help and no parameter text for it, so narrowing the class would credit a cmdlet whose help does not render at all. Correct the attribution in the two comments that made the wrong claim. Which run above the function counts. Every above-function fixture holds exactly one run up there, so reading the first instead of the last is indistinguishable in all of them -- and in 'distant-header' the first falls through anyway, on adjacency. Add 'last-run-above-function-wins': a file header first, real help last, and a body block as well. Measured on both editions, Get-Help renders the last run, so reading the first would fall through and credit a body block no reader ever sees. Both fixtures were mutation-checked: narrowing the class to `[A-Za-z]` at both sites, and taking `$aboveRuns[0]`, each now fail the suite and passed before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 18141c4 commit de4018a

1 file changed

Lines changed: 74 additions & 1 deletion

File tree

‎Tests/PfbHelpCoverage.Tests.ps1‎

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,26 @@ function Get-PfbFixture {
12511251
[CmdletBinding()]
12521252
param([Parameter()] [string]$Name)
12531253
}
1254+
'@
1255+
# The one shape that separates `\w` from `[A-Za-z]`, and the reason it needs its own
1256+
# fixture: `.NET` above is pure ASCII, so it matches both patterns identically and
1257+
# pins only the ARGUMENT group. A digit- or underscore-led dot line is directive-shaped
1258+
# to `\w` alone. Measured on both editions -- Get-Help renders auto-generated syntax
1259+
# help and no parameter text for this fixture, so narrowing the pattern would credit a
1260+
# cmdlet whose help does not render at all.
1261+
'digit-dotword-voids-block' = @'
1262+
function Get-PfbFixture {
1263+
<#
1264+
.SYNOPSIS
1265+
A synopsis Get-Help never renders, because of the .EXAMPLE body below.
1266+
.PARAMETER Name
1267+
The fixture name.
1268+
.EXAMPLE
1269+
.5 is a fraction and not a path, so this line is a malformed directive
1270+
#>
1271+
[CmdletBinding()]
1272+
param([Parameter()] [string]$Name)
1273+
}
12541274
'@
12551275
# The adjacency BOUNDARY above the function, both sides of it. 'distant-header' never
12561276
# reaches this: its last run before the keyword is the line comment, so the block above
@@ -1288,6 +1308,36 @@ function Get-PfbFixture {
12881308
[CmdletBinding()]
12891309
param([Parameter()] [string]$Name)
12901310
}
1311+
'@
1312+
# Which of SEVERAL runs above the function is the one that counts. Every other
1313+
# above-function fixture has exactly one run up there, so taking the first instead of
1314+
# the last is indistinguishable in all of them -- and in 'distant-header' the first
1315+
# falls through anyway, on adjacency. Here the file header is first and the real help
1316+
# is last, and the two verdicts differ: measured on both editions, Get-Help renders the
1317+
# LAST run, so reading the first would leave the block above unexamined and credit a
1318+
# body block Get-Help never reads.
1319+
'last-run-above-function-wins' = @'
1320+
<#
1321+
.SYNOPSIS
1322+
File header for a script, not help for the function below it.
1323+
#>
1324+
1325+
<#
1326+
.SYNOPSIS
1327+
The block directly above the function, which Get-Help renders.
1328+
.PARAMETER Name
1329+
The fixture name.
1330+
#>
1331+
function Get-PfbFixture {
1332+
<#
1333+
.SYNOPSIS
1334+
A body block Get-Help never reads, because the block above it wins.
1335+
.PARAMETER Name
1336+
The fixture name.
1337+
#>
1338+
[CmdletBinding()]
1339+
param([Parameter()] [string]$Name)
1340+
}
12911341
'@
12921342
'ordinary-start-help-at-end' = @'
12931343
function Get-PfbFixture {
@@ -1572,9 +1622,15 @@ function Get-PfbFixture {
15721622
# run test walks every line rather than just the first: both of these open with a correct
15731623
# .SYNOPSIS and a correct .PARAMETER, and Get-Help renders auto-generated syntax help for
15741624
# both. 'dotword-prose-voids-block' is the sharp one -- `.NET Core ...` is prose to a
1575-
# reader and a malformed directive to Get-Help, because the directive pattern is `\w`.
1625+
# reader and a malformed directive to Get-Help.
15761626
# (`.\tools\...` in the 'dotted-prose' fixture is the harmless twin: a backslash is not a
15771627
# word character, so that line is body text and its block renders. The pair is the point.)
1628+
#
1629+
# What separates `.NET` from prose is the DOT plus word characters, which `\w` and
1630+
# `[A-Za-z]` agree on -- `NET` is pure ASCII, so this pair does not pin the character class
1631+
# and reading it as though it did is how the class went unpinned. What it does pin is the
1632+
# argument group: narrowing `(\S.*)` to `(\S+)` is killed here and nowhere else.
1633+
# 'digit-dotword-voids-block' is the fixture that pins `\w` itself.
15781634
$records['unknown-keyword-later-in-block'].HasHelpBlock |
15791635
Should -BeFalse -Because 'measured: one unrecognised directive anywhere in the run voids the whole block, .SYNOPSIS included'
15801636
$records['unknown-keyword-later-in-block'].MissingParameters | Should -Be @('Name')
@@ -1587,6 +1643,12 @@ function Get-PfbFixture {
15871643
$records['dotted-prose'].HasHelpBlock |
15881644
Should -BeTrue -Because 'the twin case: `.\tools\...` is NOT directive-shaped, because a backslash is not a word character, so that block renders'
15891645

1646+
$records['digit-dotword-voids-block'].HasHelpBlock |
1647+
Should -BeFalse -Because 'measured on both editions: `.5 is a fraction ...` is directive-shaped to `\w` and Get-Help renders no help for this cmdlet, so narrowing the class to `[A-Za-z]` would credit a block that does not render'
1648+
$records['digit-dotword-voids-block'].MissingParameters | Should -Be @('Name')
1649+
$records['digit-dotword-voids-block'].HelpRunDefect |
1650+
Should -BeLike '*5 is not a directive*'
1651+
15901652
# The adjacency BOUNDARY above the function. One blank line is still adjacency and two is
15911653
# not, and both sides need a fixture: 'distant-header' looks like it covers this and does
15921654
# not, because its last run before the keyword is the line comment rather than the block.
@@ -1602,5 +1664,16 @@ function Get-PfbFixture {
16021664
Should -BeTrue -Because 'nothing above the function is help, so Get-Help reads the body'
16031665
$records['distant-block-falls-through'].MissingParameters | Should -BeNullOrEmpty
16041666
$records['distant-block-falls-through'].OrphanedParameters | Should -BeNullOrEmpty
1667+
1668+
# WHICH run above the function is examined, when there is more than one. Both fixtures
1669+
# above hold a single run up there, so they cannot tell the last from the first; this one
1670+
# puts a file header first and the real help last. Measured on both editions: Get-Help
1671+
# renders the LAST run's synopsis and its parameter text, so examining the first would
1672+
# find a non-adjacent header, fall through, and credit the body block instead.
1673+
$records['last-run-above-function-wins'].HelpAboveFunction |
1674+
Should -BeTrue -Because 'measured: the run nearest the function keyword is the one Get-Help renders, header or not'
1675+
$records['last-run-above-function-wins'].HasHelpBlock |
1676+
Should -BeFalse -Because 'the help that renders sits above the function, so the body block is not what a reader sees and must not be scored as though it were'
1677+
$records['last-run-above-function-wins'].MissingParameters | Should -Be @('Name')
16051678
}
16061679
}

0 commit comments

Comments
 (0)