Tests/GitHubBranches.tests.ps1

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

<#
.Synopsis
   Tests for GitHubBranches.ps1 module
#>


[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '',
    Justification = 'Suppress false positives in Pester code blocks')]
param()

BeforeAll {
    # This is common test code setup logic for all Pester test files
    $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent
    . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1')
}

Set-StrictMode -Version 1.0

Describe 'Getting branches for repository' {
    BeforeAll {
        $repositoryName = [guid]::NewGuid().Guid
        $repo = New-GitHubRepository -RepositoryName $repositoryName -AutoInit
        $branchName = 'master'
    }

    AfterAll {
        $repo | Remove-GitHubRepository -Confirm:$false
    }

    Context 'Getting all branches for a repository with parameters' {
        BeforeAll {
            $branches = @(Get-GitHubRepositoryBranch -OwnerName $script:ownerName -RepositoryName $repositoryName)
        }

        It 'Should return expected number of repository branches' {
            $branches.Count | Should -Be 1
        }

        It 'Should return the name of the expected branch' {
            $branches.name | Should -Contain $branchName
        }

        It 'Should have the expected type and addititional properties' {
            $branches[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
            $branches[0].RepositoryUrl | Should -Be $repo.RepositoryUrl
            $branches[0].BranchName | Should -Be $branches[0].name
            $branches[0].Sha | Should -Be $branches[0].commit.sha
        }
    }

    Context 'Getting all branches for a repository with the repo on the pipeline' {
        BeforeAll {
            $branches = @($repo | Get-GitHubRepositoryBranch)
        }

        It 'Should return expected number of repository branches' {
            $branches.Count | Should -Be 1
        }

        It 'Should return the name of the expected branch' {
            $branches.name | Should -Contain $branchName
        }

        It 'Should have the expected type and addititional properties' {
            $branches[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
            $branches[0].RepositoryUrl | Should -Be $repo.RepositoryUrl
            $branches[0].BranchName | Should -Be $branches[0].name
            $branches[0].Sha | Should -Be $branches[0].commit.sha
        }
    }

    Context 'Getting a specific branch for a repository with parameters' {
        BeforeAll {
            $branch = Get-GitHubRepositoryBranch -OwnerName $script:ownerName -RepositoryName $repositoryName -BranchName $branchName
        }

        It 'Should return the expected branch name' {
            $branch.name | Should -Be $branchName
        }

        It 'Should have the expected type and addititional properties' {
            $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
            $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $branch.BranchName | Should -Be $branch.name
            $branch.Sha | Should -Be $branch.commit.sha
        }
    }

    Context 'Getting a specific branch for a repository with the repo on the pipeline' {
        BeforeAll {
            $branch = $repo | Get-GitHubRepositoryBranch -BranchName $branchName
        }

        It 'Should return the expected branch name' {
            $branch.name | Should -Be $branchName
        }

        It 'Should have the expected type and addititional properties' {
            $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
            $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $branch.BranchName | Should -Be $branch.name
            $branch.Sha | Should -Be $branch.commit.sha
        }
    }

    Context 'Getting a specific branch for a repository with the branch object on the pipeline' {
        BeforeAll {
            $branch = Get-GitHubRepositoryBranch -OwnerName $script:ownerName -RepositoryName $repositoryName -BranchName $branchName
            $branchAgain = $branch | Get-GitHubRepositoryBranch
        }

        It 'Should return the expected branch name' {
            $branchAgain.name | Should -Be $branchName
        }

        It 'Should have the expected type and addititional properties' {
            $branchAgain.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
            $branchAgain.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $branchAgain.BranchName | Should -Be $branchAgain.name
            $branchAgain.Sha | Should -Be $branchAgain.commit.sha
        }
    }
}

Describe 'GitHubBranches\New-GitHubRepositoryBranch' {
    BeforeAll {
        $repoName = [Guid]::NewGuid().Guid
        $originBranchName = 'master'
        $newGitHubRepositoryParms = @{
            RepositoryName = $repoName
            AutoInit = $true
        }

        $repo = New-GitHubRepository @newGitHubRepositoryParms
    }

    Context 'When creating a new GitHub repository branch' {
        Context 'When using non-pipelined parameters' {
            BeforeAll {
                $newBranchName = 'develop1'
                $newGitHubRepositoryBranchParms = @{
                    OwnerName = $script:ownerName
                    RepositoryName = $repoName
                    BranchName = $originBranchName
                    TargetBranchName = $newBranchName
                }

                $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms
            }

            It 'Should have the expected type and addititional properties' {
                $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
                $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
                $branch.BranchName | Should -Be $newBranchName
                $branch.Sha | Should -Be $branch.object.sha
            }

            It 'Should have created the branch' {
                $getGitHubRepositoryBranchParms = @{
                    OwnerName = $script:ownerName
                    RepositoryName = $repoName
                    BranchName = $newBranchName
                }

                { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
                Should -Not -Throw
            }
        }

        Context 'When using pipelined parameters' {
            Context 'When providing pipeline input for the "Uri" parameter' {
                BeforeAll {
                    $newBranchName = 'develop2'
                    $branch = $repo | New-GitHubRepositoryBranch -TargetBranchName $newBranchName
                }

                It 'Should have the expected type and addititional properties' {
                    $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
                    $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
                    $branch.BranchName | Should -Be $newBranchName
                    $branch.Sha | Should -Be $branch.object.sha
                }

                It 'Should have created the branch' {
                    $getGitHubRepositoryBranchParms = @{
                        OwnerName = $script:ownerName
                        RepositoryName = $repoName
                        BranchName = $newBranchName
                    }

                    { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
                    Should -Not -Throw
                }
            }

            Context 'When providing pipeline input for the "TargetBranchName" parameter' {
                BeforeAll {
                    $newBranchName = 'develop3'
                    $branch = $newBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url
                }

                It 'Should have the expected type and addititional properties' {
                    $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
                    $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
                    $branch.BranchName | Should -Be $newBranchName
                    $branch.Sha | Should -Be $branch.object.sha
                }

                It 'Should have created the branch' {
                    $getGitHubRepositoryBranchParms = @{
                        OwnerName = $script:ownerName
                        RepositoryName = $repoName
                        BranchName = $newBranchName
                    }

                    { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
                    Should -Not -Throw
                }
            }

            Context 'When providing the GitHub.Branch on the pipeline' {
                BeforeAll {
                    $baseBranchName = 'develop4'
                    $baseBranch = $baseBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url

                    $newBranchName = 'develop5'
                    $branch = $baseBranch | New-GitHubRepositoryBranch -TargetBranchName $newBranchName
                }

                It 'Should have been created from the right Sha' {
                    $branch.Sha | Should -Be $baseBranch.Sha
                }

                It 'Should have the expected type and addititional properties' {
                    $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
                    $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
                    $branch.BranchName | Should -Be $newBranchName
                    $branch.Sha | Should -Be $branch.object.sha
                }

                It 'Should have created the branch' {
                    $getGitHubRepositoryBranchParms = @{
                        OwnerName = $script:ownerName
                        RepositoryName = $repoName
                        BranchName = $newBranchName
                    }

                    { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
                    Should -Not -Throw
                }
            }

            Context 'When providing the Repo on the pipeline and specifying the Sha' {
                BeforeAll {
                    $baseBranchName = 'sha1'
                    $baseBranch = $baseBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url

                    $newBranchName = 'sha2'
                    $branch = $repo | New-GitHubRepositoryBranch -Sha $baseBranch.Sha -TargetBranchName $newBranchName
                }

                It 'Should have been created from the right Sha' {
                    $branch.Sha | Should -Be $baseBranch.Sha
                }

                It 'Should have the expected type and addititional properties' {
                    $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch'
                    $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl
                    $branch.BranchName | Should -Be $newBranchName
                    $branch.Sha | Should -Be $branch.object.sha
                }

                It 'Should have created the branch' {
                    $getGitHubRepositoryBranchParms = @{
                        OwnerName = $script:ownerName
                        RepositoryName = $repoName
                        BranchName = $newBranchName
                    }

                    { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
                    Should -Not -Throw
                }
            }
        }

        Context 'When the origin branch cannot be found' {
            BeforeAll -Scriptblock {
                $missingOriginBranchName = 'Missing-Branch'
                $newBranchName = 'sha2'
            }

            It 'Should throw the correct exception' {
                $errorMessage = "Origin branch $missingOriginBranchName not found"

                $newGitHubRepositoryBranchParms = @{
                    OwnerName = $script:ownerName
                    RepositoryName = $repoName
                    BranchName = $missingOriginBranchName
                    TargetBranchName = $newBranchName
                }

                { New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } |
                Should -Throw $errorMessage
            }
        }

        Context 'When Get-GitHubRepositoryBranch throws an undefined HttpResponseException' {
            It 'Should throw the correct exception' {
                $newGitHubRepositoryBranchParms = @{
                    OwnerName = $script:ownerName
                    RepositoryName = 'test'
                    BranchName = 'test'
                    TargetBranchName = 'test'
                }

                { New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } | Should -Throw
            }
        }
    }

    AfterAll -ScriptBlock {
        if (Get-Variable -Name repo -ErrorAction SilentlyContinue)
        {
            Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false
        }
    }
}

Describe 'GitHubBranches\Remove-GitHubRepositoryBranch' {
    BeforeAll -Scriptblock {
        $repoName = [Guid]::NewGuid().Guid
        $originBranchName = 'master'
        $newGitHubRepositoryParms = @{
            RepositoryName = $repoName
            AutoInit = $true
        }

        $repo = New-GitHubRepository @newGitHubRepositoryParms
    }

    Context 'When using non-pipelined parameters' {
        BeforeAll {
            $newBranchName = 'develop1'
            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:ownerName
                RepositoryName = $repoName
                BranchName = $originBranchName
                TargetBranchName = $newBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms
        }

        It 'Should not throw an exception' {
            $removeGitHubRepositoryBranchParms = @{
                OwnerName = $script:ownerName
                RepositoryName = $repoName
                BranchName = $newBranchName
                Confirm = $false
            }

            { Remove-GitHubRepositoryBranch @removeGitHubRepositoryBranchParms } |
            Should -Not -Throw
        }

        It 'Should have removed the branch' {
            $getGitHubRepositoryBranchParms = @{
                OwnerName = $script:ownerName
                RepositoryName = $repoName
                BranchName = $newBranchName
            }

            { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
            Should -Throw
        }
    }

    Context 'When using pipelined parameters' {
        BeforeAll {
            $newBranchName = 'develop2'
            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:ownerName
                RepositoryName = $repoName
                BranchName = $originBranchName
                TargetBranchName = $newBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms
        }

        It 'Should not throw an exception' {
            { $branch | Remove-GitHubRepositoryBranch -Force } | Should -Not -Throw
        }

        It 'Should have removed the branch' {
            $getGitHubRepositoryBranchParms = @{
                OwnerName = $script:ownerName
                RepositoryName = $repoName
                BranchName = $newBranchName
            }

            { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } |
            Should -Throw
        }
    }

    AfterAll -ScriptBlock {
        if (Get-Variable -Name repo -ErrorAction SilentlyContinue)
        {
            Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false
        }
    }
}
Describe 'GitHubBranches\Get-GitHubRepositoryBranchProtectionRule' {
    Context 'When getting GitHub repository branch protection' {
        BeforeAll {
            $repoName = [Guid]::NewGuid().Guid
            $branchName = 'master'
            $protectionUrl = ("https://api.github.com/repos/$script:ownerName/" +
                "$repoName/branches/$branchName/protection")
            $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit
            New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | Out-Null
            $rule = Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.enforce_admins.enabled | Should -BeFalse
            $rule.required_linear_history.enabled | Should -BeFalse
            $rule.allow_force_pushes.enabled | Should -BeFalse
            $rule.allow_deletions.enabled | Should -BeFalse
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
        }

        Context 'When specifying the "Uri" parameter through the pipeline' {
            BeforeAll {
                $rule = $repo | Get-GitHubRepositoryBranchProtectionRule -BranchName $branchName
            }

            It 'Should have the expected type and addititional properties' {
                $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
                $rule.url | Should -Be $protectionUrl
                $rule.enforce_admins.enabled | Should -BeFalse
                $rule.required_linear_history.enabled | Should -BeFalse
                $rule.allow_force_pushes.enabled | Should -BeFalse
                $rule.allow_deletions.enabled | Should -BeFalse
                $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            }
        }

        Context 'When specifying the "BranchName" and "Uri" parameters through the pipeline' {
            BeforeAll {
                $branch = Get-GitHubRepositoryBranch -Uri $repo.svn_url -BranchName $branchName
                $rule = $branch | Get-GitHubRepositoryBranchProtectionRule
            }

            It 'Should have the expected type and addititional properties' {
                $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
                $rule.url | Should -Be $protectionUrl
                $rule.enforce_admins.enabled | Should -BeFalse
                $rule.required_linear_history.enabled | Should -BeFalse
                $rule.allow_force_pushes.enabled | Should -BeFalse
                $rule.allow_deletions.enabled | Should -BeFalse
                $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            }
        }

        AfterAll -ScriptBlock {
            if ($repo)
            {
                Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false
            }
        }
    }
}

Describe 'GitHubBranches\New-GitHubRepositoryBranchProtectionRule' {
    BeforeAll {
        $repoName = [Guid]::NewGuid().Guid
        $branchName = 'master'
        $newGitHubRepositoryParms = @{
            OrganizationName = $script:organizationName
            RepositoryName = $repoName
            AutoInit = $true
        }

        $repo = New-GitHubRepository @newGitHubRepositoryParms
    }

    Context 'When setting base protection options' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" +
                "$repoName/branches/$targetBranchName/protection")

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $newGitHubRepositoryBranchProtectionParms = @{
                Uri = $repo.svn_url
                BranchName = $targetBranchName
                EnforceAdmins = $true
                RequireLinearHistory = $true
                AllowForcePushes = $true
                AllowDeletions = $true
            }

            $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.enforce_admins.enabled | Should -BeTrue
            $rule.required_linear_history.enabled | Should -BeTrue
            $rule.allow_force_pushes.enabled | Should -BeTrue
            $rule.allow_deletions.enabled | Should -BeTrue
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
        }
    }

    Context 'When setting required status checks' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" +
                "$repoName/branches/$targetBranchName/protection")

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $statusChecks = 'test'

            $newGitHubRepositoryBranchProtectionParms = @{
                Uri = $repo.svn_url
                BranchName = $targetBranchName
                RequireUpToDateBranches = $true
                StatusChecks = $statusChecks
            }

            $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.required_status_checks.strict | Should -BeTrue
            $rule.required_status_checks.contexts | Should -Be $statusChecks
        }
    }

    Context 'When setting required pull request reviews' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" +
                "$repoName/branches/$targetBranchName/protection")

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $newGitHubRepositoryBranchProtectionParms = @{
                Uri = $repo.svn_url
                BranchName = $targetBranchName
                DismissalUsers = $script:ownerName
                DismissStaleReviews = $true
                RequireCodeOwnerReviews = $true
                RequiredApprovingReviewCount = 1
            }

            $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.required_pull_request_reviews.dismissal_restrictions.users.login |
            Should -Contain $script:OwnerName
        }
    }

    Context 'When setting push restrictions' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" +
                "$repoName/branches/$targetBranchName/protection")

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $newGitHubRepositoryBranchProtectionParms = @{
                Uri = $repo.svn_url
                BranchName = $targetBranchName
                RestrictPushUser = $script:OwnerName
            }

            $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.restrictions.users.login | Should -Contain $script:OwnerName
        }
    }

    Context 'When the branch rule already exists' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $newGitHubRepositoryBranchProtectionParms = @{
                Uri = $repo.svn_url
                BranchName = $targetBranchName
            }

            $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms
        }

        It 'Should throw the correct exception' {
            $errorMessage = "Branch protection rule for branch $targetBranchName already exists on Repository $repoName"
            { New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } |
            Should -Throw $errorMessage
        }
    }

    Context 'When specifying the "Uri" parameter through the pipeline' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" +
                "$repoName/branches/$targetBranchName/protection")

            $rule = $repo | New-GitHubRepositoryBranchProtectionRule -BranchName $targetBranchName
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.enforce_admins.enabled | Should -BeFalse
            $rule.required_linear_history.enabled | Should -BeFalse
            $rule.allow_force_pushes.enabled | Should -BeFalse
            $rule.allow_deletions.enabled | Should -BeFalse
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
        }
    }

    Context 'When specifying the "BranchName" and "Uri" parameters through the pipeline' {
        BeforeAll {
            $targetBranchName = [Guid]::NewGuid().Guid

            $newGitHubRepositoryBranchParms = @{
                OwnerName = $script:organizationName
                RepositoryName = $repoName
                BranchName = $branchName
                TargetBranchName = $targetBranchName
            }

            $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms

            $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" +
                "$repoName/branches/$targetBranchName/protection")

            $rule = $branch | New-GitHubRepositoryBranchProtectionRule
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule'
            $rule.url | Should -Be $protectionUrl
            $rule.enforce_admins.enabled | Should -BeFalse
            $rule.required_linear_history.enabled | Should -BeFalse
            $rule.allow_force_pushes.enabled | Should -BeFalse
            $rule.allow_deletions.enabled | Should -BeFalse
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
        }
    }

    AfterAll -ScriptBlock {
        if ($repo)
        {
            Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false
        }
    }
}

