See More

using namespace System.Management.Automation using namespace Microsoft.PowerShell.Commands using namespace System.Collections.Generic using namespace System.Diagnostics.CodeAnalysis using namespace NuGet.Versioning . $PSScriptRoot/ModuleFast.ps1 -ImportNuGetVersioning Import-Module $PSScriptRoot/ModuleFast.psm1 -Force BeforeAll { if ($env:MFURI) { $PSDefaultParameterValues['*-ModuleFast*:Source'] = $env:MFURI } } InModuleScope 'ModuleFast' { Describe 'ModuleFastSpec' { Context 'Constructors' { It 'Getters' { $spec = [ModuleFastSpec]'Test' 'Name', 'Guid', 'Min', 'Max', 'Required' | ForEach-Object { $spec.PSObject.Properties.name | Should -Contain $PSItem } } It 'Name' { $spec = [ModuleFastSpec]'Test' $spec.Name | Should -Be 'Test' $spec.Guid | Should -Be ([Guid]::Empty) $spec.Min | Should -BeNull $spec.Max | Should -BeNull $spec.Required | Should -BeNull } It 'Has non-settable properties' { $spec = [ModuleFastSpec]'Test' { $spec.Min = '1' } | Should -Throw { $spec.Max = '1' } | Should -Throw { $spec.Required = '1' } | Should -Throw { $spec.Name = 'fake' } | Should -Throw { $spec.Guid = New-Guid } | Should -Throw } It 'ModuleSpecification' { $in = [ModuleSpecification]@{ ModuleName = 'Test' ModuleVersion = '2.1.5' } $spec = [ModuleFastSpec]$in $spec.Name | Should -Be 'Test' $spec.Guid | Should -Be ([Guid]::Empty) $spec.Min | Should -Be '2.1.5' $spec.Max | Should -BeNull $spec.Required | Should -BeNull } } Context 'ModuleSpecification Conversion' { It 'Name' { $spec = [ModuleSpecification][ModuleFastSpec]'Test' $spec.Name | Should -Be 'Test' $spec.Version | Should -Be '0.0' $spec.RequiredVersion | Should -BeNull $spec.MaximumVersion | Should -BeNull } It 'RequiredVersion' { $spec = [ModuleSpecification][ModuleFastSpec]::new('Test', '1.2.3') $spec.Name | Should -Be 'Test' $spec.RequiredVersion | Should -Be '1.2.3.0' $spec.Version | Should -BeNull $spec.MaximumVersion | Should -BeNull } } } Describe 'Import-ModuleManifest' { It 'Reads Dynamic Manifest' { $Mocks = "$PSScriptRoot/Test/Mocks" $manifest = Import-ModuleManifest "$Mocks/Dynamic.psd1" $manifest | Should -BeOfType [System.Collections.Hashtable] $manifest.ModuleVersion | Should -Be '1.0.0' $manifest.RootModule | Should -Be 'coreclr\PrtgAPI.PowerShell.dll' } } } Describe 'Get-ModuleFastPlan' -Tag 'E2E' { BeforeAll { $SCRIPT:__existingPSModulePath = $env:PSModulePath $env:PSModulePath = $testDrive $SCRIPT:__existingProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' } AfterAll { $env:PSModulePath = $SCRIPT:__existingPSModulePath $ProgressPreference = $SCRIPT:__existingProgressPreference } Context 'Parameter Binding' { #This is used for testcases $SCRIPT:moduleName = 'Az.Accounts' Context 'ModuleFastSpec' { $moduleSpecTestCases = ( @{ Test = 'Name'; Spec = $SCRIPT:moduleName; Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Test = 'ModuleSpecification Name'; Spec = [ModuleSpecification]::new($SCRIPT:moduleName); Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Test = 'ModuleSpecification MinimumVersion'; Spec = [ModuleSpecification]::new(@{ ModuleName = $SCRIPT:moduleName; ModuleVersion = '0.0.0' }) Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Test = 'ModuleSpecification RequiredVersion'; Spec = [ModuleSpecification]::new(@{ ModuleName = $SCRIPT:moduleName; RequiredVersion = '2.7.3' }) Check = { $actual.ModuleVersion | Should -Be '2.7.3' } }, @{ Test = 'ModuleSpecification MaximumVersion'; Spec = [ModuleSpecification]::new(@{ ModuleName = $SCRIPT:moduleName; MaximumVersion = '2.7.3' }) Check = { $actual.ModuleVersion | Should -Be '2.7.3' } } ) It 'Gets Module with Parameter: ' { $actual = Get-ModuleFastPlan $Spec $actual | Should -HaveCount 1 $ModuleName | Should -Be $actual.Name $actual.ModuleVersion | Should -Not -BeNullOrEmpty if ($Check) { . $Check } } -TestCases $moduleSpecTestCases It 'Gets Module with Pipeline: ' { $actual = $Spec | Get-ModuleFastPlan $actual | Should -HaveCount 1 $ModuleName | Should -Be $actual.Name $actual.ModuleVersion | Should -Not -BeNullOrEmpty if ($Check) { . $Check } } -TestCases $moduleSpecTestCases } Context 'ModuleFastSpec String' { $stringTestCases = ( @{ Spec = 'Az.Accounts' Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Spec = 'Az.Accounts=2.7.3' Check = { $actual.ModuleVersion | Should -Be '2.7.3' } }, @{ Spec = 'Az.Accounts>2.7.3' Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Spec = 'Az.Accounts<2.7.3' Check = { $actual.ModuleVersion | Should -BeLessThan '2.7.3' } }, @{ Spec = 'Az.Accounts<=2.7.3' Check = { $actual.ModuleVersion | Should -Be '2.7.3' } }, @{ Spec = 'Az.Accounts>=2.7.3' Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Spec = 'Az.Accounts:2.7.3' Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' -Because 'With NuGet syntax, a bare version is a minimum version, not a requiredversion' } }, @{ Spec = 'Az.Accounts:[2.7.3]' Check = { $actual.ModuleVersion | Should -Be '2.7.3' } }, @{ Spec = 'Az.Accounts:(,2.7.3)' Check = { $actual.ModuleVersion | Should -BeLessThan '2.7.3' } }, @{ Spec = '@{ModuleName = ''Az.Accounts''; ModuleVersion = ''2.7.3''}' Check = { $actual.ModuleVersion | Should -BeGreaterThan '2.7.3' } }, @{ Spec = '@{ModuleName = ''Az.Accounts''; RequiredVersion = ''2.7.3''}' Check = { $actual.ModuleVersion | Should -Be '2.7.3' } }, @{ Spec = 'PrereleaseTest' Check = { $actual.Name | Should -Be 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.1' } ModuleName = 'PrereleaseTest' }, @{ Spec = 'PrereleaseTest!' Check = { $actual.Name | Should -Be 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.2-prerelease' } ModuleName = 'PrereleaseTest' }, @{ Spec = '!PrereleaseTest' Check = { $actual.Name | Should -Be 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.2-prerelease' } ModuleName = 'PrereleaseTest' }, @{ Spec = 'PrereleaseTest!<0.0.1' Check = { $actual.Name | Should -Be 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.1-prerelease' } ModuleName = 'PrereleaseTest' }, @{ Spec = 'PrereleaseTest:*' ModuleName = 'PrereleaseTest' }, @{ Spec = 'ImportExcel<2' ModuleName = 'ImportExcel' Check = { $actual.ModuleVersion | Should -Be '1.99' } }, @{ Spec = 'PnP.PowerShell:2.2.*' ModuleName = 'PnP.PowerShell' Check = { $actual.ModuleVersion | Should -Be '2.2.0' } } ) It 'Fails if hashtable-style string parameter is not a modulespec' { { Get-ModuleFastPlan '@{ModuleName = ''Az.Accounts''; ModuleVersion = ''2.7.3''; InvalidParameter = ''ThisShouldNotBeValid''}' -ErrorAction Stop } | Should -Throw '*Cannot process argument transformation on parameter*' } It 'Gets Module with String Parameter: ' { $actual = Get-ModuleFastPlan $Spec $actual | Should -HaveCount 1 $ModuleName | Should -Be $actual.Name $actual.ModuleVersion | Should -Not -BeNullOrEmpty if ($Check) { . $Check } } -TestCases $stringTestCases It 'Gets Module with String Pipeline: ' { $actual = $Spec | Get-ModuleFastPlan $actual | Should -HaveCount 1 $ModuleName | Should -Be $actual.Name $actual.ModuleVersion | Should -Not -BeNullOrEmpty if ($Check) { . $Check } } -TestCases $stringTestCases } Context 'ModuleFastSpec Combinations' { It 'Strings as Parameter' { $actual = Get-ModuleFastPlan 'Az.Accounts', 'Az.Compute', 'ImportExcel' $actual | Should -HaveCount 3 $actual | ForEach-Object { $PSItem.Name | Should -BeIn 'Az.Accounts', 'Az.Compute', 'ImportExcel' $PSItem.ModuleVersion | Should -BeGreaterThan '1.0' } } It 'Strings as Pipeline' { $actual = 'Az.Accounts', 'Az.Compute', 'ImportExcel' | Get-ModuleFastPlan $actual | Should -HaveCount 3 $actual | ForEach-Object { $PSItem.Name | Should -BeIn 'Az.Accounts', 'Az.Compute', 'ImportExcel' $PSItem.ModuleVersion | Should -BeGreaterThan '1.0' } } It 'ModuleSpecs as Parameter' { $actual = Get-ModuleFastPlan 'Az.Accounts', '@{ModuleName = "Az.Compute"; ModuleVersion = "1.0.0" }', ([ModuleSpecification]::new('ImportExcel')) $actual | Should -HaveCount 3 $actual | ForEach-Object { $PSItem.Name | Should -BeIn 'Az.Accounts', 'Az.Compute', 'ImportExcel' $PSItem.ModuleVersion | Should -BeGreaterThan '1.0' } } It 'ModuleSpecs as Pipeline' { $actual = 'Az.Accounts>1', '@{ModuleName = "Az.Compute"; ModuleVersion = "1.0.0" }', ([ModuleSpecification]::new('ImportExcel')) | Get-ModuleFastPlan $actual | Should -HaveCount 3 $actual | ForEach-Object { $PSItem.Name | Should -BeIn 'Az.Accounts', 'Az.Compute', 'ImportExcel' $PSItem.ModuleVersion | Should -BeGreaterThan '1.0' } } It 'Prerelease does not affect non-prerelease' { #The prerelease flag on az.accounts should not trigger prerelease on PrereleaseTest $actual = 'Az.Accounts!', 'PrereleaseTest' | Get-ModuleFastPlan $actual | Should -HaveCount 2 $actual | Where-Object Name -EQ 'PrereleaseTest' | ForEach-Object { $PSItem.ModuleVersion | Should -Be '0.0.1' } } It '-Prerelease overrides even if prerelease is not specified' { #The prerelease flag on az.accounts should not trigger prerelease on PrereleaseTest $actual = 'Az.Accounts!', 'PrereleaseTest' | Get-ModuleFastPlan -Prerelease $actual | Should -HaveCount 2 $actual | Where-Object Name -EQ 'PrereleaseTest' | ForEach-Object { $PSItem.ModuleVersion | Should -Be '0.0.2-prerelease' } } } } It 'Errors on Unsupported Object instead of Stringifying' { { Get-ModuleFastPlan [Tuple]::Create('Az.Accounts') -ErrorAction Stop } | Should -Throw '*Cannot process argument transformation on parameter*' } It 'Gets Module with 1 dependency' { Get-ModuleFastPlan 'Az.Compute' | Should -HaveCount 2 } It 'Gets all dependencies for a Module with lots of dependencies (Az)' { Get-ModuleFastPlan @{ModuleName = 'Az'; RequiredVersion = '11.1.0' } | Should -HaveCount 86 } It 'Gets Module with 4 section version number and a 4 section version number dependency (VMware.VimAutomation.Common)' { Get-ModuleFastPlan 'VMware.VimAutomation.Common' | Should -HaveCount 2 } It 'Gets multiple modules' { Get-ModuleFastPlan @{ModuleName = 'Az'; RequiredVersion = '11.1.0' }, @{ModuleName = 'VMWare.PowerCli'; RequiredVersion = '13.2.0.22746353' } | Should -HaveCount 168 } It 'Casts to ModuleSpecification' { $actual = (Get-ModuleFastPlan 'Az.Accounts') -as [Microsoft.PowerShell.Commands.ModuleSpecification] $actual | Should -BeOfType [Microsoft.PowerShell.Commands.ModuleSpecification] $actual.Name | Should -Be 'Az.Accounts' $actual.RequiredVersion | Should -BeGreaterThan '2.7.3' } It 'Filters Prerelease Modules by Default' { $actual = Get-ModuleFastPlan 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.1' } It 'Shows Prerelease Modules if Prerelease is specified' { $actual = Get-ModuleFastPlan 'PrereleaseTest' -Prerelease $actual.ModuleVersion | Should -Be '0.0.2-prerelease' } It 'Detects Prerelease even if Prerelease not specified' { $actual = Get-ModuleFastPlan 'PrereleaseTest=0.0.2-prerelease' $actual.ModuleVersion | Should -Be '0.0.2-prerelease' } } Describe 'Install-ModuleFast' -Tag 'E2E' { BeforeAll { $SCRIPT:__existingPSModulePath = $env:PSModulePath filter Limit-ModulePath { param( [string]$path, [Parameter(ValueFromPipeline)] [Management.Automation.PSModuleInfo]$InputObject ) if ($PSItem.Path.StartsWith($path)) { return $PSItem } } } BeforeEach { #Remove all PSModulePath to not affect existing environment $installTempPath = Join-Path $testdrive $(New-Guid) New-Item -ItemType Directory -Path $installTempPath -ErrorAction stop $env:PSModulePath = $installTempPath [SuppressMessageAttribute( <#Category#>'PSUseDeclaredVarsMoreThanAssignments', <#CheckId#>$null, Justification = 'PSScriptAnalyzer doesnt see the connection between beforeeach and Describe/It' )] $imfParams = @{ Destination = $installTempPath NoProfileUpdate = $true NoPSModulePathUpdate = $true Confirm = $false } } AfterAll { $env:PSModulePath = $SCRIPT:__existingPSModulePath } It 'Installs Module' { #HACK: The testdrive mount is not available in the threadjob runspaces so we need to translate it Install-ModuleFast @imfParams 'Az.Accounts' Get-Item $installTempPath\Az.Accounts\*\Az.Accounts.psd1 | Should -Not -BeNullOrEmpty } It '4 section version numbers (VMware.PowerCLI)' { $actual = Install-ModuleFast @imfParams 'VMware.VimAutomation.Common=13.2.0.22643733' -PassThru Get-Item $installTempPath\VMware*\*\*.psd1 | ForEach-Object { $moduleFolderVersion = $_ | Split-Path | Split-Path -Leaf Import-PowerShellDataFile -Path $_.FullName | Select-Object -ExpandProperty ModuleVersion | Should -Be $moduleFolderVersion } Get-Module VMWare* -ListAvailable | Limit-ModulePath $installTempPath | Should -HaveCount 2 } It '4 section version numbers with repeated zeroes' { $actual = Install-ModuleFast @imfParams 'xDSCResourceDesigner=1.13.0.0' -PassThru $resolvedPath = Resolve-Path $actual.Location.LocalPath Split-Path $resolvedPath -Leaf | Should -Be '1.13.0.0' Get-Module xDSCResourceDesigner -ListAvailable | Limit-ModulePath $installTempPath | Should -HaveCount 1 } It 'lots of dependencies (Az)' { Install-ModuleFast @imfParams 'Az' (Get-Module Az* -ListAvailable).count | Should -BeGreaterThan 10 } It 'specific requiredVersion' { Install-ModuleFast @imfParams @{ ModuleName = 'Az.Accounts'; RequiredVersion = '2.7.4' } Get-Module Az.Accounts -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version | Should -Be '2.7.4' } It 'specific requiredVersion when newer version is present' { Install-ModuleFast @imfParams 'Az.Accounts' Install-ModuleFast @imfParams @{ ModuleName = 'Az.Accounts'; RequiredVersion = '2.7.4' } $installedVersions = Get-Module Az.Accounts -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version $installedVersions | Should -HaveCount 2 $installedVersions | Should -Contain '2.7.4' } It 'Installs when Maximumversion is lower than currently installed' { Install-ModuleFast @imfParams 'Az.Accounts' Install-ModuleFast @imfParams @{ ModuleName = 'Az.Accounts'; MaximumVersion = '2.7.3' } Get-Module Az.Accounts -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version | Should -Contain '2.7.3' } It 'Only installs once when Update is specified and latest has not changed' { Install-ModuleFast @imfParams 'Az.Accounts' -Update Install-ModuleFast @imfParams 'Az.Accounts' -Update -Debug *>&1 | Select-String 'best remote candidate matches what is locally installed' | Should -Not -BeNullOrEmpty } It 'Only installs once when Update is specified and latest has not changed for multiple modules' { Install-ModuleFast @imfParams 'Az.Compute', 'Az.CosmosDB' -Update Install-ModuleFast @imfParams 'Az.Compute', 'Az.CosmosDB' -Update -Plan | Should -BeNullOrEmpty } It 'Updates if multiple local versions installed' { Install-ModuleFast @imfParams 'Plaster=1.1.1' Install-ModuleFast @imfParams 'Plaster=1.1.3' $actual = Install-ModuleFast @imfParams 'Plaster' -Update -PassThru $actual.ModuleVersion | Should -Be '1.1.4' } It 'Updates only dependent module that requires update' { Install-ModuleFast @imfParams @{ ModuleName = 'Az.Accounts'; RequiredVersion = '2.10.2' } Install-ModuleFast @imfParams @{ ModuleName = 'Az.Compute'; RequiredVersion = '5.0.0' } Get-Module Az.Accounts -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version | Sort-Object -Descending | Select-Object -First 1 | Should -Be '2.10.2' Install-ModuleFast @imfParams 'Az.Compute', 'Az.Accounts' #Should not update Get-Module Az.Accounts -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version | Sort-Object -Descending | Select-Object -First 1 | Should -Be '2.10.2' Install-ModuleFast @imfParams 'Az.Compute' -Update #Should disregard local install and update latest Az.Accounts Get-Module Az.Accounts -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version | Sort-Object -Descending | Select-Object -First 1 | Should -BeGreaterThan ([version]'2.10.2') Get-Module Az.Compute -ListAvailable | Limit-ModulePath $installTempPath | Select-Object -ExpandProperty Version | Sort-Object -Descending | Select-Object -First 1 | Should -BeGreaterThan ([version]'5.0.0') } It 'Detects module in other psmodulePath' { $installPath2 = Join-Path $testdrive $(New-Guid) New-Item -ItemType Directory $installPath2 | Out-Null $env:PSModulePath = "$installPath2" Install-ModuleFast @imfParams -Destination $installPath2 'PreReleaseTest' Install-ModuleFast @imfParams 'PreReleaseTest' -PassThru | Should -BeNullOrEmpty } It 'Only considers destination modules if -DestinationOnly is specified' { $installPath2 = Join-Path $testdrive $(New-Guid) New-Item -ItemType Directory $installPath2 | Out-Null $env:PSModulePath = "$installPath2" Install-ModuleFast @imfParams -Destination $installPath2 'PreReleaseTest' Install-ModuleFast @imfParams 'PreReleaseTest' -DestinationOnly -PassThru | Should -HaveCount 1 Install-ModuleFast @imfParams 'PreReleaseTest' -DestinationOnly -PassThru | Should -BeNullOrEmpty } #TODO: Possibly mock this so we don't touch the testing system documents directory It 'Destination CurrentUser installs to $HOME\Documents\PowerShell\Modules' { if (-not $profile) { Set-ItResult -Skipped -Because 'This test is not supported when $profile is not set' } $winConfigPath = Join-Path (Split-Path ($profile.CurrentUserAllHosts)) 'powershell.config.json' if (-not $IsWindows -or (Test-Path $winConfigPath)) { Set-ItResult -Skipped -Because 'This test is not supported on non-Windows or when powershell.config.json is present' } try { Remove-Item $HOME\Documents\PowerShell\Modules\PrereleaseTest -Recurse -Force -ErrorAction SilentlyContinue Install-ModuleFast @imfParams 'PrereleaseTest' -Destination CurrentUser Resolve-Path $HOME\Documents\PowerShell\Modules\PrereleaseTest -EA Stop } finally { Remove-Item $HOME\Documents\PowerShell\Modules\PrereleaseTest -Recurse -Force -ErrorAction SilentlyContinue } } It '-DestinationOnly works on modules with dependencies' { Install-ModuleFast @imfParams 'Az.Compute' -DestinationOnly -PassThru | Should -HaveCount 2 } It 'Errors trying to install prerelease over regular module' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-prerelease' } | Should -Throw '*is newer than the requested prerelease version*' } It 'Errors trying to install older prerelease over regular module' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-prerelease' } | Should -Throw '*is newer than the requested prerelease version*' } It 'Installs regular module over prerelease module with warning' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-prerelease' Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1' -WarningVariable actual *>&1 | Out-Null $actual | Should -BeLike '*is newer than existing prerelease version*' } It 'Installs newer prerelease with warning' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-aprerelease' Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-bprerelease' -WarningVariable actual *>&1 | Out-Null $actual | Should -BeLike '*is newer than existing prerelease version*' } It 'Doesnt install prerelease if same-version Prerelease already installed' { Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-prerelease' $plan = Install-ModuleFast @imfParams 'PrereleaseTest=0.0.1-prerelease' -Plan $plan | Should -BeNullOrEmpty } It 'Installs from SpecFile' { $SCRIPT:Mocks = Resolve-Path "$PSScriptRoot/Test/Mocks" $specFilePath = Join-Path $Mocks $File $modulesToInstall = Install-ModuleFast @imfParams -Path $specFilePath -Plan #TODO: Verify individual modules and versions $modulesToInstall | Should -Not -BeNullOrEmpty if ($modules) { foreach ($module in $modules) { $module | Should -BeIn $modulesToInstall $modulesToInstall.Remove($module) } #All modules should be removed at this point $modulesToInstall | Should -BeNullOrEmpty } } -TestCases @( @{ Name = 'PowerShell Data File' File = 'ModuleFast.requires.psd1' }, @{ Name = 'JSON' File = 'ModuleFast.requires.json' }, @{ Name = 'JSONArray' File = 'ModuleFastArray.requires.json' }, @{ Name = 'ScriptRequires' File = 'RequiresScript.ps1' }, @{ Name = 'ScriptModule' File = 'RequiresModule.psm1' }, @{ Name = 'DynamicManifest' File = 'Dynamic.psd1' }, @{ Name = 'ModuleBuilder' File = 'ModuleBuilder-RequiredModules.psd1' }, @{ Name = 'PSDepend-Implicit' File = 'PSDepend.psd1' } ) It 'Fails if PSDepend File has PSDependOptions DependencyType set' { $SCRIPT:Mocks = Resolve-Path "$PSScriptRoot/Test/Mocks" $specFilePath = Join-Path $Mocks 'PSDepend-NotSupported.psd1' { Install-ModuleFast @imfParams -Path $specFilePath -Plan } | Should -Throw '*DependencyType*' } It 'Fails for script if #Requires is not Present' { $scriptPath = Join-Path $testDrive 'norequires.ps1' { 'There is no requires here!' } | Out-File $scriptPath { Install-ModuleFast @imfParams -Path $scriptPath } | Should -Throw 'The script does not have a #Requires*' } It 'Fails for module if #Requires is not Present' { $scriptPath = Join-Path $testDrive 'norequires.psm1' { 'There is no requires here!' } | Out-File $scriptPath { Install-ModuleFast @imfParams -Path $scriptPath } | Should -Throw 'The script does not have a #Requires*' } It 'Fails if Module Manifest and RequiredModules is missing' { $scriptPath = Join-Path $testDrive 'testmanifestnorequires.psd1' "@{ 'ModuleVersion' = '1.0.0' }" | Out-File $scriptPath { Install-ModuleFast @imfParams -Path $scriptPath } | Should -Throw 'The manifest does not have a RequiredMOdules key*' } It 'Resolves Module Manifest RequiredModules' { $scriptPath = Join-Path $testDrive 'testmanifest.psd1' "@{ 'ModuleVersion' = '1.0.0' 'RequiredModules' = @( 'PreReleaseTest' @{ ModuleName = 'Az.Accounts' ModuleVersion = '2.7.0' } ) }" | Out-File $scriptPath $modules = Install-ModuleFast @imfParams -Path $scriptPath -Plan $modules.count | Should -Be 2 } It 'Resolves GUID with version range' { $scriptPath = Join-Path $testDrive 'testscript.ps1' "#requires -Module @{ModuleName='PreReleaseTest';Guid='7c279caf-00bc-40ae-a1ed-184ad07be1b0';ModuleVersion='0.0.1';MaximumVersion='0.0.2'}" | Out-File $scriptPath $actual = Install-ModuleFast @imfParams -WarningAction SilentlyContinue -Path $scriptPath -PassThru $actual.Name | Should -Be 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.1' } It 'Errors if GUID spec is different than installed module' { { Install-ModuleFast @imfParams -WarningAction SilentlyContinue -Specification "@{ModuleName='PreReleaseTest';Guid='3cb1a381-5d96-4b56-843e-dd97cf4c6545';ModuleVersion='0.0.1';MaximumVersion='0.0.2'}" -PassThru } | Should -Throw '*Expected 3cb1a381-5d96-4b56-843e-dd97cf4c6545 but found 7c279caf-00bc-40ae-a1ed-184ad07be1b0*' } It 'Writes a CI File' { Set-Location $testDrive Install-ModuleFast @imfParams -CI -Specification 'PreReleaseTest' Get-Item 'requires.lock.json' | Should -Not -BeNullOrEmpty #TODO: CI Content } It 'Installs from CI File and Installs CI Pinned Version' { Set-Location $testDrive Install-ModuleFast @imfParams -CI -Specification 'PreReleaseTest=0.0.1-prerelease' Get-Item 'requires.lock.json' | Should -Not -BeNullOrEmpty Remove-Item $imfParams.Destination -Recurse -Force New-Item -ItemType Directory -Path $imfParams.Destination -ErrorAction stop Install-ModuleFast @imfParams -CI $PreReleaseManifest = "$($imfParams.Destination)\PreReleaseTest\0.0.1\PreReleaseTest.psd1" Resolve-Path $PreReleaseManifest (Import-PowerShellDataFile $PreReleaseManifest).PrivateData.PSData.Prerelease | Should -Be 'prerelease' -Because 'CI lock file should have 0.1 prerelease even if 0.2 is available' #TODO: CI Content } It 'Handles an incomplete installation' { $incompleteItemPath = "$installTempPath\PreReleaseTest\0.0.1\.incomplete" Install-ModuleFast @imfParams -Specification 'PreReleaseTest=0.0.1' New-Item -ItemType File -Path $incompleteItemPath Install-ModuleFast @imfParams -Specification 'PreReleaseTest=0.0.1' -Update -WarningVariable actual 3>$null $actual | Should -BeLike '*incomplete installation detected*' Test-Path $incompleteItemPath | Should -BeFalse } It 'PassThru has proper matching output' { $actual = Install-ModuleFast @imfParams -Specification 'PrereleaseTest=0.0.1', 'ImportExcel=7.8.6', 'PendingReboot=0.9.0.6' -PassThru ($actual | Where-Object Name -EQ 'ImportExcel').ModuleVersion | Should -Be '7.8.6' ($actual | Where-Object Name -EQ 'PrereleaseTest').ModuleVersion | Should -Be '0.0.1' ($actual | Where-Object Name -EQ 'PendingReboot').ModuleVersion | Should -Be '0.9.0.6' } It 'PassThru only reports on installed modules' { Install-ModuleFast @imfParams -Specification 'Pester=5.4.0', 'Pester=5.4.1' -PassThru | Should -HaveCount 2 Install-ModuleFast @imfParams -Specification 'Pester=5.4.0', 'Pester=5.4.1' -PassThru | Should -HaveCount 0 } Describe 'GitHub Packages' { It 'Gets Specific Module' { if (-not (Get-Command Get-Secret -ea 0)) { Set-ItResult -Skipped -Because 'SecretManagement Not Present' return } $credential = [PSCredential]::new('Pester', (Get-Secret -Name 'ReadOnlyPackagesGithubPAT')) if (-not $credential) { Set-ItResult -Skipped -Because 'No ReadOnlyPackagesGithubPAT Credential' return } $actual = Install-ModuleFast @imfParams -Specification 'PrereleaseTest=0.0.1' -Source 'https://nuget.pkg.github.com/justingrote/index.json' -Credential $credential -Plan $actual.Name | Should -Be 'PrereleaseTest' $actual.ModuleVersion | Should -Be '0.0.1' } } Describe 'Plan Parameter' { It 'Does not install if Plan is specified' { Install-ModuleFast @imfParams -Specification 'PrereleaseTest' -Plan | Should -Match 'PreReleaseTest' Test-Path $installTempPath\PreReleaseTest | Should -BeFalse } } }