From 8f07330bfb9eb82d0b4af9d6f7ee0faf4aa81b0c Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Fri, 9 Oct 2026 14:34:46 +0000 Subject: [PATCH] test: cover relative paths, a missing drive and privilege control Resolve relative paths with Get-Item2, report copies and moves to a drive that does not exist, warn once about MACTripleDES across pipeline objects, and check the exceptions of PrivilegeControl for held, repeated and missing privileges. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- Tests/FileHash.Tests.ps1 | 8 +++++ Tests/ItemCmdlets.Tests.ps1 | 63 +++++++++++++++++++++++++++++++++++++ Tests/Privileges.Tests.ps1 | 53 +++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) diff --git a/Tests/FileHash.Tests.ps1 b/Tests/FileHash.Tests.ps1 index 04184d1..1babcfb 100644 --- a/Tests/FileHash.Tests.ps1 +++ b/Tests/FileHash.Tests.ps1 @@ -80,6 +80,14 @@ Describe 'Get-FileHash2' { $hashWarnings | Should -HaveCount 1 $hashWarnings[0].Message | Should -BeLike '*MACTripleDES*random key*deprecated*' } + + # PowerShell calls the cmdlet once for each object in the pipeline; the warning belongs to the command. + It 'Should warn once that MACTripleDES is deprecated for several objects in the pipeline' -Skip:$isCore { + $results = @($first, $second | Get-FileHash2 -Algorithm MACTripleDES -WarningVariable hashWarnings -WarningAction SilentlyContinue) + + $results | Should -HaveCount 2 + $hashWarnings | Should -HaveCount 1 + } } Context 'When -Path contains a folder' { It 'Should skip the folder and hash the files that follow it' { diff --git a/Tests/ItemCmdlets.Tests.ps1 b/Tests/ItemCmdlets.Tests.ps1 index 6c194a1..f06a0b4 100644 --- a/Tests/ItemCmdlets.Tests.ps1 +++ b/Tests/ItemCmdlets.Tests.ps1 @@ -683,6 +683,30 @@ Describe 'Copy-Item2, Move-Item2, and Remove-Item2 with several paths' { Get-Content -LiteralPath $first | Should -Be 'First' Get-Content -LiteralPath $second | Should -Be 'Second' } + + # A destination on a drive letter without a volume has no folder that the cmdlet could name, so Windows reports the + # drive as not ready, which AlphaFS raises as an IOException. + It ' should write a for a destination on a drive that does not exist and keep the source' -ForEach @( + @{ Command = 'Copy-Item2'; ErrorId = 'CopyError' } + @{ Command = 'Move-Item2'; ErrorId = 'MoveError' } + ) { + $used = @((Get-PSDrive -PSProvider FileSystem).Name) + @([System.IO.DriveInfo]::GetDrives() | ForEach-Object -Process { $_.Name.Substring(0, 1) }) + $letter = [char[]](68..90) | Where-Object -FilterScript { [string] $_ -notin $used } | Select-Object -Last 1 + if (-not $letter) { + Set-ItResult -Skipped -Because 'every drive letter is in use' + return + } + + $result = @(& $Command -Path $first -Destination "${letter}:\" -PassThru $true -ErrorVariable itemErrors -ErrorAction SilentlyContinue) + + $itemErrors | Should -HaveCount 1 + $itemErrors[0].FullyQualifiedErrorId | Should -BeLike "$ErrorId,*" + $itemErrors[0].CategoryInfo.Category | Should -Be 'InvalidData' + $itemErrors[0].TargetObject | Should -Be $first + $itemErrors[0].Exception | Should -BeOfType [System.IO.IOException] + $result | Should -BeNullOrEmpty + Get-Content -LiteralPath $first | Should -Be 'First' + } } Describe 'Move-Item2' { @@ -766,6 +790,45 @@ Describe 'Copy-Item2' { } } +Describe 'Relative paths' { + BeforeAll { + $parent = New-TestSandboxItem -Sandbox $sandbox -Name 'RelativeParent' -Directory + $child = Join-Path -Path $parent -ChildPath 'Child' + $sibling = Join-Path -Path $parent -ChildPath 'Sibling' + $siblingFile = Join-Path -Path $sibling -ChildPath 'Sibling.txt' + Assert-TestSandboxPath -Sandbox $sandbox -Path $child, $sibling, $siblingFile + New-Item -ItemType Directory -Path $child, $sibling | Out-Null + Set-Content -LiteralPath $siblingFile -Value 'Sibling' + } + + It 'Get-Item2 should resolve against the current location' -ForEach @( + @{ Path = '.'; Expected = 'Child' } + @{ Path = '.\'; Expected = 'Child' } + @{ Path = '..'; Expected = 'Parent' } + @{ Path = '..\Sibling'; Expected = 'Sibling' } + @{ Path = '..\Sibling\Sibling.txt'; Expected = 'SiblingFile' } + @{ Path = '..\..'; Expected = 'Grandparent' } + ) { + $expectedPath = switch ($Expected) { + 'Child' { $child } + 'Parent' { $parent } + 'Sibling' { $sibling } + 'SiblingFile' { $siblingFile } + 'Grandparent' { Split-Path -Path $parent -Parent } + } + Push-Location -LiteralPath $child + try { + $result = @(Get-Item2 -Path $Path -ErrorAction Stop) + } + finally { + Pop-Location + } + + $result | Should -HaveCount 1 + $result[0].FullName.TrimEnd('\') | Should -Be $expectedPath + } +} + Describe 'Test-Path2' { BeforeAll { $folder = New-TestSandboxItem -Sandbox $sandbox -Name 'TestPath' -Directory diff --git a/Tests/Privileges.Tests.ps1 b/Tests/Privileges.Tests.ps1 index bc311f8..b47ef99 100644 --- a/Tests/Privileges.Tests.ps1 +++ b/Tests/Privileges.Tests.ps1 @@ -380,3 +380,56 @@ Describe 'The PrivilegeEnabler class' { [ProcessPrivileges.ProcessExtensions]::GetPrivilegeState($attributes) | Should -Be $Expected } } + +Describe 'The PrivilegeControl class' { + BeforeAll { + $privateData['EnablePrivileges'] = $false + $control = New-Object -TypeName 'Security2.PrivilegeControl' + $backup = [ProcessPrivileges.Privilege]::Backup + } + + AfterAll { + $privateData['EnablePrivileges'] = $enablePrivileges + } + + BeforeEach { + Disable-Privileges -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + + AfterEach { + Disable-Privileges -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + } + + It 'Should refuse to a privilege that the access token does not hold' -ForEach @( + @{ Operation = 'enable' } + @{ Operation = 'disable' } + ) { + $failure = { + if ($Operation -eq 'enable') { + $control.EnablePrivilege([ProcessPrivileges.Privilege]::CreateToken) + } + else { + $control.DisablePrivilege([ProcessPrivileges.Privilege]::CreateToken) + } + } | Should -Throw -PassThru + + $failure.Exception.InnerException | Should -BeOfType [System.Security.AccessControl.PrivilegeNotHeldException] + $failure.Exception.InnerException.PrivilegeName | Should -BeExactly 'CreateToken' + } + + It 'Should enable and disable a held privilege and refuse to repeat either' -Skip:(-not $holdsPrivileges) { + Get-BackupPrivilegeState | Should -Be 'Disabled' + $failure = { $control.DisablePrivilege($backup) } | Should -Throw -PassThru + $failure.Exception.InnerException | Should -BeOfType [Security2.AdjustPriviledgeException] + $failure.Exception.InnerException.Message | Should -BeExactly 'Priviledge already disabled' + + $control.EnablePrivilege($backup) | Should -Be 'PrivilegeModified' + Get-BackupPrivilegeState | Should -Be 'Enabled' + $failure = { $control.EnablePrivilege($backup) } | Should -Throw -PassThru + $failure.Exception.InnerException | Should -BeOfType [Security2.AdjustPriviledgeException] + $failure.Exception.InnerException.Message | Should -BeExactly 'Priviledge already enabled' + + $control.DisablePrivilege($backup) | Should -Be 'PrivilegeModified' + Get-BackupPrivilegeState | Should -Be 'Disabled' + } +}