Describe 'GitHubBranches\Remove-GitHubRepositoryBranchProtectionRule' {
    BeforeAll {
        $repoName = [Guid]::NewGuid().Guid
        $branchName = 'master'
        $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit

        New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName |
        Out-Null
    }

    Context 'When removing GitHub repository branch protection' {
        It 'Should not throw' {
            { Remove-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName -Force } |
            Should -Not -Throw
        }

        It 'Should have removed the protection rule' {
            { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } |
            Should -Throw
        }

        Context 'When specifying the "Uri" parameter through the pipeline' {
            BeforeAll {
                $rule = New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName
            }

            It 'Should not throw' {
                { $repo | Remove-GitHubRepositoryBranchProtectionRule -BranchName $branchName -Force } |
                Should -Not -Throw
            }

            It 'Should have removed the protection rule' {
                { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } |
                Should -Throw
            }
        }

        Context 'When specifying the "Uri" and "BranchName" parameters through the pipeline' {
            BeforeAll {
                $rule = New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName
            }

            It 'Should not throw' {
                { $rule | Remove-GitHubRepositoryBranchProtectionRule -Force } |
                Should -Not -Throw
            }

            It 'Should have removed the protection rule' {
                { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } |
                Should -Throw
            }
        }

    }
    AfterAll -ScriptBlock {
        if ($repo)
        {
            Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false
        }
    }
}

