Tests/Public/Move-FileShare.Tests.ps1

[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '', Justification = 'Tests intentionally swallow errors to verify side-effects')]
param()

BeforeAll {
    $modulePath = "$PSScriptRoot/../.."
    Get-ChildItem -Path "$modulePath/Private/*.ps1" | ForEach-Object { . $_.FullName }
    Get-ChildItem -Path "$modulePath/Public/*.ps1"  | ForEach-Object { . $_.FullName }
}

Describe 'Move-FileShare' {
    BeforeEach {
        Mock Write-Host {}
        Mock Write-Warning {}
        Mock Assert-AzCopyInstalled {}
        Mock Assert-AzCliLogin { [PSCustomObject]@{ user = @{ name = 'test@contoso.com' } } }
        Mock Test-StorageAccountAccess {}
        Mock New-SasToken { 'fakesas=token' }
        Mock New-Item { [PSCustomObject]@{ FullName = 'C:\logs' } }
    }

    Context 'Pre-flight checks' {
        It 'Calls Assert-AzCopyInstalled' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {}
            Should -Invoke Assert-AzCopyInstalled -Times 1
        }

        It 'Calls Assert-AzCliLogin' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {}
            Should -Invoke Assert-AzCliLogin -Times 1
        }

        It 'Validates both storage accounts are accessible' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {}
            Should -Invoke Test-StorageAccountAccess -Times 2
        }

        It 'Generates SAS tokens for source (rl) and destination (rwdlc)' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {}
            Should -Invoke New-SasToken -ParameterFilter { $Permissions -eq 'rl' } -Times 1
            Should -Invoke New-SasToken -ParameterFilter { $Permissions -eq 'rwdlc' } -Times 1
        }
    }

    Context 'Share enumeration' {
        It 'Returns early when no shares found on source' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '[]' }
            Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst'
            Should -Invoke Write-Warning -ParameterFilter { $Message -like '*No file shares*' }
        }

        It 'Throws when requested share does not exist' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1","share2"]' }
            { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'nonexistent' } | Should -Throw '*nonexistent*'
        }

        It 'Throws when az storage share list fails' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 1; 'AuthorizationFailure' }
            { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' } | Should -Throw '*Failed to list*'
        }

        It 'Filters to specified shares when ShareNames provided' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1","share2","share3"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1','share2' -Confirm:$false } catch {}
            Should -Invoke Write-Host -ParameterFilter { $Object -like '*Targeting 2 share*' }
        }

        It 'Targets all shares when ShareNames not provided' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1","share2"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -Confirm:$false } catch {}
            Should -Invoke Write-Host -ParameterFilter { $Object -like '*Targeting all 2*' }
        }
    }

    Context 'WhatIf support' {
        It 'Proceeds through share enumeration when WhatIf is specified' {
            Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' }
            Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'dry run complete' }
            try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -WhatIf } catch {}
            # Verify WhatIf does not skip function body — enumeration and targeting still occur
            Should -Invoke Write-Host -ParameterFilter { $Object -like '*Targeting 1 share*' }
        }
    }

    Context 'Parameter validation' {
        It 'ThrottleLimit must be between 1 and 64' {
            { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ThrottleLimit 0 } | Should -Throw
            { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ThrottleLimit 65 } | Should -Throw
        }

        It 'SourceAccountName is mandatory' {
            $param = (Get-Command Move-FileShare).Parameters['SourceAccountName']
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | ForEach-Object {
                $_.Mandatory | Should -BeTrue
            }
        }

        It 'DestinationAccountName is mandatory' {
            $param = (Get-Command Move-FileShare).Parameters['DestinationAccountName']
            $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | ForEach-Object {
                $_.Mandatory | Should -BeTrue
            }
        }

    }
}