Testing/Unit/PowerShell/Orchestrator/ConvertTo-ResultsCsv.Tests.ps1

$OrchestratorPath = '../../../../Modules/Orchestrator.psm1'
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath $OrchestratorPath) -Function ConvertTo-ResultsCsv -Force

InModuleScope Orchestrator {
    Describe -Tag 'Orchestrator' -Name 'ConvertTo-ResultsCsv' {
        BeforeAll {
            Mock -CommandName Join-Path { "." }
            Mock -CommandName Test-Path { $true }
            Mock -CommandName Out-File {}
            Mock -CommandName Set-Content {}
            Mock -CommandName Remove-Item {}
            Mock -CommandName Get-Content { "" }
            Mock -CommandName Format-PlainText { "" }
            Mock -CommandName Add-Member {}
            # Return a valid encoding so Set-Content does not throw and trigger a warning
            Mock -CommandName Get-FileEncoding { 'utf8' }
            Mock -CommandName ConvertTo-Csv { "" }
            Mock -CommandName Write-Warning {}
            Mock -CommandName Get-ChildItem {
                [pscustomobject]@{"FullName"="CyberResults_00000000-0000-0000-0000-000000000000.json"; "CreationTime"=[DateTime]"2024-01-01"}
            }
        }

        It 'Handles multiple products, control groups, and controls' {
            # Test to validate that the 3-way nested for loop properly finds all controls
            Mock -CommandName ConvertFrom-Json { @{
                "Results"=[PSCustomObject]@{
                    "EXO"=@(
                        @{
                            "Controls"=@(
                                @{
                                    "Requirement"="123";
                                    "Details"="123";
                                },
                                @{
                                    "Requirement"="123";
                                    "Details"="123";
                                }
                            )
                        },
                        @{
                            "Controls"=@(
                                @{
                                    "Requirement"="123";
                                    "Details"="123";
                                }
                            )
                        }
                    );
                    "AAD"=@(
                        @{
                            "Controls"=@(
                                @{
                                    "Requirement"="123";
                                    "Details"="123";
                                }
                            )
                        }
                    );
                }}
            }
            $CsvParameters = @{
                ProductNames          = @("exo", "aad");
                OutFolderPath         = ".";
                FullCyberResultsName  = "CyberResults";
                OutCsvFileName        = "CyberResults";
                OutActionPlanFileName = "ActionPlan";
            }
            { ConvertTo-ResultsCsv @CsvParameters} | Should -Not -Throw
            Should -Invoke -CommandName ConvertFrom-Json -Exactly -Times 1
            # Note: Write-Warning may be called for configuration warnings (e.g., OrgName not provided)
            # Should -Invoke -CommandName Write-Warning -Exactly -Times 0
            # Each control contributes two calls, EXO has 3 controls, AAD has 1 = 3*2 + 1*2 = 8
            Should -Invoke -CommandName Format-PlainText -Exactly -Times 8
        }

        It 'Handles file not found errors' {
            # Test to validate that a warning is printed if there is an error opening the CyberResults file
            Mock -CommandName ConvertFrom-Json {}
            Mock -CommandName Get-Content { throw "File not found" }
            $CsvParameters = @{
                ProductNames          = @("exo", "aad");
                OutFolderPath         = ".";
                FullCyberResultsName  = "CyberResults";
                OutCsvFileName        = "CyberResults";
                OutActionPlanFileName = "ActionPlan";
            }
            { ConvertTo-ResultsCsv @CsvParameters} | Should -Not -Throw
            Should -Invoke -CommandName Format-PlainText -Exactly -Times 0
            Should -Invoke -CommandName Write-Warning -Exactly -Times 1
        }
    }
}

AfterAll {
    Remove-Module Orchestrator -ErrorAction SilentlyContinue
}