tests/Resolve-DFToolIdentityCandidateRepo.Tests.ps1

BeforeAll {
    . "$PSScriptRoot/../Private/DFCatalog.ps1"
    . "$PSScriptRoot/../Private/Get-DFGitHubRepoInfo.ps1"
    . "$PSScriptRoot/../Private/Resolve-DFToolIdentityCandidateRepo.ps1"
}

Describe 'ConvertTo-DFNormalizedHomepage' {
    It 'strips scheme, www, and trailing slash, and lowercases' {
        ConvertTo-DFNormalizedHomepage -Url 'https://www.Zed.dev/' | Should -Be 'zed.dev'
    }

    It 'normalizes differently-formatted urls for the same site identically' {
        (ConvertTo-DFNormalizedHomepage -Url 'http://zed.dev') |
            Should -Be (ConvertTo-DFNormalizedHomepage -Url 'https://www.zed.dev/')
    }

    It 'returns an empty string for null or empty input, without throwing' {
        ConvertTo-DFNormalizedHomepage -Url $null | Should -Be ''
        ConvertTo-DFNormalizedHomepage -Url '' | Should -Be ''
    }
}

Describe 'Resolve-DFToolIdentityCandidateRepo' {
    AfterEach { $script:DFCatalogProviders = $null }

    It 'resolves via detail-level RepositoryUrl when the repo is on GitHub' {
        Mock Get-DFCatalogDetail {
            New-DFToolSourceDetail -Source scoop -PackageId ripgrep -RepositoryUrl 'https://github.com/BurntSushi/ripgrep'
        }
        $result = Resolve-DFToolIdentityCandidateRepo -Source scoop -PackageId ripgrep
        $result.Repo | Should -Be 'burntsushi/ripgrep'
        $result.Homepage | Should -BeNullOrEmpty
    }

    It 'falls back to a live search''s Homepage when detail has no repo' {
        Mock Get-DFCatalogDetail { $null }
        $script:DFCatalogProviders = @{
            winget = @{
                Search = { param($Query, $Fresh)
                    New-DFToolSourceInfo -Source winget -PackageId 'Zed.Zed' -Name 'Zed' `
                        -Homepage 'https://github.com/zed-industries/zed' -MatchKind exact-id
                }
            }
        }
        $result = Resolve-DFToolIdentityCandidateRepo -Source winget -PackageId 'Zed.Zed'
        $result.Repo | Should -Be 'zed-industries/zed'
    }

    It 'falls back to the normalized homepage when neither detail nor search homepage is GitHub' {
        Mock Get-DFCatalogDetail { $null }
        $script:DFCatalogProviders = @{
            winget = @{
                Search = { param($Query, $Fresh)
                    New-DFToolSourceInfo -Source winget -PackageId 'Zed.Zed' -Name 'Zed' `
                        -Homepage 'https://zed.dev/' -MatchKind exact-id
                }
            }
        }
        $result = Resolve-DFToolIdentityCandidateRepo -Source winget -PackageId 'Zed.Zed'
        $result.Repo | Should -BeNullOrEmpty
        $result.Homepage | Should -Be 'zed.dev'
    }

    It 'never throws when Get-DFCatalogDetail throws' {
        Mock Get-DFCatalogDetail { throw 'network down' }
        $script:DFCatalogProviders = @{ scoop = @{ Search = { param($Query, $Fresh) } } }
        { Resolve-DFToolIdentityCandidateRepo -Source scoop -PackageId ripgrep } | Should -Not -Throw
    }

    It 'never throws when the provider Search throws, returning null fields' {
        Mock Get-DFCatalogDetail { $null }
        $script:DFCatalogProviders = @{ scoop = @{ Search = { param($Query, $Fresh) throw 'boom' } } }
        $result = Resolve-DFToolIdentityCandidateRepo -Source scoop -PackageId ripgrep
        $result.Repo | Should -BeNullOrEmpty
        $result.Homepage | Should -BeNullOrEmpty
    }

    It 'returns null fields (no throw) when no provider is registered for the source' {
        Mock Get-DFCatalogDetail { $null }
        $script:DFCatalogProviders = @{}
        $result = Resolve-DFToolIdentityCandidateRepo -Source scoop -PackageId ripgrep
        $result.Repo | Should -BeNullOrEmpty
        $result.Homepage | Should -BeNullOrEmpty
    }

    It 'only invokes Search when detail-level resolution already succeeded is false' {
        Mock Get-DFCatalogDetail {
            New-DFToolSourceDetail -Source scoop -PackageId ripgrep -RepositoryUrl 'https://github.com/BurntSushi/ripgrep'
        }
        $searchCalled = $false
        $script:DFCatalogProviders = @{ scoop = @{ Search = { param($Query, $Fresh) $script:searchCalled = $true } } }
        $null = Resolve-DFToolIdentityCandidateRepo -Source scoop -PackageId ripgrep
        $searchCalled | Should -BeFalse
    }
}