Skip to content

Commit 2b67a4e

Browse files
committed
Add tests for Add-Parameter and make them work
Fixes major bug in Invoke-ScriptGenerator (really in ConvertToAst) parameter set that I was not using.
1 parent 5d4bfa0 commit 2b67a4e

7 files changed

Lines changed: 153 additions & 41 deletions

File tree

.vscode/settings.json

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
{
2-
"files.trimTrailingWhitespace": true,
3-
"files.insertFinalNewline": true,
4-
"editor.tabSize": 4,
5-
"editor.insertSpaces": true,
6-
"files.encoding": "utf8",
7-
"powershell.codeFormatting.preset": "OTBS",
8-
"powershell.codeFormatting.ignoreOneLineBlock": false,
9-
"powershell.codeFormatting.newLineAfterCloseBrace": false,
10-
"powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline",
11-
"powershell.codeFormatting.alignPropertyValuePairs": true,
12-
"powershell.codeFormatting.autoCorrectAliases": true,
13-
"powershell.codeFormatting.useCorrectCasing": true,
14-
"powershell.scriptAnalysis.settingsPath": "ScriptAnalyzerSettings.psd1",
15-
"files.associations": {
16-
"*.ps1xml": "xml",
17-
".earthlyignore": "ignore"
18-
}
2+
"files.trimTrailingWhitespace": true,
3+
"files.insertFinalNewline": true,
4+
"editor.tabSize": 4,
5+
"editor.insertSpaces": true,
6+
"files.encoding": "utf8",
7+
"powershell.codeFormatting.preset": "OTBS",
8+
"powershell.codeFormatting.ignoreOneLineBlock": false,
9+
"powershell.codeFormatting.newLineAfterCloseBrace": false,
10+
"powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline",
11+
"powershell.codeFormatting.alignPropertyValuePairs": true,
12+
"powershell.codeFormatting.autoCorrectAliases": true,
13+
"powershell.codeFormatting.useCorrectCasing": true,
14+
"powershell.scriptAnalysis.settingsPath": "ScriptAnalyzerSettings.psd1",
15+
"files.associations": {
16+
"*.ps1xml": "xml",
17+
".earthlyignore": "ignore"
18+
},
19+
"coverage-gutters.coverageFileNames": ["coverage.xml"],
20+
"coverage-gutters.coverageBaseDir": "**"
1921
}
22+
23+
24+
25+
26+
27+
28+
29+

Earthfile

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION 0.8
1+
VERSION --try 0.8
22
IMPORT github.com/poshcode/tasks
33
FROM mcr.microsoft.com/dotnet/sdk:9.0
44
WORKDIR /work
@@ -43,12 +43,13 @@ build:
4343

4444
test:
4545
FROM +build
46-
RUN ["pwsh", "-Command", "Invoke-Build", "-Task", "Test", "-File", "Build.build.ps1"]
47-
48-
# re-output the build output so we can rely on running just +test locally
4946
SAVE ARTIFACT $OUTPUT_ROOT/$MODULE_NAME AS LOCAL ./Modules/$MODULE_NAME
50-
SAVE ARTIFACT $TEST_ROOT AS LOCAL ./Modules/$MODULE_NAME-TestResults
51-
47+
TRY
48+
RUN ["pwsh", "-Command", "Invoke-Build", "-Task", "Test", "-File", "Build.build.ps1"]
49+
FINALLY
50+
# re-output the build output so we can rely on running just +test locally
51+
SAVE ARTIFACT /Tests/coverage.xml AS LOCAL ./Modules/coverage.xml
52+
END
5253
all:
5354
# If we only reference with FROM (or COPY) the outputs will not be produced
5455
BUILD +test

