Tests/Exchange-MigrationAssessment.Tests.ps1

BeforeAll {
    $modulePath = Split-Path -Parent $PSScriptRoot
    Import-Module "$modulePath\Exchange-MigrationAssessment.psd1" -Force
}

Describe 'Exchange-MigrationAssessment Module' {

    Context 'Module Loading' {
        It 'Should import without errors' {
            { Import-Module "$PSScriptRoot\..\Exchange-MigrationAssessment.psd1" -Force } | Should -Not -Throw
        }

        It 'Should export exactly 5 public functions' {
            $commands = Get-Command -Module Exchange-MigrationAssessment
            $commands.Count | Should -Be 5
        }

        It 'Should export all expected functions' {
            $expected = @('Invoke-MigrationAssessment', 'Get-MailboxInventory', 'Get-DistributionGroupAudit', 'Get-MailFlowRuleExport', 'Get-PublicFolderAnalysis')
            foreach ($func in $expected) {
                Get-Command -Module Exchange-MigrationAssessment -Name $func | Should -Not -BeNullOrEmpty
            }
        }

        It 'Should not export private functions' {
            { Get-Command -Module Exchange-MigrationAssessment -Name _New-MigrationAssessmentHtml -ErrorAction Stop } | Should -Throw
        }
    }

    Context 'Get-MailboxInventory Parameter Validation' {
        It 'Should validate RecipientType values' {
            $validateSet = (Get-Command Get-MailboxInventory).Parameters['RecipientType'].Attributes |
                Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }
            $validateSet.ValidValues | Should -Contain 'UserMailbox'
            $validateSet.ValidValues | Should -Contain 'SharedMailbox'
            $validateSet.ValidValues | Should -Contain 'All'
        }

        It 'Should have MinimumSizeGB parameter' {
            (Get-Command Get-MailboxInventory).Parameters.ContainsKey('MinimumSizeGB') | Should -BeTrue
        }
    }

    Context 'Get-DistributionGroupAudit Parameter Validation' {
        It 'Should have IncludeEmpty switch' {
            (Get-Command Get-DistributionGroupAudit).Parameters['IncludeEmpty'].SwitchParameter | Should -BeTrue
        }
    }

    Context 'Get-MailFlowRuleExport Parameter Validation' {
        It 'Should have IncludeDisabled switch' {
            (Get-Command Get-MailFlowRuleExport).Parameters['IncludeDisabled'].SwitchParameter | Should -BeTrue
        }
    }

    Context 'Get-PublicFolderAnalysis Parameter Validation' {
        It 'Should have MaxDepth parameter' {
            (Get-Command Get-PublicFolderAnalysis).Parameters.ContainsKey('MaxDepth') | Should -BeTrue
        }
    }

    Context 'Invoke-MigrationAssessment Parameter Validation' {
        It 'Should have SkipPublicFolders switch' {
            (Get-Command Invoke-MigrationAssessment).Parameters['SkipPublicFolders'].SwitchParameter | Should -BeTrue
        }

        It 'Should have ExportCsv switch' {
            (Get-Command Invoke-MigrationAssessment).Parameters['ExportCsv'].SwitchParameter | Should -BeTrue
        }

        It 'Should default OutputPath to .\Reports' {
            (Get-Command Invoke-MigrationAssessment).Parameters.ContainsKey('OutputPath') | Should -BeTrue
        }
    }

    Context 'HTML Report Generation' {
        It 'Should generate valid HTML with migration data' {
            $mockData = @{
                Mailboxes    = @(
                    [PSCustomObject]@{ DisplayName = 'Exec Team'; PrimarySmtpAddress = 'exec@contoso.com'; RecipientType = 'SharedMailbox'; SizeGB = 98.4; ItemCount = 245891; HasArchive = $true; LitigationHold = $true; Database = 'DB03' }
                    [PSCustomObject]@{ DisplayName = 'Smith, Jane'; PrimarySmtpAddress = 'jsmith@contoso.com'; RecipientType = 'UserMailbox'; SizeGB = 28.9; ItemCount = 67890; HasArchive = $false; LitigationHold = $false; Database = 'DB01' }
                )
                Groups       = @(
                    [PSCustomObject]@{ Name = 'All Staff'; GroupType = 'Distribution'; MemberCount = 389; NestedGroups = 3; ExternalMembers = 0; MigrationNotes = 'Has nested groups' }
                )
                MailFlowRules = @(
                    [PSCustomObject]@{ Name = 'Disclaimer'; Priority = 0; State = 'Enabled'; MigrationConcerns = '' }
                )
                PublicFolders = @()
            }

            $html = & (Get-Module Exchange-MigrationAssessment) {
                param($data)
                _New-MigrationAssessmentHtml -AssessmentData $data
            } $mockData

            $html | Should -Match '<!DOCTYPE html>'
            $html | Should -Match 'Exchange Migration'
            $html | Should -Match 'Exec Team'
            $html | Should -Match '98.4'
        }

        It 'Should flag large mailboxes in the report' {
            $mockData = @{
                Mailboxes    = @(
                    [PSCustomObject]@{ DisplayName = 'Big Box'; PrimarySmtpAddress = 'big@contoso.com'; RecipientType = 'UserMailbox'; SizeGB = 75.0; ItemCount = 200000; HasArchive = $false; LitigationHold = $false; Database = 'DB01' }
                )
                Groups       = @()
                MailFlowRules = @()
                PublicFolders = @()
            }

            $html = & (Get-Module Exchange-MigrationAssessment) {
                param($data)
                _New-MigrationAssessmentHtml -AssessmentData $data
            } $mockData

            # Large mailboxes (>50GB) should get the 'large' CSS class
            $html | Should -Match 'class="large"'
        }

        It 'Should calculate total data size' {
            $mockData = @{
                Mailboxes    = @(
                    [PSCustomObject]@{ DisplayName = 'A'; PrimarySmtpAddress = 'a@c.com'; RecipientType = 'UserMailbox'; SizeGB = 50; ItemCount = 100; HasArchive = $false; LitigationHold = $false; Database = 'DB01' }
                    [PSCustomObject]@{ DisplayName = 'B'; PrimarySmtpAddress = 'b@c.com'; RecipientType = 'UserMailbox'; SizeGB = 50; ItemCount = 100; HasArchive = $false; LitigationHold = $false; Database = 'DB01' }
                )
                Groups       = @()
                MailFlowRules = @()
                PublicFolders = @()
            }

            $html = & (Get-Module Exchange-MigrationAssessment) {
                param($data)
                _New-MigrationAssessmentHtml -AssessmentData $data
            } $mockData

            $html | Should -Match '100'  # Total GB or some representation of combined size
        }
    }

    Context 'Module Manifest' {
        It 'Should have correct module version' {
            $manifest = Test-ModuleManifest "$PSScriptRoot\..\Exchange-MigrationAssessment.psd1"
            $manifest.Version | Should -Be '1.0.0'
        }

        It 'Should have correct author' {
            $manifest = Test-ModuleManifest "$PSScriptRoot\..\Exchange-MigrationAssessment.psd1"
            $manifest.Author | Should -Be 'Larry Roberts'
        }

        It 'Should require PowerShell 5.1' {
            $manifest = Test-ModuleManifest "$PSScriptRoot\..\Exchange-MigrationAssessment.psd1"
            $manifest.PowerShellVersion | Should -Be '5.1'
        }

        It 'Should have a project URI pointing to GitHub' {
            $manifest = Test-ModuleManifest "$PSScriptRoot\..\Exchange-MigrationAssessment.psd1"
            $manifest.ProjectUri | Should -Match 'github.com/larro1991'
        }
    }
}