tests/Get-DFGitHubRepoInfo.Tests.ps1
|
BeforeAll { . "$PSScriptRoot/../Public/New-DFDirectory.ps1" . "$PSScriptRoot/../Private/DFCatalog.ps1" . "$PSScriptRoot/../Private/Start-DFCatalogRefreshJob.ps1" . "$PSScriptRoot/../Private/Get-DFGitHubRepoInfo.ps1" } Describe 'Resolve-DFGitHubRepoUrl' { It 'extracts owner/repo from a Details RepositoryUrl (git+ and .git stripped)' { $info = [pscustomobject]@{ Details = [ordered]@{ npm = [pscustomobject]@{ RepositoryUrl = 'git+https://github.com/left-pad/left-pad.git#readme' } } Homepage = '' } $r = Resolve-DFGitHubRepoUrl -Info $info $r.Owner | Should -Be 'left-pad' $r.Repo | Should -Be 'left-pad' } It 'falls back to Homepage' { $info = [pscustomobject]@{ Details = $null; Homepage = 'https://github.com/BurntSushi/ripgrep' } (Resolve-DFGitHubRepoUrl -Info $info).Repo | Should -Be 'ripgrep' } It 'returns null for non-GitHub urls' { $info = [pscustomobject]@{ Details = $null; Homepage = 'https://zed.dev' } Resolve-DFGitHubRepoUrl -Info $info | Should -BeNullOrEmpty } } Describe 'Get-DFGitHubRepoInfo' { BeforeEach { $script:SavedXdgCache = $Env:XDG_CACHE_HOME $Env:XDG_CACHE_HOME = Join-Path $TestDrive 'cache' $githubCacheDir = Join-Path $Env:XDG_CACHE_HOME 'dotforge/catalogs/github/details' if (Test-Path $githubCacheDir) { Remove-Item $githubCacheDir -Recurse -Force } $script:DFGitHubCliOk = $null } AfterEach { $Env:XDG_CACHE_HOME = $script:SavedXdgCache; $script:DFGitHubCliOk = $null } It 'maps repo + latest release into DotForge.RepoInfo' { Mock Invoke-DFGitHubApi { param($Path) if ($Path -like '*/releases/latest') { [pscustomobject]@{ tag_name = 'v14.1.1'; published_at = '2026-06-01T00:00:00Z' } } else { [pscustomobject]@{ stargazers_count = 55000; open_issues_count = 120 pushed_at = '2026-07-01T12:00:00Z'; archived = $false default_branch = 'master'; description = 'recursively searches' license = [pscustomobject]@{ spdx_id = 'MIT' } } } } $r = Get-DFGitHubRepoInfo -Owner BurntSushi -Repo ripgrep -Fresh $r.PSObject.TypeNames[0] | Should -Be 'DotForge.RepoInfo' $r.Stars | Should -Be 55000 $r.LatestRelease | Should -Be 'v14.1.1' $r.License | Should -Be 'MIT' } It 'tolerates a missing latest release (404)' { Mock Invoke-DFGitHubApi { param($Path) if ($Path -like '*/releases/latest') { throw '404' } [pscustomobject]@{ stargazers_count = 1; open_issues_count = 0; pushed_at = '2026-01-01T00:00:00Z' archived = $true; default_branch = 'main'; description = 'x'; license = $null } } $r = Get-DFGitHubRepoInfo -Owner a -Repo b -Fresh $r.LatestRelease | Should -BeNullOrEmpty $r.Archived | Should -BeTrue } It 'returns null when the repo fetch fails' { Mock Invoke-DFGitHubApi { throw 'rate limited' } Get-DFGitHubRepoInfo -Owner a -Repo b -Fresh | Should -BeNullOrEmpty } It 'serves the second call from cache' { Mock Invoke-DFGitHubApi { param($Path) if ($Path -like '*/releases/latest') { throw '404' } [pscustomobject]@{ stargazers_count = 9; open_issues_count = 0; pushed_at = '2026-01-01T00:00:00Z' archived = $false; default_branch = 'main'; description = 'x'; license = $null } } $null = Get-DFGitHubRepoInfo -Owner a -Repo b $r = Get-DFGitHubRepoInfo -Owner a -Repo b $r.Stars | Should -Be 9 Should -Invoke Invoke-DFGitHubApi -Times 2 -Exactly # repo + release, once each } } Describe 'Invoke-DFGitHubApi transport selection' { AfterEach { $script:DFGitHubCliOk = $null } It 'uses anonymous REST when gh is unavailable' { $script:DFGitHubCliOk = $false Mock Invoke-RestMethod { [pscustomobject]@{ ok = 1 } } (Invoke-DFGitHubApi -Path 'repos/a/b').ok | Should -Be 1 Should -Invoke Invoke-RestMethod -ParameterFilter { $Uri -eq 'https://api.github.com/repos/a/b' } } } |