Source/Private/ConvertToAst.ps1

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ function ConvertToAst {
3232
} catch {
3333
Write-Debug (" Exception resolving $Path as Path " + $_.Exception.Message)
3434
}
35-
if ($Provider.Name -eq "FileSystem") {
35+
if ($Path -and $Provider.Name -eq "FileSystem") {
3636
Write-Debug " Parse File Path: $Path"
3737
$AST = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$Tokens, [ref]$ParseErrors)
3838
} else {
39-
Write-Debug " Parse Code $(($Path -split "[\r\n]")[0])"
40-
$AST = [System.Management.Automation.Language.Parser]::ParseInput($Path, [ref]$Tokens, [ref]$ParseErrors)
39+
Write-Debug " Parse Path as Code $(($PSBoundParameters.Path -split "[\r\n]")[0])"
40+
$AST = [System.Management.Automation.Language.Parser]::ParseInput($PSBoundParameters.Path, [ref]$Tokens, [ref]$ParseErrors)
41+
$Path = "scriptblock"
4142
}
4243
}
4344
"Command" {
@@ -50,7 +51,7 @@ function ConvertToAst {
5051
"Code" {
5152
Write-Debug " Parse Code as ScriptBlock"
5253
if ($Code -is [System.Management.Automation.ScriptBlock]) {
53-
$Code = $Code.GetNewClosure().Invoke().ToString()
54+
$Code = $Code.GetNewClosure().ToString()
5455

5556
if (!$Path) {
5657
$Path = "scriptblock"
@@ -63,11 +64,11 @@ function ConvertToAst {
6364
} catch {
6465
Write-Debug (" Failed to resolve Code as Path " + $_.Exception.Message)
6566
}
66-
if ($Provider.Name -eq "FileSystem") {
67+
if ($Path -and $Provider.Name -eq "FileSystem") {
6768
Write-Debug " Parse File Path: $Path"
6869
$AST = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$Tokens, [ref]$ParseErrors)
6970
} else {
70-
Write-Debug " Parse Code $(($Path -split "[\r\n]")[0])"
71+
Write-Debug " Parse Code $(($Code -split "[\r\n]")[0])"
7172
$AST = [System.Management.Automation.Language.Parser]::ParseInput($Code, [ref]$Tokens, [ref]$ParseErrors)
7273
}
7374
}

Source/Public/Add-Parameter.ps1

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ function Add-Parameter {
1111
1212
Note that THIS generator does not add parameters to script files directly, but only to functions defined in the InputObject.
1313
.EXAMPLE
14-
# Or use a file path instead
15-
$Boilerplate = @'
14+
$Boilerplate = {
1615
param(
1716
# The Foreground Color (name, #rrggbb, etc)
1817
[Alias('Fg')]
@@ -25,18 +24,18 @@ function Add-Parameter {
2524
$ForegroundColor.ToVt() + $BackgroundColor.ToVt($true) + (
2625
Use-OriginalBlock
2726
) +"`e[0m" # Reset colors
28-
'@
27+
}
28+
2929
30-
# Or use a file path instead
31-
$Source = @'
30+
$Source = {
3231
function Show-Date {
3332
param(
3433
# The text to display
3534
[string]$Format
3635
)
3736
Get-Date -Format $Format
3837
}
39-
'@
38+
}
4039
4140
Invoke-ScriptGenerator $Source -Generator Add-Parameter -Parameters @{ FunctionName = "*"; Boilerplate = $Boilerplate } -OutVariable Source
4241
@@ -150,7 +149,9 @@ function Add-Parameter {
150149
[ParameterExtractor]$ExistingParameters = $ast
151150

152151
Write-Debug "Existing parameters in $($ast.Name): $($ExistingParameters.Parameters.Name -join ', ')"
152+
$global:ParameterSource = $this.ParameterSource
153153
$Additional = $this.ParameterSource.Parameters.Where{ $_.Name -notin $ExistingParameters.Parameters.Name }
154+
Write-Debug "Additional parameters from boilerplate: $($Additional.Count)"
154155
if (($Text = $Additional.Text -join ",`n`n")) {
155156
Write-Debug "Adding parameters to $($ast.Name): $($Additional.Name -join ', ')"
156157
$this.Replacements.Add(@{

Source/Public/Invoke-ScriptGenerator.ps1

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ function Invoke-ScriptGenerator {
105105
Write-Debug "Template = $($Parameters.Template)"
106106
}
107107
} catch {
108-
Write-Debug "Could not resolve the Boilerplate/Template"
108+
Write-Debug "Could not resolve the Boilerplate/Template as a file path. Assuming it's literal content."
109109
}
110110

111111
if (-not $Generator) {
@@ -134,12 +134,14 @@ function Invoke-ScriptGenerator {
134134
# Update the AST
135135
$ParseResults = ConvertToAst -Code $Builder.ToString() -Path $ParseResults.Path
136136
# In case a Generator tries to use the actual files, update the content
137-
Set-Content $ParseResults.Path $Builder
137+
if ($Overwrite -and $ParseResults.Path -and $ParseResults.Path -ne "scriptblock") {
138+
Set-Content $ParseResults.Path $Builder
139+
}
138140
}
139141
}
140142
end {
141-
Write-Debug "Overwrite: $Overwrite and it's a file: $([bool]$ParseResults.Path) (Content is $($Builder.Length) long)"
142-
if ($Overwrite -and $ParseResults.Path) {
143+
Write-Debug "Overwrite: $Overwrite and it's a file: $(([bool]$ParseResults.Path) -and $ParseResults.Path -ne "scriptblock") (Content is $($Builder.Length) long)"
144+
if ($Overwrite -and $ParseResults.Path -and $ParseResults.Path -ne "scriptblock") {
143145
Set-Content $ParseResults.Path $Builder
144146
} else {
145147
$Builder.ToString()

Tests/Private/ConvertToAst.Tests.ps1

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ Describe "ConvertToAst" {
2626
Context "It parses piped in commands" {
2727
BeforeAll {
2828
$ParseResult = InModuleScope ModuleBuilder {
29-
Get-Command ConvertToAst | ConvertToAst
29+
Get-Command ResolveBuildManifest, ResolveOutputFolder | ConvertToAst
3030
}
3131
}
3232

3333
It "Returns a ParseResult object with the AST" {
34-
$ParseResult.PSTypeNames[0] | Should -Match .*\.ParseResult
34+
$ParseResult[0].PSTypeNames[0] | Should -Match .*\.ParseResult
35+
$ParseResult[1].PSTypeNames[0] | Should -Match .*\.ParseResult
3536
$ParseResult.AST | Should -BeOfType [System.Management.Automation.Language.Ast]
3637
}
3738
}
@@ -48,4 +49,30 @@ Describe "ConvertToAst" {
4849
$ParseResult.AST | Should -BeOfType [System.Management.Automation.Language.Ast]
4950
}
5051
}
52+
53+
Context "It parses scriptblocks" {
54+
BeforeAll {
55+
$ParseResult = InModuleScope ModuleBuilder {
56+
ConvertToAst -Code { Get-Date }
57+
}
58+
}
59+
60+
It "Returns a ParseResult object with the AST" {
61+
$ParseResult.PSTypeNames[0] | Should -Match .*\.ParseResult
62+
$ParseResult.AST | Should -BeOfType [System.Management.Automation.Language.Ast]
63+
}
64+
}
65+
66+
Context "It parses code strings" {
67+
BeforeAll {
68+
$ParseResult = InModuleScope ModuleBuilder {
69+
ConvertToAst -Code "param([string]`$Name)"
70+
}
71+
}
72+
73+
It "Returns a ParseResult object with the AST" {
74+
$ParseResult.PSTypeNames[0] | Should -Match .*\.ParseResult
75+
$ParseResult.AST | Should -BeOfType [System.Management.Automation.Language.Ast]
76+
}
77+
}
5178
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#requires -Module ModuleBuilder
2+
3+
Describe "Add-Parameter" {
4+
Context "Example 1. Adding parameters to functions" {
5+
It "Adds boilerplate parameters to functions" {
6+
$boilerplate = {
7+
param(
8+
# The Foreground Color (name, #rrggbb, etc)
9+
[Alias('Fg')]
10+
[PoshCode.Pansies.RgbColor]$ForegroundColor,
11+
12+
# The Background Color (name, #rrggbb, etc)
13+
[Alias('Bg')]
14+
[PoshCode.Pansies.RgbColor]$BackgroundColor
15+
)
16+
}
17+
18+
$source = {
19+
function Show-Date {
20+
param(
21+
# The Date Format String
22+
[string]$Format = "o"
23+
)
24+
Get-Date -Format $Format
25+
}
26+
27+
function Show-UserName {
28+
[OutputType([string])]
29+
[CmdletBinding(DefaultParameterSetName = "SimpleFormat")]
30+
param()
31+
[Environment]::UserName
32+
}
33+
}
34+
35+
# Use Invoke-ScriptGenerator instead of calling Add-Parameter directly, to get the result of the transformation as text
36+
$result = Invoke-ScriptGenerator -Code $source -Generator Add-Parameter -Parameters @{
37+
FunctionName = "*"
38+
Boilerplate = $boilerplate
39+
}
40+
41+
$Tokens = $null
42+
$ParseErrors = $null
43+
$Ast = [System.Management.Automation.Language.Parser]::ParseInput($result, $Path, [ref]$Tokens, [ref]$ParseErrors)
44+
$ParseErrors | Should -BeNullOrEmpty
45+
$Ast | Should -Not -BeNullOrEmpty
46+
47+
# it should add those two parameters to both functions, without modifying the existing parameter
48+
$showDate = $Ast.Find({
49+
param($node)
50+
$node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and
51+
$node.Name -eq 'Show-Date'
52+
}, $true)
53+
54+
$showUserName = $Ast.Find({
55+
param($node)
56+
$node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and
57+
$node.Name -eq 'Show-UserName'
58+
}, $true)
59+
60+
61+
$showDate | Should -Not -BeNullOrEmpty
62+
$showDate.Body.ParamBlock.Parameters.Name.VariablePath.UserPath
63+
| Should -Be @('Format', 'ForegroundColor', 'BackgroundColor')
64+
65+
$showUserName | Should -Not -BeNullOrEmpty
66+
$showUserName.Body.ParamBlock.Parameters.Name.VariablePath.UserPath
67+
| Should -Be @('ForegroundColor', 'BackgroundColor')
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)