Tests/Save-GitWorktree.Tests.ps1

BeforeAll {
    Import-Module "$PSScriptRoot\..\GittHelpers.psd1" -Force
}

Describe 'Save-GitWorktree' {
    BeforeEach {
        $script:WtPath = $TestDrive
        $script:FakeWt = [PSCustomObject]@{
            Path       = $script:WtPath
            Branch     = 'feature/my-feature'
            IsBare     = $false
            IsDetached = $false
            Head       = 'abc1234'
        }
        Mock Get-GitRoot      { return $TestDrive }           -ModuleName GittHelpers
        Mock Get-WorktreeList { return @($script:FakeWt) }   -ModuleName GittHelpers
        Mock Resolve-Path     { [PSCustomObject]@{ Path = $script:WtPath } } -ModuleName GittHelpers
        Mock git              { $global:LASTEXITCODE = 0 }   -ModuleName GittHelpers
        Mock Set-Location     { }                            -ModuleName GittHelpers
    }

    It 'Requires -Message' {
        { Save-GitWorktree -Message '' } | Should -Throw
    }

    It 'Throws when path is not a worktree' {
        Mock Get-WorktreeList { return @() } -ModuleName GittHelpers
        { Save-GitWorktree -Message 'test' -Path $script:WtPath } | Should -Throw
    }

    It 'Throws when worktree is detached HEAD' {
        $script:FakeWt.Branch = $null
        Mock Get-WorktreeList { return @($script:FakeWt) } -ModuleName GittHelpers
        { Save-GitWorktree -Message 'test' -Path $script:WtPath } | Should -Throw
    }

    It 'Does not push when -NoPush is specified' {
        $script:PushCalled = $false
        Mock git {
            $global:LASTEXITCODE = 0
            if ($args -contains 'push')  { $script:PushCalled = $true }
            if ($args -contains 'diff')  { return 'file.txt' }
        } -ModuleName GittHelpers

        Save-GitWorktree -Message 'test' -NoPush -NoPrune -Path $script:WtPath -Confirm:$false
        $script:PushCalled | Should -BeFalse
    }

    It 'Opens browser to PR URL when -PullRequest is set' {
        Mock git {
            $global:LASTEXITCODE = 0
            if ($args -contains 'diff')    { return 'file.txt' }
            if (($args -join ' ') -match 'get-url') { return 'https://github.com/user/repo' }
        } -ModuleName GittHelpers
        Mock Start-Process { } -ModuleName GittHelpers

        Save-GitWorktree -Message 'test' -PullRequest -NoPrune -Path $script:WtPath -Confirm:$false
        Should -Invoke Start-Process -ModuleName GittHelpers -Times 1 `
            -ParameterFilter { $FilePath -match 'github\.com' }
    }

    It 'Warns and skips PR creation when -PullRequest is combined with -NoPush' {
        { Save-GitWorktree -Message 'test' -PullRequest -NoPush -NoPrune -Path $script:WtPath -Confirm:$false `
            -WarningAction SilentlyContinue } | Should -Not -Throw
    }

    It 'Warns when no remote origin is configured and -PullRequest is set' {
        Mock git {
            $global:LASTEXITCODE = 0
            if ($args -contains 'diff') { return 'file.txt' }
            # get-url returns nothing — no origin
        } -ModuleName GittHelpers
        Mock Start-Process { } -ModuleName GittHelpers

        { Save-GitWorktree -Message 'test' -PullRequest -NoPrune -Path $script:WtPath -Confirm:$false `
            -WarningAction SilentlyContinue } | Should -Not -Throw
        Should -Invoke Start-Process -ModuleName GittHelpers -Times 0
    }
}

Describe 'Get-PullRequestUrl' {
    It 'Builds a GitHub PR URL from an HTTPS remote' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'https://github.com/owner/repo.git' -Branch 'feature/login'
        }
        $result | Should -Be 'https://github.com/owner/repo/compare/feature/login?expand=1'
    }

    It 'Builds a GitHub PR URL from an SSH remote' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'git@github.com:owner/repo.git' -Branch 'feature/login'
        }
        $result | Should -Be 'https://github.com/owner/repo/compare/feature/login?expand=1'
    }

    It 'Builds an Azure DevOps PR URL from an HTTPS remote' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'https://dev.azure.com/org/project/_git/repo' -Branch 'feature/login'
        }
        $result | Should -Be 'https://dev.azure.com/org/project/_git/repo/pullrequestcreate?sourceRef=feature%2Flogin'
    }

    It 'Builds an Azure DevOps PR URL from an SSH remote' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'git@ssh.dev.azure.com:v3/org/project/repo' -Branch 'feature/login'
        }
        $result | Should -Be 'https://dev.azure.com/org/project/_git/repo/pullrequestcreate?sourceRef=feature%2Flogin'
    }

    It 'Appends targetRef to Azure DevOps URL when -BaseBranch is provided' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'https://dev.azure.com/org/project/_git/repo' -Branch 'feature/login' -BaseBranch 'master'
        }
        $result | Should -Match 'targetRef=master'
    }

    It 'Builds a Bitbucket PR URL' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'https://bitbucket.org/workspace/repo.git' -Branch 'feature/login'
        }
        $result | Should -Be 'https://bitbucket.org/workspace/repo/pull-requests/new?source=feature%2Flogin'
    }

    It 'Builds a GitLab MR URL' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'https://gitlab.com/namespace/repo.git' -Branch 'feature/login'
        }
        $result | Should -Match 'merge_requests/new'
        $result | Should -Match 'feature%2Flogin'
    }

    It 'Returns the base remote URL for unknown providers' {
        $result = & (Get-Module GittHelpers) {
            Get-PullRequestUrl -RemoteUrl 'https://mygitserver.internal/owner/repo.git' -Branch 'feature/login'
        }
        $result | Should -Be 'https://mygitserver.internal/owner/repo'
    }
}