Describe 'GitHubBranches\Get-GitHubRepositoryBranchPatternProtectionRule' {
    BeforeAll {
        $repoName = [Guid]::NewGuid().Guid
        $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

        $newGitHubRepositoryParms = @{
            OrganizationName = $script:organizationName
            RepositoryName = $repoName
        }
        $repo = New-GitHubRepository @newGitHubRepositoryParms

        $teamName = [Guid]::NewGuid().Guid

        $newGithubTeamParms = @{
            OrganizationName = $script:OrganizationName
            TeamName = $teamName
        }
        $team = New-GitHubTeam @newGithubTeamParms

        $setGitHubRepositoryTeamPermissionParms = @{
            Uri = $repo.svn_url
            TeamSlug = $team.slug
            Permission = 'Push'
        }
        Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms
    }

    Context 'When getting branch pattern protection default options' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName

            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresApprovingReviews | Should -BeFalse
            $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty
            $rule.dismissesStaleReviews | Should -BeFalse
            $rule.requiresCodeOwnerReviews | Should -BeFalse
            $rule.restrictsReviewDismissals | Should -BeFalse
            $rule.DismissalTeams | Should -BeNullOrEmpty
            $rule.DismissalUsers | Should -BeNullOrEmpty
            $rule.requiresStatusChecks | Should -BeFalse
            $rule.requiresStrictStatusChecks | Should -BeTrue
            $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty
            $rule.requiresCommitSignatures | Should -BeFalse
            $rule.requiresLinearHistory | Should -BeFalse
            $rule.isAdminEnforced | Should -BeFalse
            $rule.restrictsPushes | Should -BeFalse
            $rule.RestrictPushUsers | Should -BeNullOrEmpty
            $rule.RestrictPushTeams | Should -BeNullOrEmpty
            $rule.RestictPushApps | Should -BeNullOrEmpty
            $rule.allowsForcePushes | Should -BeFalse
            $rule.allowsDeletions | Should -BeFalse
        }
    }

    Context 'When getting base protection options' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
                RequireCommitSignatures = $true
                RequireLinearHistory = $true
                IsAdminEnforced = $true
                RestrictPushUser = $script:OwnerName
                RestrictPushTeam = $TeamName
                AllowForcePushes = $true
                AllowDeletions = $true
            }
            New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms

            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresApprovingReviews | Should -BeFalse
            $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty
            $rule.dismissesStaleReviews | Should -BeFalse
            $rule.requiresCodeOwnerReviews | Should -BeFalse
            $rule.restrictsReviewDismissals | Should -BeFalse
            $rule.DismissalTeams | Should -BeNullOrEmpty
            $rule.DismissalUsers | Should -BeNullOrEmpty
            $rule.requiresStatusChecks | Should -BeFalse
            $rule.requiresStrictStatusChecks | Should -BeTrue
            $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty
            $rule.requiresCommitSignatures | Should -BeTrue
            $rule.requiresLinearHistory | Should -BeTrue
            $rule.isAdminEnforced | Should -BeTrue
            $rule.restrictsPushes | Should -BeTrue
            $rule.RestrictPushUsers.Count | Should -Be 1
            $rule.RestrictPushUsers | Should -Contain $script:OwnerName
            $rule.RestrictPushTeams.Count | Should -Be 1
            $rule.RestrictPushTeams | Should -Contain $teamName
            $rule.RestrictPushApps | Should -BeNullOrEmpty
            $rule.allowsForcePushes | Should -BeTrue
            $rule.allowsDeletions | Should -BeTrue
        }
    }

    Context 'When getting required pull request reviews' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
                RequiredApprovingReviewCount = 1
                DismissStaleReviews = $true
                RequireCodeOwnerReviews = $true
                DismissalUser = $script:OwnerName
                DismissalTeam = $teamName
            }
            New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms

            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
        }

        It 'Should have the expected type and addititional properties' {
            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresApprovingReviews | Should -BeTrue
            $rule.requiredApprovingReviewCount | Should -Be 1
            $rule.dismissesStaleReviews | Should -BeTrue
            $rule.requiresCodeOwnerReviews | Should -BeTrue
            $rule.restrictsReviewDismissals | Should -BeTrue
            $rule.DismissalTeams.Count | Should -Be 1
            $rule.DismissalTeams | Should -Contain $teamName
            $rule.DismissalUsers.Count | Should -Be 1
            $rule.DismissalUsers | Should -Contain $script:OwnerName
        }
    }

    Context 'When getting required status checks' {
        BeforeAll {
            $statusChecks = 'test'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
                RequireStrictStatusChecks = $true
                StatusCheck = $statusChecks
            }
            New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms

            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresStatusChecks | Should -BeTrue
            $rule.requiresStrictStatusChecks | Should -BeTrue
            $rule.requiredStatusCheckContexts | Should -Contain $statusChecks
        }
    }

    Context 'When specifying the "Uri" parameter through the pipeline' {
        BeforeAll {
            $rule = $repo | Get-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName
        }

        It 'Should have the expected type and addititional properties' {
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
        }
    }

    AfterAll -ScriptBlock {
        if (Get-Variable -Name repo -ErrorAction SilentlyContinue)
        {
            $repo | Remove-GitHubRepository -Force
        }

        if (Get-Variable -Name team -ErrorAction SilentlyContinue)
        {
            $team | Remove-GitHubTeam -Force
        }
    }
}

