tests/Report.JsonEvidence.Tests.ps1
|
#Requires -Version 7.0 #Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } <# Pester tests for src/report/renderers/Export-JsonEvidence.ps1 -- the resources-only JSON evidence export (ADO Story AB#396). Uses the repo's existing tests/datadump/sample-collect.json fixture as -Collect. No Azure connection required. #> BeforeAll { $script:Root = Split-Path $PSScriptRoot -Parent . "$script:Root/src/report/renderers/Export-JsonEvidence.ps1" $script:CollectPath = Join-Path $script:Root 'tests' 'datadump' 'sample-collect.json' $script:Collect = Get-Content $script:CollectPath -Raw | ConvertFrom-Json -Depth 100 # A representative scored-Findings object -- Export-JsonEvidence must # never leak any of this into the output (AB#396's core requirement). $script:Findings = [pscustomobject]@{ GeneratedOn = (Get-Date).ToString('o') Frameworks = @([pscustomobject]@{ Framework = 'CAF'; Score = 70 }) Areas = @([pscustomobject]@{ Framework = 'CAF'; Area = 'Networking'; Score = 50 }) Gaps = @([pscustomobject]@{ Id = 'CAF-NET-01'; Severity = 'high'; Title = 'x' }) Manual = @() Errors = @() Findings = @([pscustomobject]@{ Id = 'CAF-NET-01'; Status = 'Fail' }) } $script:OutDir = Join-Path $script:Root 'tests' 'test-output' 'json-evidence' if (Test-Path $script:OutDir) { Remove-Item $script:OutDir -Recurse -Force } } AfterAll { if (Test-Path $script:OutDir) { Remove-Item $script:OutDir -Recurse -Force -ErrorAction SilentlyContinue } } Describe 'Export-JsonEvidence AB#396' { BeforeAll { $script:EvidencePath = Export-JsonEvidence -Findings $script:Findings -Collect $script:Collect -OutputPath $script:OutDir $script:Raw = Get-Content $script:EvidencePath -Raw $script:Parsed = $script:Raw | ConvertFrom-Json -Depth 100 } It 'writes evidence.json into -OutputPath and returns its path' { $script:EvidencePath | Should -Exist (Split-Path $script:EvidencePath -Leaf) | Should -Be 'evidence.json' } It 'is well-formed, parseable JSON' { { $script:Raw | ConvertFrom-Json -Depth 100 } | Should -Not -Throw } It 'contains the raw collected resource sections' { $script:Parsed.networking.virtualNetworks.Count | Should -Be 3 $script:Parsed.compute.virtualMachines.Count | Should -Be 3 $script:Parsed.domains.storage.storageAccounts.Count | Should -Be 2 $script:Parsed.advisor.Count | Should -Be 10 } It 'contains NO assessment metadata, scores, gaps, or findings from the scored Findings object' { foreach ($forbidden in 'GeneratedOn', 'Frameworks', 'Gaps', 'Manual', 'Errors') { $script:Parsed.PSObject.Properties.Name | Should -Not -Contain $forbidden } # 'Findings' as a top-level key would only ever come from the scored # object -- Collect has no such key in its own canonical shape. $script:Parsed.PSObject.Properties.Name | Should -Not -Contain 'Findings' } It 'ignores -Findings entirely -- identical output regardless of what is passed' { $altDir = Join-Path $script:Root 'tests' 'test-output' 'json-evidence-alt' if (Test-Path $altDir) { Remove-Item $altDir -Recurse -Force } try { $altPath = Export-JsonEvidence -Findings $null -Collect $script:Collect -OutputPath $altDir (Get-Content $altPath -Raw) | Should -Be $script:Raw } finally { if (Test-Path $altDir) { Remove-Item $altDir -Recurse -Force -ErrorAction SilentlyContinue } } } It 'is deterministic -- re-rendering the same Collect produces byte-identical output' { $repeatDir = Join-Path $script:Root 'tests' 'test-output' 'json-evidence-repeat' if (Test-Path $repeatDir) { Remove-Item $repeatDir -Recurse -Force } try { $repeatPath = Export-JsonEvidence -Findings $script:Findings -Collect $script:Collect -OutputPath $repeatDir (Get-Content $repeatPath -Raw) | Should -Be $script:Raw } finally { if (Test-Path $repeatDir) { Remove-Item $repeatDir -Recurse -Force -ErrorAction SilentlyContinue } } } } Describe 'Export-JsonEvidence -- defensive/edge cases' { It 'does not throw and emits an empty object when -Collect is $null' { $dir = Join-Path $script:Root 'tests' 'test-output' 'json-evidence-null' if (Test-Path $dir) { Remove-Item $dir -Recurse -Force } try { $path = Export-JsonEvidence -Findings $null -Collect $null -OutputPath $dir $path | Should -Exist $parsed = Get-Content $path -Raw | ConvertFrom-Json -Depth 100 # @(...) forces array semantics on the Properties collection itself -- # under Set-StrictMode, dot-accessing .Name on a ZERO-element # PSMemberInfoCollection throws (no elements to enumerate a .Name # across), rather than returning an empty array as one might expect. @($parsed.PSObject.Properties).Count | Should -Be 0 } finally { if (Test-Path $dir) { Remove-Item $dir -Recurse -Force -ErrorAction SilentlyContinue } } } } |