tests/Export-HardeningReport.Tests.ps1
|
BeforeAll { # Load Core module for Write-Log and Write-ErrorLog dependencies $corePath = (Resolve-Path "$PSScriptRoot\..\modules\Core.psm1").Path Import-Module $corePath -Force # Source Export-HardeningReport function and its private helpers directly $exportReportPath = (Resolve-Path "$PSScriptRoot\..\functions\System\Hardening\Export-HardeningReport.ps1").Path . $exportReportPath # Load test fixtures $script:basisReport = Get-Content "$PSScriptRoot\fixtures\ComplianceReport-Basis.json" | ConvertFrom-Json $script:recommendedReport = Get-Content "$PSScriptRoot\fixtures\ComplianceReport-Recommended.json" | ConvertFrom-Json } AfterAll { Remove-Module Core -Force -ErrorAction SilentlyContinue } Describe "Export-HardeningReport" { Context "Parameter Validation" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "accepts a valid compliance report object" { { Export-HardeningReport -ComplianceReport $script:basisReport } | Should -Not -Throw } It "requires a compliance report parameter" { { Export-HardeningReport } | Should -Throw } It "accepts JSON format" { { Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON } | Should -Not -Throw } It "accepts CSV format" { { Export-HardeningReport -ComplianceReport $script:basisReport -Format CSV } | Should -Not -Throw } It "accepts HTML format" { { Export-HardeningReport -ComplianceReport $script:basisReport -Format HTML } | Should -Not -Throw } It "accepts Text format (default)" { { Export-HardeningReport -ComplianceReport $script:basisReport -Format Text } | Should -Not -Throw } } Context "Report Generation" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "generates Text report by default" { $report = Export-HardeningReport -ComplianceReport $script:basisReport $report | Should -Not -BeNullOrEmpty $report -like '*COMPLIANCE SUMMARY*' | Should -Be $true } It "generates JSON report" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON { $report | ConvertFrom-Json } | Should -Not -Throw $json = $report | ConvertFrom-Json $json.ComplianceSummary.CompliancePercentage | Should -Be $script:basisReport.CompliancePercentage } It "generates CSV report" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format CSV $report | Should -Not -BeNullOrEmpty $report[0] -like '*Profile*' | Should -Be $true } It "generates HTML report" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format HTML $report | Should -Not -BeNullOrEmpty $report -like '*<!DOCTYPE html>*' | Should -Be $true } It "includes profile details in report" { $report = Export-HardeningReport -ComplianceReport $script:recommendedReport -Format Text $report | Should -Match 'Recommended' } It "includes compliance percentage in report" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text $report | Should -Match "$($script:basisReport.CompliancePercentage)%" } } Context "File Output" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "saves report to file" { $testPath = Join-Path -Path $env:TEMP -ChildPath "test-report-$(Get-Random).txt" try { Export-HardeningReport -ComplianceReport $script:basisReport -Format Text -OutputPath $testPath | Out-Null Test-Path -Path $testPath | Should -Be $true } finally { Remove-Item -Path $testPath -Force -ErrorAction SilentlyContinue } } It "returns file info object when saving" { $testPath = Join-Path -Path $env:TEMP -ChildPath "test-report-$(Get-Random).json" try { $result = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON -OutputPath $testPath $result | Should -Not -BeNullOrEmpty # Normalize paths for comparison (Windows may expand short names) $result.FullName | Should -Match ([regex]::Escape("test-report")) Test-Path -Path $testPath | Should -Be $true } finally { Remove-Item -Path $testPath -Force -ErrorAction SilentlyContinue } } } Context "Detailed Mode" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "includes rule details when specified" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON -IncludeRuleDetails $json = $report | ConvertFrom-Json $json.RuleDetails | Should -Not -BeNullOrEmpty $json.RuleDetails.Count | Should -BeGreaterThan 0 } It "omits rule details when not specified" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $json = $report | ConvertFrom-Json $json.RuleDetails | Should -BeNullOrEmpty } } Context "Format Support" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "Text format includes summary section" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text $report | Should -Match 'COMPLIANCE SUMMARY' } It "JSON format is valid JSON" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $json = $report | ConvertFrom-Json $json | Should -Not -BeNullOrEmpty $json.ComplianceSummary | Should -Not -BeNullOrEmpty } It "CSV format includes headers" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format CSV $lines = @($report) $lines[0] | Should -Match 'Profile' } It "HTML format includes DOCTYPE" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format HTML $report | Should -Match '<!DOCTYPE' } It "Text format includes category breakdown" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text $report | Should -Match 'CATEGORY BREAKDOWN' } It "JSON includes metadata" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $json = $report | ConvertFrom-Json $json.ReportMetadata.Profile | Should -Be $script:basisReport.Profile $json.ReportMetadata.SessionId | Should -Be $script:basisReport.SessionId } } Context "Integration with Compliance Reports" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "exports Basis profile report successfully" { $report = Export-HardeningReport -ComplianceReport $script:basisReport $report | Should -Not -BeNullOrEmpty $report | Should -Match 'Basis' } It "exports Recommended profile report successfully" { $report = Export-HardeningReport -ComplianceReport $script:recommendedReport $report | Should -Not -BeNullOrEmpty $report | Should -Match 'Recommended' } It "exports different compliance percentages correctly" { $report1 = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text $report2 = Export-HardeningReport -ComplianceReport $script:recommendedReport -Format Text $report1 | Should -Match '85%' $report2 | Should -Match '95%' } } Context "Multiple Format Export" { BeforeEach { Mock Write-Log -ParameterFilter { $true } } It "can export to multiple formats from same compliance data" { $textReport = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text $jsonReport = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $csvReport = @(Export-HardeningReport -ComplianceReport $script:basisReport -Format CSV) $htmlReport = Export-HardeningReport -ComplianceReport $script:basisReport -Format HTML $textReport | Should -Not -BeNullOrEmpty $jsonReport | Should -Not -BeNullOrEmpty $csvReport | Should -Not -BeNullOrEmpty $htmlReport | Should -Not -BeNullOrEmpty } It "all formats contain compliance percentage" { $textReport = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text $jsonReport = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $htmlReport = Export-HardeningReport -ComplianceReport $script:basisReport -Format HTML $textReport | Should -Match '85%' ($jsonReport | ConvertFrom-Json).ComplianceSummary.CompliancePercentage | Should -Be 85 $htmlReport | Should -Match '85' } } Context "Documentation" { It "has complete help documentation" { $help = Get-Help Export-HardeningReport $help.Synopsis | Should -Not -BeNullOrEmpty } It "help includes parameter descriptions" { $help = Get-Help Export-HardeningReport $help.Parameters.Parameter.Name | Should -Contain 'ComplianceReport' $help.Parameters.Parameter.Name | Should -Contain 'Format' } } Context "Error Handling" { BeforeEach { Mock Write-Log -ParameterFilter { $true } Mock Write-ErrorLog -ParameterFilter { $true } } It "throws on null compliance report" { { Export-HardeningReport -ComplianceReport $null } | Should -Throw } It "throws on invalid format" { { Export-HardeningReport -ComplianceReport $script:basisReport -Format "InvalidFormat" } | Should -Throw } It "processes report even with minimal properties" { $minimalReport = [PSCustomObject]@{ CompliancePercentage = 50 Status = "Test" TotalRules = 10 CompliantRules = 5 NonCompliantRules = 5 Profile = "Test" TargetSystem = "Test" VerificationTime = (Get-Date) SessionId = "TEST-001" CategoryBreakdown = @{} RuleResults = @() } # Should succeed with minimal properties $result = Export-HardeningReport -ComplianceReport $minimalReport -Format Text $result | Should -Not -BeNullOrEmpty } It "creates file with proper UTF-8 encoding" { $testPath = Join-Path -Path $env:TEMP -ChildPath "test-utf8-$(Get-Random).txt" try { Export-HardeningReport -ComplianceReport $script:basisReport -Format Text -OutputPath $testPath $fileContent = Get-Content -Path $testPath -Encoding UTF8 $fileContent | Should -Not -BeNullOrEmpty } finally { Remove-Item -Path $testPath -Force -ErrorAction SilentlyContinue } } It "overwrites existing file when OutputPath exists" { $testPath = Join-Path -Path $env:TEMP -ChildPath "test-overwrite-$(Get-Random).txt" try { # Create initial file "Old Content" | Set-Content -Path $testPath -Encoding UTF8 # Export report (should overwrite) Export-HardeningReport -ComplianceReport $script:basisReport -Format Text -OutputPath $testPath # Verify file was overwritten $content = @(Get-Content -Path $testPath -Encoding UTF8) $fullContent = $content -join "`n" $fullContent | Should -Match "COMPLIANCE SUMMARY" } finally { Remove-Item -Path $testPath -Force -ErrorAction SilentlyContinue } } } } Describe "Export-HardeningReport - Edge Cases" { BeforeEach { Mock Write-Log -ParameterFilter { $true } Mock Write-ErrorLog -ParameterFilter { $true } } Context "CSV Format Validation" { It "CSV output is properly formatted with headers" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format CSV $lines = @($report) $lines | Should -Not -BeNullOrEmpty # First line should contain headers $lines[0] | Should -Match "Profile|TargetSystem" } } Context "Fixture Data Validation" { It "Basis report has expected profile name" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $json = $report | ConvertFrom-Json $json.ReportMetadata.Profile | Should -Be "Basis" } It "Recommended report has higher compliance percentage than Basis" { $report1 = Export-HardeningReport -ComplianceReport $script:basisReport -Format JSON $report2 = Export-HardeningReport -ComplianceReport $script:recommendedReport -Format JSON $json1 = $report1 | ConvertFrom-Json $json2 = $report2 | ConvertFrom-Json $json2.ComplianceSummary.CompliancePercentage | Should -BeGreaterThan $json1.ComplianceSummary.CompliancePercentage } } Context "WhatIf Support" { It "respects -WhatIf flag and does not create file" { $testPath = Join-Path -Path $env:TEMP -ChildPath "test-whatif-$(Get-Random).txt" try { Export-HardeningReport -ComplianceReport $script:basisReport -Format Text -OutputPath $testPath -WhatIf Test-Path -Path $testPath | Should -Be $false } finally { Remove-Item -Path $testPath -Force -ErrorAction SilentlyContinue } } It "without -WhatIf creates file normally" { $testPath = Join-Path -Path $env:TEMP -ChildPath "test-normal-$(Get-Random).txt" try { Export-HardeningReport -ComplianceReport $script:basisReport -Format Text -OutputPath $testPath Test-Path -Path $testPath | Should -Be $true } finally { Remove-Item -Path $testPath -Force -ErrorAction SilentlyContinue } } It "allows report generation without -WhatIf when OutputPath omitted" { $report = Export-HardeningReport -ComplianceReport $script:basisReport -Format Text -WhatIf $report | Should -Not -BeNullOrEmpty $report | Should -Match 'COMPLIANCE SUMMARY' } } } |