Describe 'GitHubBranches\New-GitHubRepositoryBranchPatternProtectionRule' {
    BeforeAll {
        $repoName = [Guid]::NewGuid().Guid

        $newGitHubRepositoryParms = @{
            OrganizationName = $script:organizationName
            RepositoryName = $repoName
        }
        $repo = New-GitHubRepository @newGitHubRepositoryParms

        $pushTeamName = [Guid]::NewGuid().Guid

        $newGithubTeamParms = @{
            OrganizationName = $script:OrganizationName
            TeamName = $pushTeamName
        }
        $pushTeam = New-GitHubTeam @newGithubTeamParms

        $setGitHubRepositoryTeamPermissionParms = @{
            Uri = $repo.svn_url
            TeamSlug = $pushTeam.slug
            Permission = 'Push'
        }
        Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms

        $pullTeamName = [Guid]::NewGuid().Guid

        $newGithubTeamParms = @{
            OrganizationName = $script:OrganizationName
            TeamName = $pullTeamName
        }
        $pullTeam = New-GitHubTeam @newGithubTeamParms

        $setGitHubRepositoryTeamPermissionParms = @{
            Uri = $repo.svn_url
            TeamSlug = $pullTeam.slug

            Permission = 'Pull'
        }
        Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms
    }

    Context 'When setting default protection options' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
            }
        }

        It 'Should not throw' {
            { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
            Should -Not -Throw
        }

        It 'Should have set the correct properties' {
            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName

            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresApprovingReviews | Should -BeFalse
            $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty
            $rule.dismissesStaleReviews | Should -BeFalse
            $rule.requiresCodeOwnerReviews | Should -BeFalse
            $rule.restrictsReviewDismissals | Should -BeFalse
            $rule.DismissalTeams | Should -BeNullOrEmpty
            $rule.DismissalUsers | Should -BeNullOrEmpty
            $rule.requiresStatusChecks | Should -BeFalse
            $rule.requiresStrictStatusChecks | Should -BeTrue
            $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty
            $rule.requiresCommitSignatures | Should -BeFalse
            $rule.requiresLinearHistory | Should -BeFalse
            $rule.isAdminEnforced | Should -BeFalse
            $rule.restrictsPushes | Should -BeFalse
            $rule.RestrictPushUsers | Should -BeNullOrEmpty
            $rule.RestrictPushTeams | Should -BeNullOrEmpty
            $rule.RestictPushApps | Should -BeNullOrEmpty
            $rule.allowsForcePushes | Should -BeFalse
            $rule.allowsDeletions | Should -BeFalse
        }
    }

    Context 'When setting base protection options' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
                RequireCommitSignatures = $true
                RequireLinearHistory = $true
                IsAdminEnforced = $true
                RestrictPushUser = $script:OwnerName
                RestrictPushTeam = $pushTeamName
                AllowForcePushes = $true
                AllowDeletions = $true
            }
        }

        It 'Should not throw' {
            { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
            Should -Not -Throw
        }

        It 'Should have set the correct properties' {
            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName

            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresApprovingReviews | Should -BeFalse
            $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty
            $rule.dismissesStaleReviews | Should -BeFalse
            $rule.requiresCodeOwnerReviews | Should -BeFalse
            $rule.restrictsReviewDismissals | Should -BeFalse
            $rule.DismissalTeams | Should -BeNullOrEmpty
            $rule.DismissalUsers | Should -BeNullOrEmpty
            $rule.requiresStatusChecks | Should -BeFalse
            $rule.requiresStrictStatusChecks | Should -BeTrue
            $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty
            $rule.requiresCommitSignatures | Should -BeTrue
            $rule.requiresLinearHistory | Should -BeTrue
            $rule.isAdminEnforced | Should -BeTrue
            $rule.restrictsPushes | Should -BeTrue
            $rule.RestrictPushUsers.Count | Should -Be 1
            $rule.RestrictPushUsers | Should -Contain $script:OwnerName
            $rule.RestrictPushTeams.Count | Should -Be 1
            $rule.RestrictPushTeams | Should -Contain $pushTeamName
            $rule.RestrictPushApps | Should -BeNullOrEmpty
            $rule.allowsForcePushes | Should -BeTrue
            $rule.allowsDeletions | Should -BeTrue
        }

        Context 'When the Restrict Push Team does not exist in the organization' {
            BeforeAll {
                $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'
                $mockTeamName = 'MockTeam'

                $newGitHubRepositoryBranchPatternProtectionParms = @{
                    Uri = $repo.svn_url
                    BranchPatternName = $branchPatternName
                    RestrictPushTeam = $mockTeamName
                }
            }

            It 'Should throw the correct exception' {
                $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'"
                { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
                Should -Throw $errorMessage
            }
        }

        Context 'When the Restrict Push Team does not have push Permissions to the Repository' {
            BeforeAll {
                $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

                $newGitHubRepositoryBranchPatternProtectionParms = @{
                    Uri = $repo.svn_url
                    BranchPatternName = $branchPatternName
                    RestrictPushTeam = $pullTeamName
                }
            }

            It 'Should throw the correct exception' {
                $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'"
                { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
                Should -Throw $errorMessage
            }
        }
    }

    Context 'When setting required pull request reviews' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
                RequiredApprovingReviewCount = 1
                DismissStaleReviews = $true
                RequireCodeOwnerReviews = $true
                DismissalUser = $script:OwnerName
                DismissalTeam = $pushTeamName
            }
        }

        It 'Should not throw' {
            { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
            Should -Not -Throw
        }

        It 'Should have set the correct properties' {
            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresApprovingReviews | Should -BeTrue
            $rule.requiredApprovingReviewCount | Should -Be 1
            $rule.dismissesStaleReviews | Should -BeTrue
            $rule.requiresCodeOwnerReviews | Should -BeTrue
            $rule.restrictsReviewDismissals | Should -BeTrue
            $rule.DismissalTeams.Count | Should -Be 1
            $rule.DismissalTeams | Should -Contain $pushTeamName
            $rule.DismissalUsers.Count | Should -Be 1
            $rule.DismissalUsers | Should -Contain $script:OwnerName
        }

        Context 'When the Dismissal Team does not exist in the organization' {
            BeforeAll {
                $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'
                $mockTeamName = 'MockTeam'

                $newGitHubRepositoryBranchPatternProtectionParms = @{
                    Uri = $repo.svn_url
                    BranchPatternName = $branchPatternName
                    DismissalTeam = $mockTeamName
                }
            }

            It 'Should throw the correct exception' {
                $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'"
                { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
                Should -Throw $errorMessage
            }
        }

        Context 'When the Dismissal Team does not have write Permissions to the Repository' {
            BeforeAll {
                $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

                $newGitHubRepositoryBranchPatternProtectionParms = @{
                    Uri = $repo.svn_url
                    BranchPatternName = $branchPatternName
                    DismissalTeam = $pullTeamName
                }
            }

            It 'Should throw the correct exception' {
                $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'"
                { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
                Should -Throw $errorMessage
            }
        }
    }

    Context 'When setting required status checks' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'
            $statusCheck = 'test'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
                RequireStrictStatusChecks = $true
                StatusCheck = $statusCheck
            }
        }

        It 'Should not throw' {
            { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
            Should -Not -Throw
        }

        It 'Should have set the correct properties' {
            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName

            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
            $rule.requiresStatusChecks | Should -BeTrue
            $rule.requiresStrictStatusChecks | Should -BeTrue
            $rule.requiredStatusCheckContexts | Should -Contain $statusCheck
        }
    }

    Context 'When the branch pattern rule already exists' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $newGitHubRepositoryBranchPatternProtectionParms = @{
                Uri = $repo.svn_url
                BranchPatternName = $branchPatternName
            }
            $rule = New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms
        }

        It 'Should throw the correct exception' {
            $errorMessage = "GraphQl Error: Name already protected: $branchPatternName"
            { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } |
            Should -Throw $errorMessage
        }
    }

    Context 'When specifying the "Uri" parameter through the pipeline' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'
        }

        It 'Should not throw' {
            { $repo | New-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName } |
            Should -Not -Throw
        }

        It 'Should have set the correct properties' {
            $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName

            $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule'
            $rule.pattern | Should -Be $branchPatternName
            $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl
        }
    }

    AfterAll -ScriptBlock {
        if (Get-Variable -Name repo -ErrorAction SilentlyContinue)
        {
            $repo | Remove-GitHubRepository -Force
        }

        if (Get-Variable -Name pushTeam -ErrorAction SilentlyContinue)
        {
            $pushTeam | Remove-GitHubTeam -Force
        }

        if (Get-Variable -Name pullTeam -ErrorAction SilentlyContinue)
        {
            $pullTeam | Remove-GitHubTeam -Force
        }
    }
}

