functions/_Get-RemoteGistMap.Tests.ps1

# <copyright file="_Get-RemoteGistMap.Tests.ps1" company="Endjin Limited">
# Copyright (c) Endjin Limited. All rights reserved.
# </copyright>

Describe "_Get-RemoteGistMap" {

    BeforeAll {
        # Define stubs for external module functions to avoid dependency and ensure mocking works
        function ConvertTo-Yaml { param($Data, $OutFile, [switch]$Force) }
        function _Get-VendirPath { }
        function _Install-Vendir { }

        $sut = "$PSScriptRoot\_Get-RemoteGistMap.ps1"
        . $sut

        $script:testGitSource = @{
            url  = 'https://github.com/endjin/endjin-gists.git'
            ref  = 'main'
            path = 'module/gist-map.yml'
        }
    }

    Context "Successful Fetch" {
        BeforeAll {
            Mock _Get-VendirPath { return 'vendir' }
            Mock ConvertTo-Yaml { }
            Mock New-Item { [PSCustomObject]@{ FullName = $Path } }
            Mock Push-Location { }
            Mock Pop-Location { }
            Mock Remove-Item { }
            # General mock for Get-Content handles the verbose read of vendir.yml
            Mock Get-Content { return "vendir config content" }
        }

        It "Should return YAML content when vendir sync succeeds" {
            Mock Invoke-Command {
                $global:LASTEXITCODE = 0
                return "Success"
            }
            Mock Test-Path { return $true }
            Mock Get-Content { return "group1:`n - name: gist1" } -ParameterFilter { $Path -like '*gist-map.yml' }

            $result = _Get-RemoteGistMap -GitSource $script:testGitSource

            $result | Should -Be "group1:`n - name: gist1"
        }

        It "Should call _Get-VendirPath to resolve vendir" {
            Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" }
            Mock Test-Path { return $true }
            Mock Get-Content { return "yaml content" } -ParameterFilter { $Path -like '*gist-map.yml' }

            _Get-RemoteGistMap -GitSource $script:testGitSource

            Should -Invoke _Get-VendirPath -Times 1
        }

        It "Should generate vendir config with newRootPath for files in subdirectories" {
            Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" }
            Mock Test-Path { return $true }
            Mock Get-Content { return "yaml content" } -ParameterFilter { $Path -like '*gist-map.yml' }

            $capturedData = $null
            Mock ConvertTo-Yaml { $script:capturedData = $Data }

            _Get-RemoteGistMap -GitSource $script:testGitSource

            $script:capturedData.directories[0].contents[0].newRootPath | Should -Be 'module'
        }
    }

    Context "Vendir Sync Failure" {
        BeforeAll {
            Mock _Get-VendirPath { return 'vendir' }
            Mock ConvertTo-Yaml { }
            Mock New-Item { [PSCustomObject]@{ FullName = $Path } }
            Mock Push-Location { }
            Mock Pop-Location { }
            Mock Remove-Item { }
            Mock Get-Content { return "vendir config content" }
        }

        It "Should return null when vendir sync fails" {
            Mock Invoke-Command {
                $global:LASTEXITCODE = 1
                return "Error"
            }

            $result = _Get-RemoteGistMap -GitSource $script:testGitSource

            $result | Should -BeNullOrEmpty
        }
    }

    Context "VendirPath Resolution Failure" {
        It "Should return null when _Get-VendirPath throws" {
            Mock _Get-VendirPath { throw "vendir not available" }
            Mock Remove-Item { }

            $result = _Get-RemoteGistMap -GitSource $script:testGitSource

            $result | Should -BeNullOrEmpty
        }
    }

    Context "File Not Found After Sync" {
        BeforeAll {
            Mock _Get-VendirPath { return 'vendir' }
            Mock ConvertTo-Yaml { }
            Mock New-Item { [PSCustomObject]@{ FullName = $Path } }
            Mock Push-Location { }
            Mock Pop-Location { }
            Mock Remove-Item { }
            Mock Get-Content { return "vendir config content" }
        }

        It "Should return null when synced file does not exist" {
            Mock Invoke-Command {
                $global:LASTEXITCODE = 0
                return "Success"
            }
            Mock Test-Path { return $false }

            $result = _Get-RemoteGistMap -GitSource $script:testGitSource

            $result | Should -BeNullOrEmpty
        }
    }

    Context "Git Source Without Subdirectory" {
        BeforeAll {
            Mock _Get-VendirPath { return 'vendir' }
            Mock ConvertTo-Yaml { }
            Mock New-Item { [PSCustomObject]@{ FullName = $Path } }
            Mock Push-Location { }
            Mock Pop-Location { }
            Mock Remove-Item { }
            Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" }
            Mock Test-Path { return $true }
            # General mock handles the verbose read of vendir.yml
            Mock Get-Content { return "vendir config content" }
            Mock Get-Content { return "yaml content" } -ParameterFilter { $Path -like '*gist-map.yml' }
        }

        It "Should not add newRootPath when file is at repository root" {
            $rootGitSource = @{
                url  = 'https://github.com/endjin/endjin-gists.git'
                ref  = 'main'
                path = 'gist-map.yml'
            }

            $capturedData = $null
            Mock ConvertTo-Yaml { $script:capturedData = $Data }

            _Get-RemoteGistMap -GitSource $rootGitSource

            $script:capturedData.directories[0].contents[0].Keys | Should -Not -Contain 'newRootPath'
        }
    }
}