tests/Start-DFSession.Tests.ps1
|
BeforeAll { . "$PSScriptRoot/TestSupport.ps1" foreach ($f in Get-DFTestModuleFile) { . $f } # A private Tools folder: each companion records that it ran. function script:New-SessionTool([string]$Name, [string]$Extra = '') { $json = "{ ""name"": ""$Name"", ""executable"": ""$Name.exe""$Extra }" Set-Content (Join-Path $script:Tools "$Name.json") $json "`$global:DFTestActivated += '$Name'" | Set-Content (Join-Path $script:Tools "$Name.ps1") } } Describe 'Start-DFSession' { BeforeEach { Set-DFTestXdg Set-DFTestConfig $null $script:DFSessionStatus = $null $script:DFToolRecordCache = @{} $script:DFToolDb = $null $script:DFToolAvailability = @{} $script:Tools = Join-Path $TestDrive "tools-$([guid]::NewGuid().ToString('N').Substring(0, 6))" New-Item -ItemType Directory $script:Tools | Out-Null $global:DFTestActivated = @() New-SessionTool 'alpha' New-SessionTool 'beta' New-SessionTool 'gamma' New-SessionTool 'unrequested' $script:DFGroupDb = Get-DFGroupDb -Path (New-Item (Join-Path $script:Tools 'groups.txt') -Force -Value '{ "pair": { "description": "d", "tools": ["alpha", "beta"] } }').FullName $script:Installed = @('alpha.exe', 'beta.exe', 'unrequested.exe') Mock Test-DFToolAvailable { $Executable -in $script:Installed } Mock Write-DFConflictNotice { } } AfterEach { Restore-DFTestXdg Set-DFTestConfig $null $script:DFGroupDb = $null Remove-Variable DFTestActivated -Scope Global -ErrorAction Ignore } It 'activates only requested, installed tools, and never looks at an unrequested one' { Start-DFSession -Config @{ Tools = @('+pair', 'gamma') } -ToolsPath $script:Tools 3>$null $global:DFTestActivated | Should -Be @('alpha', 'beta') Should -Invoke Test-DFToolAvailable -Times 0 -ParameterFilter { $Executable -eq 'unrequested.exe' } } It 'records each requested tool''s state in Get-DFToolStatus' { Start-DFSession -Config @{ Tools = @('+pair', 'gamma'); ExcludeTools = @('beta') } -ToolsPath $script:Tools 3>$null $s = Get-DFToolStatus ($s | Where-Object Name -eq 'alpha').State | Should -Be 'Active' ($s | Where-Object Name -eq 'alpha').RequestedBy | Should -Be '+pair' ($s | Where-Object Name -eq 'beta').State | Should -Be 'Excluded' ($s | Where-Object Name -eq 'gamma').State | Should -Be 'Missing' (Get-DFToolStatus -Missing).Name | Should -Be @('gamma') } It 'marks a tool whose companion throws as Failed and keeps going' { 'throw "boom"' | Set-Content (Join-Path $script:Tools 'alpha.ps1') Start-DFSession -Config @{ Tools = @('alpha', 'beta') } -ToolsPath $script:Tools 3>$null $failed = Get-DFToolStatus -Failed $failed.Name | Should -Be 'alpha' $failed.Detail | Should -Match 'boom' $global:DFTestActivated | Should -Be @('beta') } # Characterization (improve-code-quality Phase 1, 2026-10-10). It 'marks a requested tool whose record can''t be read as Failed, warns, and still loads the rest' { Set-Content (Join-Path $script:Tools 'broken.json') '{ "name": "broken", "executable": ' $w = Start-DFSession -Config @{ Tools = @('broken', 'alpha') } -ToolsPath $script:Tools 3>&1 | Where-Object { $_ -is [System.Management.Automation.WarningRecord] } | ForEach-Object { "$_" } ($w -join "`n") | Should -Match 'Failed to parse broken\.json' ($w -join "`n") | Should -Match '1 tool failed to load' (Get-DFToolStatus -Name broken).State | Should -Be 'Failed' (Get-DFToolStatus -Name broken).Detail | Should -Be 'its tool record is missing or invalid (see the warning above)' (Get-DFToolStatus -Name alpha).State | Should -Be 'Active' $global:DFTestActivated | Should -Be @('alpha') } It 'prints nothing about missing tools when none are missing' { Start-DFSession -Config @{ Tools = @('alpha') } -ToolsPath $script:Tools -WarningVariable w 3>$null @($w | Where-Object { $_ -match 'not installed' }) | Should -BeNullOrEmpty } It 'lists up to five missing tools by name, with the install command' { Start-DFSession -Config @{ Tools = @('alpha', 'gamma') } -ToolsPath $script:Tools -WarningVariable w 3>$null "$w" | Should -Match "1 requested tool isn't installed: gamma\. Run Install-DFTool -Missing" } It 'gives only the count and the commands when more than five are missing' { foreach ($n in 'm1', 'm2', 'm3', 'm4', 'm5', 'm6') { New-SessionTool $n } Start-DFSession -Config @{ Tools = @('m1', 'm2', 'm3', 'm4', 'm5', 'm6') } -ToolsPath $script:Tools -WarningVariable w 3>$null "$w" | Should -Match "6 requested tools aren't installed\. See Get-DFToolStatus -Missing" "$w" | Should -Not -Match 'm1' } It 'names the stand-in when a role''s preferred tool is missing' { New-SessionTool 'promptA' ', "roles": { "prompt": { "priority": 10 } }' New-SessionTool 'promptB' ', "roles": { "prompt": { "priority": 5 } }' $script:Installed += 'promptB.exe' Start-DFSession -Config @{ Tools = @('promptA', 'promptB'); Defaults = @{ prompt = 'promptA' } } -ToolsPath $script:Tools -WarningVariable w 3>$null "$w" | Should -Match 'promptA \(prompt — using promptB\)' (Get-DFToolStatus -Name promptA).Detail | Should -Match 'using promptB' (Get-DFToolStatus -Name promptB).Roles | Should -Contain 'prompt' } It 'only adds when called again, and warns about a tool no longer requested' { Start-DFSession -Config @{ Tools = @('alpha') } -ToolsPath $script:Tools 3>$null Start-DFSession -Config @{ Tools = @('beta') } -ToolsPath $script:Tools -WarningVariable w 3>$null $global:DFTestActivated | Should -Be @('alpha', 'beta') "$w" | Should -Match "alpha.*no longer requested.*new shell" (Get-DFToolStatus -Name alpha).State | Should -Be 'Active' } It 'finds a tool that an earlier tool''s companion puts on PATH (node tools after fnm)' { # A real fnm puts node/npm on PATH only when its companion runs. The availability # check for npm must not have been answered (and remembered) before that. $bin = Join-Path $TestDrive "fakenode-$([guid]::NewGuid().ToString('N').Substring(0, 6))" New-Item -ItemType Directory $bin | Out-Null Set-Content (Join-Path $bin 'nodetool.cmd') '@echo off' Set-Content (Join-Path $script:Tools 'nodetool.json') '{ "name": "nodetool", "executable": "nodetool.cmd", "after": ["vm"] }' Set-Content (Join-Path $script:Tools 'vm.json') '{ "name": "vm", "executable": "vm.exe" }' "`$Env:Path = '$bin;' + `$Env:Path" | Set-Content (Join-Path $script:Tools 'vm.ps1') $script:Installed += 'vm.exe' # Real lookups for nodetool, so PATH matters; the fake list for the rest. Mock Test-DFToolAvailable { if ($Executable -eq 'nodetool.cmd') { [bool](Get-Command $Executable -ErrorAction Ignore) } else { $Executable -in $script:Installed } } $savedPath = $Env:Path try { # Ask about nodetool before vm runs, as role-winner selection can. $null = Test-DFToolAvailable -Executable 'nodetool.cmd' Start-DFSession -Config @{ Tools = @('nodetool', 'vm') } -ToolsPath $script:Tools 3>$null (Get-DFToolStatus -Name nodetool).State | Should -Be 'Active' } finally { $Env:Path = $savedPath } } It 'stores the config, so Get-DFConfig reads it afterwards' { Start-DFSession -Config @{ Tools = @('alpha'); Theme = 'nord' } -ToolsPath $script:Tools 3>$null Get-DFConfig Theme | Should -Be 'nord' } It 'exports the XDG folders' { Start-DFSession -Config @{ Tools = @() } -ToolsPath $script:Tools 3>$null $Env:XDG_STATE_HOME | Should -BeLike "$TestDrive*" Test-Path $Env:XDG_STATE_HOME | Should -BeTrue } It 'runs the conflict check over the active tools only' { Start-DFSession -Config @{ Tools = @('alpha', 'gamma') } -ToolsPath $script:Tools 3>$null Should -Invoke Write-DFConflictNotice -Times 1 -ParameterFilter { (@($Tools).name -join ',') -eq 'alpha' } } } Describe 'Get-DFToolStatus before any session' { BeforeEach { $script:DFSessionStatus = $null } It 'says Start-DFSession has not run, and returns nothing' { Get-DFToolStatus -WarningVariable w 3>$null | Should -BeNullOrEmpty "$w" | Should -Match 'Start-DFSession' } } |