diff --git a/Build.build.ps1 b/Build.build.ps1
index 2ecfbdf..c43268f 100644
--- a/Build.build.ps1
+++ b/Build.build.ps1
@@ -19,6 +19,15 @@ param(
# Collect code coverage when tests are run
[switch]$CollectCoverage,
+ # The PesterFilter from New-PesterConfiguration.
+ # Supports specifying any of:
+ # Tag: Tags of Describe, Context or It to be run.
+ # ExcludeTag: Tags of Describe, Context or It to be excluded from the run.
+ # Line: Filter by file and scriptblock start line, useful to run parsed tests programmatically to avoid problems with expanded names. Example: 'C:\tests\file1.Tests.ps1:37'
+ # ExcludeLine: Exclude by file and scriptblock start line, takes precedence over Line.
+ # FullName: Full name of test with -like wildcards, joined by dot. Example: '*.describe Get-Item.test1'
+ [hashtable]$PesterFilter,
+
# Which projects to build
[Alias("Projects")]
$dotnetProjects = @(),
@@ -39,6 +48,7 @@ $ErrorView = 'DetailedView'
# The name of the module to publish
$script:PSModuleName = "TerminalBlocks"
+$script:RequiredCodeCoverage = 0.85
# Use Env because Earthly can override it
$Env:OUTPUT_ROOT ??= Join-Path $BuildRoot Modules
diff --git a/RequiredModules.psd1 b/RequiredModules.psd1
index 109c593..48b2068 100644
--- a/RequiredModules.psd1
+++ b/RequiredModules.psd1
@@ -2,7 +2,7 @@
@{
Configuration = "[1.5.0, 2.0)"
Metadata = "[1.5.1, 2.0)"
- Pester = "[4.10.1,5.0)"
+ Pester = "[5.6.1, 6.0)"
ModuleBuilder = "[3.0.0, 4.0)"
PSScriptAnalyzer = "[1.21.0,2.0)"
PowerShellGet = "2.0.4"
diff --git a/Source/Private/CompressToBase64.ps1 b/Source/Private/CompressToBase64.ps1
new file mode 100644
index 0000000..ff02d83
--- /dev/null
+++ b/Source/Private/CompressToBase64.ps1
@@ -0,0 +1,57 @@
+function CompressToBase64 {
+ <#
+ .SYNOPSIS
+ Compresses and encodes a module file for embedding into a script
+ .DESCRIPTION
+ Reads the raw bytes and then compress (gzip) them, before base64 encoding the result
+ .EXAMPLE
+ Get-ChildItem *.dll, *.psm1 | CompressToBase64 -ExpandScript ImportBase64Module > Script.ps1
+
+ Script.ps1 will contain the base64 encoded (and compressed) contents of the files, piped to the ImportBase64Module function
+ .LINK
+ ImportBase64Module
+ #>
+ [CmdletBinding(DefaultParameterSetName = "Base64")]
+ [OutputType([string])]
+ param(
+ # The path to the dll or script file to compress
+ [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
+ [Alias("PSPath")]
+ [string[]]$Path,
+
+ # If set, wraps the Base64 encoded content in the specified command
+ [Parameter(Mandatory, Position = 1, ParameterSetName = "ExpandScriptName")]
+ [string]$ExpandScriptName,
+
+ # If set, wraps the Base64 encoded content in the specified command
+ [Parameter(Mandatory, Position = 1, ParameterSetName = "ExpandScript")]
+ [ScriptBlock]$ExpandScript
+ )
+ begin {
+ $Result = @()
+ if ($ExpandScriptName -and !$ExpandScript) {
+ $ExpandScript = (Get-Command $ExpandScriptName).ScriptBlock
+ }
+ }
+ process {
+ foreach ($File in $Path | Convert-Path) {
+ $Source = [System.IO.MemoryStream][System.IO.File]::ReadAllBytes($File)
+ $OutputStream = [System.IO.Compression.DeflateStream]::new(
+ [System.IO.MemoryStream]::new(),
+ [System.IO.Compression.CompressionMode]::Compress)
+ $Source.CopyTo($OutputStream)
+ $OutputStream.Flush()
+ $ByteArray = $OutputStream.BaseStream.ToArray()
+ if (!$ExpandScript) {
+ [Convert]::ToBase64String($ByteArray)
+ } else {
+ $Result += [Convert]::ToBase64String($ByteArray)
+ }
+ }
+ }
+ end {
+ if ($ExpandScript) {
+ [ScriptBlock]::Create("@(`n'$($Result -join "'`n'")'`n)|.{`n${ExpandScript}`n}").ToString()
+ }
+ }
+}
diff --git a/Source/Private/CopyReadMe.ps1 b/Source/Private/CopyReadMe.ps1
index 533cc5a..a8e8576 100644
--- a/Source/Private/CopyReadMe.ps1
+++ b/Source/Private/CopyReadMe.ps1
@@ -1,4 +1,8 @@
function CopyReadMe {
+ <#
+ .SYNOPSIS
+ Copy the readme file as an about_ help file
+ #>
[CmdletBinding()]
param(
# The path to the ReadMe document to copy
@@ -22,19 +26,18 @@ function CopyReadMe {
[Switch]$Force
)
process {
- # Copy the readme file as an about_ help file
- Write-Verbose "Test for ReadMe: $Pwd/$($ReadMe)"
+ Write-Verbose "Test for ReadMe: $ReadMe"
if ($ReadMe -and (Test-Path $ReadMe -PathType Leaf)) {
# Make sure there's a language path
$LanguagePath = Join-Path $OutputDirectory $Culture
if (!(Test-Path $LanguagePath -PathType Container)) {
+ Write-Verbose "Create language path: $LanguagePath"
$null = New-Item $LanguagePath -Type Directory -Force
}
- Write-Verbose "Copy ReadMe to: $LanguagePath"
$about_module = Join-Path $LanguagePath "about_$($ModuleName).help.txt"
if (!(Test-Path $about_module)) {
- Write-Verbose "Turn readme into about_module"
+ Write-Verbose "Copy $ReadMe to: $about_module"
Copy-Item -LiteralPath $ReadMe -Destination $about_module -Force:$Force
}
}
diff --git a/Source/Private/ImportBase64Module.ps1 b/Source/Private/ImportBase64Module.ps1
new file mode 100644
index 0000000..8141f42
--- /dev/null
+++ b/Source/Private/ImportBase64Module.ps1
@@ -0,0 +1,43 @@
+# The comment-based help for this function is outside the function to avoid packing it
+# Normally, I put it inside, but I do not want this in packed scripts
+
+<#
+ .SYNOPSIS
+ Expands Base64+GZip strings and loads the result as an assembly or module
+ .DESCRIPTION
+ Converts Base64 encoded string to bytes and decompresses (gzip) it.
+ If the result is a valid assembly, it is loaded.
+ Otherwise, it is imported as a module.
+ .PARAMETER Base64Content
+ A Base64 encoded and deflated assembly or script
+ .LINK
+ CompressToBase64
+#>
+function ImportBase64Module {
+ [CmdletBinding(DefaultParameterSetName = "ByteArray")]
+ param(
+ [Parameter(Mandatory, ValueFromPipeline)]
+ [string]$Base64Content
+ )
+ process {
+ $Out = [System.IO.MemoryStream]::new()
+ $In = [System.IO.MemoryStream][System.Convert]::FromBase64String($Base64Content)
+ $zip = [System.IO.Compression.DeflateStream]::new($In, [System.IO.Compression.CompressionMode]::Decompress)
+ $zip.CopyTo($Out)
+ trap [System.IO.InvalidDataException] {
+ Write-Debug "Base64Content not Compressed. Skipping Deflate."
+ $In.CopyTo($Out)
+ continue
+ }
+ $null = $Out.Seek(0, "Begin")
+ $null = [System.Reflection.Assembly]::Load($Out.ToArray())
+ trap [BadImageFormatException] {
+ Write-Debug "Base64Content not an Assembly. Trying New-Module and ScriptBlock.Create."
+ $null = $Out.Seek(0, "Begin")
+ # Use StreamReader to handle possible BOM
+ $Source = [System.IO.StreamReader]::new($Out, $true).ReadToEnd()
+ $null = New-Module ([ScriptBlock]::Create($Source)) -Verbose:$false | Import-Module -Scope Global -Verbose:$false
+ continue
+ }
+ }
+}
diff --git a/Source/Private/MoveUsingStatements.ps1 b/Source/Private/MoveUsingStatements.ps1
deleted file mode 100644
index 82c2c87..0000000
--- a/Source/Private/MoveUsingStatements.ps1
+++ /dev/null
@@ -1,77 +0,0 @@
-function MoveUsingStatements {
- <#
- .SYNOPSIS
- A command to comment out and copy to the top of the file the Using Statements
- .DESCRIPTION
- When all files are merged together, the Using statements from individual files
- don't necessarily end up at the beginning of the PSM1, creating Parsing Errors.
-
- This function uses AST to comment out those statements (to preserver line numbering)
- and insert them (conserving order) at the top of the script.
- #>
- [CmdletBinding()]
- param(
- # Path to the PSM1 file to amend
- [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]
- [System.Management.Automation.Language.Ast]$AST,
-
- [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)]
- [AllowNull()]
- [System.Management.Automation.Language.ParseError[]]$ParseErrors,
-
- # The encoding defaults to UTF8 (or UTF8NoBom on Core)
- [Parameter(DontShow)]
- [string]$Encoding = $(if ($IsCoreCLR) {
- "UTF8NoBom"
- } else {
- "UTF8"
- })
- )
- process {
- # Avoid modifying the file if there's no Parsing Error caused by Using Statements or other errors
- if (!$ParseErrors.Where{ $_.ErrorId -eq 'UsingMustBeAtStartOfScript' }) {
- Write-Debug "No using statement errors found."
- return
- } else {
- # as decided https://github.com/PoshCode/ModuleBuilder/issues/96
- Write-Debug "Parsing errors found. We'll still attempt to Move using statements."
- }
-
- # Find all Using statements including those non erroring (to conserve their order)
- $UsingStatementExtents = $AST.FindAll(
- { $Args[0] -is [System.Management.Automation.Language.UsingStatementAst] },
- $false
- ).Extent
-
- # Edit the Script content by commenting out existing statements (conserving line numbering)
- $ScriptText = $AST.Extent.Text
- $InsertedCharOffset = 0
- $StatementsToCopy = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
-
- foreach ($UsingSatement in $UsingStatementExtents) {
- $ScriptText = $ScriptText.Insert($UsingSatement.StartOffset + $InsertedCharOffset, '#')
- $InsertedCharOffset++
-
- # Keep track of unique statements we'll need to insert at the top
- $null = $StatementsToCopy.Add($UsingSatement.Text)
- }
-
- $ScriptText = $ScriptText.Insert(0, ($StatementsToCopy -join "`r`n") + "`r`n")
- $null = Set-Content -Value $ScriptText -Path $RootModule -Encoding $Encoding
-
- # Verify we haven't introduced new Parsing errors
- $null = [System.Management.Automation.Language.Parser]::ParseFile(
- $RootModule,
- [ref]$null,
- [ref]$ParseErrors
- )
-
- if ($ParseErrors.Count) {
- $Message = $ParseErrors |
- Format-Table -Auto @{n = "File"; expr = { $_.Extent.File | Split-Path -Leaf }},
- @{n = "Line"; expr = { $_.Extent.StartLineNumber }},
- Extent, ErrorId, Message | Out-String
- Write-Warning "Parse errors in build output:`n$Message"
- }
- }
-}
diff --git a/Source/Public/Move-UsingStatement.ps1 b/Source/Public/Move-UsingStatement.ps1
new file mode 100644
index 0000000..4710361
--- /dev/null
+++ b/Source/Public/Move-UsingStatement.ps1
@@ -0,0 +1,65 @@
+using namespace System.Management.Automation.Language
+
+function Move-UsingStatement {
+ <#
+ .SYNOPSIS
+ A Script Generator that commetnts out using statements and copies them to the top of the file
+ .DESCRIPTION
+ Move-UsingStatement supports having using statements repeated in multiple files that are merged by ModuleBuilder.
+ When all the files are merged together, the using statements from individual files
+ don't necessarily end up at the beginning of the PSM1, which creates Parsing Errors.
+
+ This function uses the AST to generate TextReplacements to:
+ 1. Comment out the original using statements (to preserve line numbering)
+ 2. Insert the using statements (conserving order, but removing duplicates) at the top of the script
+ #>
+ [CmdletBinding()]
+ [OutputType([TextReplacement])]
+ param(
+ # The AST of the original script module to refactor
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias("Ast")]
+ [Ast]$InputObject,
+
+ # Parser Errors from parsing the original script module
+ [Parameter(ValueFromPipelineByPropertyName)]
+ [AllowNull()]
+ [ParseError[]]$ParseErrors
+ )
+ process {
+ # Avoid modifying the file if there's no Parsing Error caused by Using Statements or other errors
+ if (!$ParseErrors.Where{ $_.ErrorId -eq 'UsingMustBeAtStartOfScript' }) {
+ Write-Debug "No using statement errors found."
+ return
+ } else {
+ # as decided https://github.com/PoshCode/ModuleBuilder/issues/96
+ Write-Debug "Parsing errors found. We'll still attempt to Move using statements."
+ }
+
+ # Find all Using statements including those non erroring (to conserve their order)
+ $UsingStatementExtents = $InputObject.FindAll(
+ { $Args[0] -is [System.Management.Automation.Language.UsingStatementAst] },
+ $false
+ ).Extent
+
+ # Edit the Script content by commenting out existing statements (conserving line numbering)
+ $StatementsToCopy = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
+
+ foreach ($UsingSatement in $UsingStatementExtents) {
+ [TextReplacement]@{
+ StartOffset = $UsingSatement.StartOffset
+ EndOffset = $UsingSatement.EndOffset
+ Text = '# ' + $UsingSatement.Text
+ }
+ # Keep track of unique statements we'll need to insert at the top
+ $null = $StatementsToCopy.Add($UsingSatement.Text)
+ }
+ if ($StatementsToCopy.Count -gt 0) {
+ [TextReplacement]@{
+ StartOffset = 0
+ EndOffset = 0
+ Text = ($StatementsToCopy -join "`r`n")+ "`r`n"
+ }
+ }
+ }
+}
diff --git a/Tests/Integration/Parameters.Tests.ps1 b/Tests/Integration/Parameters.Tests.ps1
index 6206696..dd0b7d6 100644
--- a/Tests/Integration/Parameters.Tests.ps1
+++ b/Tests/Integration/Parameters.Tests.ps1
@@ -1,9 +1,11 @@
-#requires -Module ModuleBuilder
. $PSScriptRoot\..\Convert-FolderSeparator.ps1
Describe "Parameters.Set in build manifest" -Tag Integration {
BeforeAll {
+ # This file should not be deleted by the build, because VersionedOutput defaults true now
+ # So the actual Build output will be ../Result3/Parameters/3.0.0
New-Item $PSScriptRoot\Result3\Parameters\ReadMe.md -ItemType File -Force
+
$Output = Build-Module $PSScriptRoot\Parameters\build.psd1
if ($Output) {
$Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
@@ -11,19 +13,19 @@ Describe "Parameters.Set in build manifest" -Tag Integration {
}
}
- It "Passthru works" {
+ It "Passthru can be set from build.psd1" {
$Output | Should -Not -BeNullOrEmpty
}
- It "The Target is Build" {
- "$PSScriptRoot\Result3\Parameters\ReadMe.md" | Should -Exist
+ It "The version can be set from build.psd1" {
+ $Metadata.ModuleVersion | Should -Be "3.0.0"
}
- It "The version is set" {
- $Metadata.ModuleVersion | Should -Be "3.0.0"
+ It "Files outside the Output should not be cleaned up or overwritten" {
+ "$PSScriptRoot\Result3\Parameters\ReadMe.md" | Should -Exist
}
- It "The PreRelease is set" {
+ It "The PreRelease is set properly even when set from build.psd1" {
$Metadata.PrivateData.PSData.Prerelease | Should -Be 'alpha001'
}
}
diff --git a/Tests/Integration/Source1.Tests.ps1 b/Tests/Integration/Source1.Tests.ps1
index 63b5bb9..633737d 100644
--- a/Tests/Integration/Source1.Tests.ps1
+++ b/Tests/Integration/Source1.Tests.ps1
@@ -1,16 +1,17 @@
-#requires -Module ModuleBuilder
. $PSScriptRoot\..\Convert-FolderSeparator.ps1
+$ProgressPreference = "SilentlyContinue"
Describe "When we call Build-Module" -Tag Integration {
- $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru
- $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
+ BeforeAll {
+ $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru
+ $Metadata = Import-Metadata $Output.Path
+ $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
+ }
It "Should not put the module's DefaultCommandPrefix into the psm1 as code. Duh!" {
$Module | Should -Not -FileContentMatch '^Source$'
}
- $Metadata = Import-Metadata $Output.Path
-
It "Should update FunctionsToExport in the manifest" {
$Metadata.FunctionsToExport | Should -Be @("Get-Source", "Set-Source")
}
@@ -29,15 +30,16 @@ Describe "When we call Build-Module" -Tag Integration {
}
Describe "Regression test for #55: I can pass SourceDirectories" -Tag Integration, Regression {
- $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -SourceDirectories "Private" -Passthru
- $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
+ BeforeAll {
+ $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -SourceDirectories "Private" -Passthru
+ $Metadata = Import-Metadata $Output.Path
+ $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
+ }
It "Should not put the module's DefaultCommandPrefix into the psm1 as code. Duh!" {
$Module | Should -Not -FileContentMatch '^Source$'
}
- $Metadata = Import-Metadata $Output.Path
-
It "Should not have any FunctionsToExport if SourceDirectories don't match the PublicFilter" {
$Metadata.FunctionsToExport | Should -Be @()
}
@@ -54,8 +56,8 @@ Describe "Regression test for #55: I can pass SourceDirectories" -Tag Integratio
Describe "Regression test for #55: I can pass SourceDirectories and PublicFilter" -Tag Integration, Regression {
BeforeAll {
$Output = Build-Module $PSScriptRoot\Source1\build.psd1 -SourceDirectories "Private" -PublicFilter "Pub*\*" -Passthru
- $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
$Metadata = Import-Metadata $Output.Path
+ $Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
}
It "Should not put the module's DefaultCommandPrefix into the psm1 as code. Duh!" {
@@ -80,9 +82,10 @@ Describe "Regression test for #55: I can pass SourceDirectories and PublicFilter
}
Describe "Regression test for #84: Multiple Aliases per command will Export" -Tag Integration, Regression {
- $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru
-
- $Metadata = Import-Metadata $Output.Path
+ BeforeAll {
+ $Output = Build-Module $PSScriptRoot\Source1\build.psd1 -Passthru
+ $Metadata = Import-Metadata $Output.Path
+ }
It "Should update AliasesToExport in the manifest" {
$Metadata.AliasesToExport | Should -Be @("Get-MyAlias","GS","GSou", "SS", "SSou")
@@ -90,17 +93,19 @@ Describe "Regression test for #84: Multiple Aliases per command will Export" -Ta
}
Describe "Supports building without a build.psd1" -Tag Integration {
- Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse
- # This is the old build, with a build.psd1
- $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru
- $ManifestContent = Get-Content $Output.Path
- $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1"))
- Remove-Item (Split-Path $Output.Path) -Recurse
+ BeforeAll {
+ Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse
+ # This is the old build, with a build.psd1
+ $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru
+ $ManifestContent = Get-Content $Output.Path
+ $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1"))
+ Remove-Item (Split-Path $Output.Path) -Recurse
- # Then remove the build.psd1 and rebuild it
- Remove-Item TestDrive:\Source1\build.psd1
+ # Then remove the build.psd1 and rebuild it
+ Remove-Item TestDrive:\Source1\build.psd1
- $Build = @{ }
+ $Build = @{ }
+ }
It "No longer fails if there's no build.psd1" {
$BuildParameters = @{
@@ -158,17 +163,19 @@ Describe "Supports building without a build.psd1" -Tag Integration {
}
Describe "Defaults to VersionedOutputDirectory" -Tag Integration {
- Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse
- # This is the old build, with a build.psd1
- $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru
- $ManifestContent = Get-Content $Output.Path
- $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1"))
- Remove-Item (Split-Path $Output.Path) -Recurse
+ BeforeAll {
+ Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse
+ # This is the old build, with a build.psd1
+ $Output = Build-Module TestDrive:\Source1\build.psd1 -Passthru
+ $ManifestContent = Get-Content $Output.Path
+ $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1"))
+ Remove-Item (Split-Path $Output.Path) -Recurse
- # Then remove the build.psd1 and rebuild it
- Remove-Item TestDrive:\Source1\build.psd1
+ # Then remove the build.psd1 and rebuild it
+ Remove-Item TestDrive:\Source1\build.psd1
- $Build = @{ }
+ $Build = @{ }
+ }
It "Builds into a folder with version by default" {
$BuildParameters = @{
@@ -207,20 +214,22 @@ Describe "Defaults to VersionedOutputDirectory" -Tag Integration {
}
Describe "Supports building discovering the module without a build.psd1" -Tag Integration {
- Copy-Item $PSScriptRoot\Source1 TestDrive:\source -Recurse
+ BeforeAll {
+ Copy-Item $PSScriptRoot\Source1 TestDrive:\source -Recurse
- # This is the old build, with a build.psd1
- $Output = Build-Module TestDrive:\source\build.psd1 -Passthru
- $ManifestContent = Get-Content $Output.Path
- $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1"))
- Remove-Item (Split-Path $Output.Path) -Recurse
+ # This is the old build, with a build.psd1
+ $Output = Build-Module TestDrive:\source\build.psd1 -Passthru
+ $ManifestContent = Get-Content $Output.Path
+ $ModuleContent = Get-Content ([IO.Path]::ChangeExtension($Output.Path, ".psm1"))
+ Remove-Item (Split-Path $Output.Path) -Recurse
- # Then remove the build.psd1 and rebuild it
- Remove-Item TestDrive:\source\build.psd1
+ # Then remove the build.psd1 and rebuild it
+ Remove-Item TestDrive:\source\build.psd1
- Push-Location -StackName 'IntegrationTest' -Path TestDrive:\
+ Push-Location -StackName 'IntegrationTest' -Path TestDrive:\
- $Build = @{ }
+ $Build = @{ }
+ }
It "No longer fails if there's no build.psd1" {
$Build.Output = Build-Module -Passthru
@@ -239,16 +248,18 @@ Describe "Supports building discovering the module without a build.psd1" -Tag In
It "Should update FunctionsToExport in the manifest" {
$Build.Metadata.FunctionsToExport | Should -Be @("Get-Source", "Set-Source")
}
-
- Pop-Location -StackName 'IntegrationTest'
+ AfterAll {
+ Pop-Location -StackName 'IntegrationTest'
+ }
}
Describe "Regression test for #88 not copying prefix files" -Tag Integration, Regression {
- $Output = Build-Module $PSScriptRoot\build.psd1 -Passthru
-
- $Metadata = Import-Metadata $Output.Path
+ BeforeAll {
+ $Output = Build-Module $PSScriptRoot\build.psd1 -Passthru
+ $Metadata = Import-Metadata $Output.Path
+ }
- It "Should update AliasesToExport in the manifest" {
+ It "Should update the top of the module with that prefix" {
$Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
$ModuleInfo = Get-Content $Module
$ModuleInfo[0] | Should -be "using module Configuration"
@@ -256,21 +267,22 @@ Describe "Regression test for #88 not copying prefix files" -Tag Integration, Re
}
Describe "Regression test for #40.2 not copying suffix if prefix" -Tag Integration, Regression {
- Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse
-
- New-Item TestDrive:\Source1\_GlobalScope.ps1 -Value '$Global:Module = "Testing"'
+ BeforeAll {
+ Copy-Item $PSScriptRoot\Source1 TestDrive:\Source1 -Recurse
- $metadata = Import-Metadata TestDrive:\Source1\build.psd1
- $metadata += @{
- Prefix = "./_GlobalScope.ps1"
- Suffix = "./_GlobalScope.ps1"
- }
- $metadata | Export-Metadata TestDrive:\Source1\build.psd1
+ New-Item TestDrive:\Source1\_GlobalScope.ps1 -Value '$Global:Module = "Testing"'
- $Output = Build-Module TestDrive:\Source1 -Passthru
+ $metadata = Import-Metadata TestDrive:\Source1\build.psd1
+ $metadata += @{
+ Prefix = "./_GlobalScope.ps1"
+ Suffix = "./_GlobalScope.ps1"
+ }
+ $metadata | Export-Metadata TestDrive:\Source1\build.psd1
- $Metadata = Import-Metadata $Output.Path
+ $Output = Build-Module TestDrive:\Source1 -Passthru
+ $Metadata = Import-Metadata $Output.Path
+ }
It "Should inject the content of the _GlobalScope file at the TOP and BOTTOM" {
$Module = [IO.Path]::ChangeExtension($Output.Path, "psm1")
$Code = Get-Content $Module
@@ -288,10 +300,12 @@ Describe "Regression test for #40.2 not copying suffix if prefix" -Tag Integrati
# There's no such thing as a drive root on unix
if ($PSVersionTable.Platform -eq "Win32NT") {
Describe "Able to build from the drive root" {
- $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester"
- $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force
+ BeforeAll {
+ $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester"
+ $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force
- $Result = Build-Module -SourcePath 'TestDrive:/MyModule.psd1' -Version "1.0.0" -OutputDirectory './output' -Encoding UTF8 -SourceDirectories @('Public') -Target Build -Passthru
+ $Result = Build-Module -SourcePath 'TestDrive:/MyModule.psd1' -Version "1.0.0" -OutputDirectory './output' -Encoding UTF8 -SourceDirectories @('Public') -Target Build -Passthru
+ }
It "Builds the Module in the designated output folder" {
$Result.ModuleBase | Convert-FolderSeparator | Should -Be (Convert-FolderSeparator "TestDrive:/Output/MyModule/1.0.0")
@@ -301,20 +315,21 @@ if ($PSVersionTable.Platform -eq "Win32NT") {
}
Describe "Copies additional items specified in CopyPaths" {
+ BeforeAll {
+ $null = New-Item "TestDrive:/build.psd1" -Type File -Force -Value "@{
+ SourcePath = 'TestDrive:/MyModule.psd1'
+ SourceDirectories = @('Public')
+ OutputDirectory = './output'
+ CopyPaths = './lib', './MyModule.format.ps1xml'
+ }"
+ $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester"
+ $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force
+ $null = New-Item "TestDrive:/MyModule.format.ps1xml" -Type File -Value '' -Force
+ $null = New-Item "TestDrive:/lib/imaginary1.dll" -Type File -Value '1' -Force
+ $null = New-Item "TestDrive:/lib/subdir/imaginary2.dll" -Type File -Value '2' -Force
- $null = New-Item "TestDrive:/build.psd1" -Type File -Force -Value "@{
- SourcePath = 'TestDrive:/MyModule.psd1'
- SourceDirectories = @('Public')
- OutputDirectory = './output'
- CopyPaths = './lib', './MyModule.format.ps1xml'
- }"
- $null = New-ModuleManifest "TestDrive:/MyModule.psd1" -ModuleVersion "1.0.0" -Author "Tester"
- $null = New-Item "TestDrive:/Public/Test.ps1" -Type File -Value 'MATCHING TEST CONTENT' -Force
- $null = New-Item "TestDrive:/MyModule.format.ps1xml" -Type File -Value '' -Force
- $null = New-Item "TestDrive:/lib/imaginary1.dll" -Type File -Value '1' -Force
- $null = New-Item "TestDrive:/lib/subdir/imaginary2.dll" -Type File -Value '2' -Force
-
- $Result = Build-Module -SourcePath 'TestDrive:/build.psd1' -OutputDirectory './output' -Version '1.0.0' -Passthru -Target Build
+ $Result = Build-Module -SourcePath 'TestDrive:/build.psd1' -OutputDirectory './output' -Version '1.0.0' -Passthru -Target Build
+ }
It "Copies single files that are in CopyPaths" {
(Convert-FolderSeparator $Result.ModuleBase) | Should -Be (Convert-FolderSeparator "$TestDrive/output/MyModule/1.0.0")
diff --git a/Tests/Integration/Source2/Generators/NewTerminalBlock.ps1 b/Tests/Integration/Source2/Generators/NewTerminalBlock.ps1
new file mode 100644
index 0000000..bb25eb5
--- /dev/null
+++ b/Tests/Integration/Source2/Generators/NewTerminalBlock.ps1
@@ -0,0 +1,95 @@
+using module ModuleBuilder
+class TerminalBlockGenerator : ScriptGenerator {
+
+ [void] Generate() {
+
+ $base.AddParameter({
+ param(
+ [Alias("Prepend")]
+ [String]$Prefix,
+
+ [Alias("Suffix", "Append")]
+ [String]$Postfix,
+
+ # The separator character(s) are used between blocks of output by this scriptblock
+ # Pass two characters: the first for normal (Left aligned) blocks, the second for right-aligned blocks
+ [ArgumentCompleter({
+ [System.Collections.Generic.List[System.Management.Automation.CompletionResult]]::new(
+ [System.Management.Automation.CompletionResult[]]@(
+ # The Consolas-friendly block characters ▌and▐ and ╲ followed by all the extended Terminal characters
+ @([string[]][char[]]@(@(0xe0b0..0xe0d4) + @(0x2588..0x259b) + @(0x256d..0x2572))).ForEach({
+ [System.Management.Automation.CompletionResult]::new("'$_'", $_, "ParameterValue", $_) })
+ ))
+ })]
+ [String]$Separator,
+
+ # The cap character(s) are used on the ends of blocks of output
+ # Pass two characters: the first for the left side, the second for the right side.
+ [ArgumentCompleter({
+ [System.Collections.Generic.List[System.Management.Automation.CompletionResult]]::new(
+ [System.Management.Automation.CompletionResult[]]@(
+ # The Consolas-friendly block characters ▌and▐ and ╲ followed by all the extended Terminal characters
+ @([string[]][char[]]@(@(0xe0b0..0xe0d4) + @(0x2588..0x259b) + @(0x256d..0x2572))).ForEach({
+ [System.Management.Automation.CompletionResult]::new("'$_'", $_, "ParameterValue", $_) })
+ ))
+ })]
+ [PoshCode.BlockCaps]$Caps,
+
+ # The foreground color to use when the last command succeeded
+ [Alias("ForegroundColor", "Fg", "DFg")]
+ [AllowNull()][EmptyStringAsNull()]
+ [ArgumentCompleter([PoshCode.Pansies.Palettes.X11Palette])]
+ [PoshCode.Pansies.RgbColor]$DefaultForegroundColor,
+
+ # The background color to use when the last command succeeded
+ [Alias("BackgroundColor", "Bg", "DBg")]
+ [AllowNull()][EmptyStringAsNull()]
+ [ArgumentCompleter([PoshCode.Pansies.Palettes.X11Palette])]
+ [PoshCode.Pansies.RgbColor]$DefaultBackgroundColor,
+
+ # The foreground color to use when the process is elevated (running as administrator)
+ [Alias("AdminFg", "AFg")]
+ [AllowNull()][EmptyStringAsNull()]
+ [ArgumentCompleter([PoshCode.Pansies.Palettes.X11Palette])]
+ [PoshCode.Pansies.RgbColor]$AdminForegroundColor,
+
+ # The background color to use when the process is elevated (running as administrator)
+ [Alias("AdminBg", "ABg")]
+ [AllowNull()][EmptyStringAsNull()]
+ [ArgumentCompleter([PoshCode.Pansies.Palettes.X11Palette])]
+ [PoshCode.Pansies.RgbColor]$AdminBackgroundColor,
+
+ # The foreground color to use when the last command failed
+ [Alias("ErrorFg", "EFg")]
+ [AllowNull()][EmptyStringAsNull()]
+ [ArgumentCompleter([PoshCode.Pansies.Palettes.X11Palette])]
+ [PoshCode.Pansies.RgbColor]$ErrorForegroundColor,
+
+ # The background color to use when the last command failed
+ [Alias("ErrorBg", "EBg")]
+ [AllowNull()][EmptyStringAsNull()]
+ [ArgumentCompleter([PoshCode.Pansies.Palettes.X11Palette])]
+ [PoshCode.Pansies.RgbColor]$ErrorBackgroundColor
+ )
+ })
+
+ $base.AddBeforeEnd(@'
+ # Support default parameter values
+ $Parameters = Get-ParameterValue
+ $Parameters["Content"] = {
+'@)
+ $base.AddAfterEnd(@'
+ }.GetNewClosure()
+
+ # Strip common parameters if they're on here (so we can use -Verbose)
+ foreach ($name in @($Parameters.Keys.Where{ $_ -notin [PoshCode.TerminalBlock].GetProperties().Name })) {
+ $null = $Parameters.Remove($name)
+ }
+
+ # Store the InvocationInfo for serialization
+ $Parameters["MyInvocation"] = [System.Management.Automation.InvocationInfo].GetProperty("ScriptPosition", [System.Reflection.BindingFlags]"Instance,NonPublic").GetValue($MyInvocation).Text
+
+ [PoshCode.TerminalBlock]$Parameters
+'@)
+ }
+}
diff --git a/Tests/Private/CompressToBase64.Tests.ps1 b/Tests/Private/CompressToBase64.Tests.ps1
new file mode 100644
index 0000000..e5c4268
--- /dev/null
+++ b/Tests/Private/CompressToBase64.Tests.ps1
@@ -0,0 +1,61 @@
+Describe "CompressToBase64" {
+ Context "It compresses and encodes a file for embedding into a script" {
+ BeforeAll {
+ $Base64 = InModuleScope ModuleBuilder {
+ CompressToBase64 $PSCommandPath
+ }
+ }
+
+ It "Returns a base64 encoded string" {
+ $Base64 | Should -BeOfType [string]
+ $Base64 | Should -Match "^[A-Za-z0-9\+\/]+=*$"
+ $Base64.Length | Should -BeGreaterThan 0
+ }
+
+ It "Returns the gzipped and encoded script" {
+ $OutputStream = [System.IO.MemoryStream]::new()
+ $InputStream = [System.IO.MemoryStream][System.Convert]::FromBase64String($Base64)
+ $DeflateStream = [System.IO.Compression.DeflateStream]::new($InputStream, [System.IO.Compression.CompressionMode]::Decompress)
+ $DeflateStream.CopyTo($OutputStream)
+ $OutputStream.Seek(0, "Begin")
+ $Source = [System.IO.StreamReader]::new($OutputStream, $true).ReadToEnd()
+
+ $Source | Should -Be (Get-Content $PSCommandPath -Raw)
+ }
+ }
+
+ Context "It wraps the Base64 encoded content in the specified command" {
+ BeforeAll {
+ $Base64 = InModuleScope ModuleBuilder {
+ CompressToBase64 $PSCommandPath -ExpandScriptName ImportBase64Module
+ }
+ }
+
+ It "Returns a string" {
+ $Base64 | Should -BeOfType [string]
+ }
+
+ It "Pipes the encoding into the command" {
+ $Block = InModuleScope ModuleBuilder {
+ (Get-Command ImportBase64Module).ScriptBlock
+ }
+
+ $Base64 | Should -Match "|.{`n$Block`n}$"
+ }
+ }
+
+ Context "It wraps the Base64 encoded content in the specified scriptblock" {
+ BeforeAll {
+ $Base64 = InModuleScope ModuleBuilder {
+ Get-ChildItem $PSCommandPath | CompressToBase64 -ExpandScript { ImportBase64Module }
+ }
+ }
+
+ It "Returns a string" {
+ $Base64 | Should -BeOfType [string]
+ }
+ It "Pipes the encoding into the scriptblock" {
+ $Base64 | Should -Match "|.{`nImportBase64Module`n}$"
+ }
+ }
+}
diff --git a/Tests/Private/ConvertToAst.Tests.ps1 b/Tests/Private/ConvertToAst.Tests.ps1
index 5ccca7e..4d49920 100644
--- a/Tests/Private/ConvertToAst.Tests.ps1
+++ b/Tests/Private/ConvertToAst.Tests.ps1
@@ -1,9 +1,16 @@
-#requires -Module ModuleBuilder
Describe "ConvertToAst" {
+ BeforeAll {
+ $PSDefaultParameterValues = @{
+ "Mock:ModuleName" = "ModuleBuilder"
+ "Assert-MockCalled:ModuleName" = "ModuleBuilder"
+ }
+ }
Context "It returns a ParseResult for file paths" {
- $ParseResult = InModuleScope ModuleBuilder {
- ConvertToAst $PSCommandPath
+ BeforeAll {
+ $ParseResult = InModuleScope ModuleBuilder {
+ ConvertToAst -Code $PSCommandPath
+ }
}
It "Returns a ParseResult object" {
@@ -18,12 +25,13 @@ Describe "ConvertToAst" {
It "Has a Tokens property" {
$ParseResult.Tokens | Should -BeOfType [System.Management.Automation.Language.Token]
}
-
}
Context "It parses piped in commands" {
- $ParseResult = InModuleScope ModuleBuilder {
- Get-Command ConvertToAst | ConvertToAst
+ BeforeAll {
+ $ParseResult = InModuleScope ModuleBuilder {
+ Get-Command ConvertToAst | ConvertToAst
+ }
}
It "Returns a ParseResult object with the AST" {
@@ -33,8 +41,10 @@ Describe "ConvertToAst" {
}
Context "It parses piped in modules" {
- $ParseResult = InModuleScope ModuleBuilder {
- Get-Module ModuleBuilder | ConvertToAst
+ BeforeAll {
+ $ParseResult = InModuleScope ModuleBuilder {
+ Get-Module ModuleBuilder | ConvertToAst
+ }
}
It "Returns a ParseResult object with the AST" {
diff --git a/Tests/Private/CopyReadMe.Tests.ps1 b/Tests/Private/CopyReadMe.Tests.ps1
index b72bc71..04d0ac2 100644
--- a/Tests/Private/CopyReadMe.Tests.ps1
+++ b/Tests/Private/CopyReadMe.Tests.ps1
@@ -1,61 +1,60 @@
-#requires -Module ModuleBuilder
Describe "Copy ReadMe" {
- . $PSScriptRoot\..\Convert-FolderSeparator.ps1
+ BeforeAll {
+ . $PSScriptRoot\..\Convert-FolderSeparator.ps1
+ $PSDefaultParameterValues = @{
+ "Mock:ModuleName" = "ModuleBuilder"
+ "Assert-MockCalled:ModuleName" = "ModuleBuilder"
+ }
+ }
Context "There's no ReadMe" {
# It should not even call Test-Path
It "Does nothing if no ReadMe is passed" {
- Mock Test-Path -ModuleName ModuleBuilder
+ Mock Test-Path
InModuleScope ModuleBuilder {
Get-Module ModuleBuilder | CopyReadMe -OutputDirectory TestDrive:\
}
- Assert-MockCalled Test-Path -Times 0 -ModuleName ModuleBuilder
+ Assert-MockCalled Test-Path -Times 0
}
# It's possible it should warn in this case?
It "Does nothing if ReadMe doesn't exist" {
- Mock Test-Path -ModuleName ModuleBuilder
- Mock Join-Path -ModuleName ModuleBuilder
+ Mock Test-Path
+ Mock Join-Path
InModuleScope ModuleBuilder {
Get-Module ModuleBuilder | CopyReadMe -Readme ReadMe.md -OutputDirectory TestDrive:\
}
# Test-Path is only called once -- means it didn't check for the folder
- Assert-MockCalled Test-Path -Times 1 -ModuleName ModuleBuilder
- Assert-MockCalled Join-Path -Times 0 -ModuleName ModuleBuilder
+ Assert-MockCalled Test-Path -Times 1
+ Assert-MockCalled Join-Path -Times 0
}
}
Context "There is a ReadMe" {
- # Nothing is actually created when this test runs
- Mock New-Item -ModuleName ModuleBuilder
- Mock Copy-Item -ModuleName ModuleBuilder
-
- # Test-Path returns true only for the source document
- ${global:Test Script Path} = Join-Path $PSScriptRoot CopyReadMe.Tests.ps1
- Mock Test-Path { $Path -eq ${global:Test Script Path} } -ModuleName ModuleBuilder
+ BeforeAll {
+ # Test-Path returns true only for the source document
+ ${global:Test Script Path} = Join-Path $PSScriptRoot CopyReadMe.Tests.ps1
- Remove-Item TestDrive:\En -Recurse -Force -ErrorAction SilentlyContinue
+ Remove-Item "$TestDrive/en" -Recurse -Force -ErrorAction SilentlyContinue
- InModuleScope ModuleBuilder {
- CopyReadMe -ReadMe ${global:Test Script Path} -Module ModuleBuilder -OutputDirectory TestDrive:\ -Culture "En"
+ InModuleScope ModuleBuilder {
+ CopyReadMe -ReadMe ${global:Test Script Path} -Module ModuleBuilder -OutputDirectory $TestDrive -Culture "en"
+ }
}
It "Creates a language path in the output" {
- Assert-MockCalled New-Item -ModuleName ModuleBuilder -ParameterFilter {
- (Convert-FolderSeparator "$Path") -eq (Convert-FolderSeparator "TestDrive:\En")
- }
+ "$TestDrive/en" | Should -Exist
}
It "Copies the readme as about_module.help.txt" {
- Assert-MockCalled Copy-Item -ModuleName ModuleBuilder -ParameterFilter {
- (Convert-FolderSeparator $Destination) -eq (Convert-FolderSeparator "TestDrive:\En\about_ModuleBuilder.help.txt")
- }
+ "$TestDrive/en/about_ModuleBuilder.help.txt" | Should -Exist
+ }
+ AfterAll {
+ Remove-Item "$TestDrive/en" -Recurse -Force -ErrorAction SilentlyContinue
}
-
- Remove-Item TestDrive:\En -Recurse -Force -ErrorAction SilentlyContinue
}
}
diff --git a/Tests/Private/GetBuildInfo.Tests.ps1 b/Tests/Private/GetBuildInfo.Tests.ps1
index ab0ba09..1dbea4f 100644
--- a/Tests/Private/GetBuildInfo.Tests.ps1
+++ b/Tests/Private/GetBuildInfo.Tests.ps1
@@ -1,79 +1,73 @@
-#requires -Module ModuleBuilder
Describe "GetBuildInfo" {
. $PSScriptRoot\..\Convert-FolderSeparator.ps1
- Mock Import-Metadata -ModuleName ModuleBuilder {
- @{
- #Omitting path to let it resolve [Path = "MyModule.psd1"]
- SourceDirectories = "Classes", "Public"
+ BeforeAll {
+ $PSDefaultParameterValues = @{
+ "Mock:ModuleName" = "ModuleBuilder"
+ "Assert-MockCalled:ModuleName" = "ModuleBuilder"
}
}
- Context "It collects the initial data" {
-
- # use -Force to create the subdirectories
- New-Item -Force "TestDrive:\MyModule\Source\build.psd1" -Type File -Value "@{ Path = 'MyModule.psd1' }"
- New-ModuleManifest "TestDrive:\MyModule\Source\MyModule.psd1" -Author Tester
+ Context "Collects the initial data" {
+ BeforeAll {
+ # use -Force to create the subdirectories
+ New-Item -Force "$TestDrive/MyModule/Source/build.psd1" -Type File -Value "@{ Path = 'MyModule.psd1'; SourceDirectories = 'Classes', 'Public' }"
+ New-ModuleManifest "$TestDrive/MyModule/Source/MyModule.psd1" -Author Tester
- $Result = InModuleScope -ModuleName ModuleBuilder {
+ $Result = InModuleScope ModuleBuilder {
- # Used to resolve the overridden parameters in $Invocation
- $OutputDirectory = '..\ridiculoustestvalue'
+ # Used to resolve the overridden parameters in $Invocation
+ $OutputDirectory = '../ridiculoustestvalue'
- GetBuildInfo -BuildManifest TestDrive:\MyModule\Source\build.psd1 -BuildCommandInvocation @{
- MyCommand = @{
- Parameters = @{
- Encoding = @{ParameterType = "string" }
- Target = @{ParameterType = "string" }
- SourcePath = @{ParameterType = "string" }
- SourceDirectories = @{ParameterType = "string[]" }
- OutputDirectory = @{ParameterType = "string" }
+ GetBuildInfo -BuildManifest $TestDrive/MyModule/Source/build.psd1 -BuildCommandInvocation @{
+ MyCommand = @{
+ Parameters = @{
+ Encoding = @{ParameterType = "string" }
+ Target = @{ParameterType = "string" }
+ SourcePath = @{ParameterType = "string" }
+ SourceDirectories = @{ParameterType = "string[]" }
+ OutputDirectory = @{ParameterType = "string" }
+ }
+ }
+ BoundParameters = @{
+ OutputDirectory = '../ridiculoustestvalue'
}
}
- BoundParameters = @{
- OutputDirectory = '..\ridiculoustestvalue'
- }
- }
- }
-
- It "Parses the build.psd1" {
- Assert-MockCalled Import-Metadata -ModuleName ModuleBuilder -ParameterFilter {
- (Convert-FolderSeparator $Path) -eq (Convert-FolderSeparator "TestDrive:\MyModule\Source\build.psd1")
}
}
It "Reads bound parameters from the BuildCommandInvocation" {
- $Result.OutputDirectory |Should -Be "..\ridiculoustestvalue"
+ $Result.OutputDirectory |Should -Be "../ridiculoustestvalue"
}
It "Returns the resolved Module path, SourceDirectories, and overridden OutputDirectory (via Invocation param)" {
# if set in build.psd1 it will stay the same (i.e. relative)
(Convert-FolderSeparator $Result.SourcePath) |
- Should -Be (Convert-FolderSeparator "TestDrive:\MyModule\Source\MyModule.psd1")
+ Should -Be (Convert-FolderSeparator "$TestDrive/MyModule/Source/MyModule.psd1")
$Result.SourceDirectories | Should -Be @("Classes", "Public")
- $Result.OutputDirectory | Should -Be '..\ridiculoustestvalue'
+ $Result.OutputDirectory | Should -Be '../ridiculoustestvalue'
}
}
Context 'Error when calling GetBuildInfo the wrong way' {
It 'Should throw if the SourcePath does not exist' {
- {InModuleScope -ModuleName ModuleBuilder {
- GetBuildInfo -BuildManifest TestDrive:\NOTEXIST\Source\build.psd1
+ {InModuleScope ModuleBuilder {
+ GetBuildInfo -BuildManifest $TestDrive/NOTEXIST/Source/build.psd1
}} | Should -Throw
}
It 'Should throw if the Build Manifest does not point to a build.psd1 file' {
- {InModuleScope -ModuleName ModuleBuilder {
- GetBuildInfo -BuildManifest TestDrive:\NOTEXIST\Source\ERROR.psd1
+ {InModuleScope ModuleBuilder {
+ GetBuildInfo -BuildManifest $TestDrive/NOTEXIST/Source/ERROR.psd1
}} | Should -Throw
}
It 'Should throw if the Module manifest does not exist' {
# use -Force to create the subdirectories
- New-Item -Force TestDrive:\NoModuleManifest\Source\build.psd1 -ItemType File
- {InModuleScope -ModuleName ModuleBuilder {
- GetBuildInfo -BuildManifest TestDrive:\NoModuleManifest\Source\build.psd1
+ New-Item -Force $TestDrive/NoModuleManifest/Source/build.psd1 -ItemType File
+ {InModuleScope ModuleBuilder {
+ GetBuildInfo -BuildManifest $TestDrive/NoModuleManifest/Source/build.psd1
}} | Should -Throw
}
}
diff --git a/Tests/Private/GetRelativePath.Tests.ps1 b/Tests/Private/GetRelativePath.Tests.ps1
index e11aae9..2c4d219 100644
--- a/Tests/Private/GetRelativePath.Tests.ps1
+++ b/Tests/Private/GetRelativePath.Tests.ps1
@@ -1,7 +1,9 @@
-#requires -Module ModuleBuilder
+
Describe "GetRelativePath" {
- . $PSScriptRoot\..\Convert-FolderSeparator.ps1
- $CommandInfo = InModuleScope ModuleBuilder { Get-Command GetRelativePath }
+ BeforeAll {
+ . $PSScriptRoot\..\Convert-FolderSeparator.ps1
+ $CommandInfo = InModuleScope ModuleBuilder { Get-Command GetRelativePath }
+ }
Context "All Parameters are mandatory" {
@@ -23,34 +25,36 @@ Describe "GetRelativePath" {
# I'm not going to bother writing tests for this other than "it's the same as .NET's"
if ([System.IO.Path]::GetRelativePath) {
Context "The output always matches [System.IO.Path]::GetRelativePath" {
- $TestCases = @(
- @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source" }
- @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source\Public" }
- @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output" }
- @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output\" }
- @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output\" }
- @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output" }
- @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Modules\MyModule" }
- @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Projects\Modules\MyModule" }
- # These ones are backwards, but they still work
- @{ RelativeTo = "G:\Module\Source" ; Path = "G:\Module" }
- @{ RelativeTo = "G:\Module\Source\Public"; Path = "G:\Module" }
- # These are linux-like:
- @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder/Source"; }
- @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Output"; }
- @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/"; }
- # Weird PowerShell Paths
- @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:\Projects" }
- @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:/Projects" }
- @{ RelativeTo = "TestDrive:/Projects"; Path = "TestDrive:/Projects/Modules/ModuleBuilder" }
- )
-
- # On Windows, there's a shortcut when the path points to totally different drive letters:
- if ($PSVersionTable.Platform -eq "Win32NT") {
- $TestCases += @(
- @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "C:\Modules\MyModule" }
- @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "F:\Projects\Modules\MyModule" }
+ BeforeDiscovery {
+ $TestCases = @(
+ @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source" }
+ @{ RelativeTo = "G:\Module"; Path = "G:\Module\Source\Public" }
+ @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output" }
+ @{ RelativeTo = "G:\Module\Source"; Path = "G:\Module\Output\" }
+ @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output\" }
+ @{ RelativeTo = "G:\Module\Source\"; Path = "G:\Module\Output" }
+ @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Modules\MyModule" }
+ @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "G:\Projects\Modules\MyModule" }
+ # These ones are backwards, but they still work
+ @{ RelativeTo = "G:\Module\Source" ; Path = "G:\Module" }
+ @{ RelativeTo = "G:\Module\Source\Public"; Path = "G:\Module" }
+ # These are linux-like:
+ @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder/Source"; }
+ @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/Output"; }
+ @{ RelativeTo = "/mnt/c/Users/Jaykul/Projects/Modules/ModuleBuilder"; Path = "/mnt/c/Users/Jaykul/Projects/"; }
+ # Weird PowerShell Paths
+ @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:\Projects" }
+ @{ RelativeTo = "TestDrive:/Projects/Modules/ModuleBuilder"; Path = "TestDrive:/Projects" }
+ @{ RelativeTo = "TestDrive:/Projects"; Path = "TestDrive:/Projects/Modules/ModuleBuilder" }
)
+
+ # On Windows, there's a shortcut when the path points to totally different drive letters:
+ if ($PSVersionTable.Platform -eq "Win32NT") {
+ $TestCases += @(
+ @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "C:\Modules\MyModule" }
+ @{ RelativeTo = "G:\Projects\Modules\MyModule\Source\Public"; Path = "F:\Projects\Modules\MyModule" }
+ )
+ }
}
It "Returns the same result as Path.GetRelativePath for " -TestCases $TestCases {
diff --git a/Tests/Private/ImportBase64Module.Tests.ps1 b/Tests/Private/ImportBase64Module.Tests.ps1
new file mode 100644
index 0000000..fe96371
--- /dev/null
+++ b/Tests/Private/ImportBase64Module.Tests.ps1
@@ -0,0 +1,38 @@
+Describe "ImportBase64Module" {
+ BeforeAll {
+ $PSDefaultParameterValues = @{
+ "Mock:ModuleName" = "ModuleBuilder"
+ "Assert-MockCalled:ModuleName" = "ModuleBuilder"
+ }
+
+ $Source = Convert-Path (Join-Path $PSScriptRoot ../Integration/Source1/Public/Set-Source.ps1)
+
+ $CommandUnderTest, $Base64 = InModuleScope ModuleBuilder {
+ Get-Command ImportBase64Module
+ CompressToBase64 (Join-Path $PSScriptRoot ../Integration/Source1/Public/Set-Source.ps1) -Debug
+ }
+
+ $Plain = Get-Content $Source -Raw
+
+ }
+
+ It "Calls New-Module with the decompressed script" {
+ Mock New-Module
+ & $CommandUnderTest $Base64
+
+ Assert-MockCalled New-Module -ParameterFilter {
+ "$ScriptBlock" -eq $Plain
+ }
+ }
+
+ It "Calls Import-Module with the new module" {
+ Mock Import-Module
+ & $CommandUnderTest $Base64
+
+ Assert-MockCalled Import-Module -ParameterFilter {
+ $ModuleInfo[0].Definition -eq $Plain
+ }
+ }
+
+ # TODO: Test assemblies
+}
diff --git a/Tests/Private/ImportModuleManifest.Tests.ps1 b/Tests/Private/ImportModuleManifest.Tests.ps1
index 7c7dbf1..0b02e33 100644
--- a/Tests/Private/ImportModuleManifest.Tests.ps1
+++ b/Tests/Private/ImportModuleManifest.Tests.ps1
@@ -1,8 +1,9 @@
-#requires -Module ModuleBuilder
Describe "ImportModuleManifest" {
Context "Mandatory Parameter" {
- $CommandInfo = InModuleScope ModuleBuilder { Get-Command ImportModuleManifest }
+ BeforeAll {
+ $CommandInfo = InModuleScope ModuleBuilder { Get-Command ImportModuleManifest }
+ }
It 'has a mandatory Path parameter for the PSPath by pipeline' {
$Path = $CommandInfo.Parameters['Path']
diff --git a/Tests/Private/InitializeBuild.Tests.ps1 b/Tests/Private/InitializeBuild.Tests.ps1
index b48427e..9673f92 100644
--- a/Tests/Private/InitializeBuild.Tests.ps1
+++ b/Tests/Private/InitializeBuild.Tests.ps1
@@ -1,24 +1,24 @@
-#requires -Module ModuleBuilder
Describe "InitializeBuild" {
- . $PSScriptRoot\..\Convert-FolderSeparator.ps1
-
+ BeforeAll {
+ . $PSScriptRoot\..\Convert-FolderSeparator.ps1
+ }
Context "It collects the initial data" {
+ BeforeAll {
+ # Note that "Path" is an alias for "SourcePath"
+ New-Item "TestDrive:\build.psd1" -Type File -Force -Value '@{
+ Path = ".\Source\MyModule.psd1"
+ SourceDirectories = @("Classes", "Private", "Public")
+ }'
- # Note that "Path" is an alias for "SourcePath"
- New-Item "TestDrive:\build.psd1" -Type File -Force -Value '@{
- Path = ".\Source\MyModule.psd1"
- SourceDirectories = @("Classes", "Private", "Public")
- }'
-
- New-Item "TestDrive:\Source\" -Type Directory
+ New-Item "TestDrive:\Source\" -Type Directory
- New-ModuleManifest "TestDrive:\Source\MyModule.psd1" -RootModule "MyModule.psm1" -Author "Test Manager" -ModuleVersion "1.0.0"
-
- $Result = @{}
+ New-ModuleManifest "TestDrive:\Source\MyModule.psd1" -RootModule "MyModule.psm1" -Author "Test Manager" -ModuleVersion "1.0.0"
+ $Result = @{}
+ }
It "Handles Build-Module parameters, and the build.psd1 configuration" {
Push-Location TestDrive:\
- $Result.Result = InModuleScope -ModuleName ModuleBuilder {
+ $Result.Result = InModuleScope ModuleBuilder {
function Test-Build {
[CmdletBinding()]
param(
@@ -38,35 +38,33 @@ Describe "InitializeBuild" {
}
}
- Test-Build 'TestDrive:\' -Suffix "Export-ModuleMember *"
+ Test-Build 'TestDrive:\' -Suffix "Export-ModuleMember *" -WarningAction SilentlyContinue
}
Pop-Location
$Result.Result | Should -Not -BeOfType [System.Management.Automation.ErrorRecord]
}
- $Result = $Result.Result
- # $Result | Format-List * -Force | Out-Host
It "Returns the ModuleInfo combined with the BuildInfo" {
- $Result.Name | Should -Be "MyModule"
- $Result.SourceDirectories | Should -Be @("Classes", "Private", "Public")
- (Convert-FolderSeparator $Result.ModuleBase) | Should -Be (Convert-FolderSeparator "TestDrive:\Source")
- (Convert-FolderSeparator $Result.SourcePath) | Should -Be (Convert-FolderSeparator "TestDrive:\Source\MyModule.psd1")
+ $Result.Result.Name | Should -Be "MyModule"
+ $Result.Result.SourceDirectories | Should -Be @("Classes", "Private", "Public")
+ (Convert-FolderSeparator $Result.Result.ModuleBase) | Should -Be (Convert-FolderSeparator "TestDrive:\Source")
+ (Convert-FolderSeparator $Result.Result.SourcePath) | Should -Be (Convert-FolderSeparator "TestDrive:\Source\MyModule.psd1")
}
It "Returns default values from the Build Command" {
- $Result.OutputDirectory | Should -Be ".\Output"
+ $Result.Result.OutputDirectory | Should -Be ".\Output"
}
It "Returns overriden values from the build manifest" {
- $Result.SourceDirectories | Should -Be @("Classes", "Private", "Public")
+ $Result.Result.SourceDirectories | Should -Be @("Classes", "Private", "Public")
}
It "Returns overriden values from parameters" {
- $Result.SourcePath | Should -Be (Convert-Path 'TestDrive:\Source\MyModule.psd1')
+ $Result.Result.SourcePath | Should -Be (Convert-Path 'TestDrive:\Source\MyModule.psd1')
}
It "Sets VersionedOutputDirectory FALSE when UnversionedOutputDirectory is TRUE" {
- $Result.VersionedOutputDirectory | Should -Be $false
+ $Result.Result.VersionedOutputDirectory | Should -Be $false
}
}
}
diff --git a/Tests/Private/ParseLineNumber.Tests.ps1 b/Tests/Private/ParseLineNumber.Tests.ps1
index 40fa5f2..16521a5 100644
--- a/Tests/Private/ParseLineNumber.Tests.ps1
+++ b/Tests/Private/ParseLineNumber.Tests.ps1
@@ -1,4 +1,3 @@
-#requires -Module ModuleBuilder
Describe "ParseLineNumber" {
It 'Should get the SourceFile and LineNumber from stack trace messages with modules' {
@@ -45,7 +44,7 @@ Describe "ParseLineNumber" {
$Source.SourceLineNumber | Should -Be 14
}
- It 'Should get and and line number from errors at the console' {
+ It 'Should get ScriptBlock and No file and line number from errors at the console' {
$Source = InModuleScope ModuleBuilder { ParseLineNumber "at , : line 1" }
$Source.SourceFile | Should -Be ""
diff --git a/Tests/Private/ResolveBuildManifest.Tests.ps1 b/Tests/Private/ResolveBuildManifest.Tests.ps1
index be68129..179ca1d 100644
--- a/Tests/Private/ResolveBuildManifest.Tests.ps1
+++ b/Tests/Private/ResolveBuildManifest.Tests.ps1
@@ -1,4 +1,3 @@
-#requires -Module ModuleBuilder
Describe "ResolveBuildManifest" {
# use the integration test code
BeforeAll {
diff --git a/Tests/Private/ResolveOutputFolder.Tests.ps1 b/Tests/Private/ResolveOutputFolder.Tests.ps1
index 40b95b0..c85e698 100644
--- a/Tests/Private/ResolveOutputFolder.Tests.ps1
+++ b/Tests/Private/ResolveOutputFolder.Tests.ps1
@@ -1,59 +1,64 @@
-#requires -Module ModuleBuilder
Describe "ResolveOutputFolder" {
. $PSScriptRoot\..\Convert-FolderSeparator.ps1
- $CommandInTest = InModuleScope ModuleBuilder { Get-Command ResolveOutputFolder }
- filter ToTestDrive { "$_".Replace($TestDrive, "TestDrive:") }
-
- $TestCases = [Hashtable[]]@(
- @{ # Be like Jaykul
- Source = "ModuleName/Source"
- Output = "ModuleName"
- Result = "ModuleName/1.2.3"
- Forced = "ModuleName/1.2.3"
- }
- @{ # Be like azure
- Source = "1/s"
- Output = "1/b"
- Result = "1/b/ModuleName"
- Forced = "1/b/ModuleName/1.2.3"
- }
- @{ # The default option would be Module/Source build to Module/Output
- Source = "ModuleName/Source"
- Output = "ModuleName/Output"
- Result = "ModuleName/Output/ModuleName"
- Forced = "ModuleName/Output/ModuleName/1.2.3"
- }
- @{ # Which is the same even without the common named parent
- Source = "Source"
- Output = "Output"
- Result = "Output/ModuleName"
- Forced = "Output/ModuleName/1.2.3"
- }
- @{ # An edge case, build straight to a modules folder
- Source = "ModuleName/Source"
- Output = "Modules"
- Result = "Modules/ModuleName"
- Forced = "Modules/ModuleName/1.2.3"
- }
- @{ # What if they pass in the correct path ahead of time?
- Source = "1/s"
- Output = "1/b/ModuleName"
- Result = "1/b/ModuleName"
- Forced = "1/b/ModuleName/1.2.3"
- }
- @{ # What if they pass in the correct path ahead of time?
- Source = "1/s"
- Output = "1/b/ModuleName/1.2.3"
- Result = "1/b/ModuleName/1.2.3"
- Forced = "1/b/ModuleName/1.2.3"
- }
- @{ # Super edge case: what if they pass in an incorrectly versioned output path?
- Source = "1/s"
- Output = "1/b/ModuleName/4.5.6"
- Result = "1/b/ModuleName/4.5.6/ModuleName"
- Forced = "1/b/ModuleName/4.5.6/ModuleName/1.2.3"
- }
- )
+ BeforeAll {
+ filter ToTestDrive { "$_".Replace($TestDrive, "TestDrive:") }
+
+ $CommandInTest = InModuleScope ModuleBuilder { Get-Command ResolveOutputFolder }
+ }
+
+ BeforeDiscovery {
+
+ $TestCases = [Hashtable[]]@(
+ @{ # Be like Jaykul
+ Source = "ModuleName/Source"
+ Output = "ModuleName"
+ Result = "ModuleName/1.2.3"
+ Forced = "ModuleName/1.2.3"
+ }
+ @{ # Be like azure
+ Source = "1/s"
+ Output = "1/b"
+ Result = "1/b/ModuleName"
+ Forced = "1/b/ModuleName/1.2.3"
+ }
+ @{ # The default option would be Module/Source build to Module/Output
+ Source = "ModuleName/Source"
+ Output = "ModuleName/Output"
+ Result = "ModuleName/Output/ModuleName"
+ Forced = "ModuleName/Output/ModuleName/1.2.3"
+ }
+ @{ # Which is the same even without the common named parent
+ Source = "Source"
+ Output = "Output"
+ Result = "Output/ModuleName"
+ Forced = "Output/ModuleName/1.2.3"
+ }
+ @{ # An edge case, build straight to a modules folder
+ Source = "ModuleName/Source"
+ Output = "Modules"
+ Result = "Modules/ModuleName"
+ Forced = "Modules/ModuleName/1.2.3"
+ }
+ @{ # What if they pass in the correct path ahead of time?
+ Source = "1/s"
+ Output = "1/b/ModuleName"
+ Result = "1/b/ModuleName"
+ Forced = "1/b/ModuleName/1.2.3"
+ }
+ @{ # What if they pass in the correct path ahead of time?
+ Source = "1/s"
+ Output = "1/b/ModuleName/1.2.3"
+ Result = "1/b/ModuleName/1.2.3"
+ Forced = "1/b/ModuleName/1.2.3"
+ }
+ @{ # Super edge case: what if they pass in an incorrectly versioned output path?
+ Source = "1/s"
+ Output = "1/b/ModuleName/4.5.6"
+ Result = "1/b/ModuleName/4.5.6/ModuleName"
+ Forced = "1/b/ModuleName/4.5.6/ModuleName/1.2.3"
+ }
+ )
+ }
Context "Build ModuleName" {
It "From '' to '