Skip to content

Commit b4345ec

Browse files
Fix explicit empty text defaults (#474)
## Summary - preserve an explicitly declared empty JSON default during manifest conversion - allow a text prompt to accept blank input only when its manifest explicitly declares a default - add end-to-end regression coverage for `default: ""` ## Verification - `pwsh -NoLogo -NoProfile -Command '$cfg = New-PesterConfiguration; $cfg.Run.Path = "./tests/EmptyDefaultTextParameter.Tests.ps1"; $cfg.Output.Verbosity = "Normal"; $cfg.Run.PassThru = $true; $result = Invoke-Pester -Configuration $cfg; exit $result.FailedCount'` - 3 passed, 0 failed Fixes #473.
1 parent cd6cd49 commit b4345ec

4 files changed

Lines changed: 112 additions & 5 deletions

File tree

‎Plaster/Private/ConvertFrom-JsonManifest.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function ConvertFrom-JsonManifest {
7171
$paramElement.SetAttribute('prompt', $param.prompt)
7272
}
7373

74-
if ($param.default) {
74+
if ($param.PSObject.Properties.Match('default').Count -gt 0) {
7575
if ($param.default -is [array]) {
7676
$paramElement.SetAttribute('default', ($param.default -join ','))
7777
} else {

‎Plaster/Private/Read-PromptForInput.ps1‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ function Read-PromptForInput {
33
param(
44
$prompt,
55
$default,
6-
$pattern
6+
$pattern,
7+
[switch]$AllowEmpty
78
)
89
if (!$pattern) {
910
$patternMatch = $true
1011
}
1112

1213
do {
1314
$value = Read-Host -Prompt $prompt
14-
if (!$value -and $default) {
15+
if (!$value -and ($AllowEmpty -or $default)) {
1516
$value = $default
1617
$patternMatch = $true
1718
} elseif ($value -and $pattern) {
@@ -21,7 +22,7 @@ function Read-PromptForInput {
2122
$PSCmdlet.WriteDebug("Value '$value' did not match the pattern '$pattern'")
2223
}
2324
}
24-
} while (!$value -or !$patternMatch)
25+
} while ((!$value -and !$AllowEmpty) -or !$patternMatch)
2526

2627
$value
2728
}

‎Plaster/Private/Resolve-ProcessParameter.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function Resolve-ProcessParameter {
7676
}
7777
}
7878
# Prompt the user for text input.
79-
$value = Read-PromptForInput $prompt $default @splat
79+
$value = Read-PromptForInput $prompt $default $pattern -AllowEmpty:$Node.HasAttribute('default')
8080
$valueToStore = $value
8181
}
8282
'user-fullname' {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
BeforeDiscovery {
2+
if ($null -eq $env:BHProjectPath) {
3+
$path = Join-Path -Path $PSScriptRoot -ChildPath '..\build.ps1'
4+
. $path -Task Build
5+
}
6+
$manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest
7+
$outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output'
8+
$outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName
9+
$outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion
10+
$outputModVerManifest = Join-Path $outputModVerDir "$($env:BHProjectName).psd1"
11+
Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore
12+
Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop
13+
}
14+
15+
Describe 'Empty text parameter defaults' -Tag 'Unit' {
16+
InModuleScope $env:BHProjectName {
17+
It 'preserves an explicit empty JSON default' {
18+
$manifest = ConvertFrom-JsonManifest -JsonContent @'
19+
{
20+
"schemaVersion": "2.0",
21+
"metadata": {
22+
"name": "EmptyDefault",
23+
"id": "513d2fdc-3cce-47d9-9531-d85114efb224",
24+
"version": "1.0.0",
25+
"title": "Empty default",
26+
"description": "Tests explicit empty defaults.",
27+
"author": "Plaster",
28+
"tags": ["Test"]
29+
},
30+
"parameters": [
31+
{
32+
"name": "ModuleDesc",
33+
"type": "text",
34+
"prompt": "Enter a description",
35+
"default": ""
36+
}
37+
],
38+
"content": [
39+
{
40+
"type": "file",
41+
"source": "source.txt",
42+
"destination": "source.txt"
43+
}
44+
]
45+
}
46+
'@
47+
48+
$parameter = $manifest.plasterManifest.parameters.parameter
49+
$parameter.HasAttribute('default') | Should -BeTrue
50+
$parameter.default | Should -BeExactly ''
51+
}
52+
53+
It 'accepts blank input when an empty default is explicit' {
54+
$script:responses = [System.Collections.Generic.Queue[string]]::new()
55+
$script:responses.Enqueue('')
56+
$script:responses.Enqueue('unexpected second prompt')
57+
Mock Read-Host { $script:responses.Dequeue() }
58+
59+
$result = Read-PromptForInput -prompt 'Enter a description' -default '' -AllowEmpty
60+
61+
$result | Should -BeExactly ''
62+
Should -Invoke Read-Host -Times 1 -Exactly
63+
}
64+
It 'completes a JSON template when its text default is empty' {
65+
$templatePath = Join-Path $TestDrive 'template'
66+
$destinationPath = Join-Path $TestDrive 'output'
67+
New-Item -ItemType Directory -Path $templatePath | Out-Null
68+
@'
69+
{
70+
"schemaVersion": "2.0",
71+
"metadata": {
72+
"name": "EmptyDefault",
73+
"id": "513d2fdc-3cce-47d9-9531-d85114efb224",
74+
"version": "1.0.0",
75+
"title": "Empty default",
76+
"description": "Tests explicit empty defaults.",
77+
"author": "Plaster",
78+
"tags": ["Test"]
79+
},
80+
"parameters": [
81+
{
82+
"name": "ModuleDesc",
83+
"type": "text",
84+
"prompt": "Enter a description",
85+
"default": ""
86+
}
87+
],
88+
"content": [
89+
{
90+
"type": "templateFile",
91+
"source": "description.txt",
92+
"destination": "description.txt"
93+
}
94+
]
95+
}
96+
'@ | Set-Content -LiteralPath (Join-Path $templatePath 'plasterManifest.json') -Encoding utf8
97+
'<%=$PLASTER_PARAM_ModuleDesc%>' | Set-Content -LiteralPath (Join-Path $templatePath 'description.txt') -Encoding utf8
98+
Mock Read-Host { '' }
99+
100+
Invoke-Plaster -TemplatePath $templatePath -DestinationPath $destinationPath -NoLogo
101+
102+
(Get-Content -LiteralPath (Join-Path $destinationPath 'description.txt') -Raw).Trim() | Should -BeExactly ''
103+
Should -Invoke Read-Host -Times 1 -Exactly
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)