2020-03-24 11:08:37 -07:00
# Copyright (c) Microsoft Corporation.
2018-02-13 09:23:53 -08:00
# Licensed under the MIT License.
2019-04-04 23:01:01 -07:00
Import-Module HelpersCommon
2017-03-01 10:36:02 -08:00
Describe "Test-ModuleManifest tests" -tags "CI" {
2018-09-28 13:28:08 -07:00
BeforeEach {
$testModulePath = "testdrive:/module/test.psd1"
New-Item -ItemType Directory -Path testdrive : / module > $null
}
2017-03-01 10:36:02 -08:00
AfterEach {
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue testdrive : / module
}
It "module manifest containing paths with backslashes or forwardslashes are resolved correctly" {
2018-09-28 13:28:08 -07:00
New-Item -ItemType Directory -Path testdrive : / module / foo > $null
New-Item -ItemType Directory -Path testdrive : / module / bar > $null
2022-02-23 15:01:12 -08:00
2018-09-28 13:28:08 -07:00
New-Item -ItemType File -Path testdrive : / module / foo / bar . psm1 > $null
2022-02-23 15:01:12 -08:00
New-Item -ItemType File -Path testdrive : / module / foo / bar . ps1 > $null
New-Item -ItemType File -Path testdrive : / module / foo / bar . ps1xml > $null
2018-09-28 13:28:08 -07:00
New-Item -ItemType File -Path testdrive : / module / bar / foo . psm1 > $null
2022-02-23 15:01:12 -08:00
New-Item -ItemType File -Path testdrive : / module / bar / foo . ps1 > $null
New-Item -ItemType File -Path testdrive : / module / bar / foo . ps1xml > $null
2017-03-01 10:36:02 -08:00
$testModulePath = "testdrive:/module/test.psd1"
$fileList = "foo\bar.psm1" , "bar/foo.psm1"
2022-02-23 15:01:12 -08:00
$scripts = "foo\/bar.ps1" , "bar/\foo.ps1"
$ps1xml = "foo//bar.ps1xml" , "bar\\foo.ps1xml"
2017-03-01 10:36:02 -08:00
2022-02-23 15:01:12 -08:00
New-ModuleManifest -NestedModules $fileList -RootModule foo \ bar . psm1 -RequiredAssemblies $fileList -Path $testModulePath -TypesToProcess $ps1xml -FormatsToProcess $ps1xml -ScriptsToProcess $scripts -FileList $fileList -ModuleList $fileList
2017-03-01 10:36:02 -08:00
2018-03-14 12:13:32 -07:00
Test-Path $testModulePath | Should -BeTrue
2017-03-01 10:36:02 -08:00
# use -ErrorAction Stop to cause test to fail if Test-ModuleManifest writes to error stream
2018-03-14 12:13:32 -07:00
Test-ModuleManifest -Path $testModulePath -ErrorAction Stop | Should -BeOfType System . Management . Automation . PSModuleInfo
2017-03-01 10:36:02 -08:00
}
2017-07-07 09:25:46 -07:00
It "module manifest containing missing files returns error: <parameter>" -TestCases (
2020-01-13 15:14:31 +00:00
@ { parameter = "RequiredAssemblies" ; errorId = "Modules_InvalidRequiredAssembliesInModuleManifest" },
@ { parameter = "NestedModules" ; errorId = "Modules_InvalidNestedModuleinModuleManifest" },
@ { parameter = "RequiredModules" ; errorId = "Modules_InvalidRequiredModulesinModuleManifest" },
@ { parameter = "FileList" ; errorId = "Modules_InvalidFilePathinModuleManifest" },
@ { parameter = "ModuleList" ; errorId = "Modules_InvalidModuleListinModuleManifest" },
@ { parameter = "TypesToProcess" ; errorId = "Modules_InvalidManifest" },
@ { parameter = "FormatsToProcess" ; errorId = "Modules_InvalidManifest" },
@ { parameter = "RootModule" ; errorId = "Modules_InvalidRootModuleInModuleManifest" },
@ { parameter = "ScriptsToProcess" ; errorId = "Modules_InvalidManifest" }
2017-03-01 10:36:02 -08:00
) {
2020-01-13 15:14:31 +00:00
param ( $parameter , $errorId )
2017-03-01 10:36:02 -08:00
2018-09-28 13:28:08 -07:00
New-Item -ItemType Directory -Path testdrive : / module / foo > $null
New-Item -ItemType File -Path testdrive : / module / foo / bar . psm1 > $null
2017-03-01 10:36:02 -08:00
$args = @ { $parameter = "doesnotexist.psm1" }
New-ModuleManifest -Path $testModulePath @args
2020-01-13 15:14:31 +00:00
$fullyQualifiedErrorId = " $errorId ,Microsoft.PowerShell.Commands.TestModuleManifestCommand"
2017-03-01 10:36:02 -08:00
2020-01-13 15:14:31 +00:00
{ Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | Should -Throw -ErrorId $fullyQualifiedErrorId
2017-03-01 10:36:02 -08:00
}
2017-07-07 09:25:46 -07:00
It "module manifest containing valid unprocessed rootmodule file type succeeds: <rootModuleValue>" -TestCases (
2017-03-01 10:36:02 -08:00
@ { rootModuleValue = "foo.psm1" },
2019-02-07 11:24:06 -08:00
@ { rootModuleValue = "foo.dll" },
@ { rootModuleValue = "foo.exe" }
2017-03-01 10:36:02 -08:00
) {
param ( $rootModuleValue )
2018-09-28 13:28:08 -07:00
New-Item -ItemType File -Path testdrive : / module / $rootModuleValue > $null
2017-03-01 10:36:02 -08:00
New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue
$moduleManifest = Test-ModuleManifest -Path $testModulePath -ErrorAction Stop
2018-03-14 12:13:32 -07:00
$moduleManifest | Should -BeOfType System . Management . Automation . PSModuleInfo
$moduleManifest . RootModule | Should -Be $rootModuleValue
2017-03-01 10:36:02 -08:00
}
2019-03-10 22:57:19 +01:00
It "module manifest containing valid rootmodule without specifying .psm1 extension succeeds" {
$rootModuleFileName = "bar.psm1" ;
New-Item -ItemType File -Path testdrive : / module / $rootModuleFileName > $null
New-ModuleManifest -Path $testModulePath -RootModule "bar"
$moduleManifest = Test-ModuleManifest -Path $testModulePath -ErrorAction Stop
$moduleManifest | Should -BeOfType System . Management . Automation . PSModuleInfo
$moduleManifest . RootModule | Should -Be "bar"
}
2017-07-07 09:25:46 -07:00
It "module manifest containing valid processed empty rootmodule file type fails: <rootModuleValue>" -TestCases (
2020-01-13 15:14:31 +00:00
@ { rootModuleValue = "foo.cdxml" ; errorId = "System.Xml.XmlException" } # fails when cmdlet tries to read it as XML
2017-03-01 10:36:02 -08:00
) {
2020-01-13 15:14:31 +00:00
param ( $rootModuleValue , $errorId )
2017-03-01 10:36:02 -08:00
2018-09-28 13:28:08 -07:00
New-Item -ItemType File -Path testdrive : / module / $rootModuleValue > $null
2017-03-01 10:36:02 -08:00
New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue
2020-01-13 15:14:31 +00:00
$fullyQualifiedErrorId = " $errorId ,Microsoft.PowerShell.Commands.TestModuleManifestCommand"
{ Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | Should -Throw -ErrorId $fullyQualifiedErrorId
2017-03-01 10:36:02 -08:00
}
2017-07-07 09:25:46 -07:00
It "module manifest containing empty rootmodule succeeds: <rootModuleValue>" -TestCases (
2017-03-01 10:36:02 -08:00
@ { rootModuleValue = $null },
@ { rootModuleValue = "" }
) {
param ( $rootModuleValue )
New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue
$moduleManifest = Test-ModuleManifest -Path $testModulePath -ErrorAction Stop
2018-03-14 12:13:32 -07:00
$moduleManifest | Should -BeOfType System . Management . Automation . PSModuleInfo
$moduleManifest . RootModule | Should -BeNullOrEmpty
2017-03-01 10:36:02 -08:00
}
2017-07-07 09:25:46 -07:00
It "module manifest containing invalid rootmodule returns error: <rootModuleValue>" -TestCases (
2020-01-13 15:14:31 +00:00
@ { rootModuleValue = "foo.psd1" ; errorId = "Modules_InvalidManifest" }
2017-03-01 10:36:02 -08:00
) {
2020-01-13 15:14:31 +00:00
param ( $rootModuleValue , $errorId )
2017-03-01 10:36:02 -08:00
2018-09-28 13:28:08 -07:00
New-Item -ItemType File -Path testdrive : / module / $rootModuleValue > $null
2017-03-01 10:36:02 -08:00
New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue
2020-01-13 15:14:31 +00:00
$fullyQualifiedErrorId = " $errorId ,Microsoft.PowerShell.Commands.TestModuleManifestCommand"
{ Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | Should -Throw -ErrorId $fullyQualifiedErrorId
2017-03-01 10:36:02 -08:00
}
2017-07-07 09:25:46 -07:00
It "module manifest containing non-existing rootmodule returns error: <rootModuleValue>" -TestCases (
2020-01-13 15:14:31 +00:00
@ { rootModuleValue = "doesnotexist.psm1" ; errorId = "Modules_InvalidRootModuleInModuleManifest" }
2017-03-01 10:36:02 -08:00
) {
2020-01-13 15:14:31 +00:00
param ( $rootModuleValue , $errorId )
2017-03-01 10:36:02 -08:00
New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue
2020-01-13 15:14:31 +00:00
$fullyQualifiedErrorId = " $errorId ,Microsoft.PowerShell.Commands.TestModuleManifestCommand"
{ Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | Should -Throw -ErrorId $fullyQualifiedErrorId
2017-03-01 10:36:02 -08:00
}
2018-09-28 13:28:08 -07:00
It "module manifest containing nested module gets returned: <variation>" -TestCases (
@ { variation = "no analysis as all exported with no wildcard" ; exportValue = "@()" },
@ { variation = "analysis as exported with wildcard" ; exportValue = "*" }
) {
param ( $exportValue )
New-Item -ItemType File -Path testdrive : / module / Foo . psm1 > $null
New-ModuleManifest -Path $testModulePath -NestedModules "Foo.psm1" -FunctionsToExport $exportValue -CmdletsToExport $exportValue -VariablesToExport $exportValue -AliasesToExport $exportValue
$module = Test-ModuleManifest -Path $testModulePath
$module . NestedModules | Should -HaveCount 1
$module . NestedModules . Name | Should -BeExactly "Foo"
}
2024-08-19 15:40:31 -07:00
It 'Works for manifest specified as UNC path' -Skip: (! $IsWindows ) {
# chance the testdrive path to a UNC path
$testModulePath = '\\localhost\' + " $testDrive \test.psd1" . Replace ( ':' , '$' )
New-Item -ItemType File -Path testdrive : / foo . psm1 > $null
New-ModuleManifest -Path $testModulePath -RootModule "foo.psm1"
$module = Test-ModuleManifest -Path $testModulePath
$module . RootModule | Should -Be "foo.psm1"
}
2017-03-01 10:36:02 -08:00
}
2017-04-30 17:58:44 -07:00
Describe "Tests for circular references in required modules" -tags "CI" {
function CreateTestModules([string]$RootPath , [ string[] ] $ModuleNames , [ bool ] $AddVersion , [ bool ] $AddGuid , [ bool ] $AddCircularReference )
{
$RequiredModulesSpecs = @ ();
foreach ( $moduleDir in New-Item $ModuleNames -ItemType Directory -Force )
{
if ( $lastItem )
{
if ( $AddVersion -or $AddGuid ) { $RequiredModulesSpecs += $lastItem }
else { $RequiredModulesSpecs += $lastItem . ModuleName }
}
$ModuleVersion = '3.0'
$GUID = New-Guid
2020-05-07 13:00:30 +01:00
New-ModuleManifest (( Join-Path $moduleDir . Name $moduleDir . Name ) + ".psd1" ) -RequiredModules $RequiredModulesSpecs -ModuleVersion $ModuleVersion -Guid $GUID
2017-04-30 17:58:44 -07:00
$lastItem = @ { ModuleName = $moduleDir . Name }
if ( $AddVersion ) { $lastItem += @ { ModuleVersion = $ModuleVersion }}
if ( $AddGuid ) { $lastItem += @ { GUID = $GUID }}
}
if ( $AddCircularReference )
{
# rewrite first module's manifest to have a reference to the last module, i.e. making a circular reference
if ( $AddVersion -or $AddGuid )
{
$firstModuleName = $RequiredModulesSpecs [ 0 ]. ModuleName
$firstModuleVersion = $RequiredModulesSpecs [ 0 ]. ModuleVersion
$firstModuleGuid = $RequiredModulesSpecs [ 0 ]. GUID
$RequiredModulesSpecs = $lastItem
}
else
{
$firstModuleName = $RequiredModulesSpecs [ 0 ]
$firstModuleVersion = '3.0' # does not matter - not used in references
$firstModuleGuid = New-Guid # does not matter - not used in references
$RequiredModulesSpecs = $lastItem . ModuleName
}
2020-05-07 13:00:30 +01:00
New-ModuleManifest (( Join-Path $firstModuleName $firstModuleName ) + ".psd1" ) -RequiredModules $RequiredModulesSpecs -ModuleVersion $firstModuleVersion -Guid $firstModuleGuid
2017-04-30 17:58:44 -07:00
}
}
function TestImportModule([bool]$AddVersion , [ bool ] $AddGuid , [ bool ] $AddCircularReference )
{
$moduleRootPath = Join-Path $TestDrive 'TestModules'
2018-09-28 13:28:08 -07:00
New-Item $moduleRootPath -ItemType Directory -Force > $null
2017-04-30 17:58:44 -07:00
Push-Location $moduleRootPath
$moduleCount = 6 # this depth was enough to find a bug in cyclic reference detection product code; greater depth will slow tests down
2017-07-22 05:03:49 +01:00
$ModuleNames = 1 .. $moduleCount | ForEach-Object { "TestModule $_ " }
2017-04-30 17:58:44 -07:00
CreateTestModules $moduleRootPath $ModuleNames $AddVersion $AddGuid $AddCircularReference
2017-07-07 09:25:46 -07:00
2017-04-30 17:58:44 -07:00
$newpath = [ system.io.path ]:: PathSeparator + " $moduleRootPath "
$OriginalPSModulePathLength = $env:PSModulePath . Length
$env:PSModulePath += $newpath
$lastModule = $ModuleNames [ $moduleCount - 1 ]
try
{
Import-Module $lastModule -ErrorAction Stop
2018-03-14 12:13:32 -07:00
Get-Module $lastModule | Should -Not -BeNullOrEmpty
2017-04-30 17:58:44 -07:00
}
finally
{
#cleanup
Remove-Module $ModuleNames -Force -ErrorAction SilentlyContinue
$env:PSModulePath = $env:PSModulePath . Substring ( 0 , $OriginalPSModulePathLength )
Pop-Location
Remove-Item $moduleRootPath -Recurse -Force -ErrorAction SilentlyContinue
}
}
It "No circular references and RequiredModules field has only module names" {
TestImportModule $false $false $false
}
It "No circular references and RequiredModules field has module names and versions" {
TestImportModule $true $false $false
}
It "No circular references and RequiredModules field has module names, versions and GUIDs" {
TestImportModule $true $true $false
}
It "Add a circular reference to RequiredModules and verify error" {
2018-05-17 14:42:04 -07:00
{ TestImportModule $false $false $true } | Should -Throw -ErrorId "Modules_InvalidManifest,Microsoft.PowerShell.Commands.ImportModuleCommand"
2017-04-30 17:58:44 -07:00
}
}
2017-08-29 06:36:46 +08:00
Describe "Test-ModuleManifest Performance bug followup" -tags "CI" {
BeforeAll {
$TestModulesPath = [ System.IO.Path ]:: Combine ( $PSScriptRoot , 'assets' , 'testmodulerunspace' )
2020-01-13 19:35:33 +00:00
$PSHomeModulesPath = " $PSHOME \Modules"
2017-08-29 06:36:46 +08:00
# Install the Test Module
2019-04-04 23:01:01 -07:00
if ( Test-CanWriteToPsHome ) {
Copy-Item $TestModulesPath \* $PSHomeModulesPath -Recurse -Force -ErrorAction Stop
}
2017-08-29 06:36:46 +08:00
}
2019-04-04 23:01:01 -07:00
It "Test-ModuleManifest should not load unnessary modules" -Skip: (!( Test-CanWriteToPsHome )) {
2017-08-29 06:36:46 +08:00
2020-05-07 13:00:30 +01:00
$job = Start-Job -Name "job1" -ScriptBlock { Test-ModuleManifest " $using :PSHomeModulesPath\ModuleWithDependencies2\2.0\ModuleWithDependencies2.psd1" -Verbose } | Wait-Job
2018-04-02 16:18:56 -07:00
2017-08-29 06:36:46 +08:00
$verbose = $job . ChildJobs [ 0 ]. Verbose . ReadAll ()
2020-01-13 19:35:33 +00:00
# Before the fix, all modules under $PSHOME will be imported and will be far more than 15 verbose messages. However, we cannot fix the number in case verbose message may vary.
2018-03-14 12:13:32 -07:00
$verbose . Count | Should -BeLessThan 15
2017-08-29 06:36:46 +08:00
}
AfterAll {
#clean up the test modules
2019-04-04 23:01:01 -07:00
if ( Test-CanWriteToPsHome ) {
Remove-Item $PSHomeModulesPath \ ModuleWithDependencies2 -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item $PSHomeModulesPath \ NestedRequiredModule1 -Recurse -Force -ErrorAction SilentlyContinue
}
2017-08-29 06:36:46 +08:00
}
}