Describe 'GitHubBranches\Remove-GitHubRepositoryBranchPatternProtectionRule' {
    BeforeAll {
        $repoName = [Guid]::NewGuid().Guid

        $repo = New-GitHubRepository -RepositoryName $repoName
    }

    Context 'When removing GitHub repository branch pattern protection' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
        }

        It 'Should not throw' {
            { Remove-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName -Force } |
            Should -Not -Throw
        }

        It 'Should have removed the protection rule' {
            { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } |
            Should -Throw
        }
    }

    Context 'When specifying the "Uri" parameter through the pipeline' {
        BeforeAll {
            $branchPatternName = [Guid]::NewGuid().Guid + '/**/*'

            $rule = New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName
        }

        It 'Should not throw' {
            { $repo | Remove-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName -Force } |
            Should -Not -Throw
        }

        It 'Should have removed the protection rule' {
            { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } |
            Should -Throw
        }
    }

    AfterAll {
        if (Get-Variable -Name repo -ErrorAction SilentlyContinue)
        {
            $repo | Remove-GitHubRepository -Force
        }
    }
}

AfterAll {
    if (Test-Path -Path $script:originalConfigFile -PathType Leaf)
    {
        # Restore the user's configuration to its pre-test state
        Restore-GitHubConfiguration -Path $script:originalConfigFile
        $script:originalConfigFile = $null
    }
}