Full Code of flofreud/posh-gvm for AI

master 7101f92684fe cached
14 files
112.3 KB
29.9k tokens
1 requests
Download .txt
Repository: flofreud/posh-gvm
Branch: master
Commit: 7101f92684fe
Files: 14
Total size: 112.3 KB

Directory structure:
gitextract_9qyeor5j/

├── CHANGELOG.md
├── Commands.Tests.ps1
├── Commands.ps1
├── GetPoshGvm.ps1
├── Init.Tests.ps1
├── Init.ps1
├── LICENSE
├── README.md
├── TabExpansion.ps1
├── TestUtils.ps1
├── Utils.Tests.ps1
├── Utils.ps1
├── VERSION.txt
└── posh-gvm.psm1

================================================
FILE CONTENTS
================================================

================================================
FILE: CHANGELOG.md
================================================
### Version 1.3.0
* BUGFIX: update url to API endpoint
* BUGFIX: support for symlink handling in Win10
* IMPROVE: use 7zip for archive extraction if available on path
* BUGFIX: walkaround for rare ACCESS_DENIED error on SDK installation
* BUGFIX: always show correct download file sizes

### Version 1.2.2
* BUGFIX: explicitly handle a missing version definition for uninstall
* BUGFIX: added -Force for Remove-Item in the uninstall process

### Version 1.2.1
* BUGFIX: fixed wrong url construction for broadcast api

### Version 1.2.0
* IMPROVE: update to the new broadcast api for GVM

### Version 1.1.4
* IMPROVE: version check requests where executed on module import and took some time, these checks will now be executed on first gvm-call

### Version 1.1.3
* IMPROVE: the new version messaging

### Version 1.1.2
* BUGFIX: installation routine in GetPoshGvm.ps1 broken

### Version 1.1.1
* BUGFIX: default of $Global:PGVM_AUTO_SELFUPDATE was $true but should have been $false

### Version 1.1.0
* FEATURE: use unzip.exe if available on path for better install performance
* FEATURE: self-update
* FEATURE: automatic check for new posh-gvm versions

### Version 1.0.0
* posh-gvm before it has self-update functionality


================================================
FILE: Commands.Tests.ps1
================================================
. .\Commands.ps1
. .\Utils.ps1
. .\Init.ps1
. .\TestUtils.ps1

Describe 'gvm' {
    Context 'No posh-gvm dir available'{
        $Script:GVM_FORCE_OFFLINE = $true
        Mock-PGVM-Dir
        Remove-Item $global:PGVM_DIR -Recurse
        Mock Init-Posh-Gvm -verifiable
        Mock Init-Candidate-Cache -verifiable
        Mock Show-Help
        gvm

        It 'initalize posh-gvm' {
            Assert-VerifiableMocks
        }

        It 'prints help' {
            Assert-MockCalled Show-Help 1
        }

        Reset-PGVM-Dir
    }

    Context 'Posh-gvm dir available'{
        $Script:GVM_FORCE_OFFLINE = $true
        Mock-PGVM-Dir
        Mock Init-Posh-Gvm
        Mock Init-Candidate-Cache -verifiable
        Mock Show-Help
        gvm

        It 'initalize posh-gvm' {
            Assert-VerifiableMocks
        }

        It 'does not init again' {
            Assert-MockCalled Init-Posh-Gvm 0
        }

        It 'prints help' {
            Assert-MockCalled Show-Help 1
        }

    }

    Context 'posh-gvm is forced offline' {
        Mock-PGVM-DIR
        Mock Init-Candidate-Cache -verifiable
        Mock Check-Available-Broadcast
        Mock Show-Help -verifiable
        $Script:GVM_FORCE_OFFLINE = $true

        gvm

        It 'does not load broadcast message from api' {
            Assert-MockCalled Check-Available-Broadcast 0
        }

        It 'performs default command actions' {
            Assert-VerifiableMocks
        }

        Reset-PGVM-DIR
    }

    Context 'posh-gvm offline command called' {
        Mock-PGVM-DIR
        Mock Init-Candidate-Cache -verifiable
        Mock Check-Available-Broadcast
        Mock Set-Offline-Mode -verifiable
        $Script:GVM_FORCE_OFFLINE = $false

        gvm offline

        It 'does not load broadcast message from api' {
            Assert-MockCalled Check-Available-Broadcast 0
        }

        It 'performs offline command actions' {
            Assert-VerifiableMocks
        }

        Reset-PGVM-DIR
    }

    Context 'posh-gvm online and command i called' {
        Mock-Dispatcher-Test
        Mock Install-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.2' -and $InstallPath -eq '\bla' }

        gvm i grails 2.2.2 \bla

        It 'checks for new broadcast, inits the Candidate-Cache and calls install-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command install called' {
        Mock-Dispatcher-Test
        Mock Install-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.2' -and $InstallPath -eq '' }

        gvm install grails 2.2.2

        It 'checks for new broadcast, inits the Candidate-Cache and calls install-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command uninstall called' {
        Mock-Dispatcher-Test
        Mock Uninstall-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.2' }

        gvm uninstall grails 2.2.2

        It 'checks for new broadcast, inits the Candidate-Cache and calls uninstall-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command rm called' {
        Mock-Dispatcher-Test
        Mock Uninstall-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.1' }

        gvm rm grails 2.2.1

        It 'checks for new broadcast, inits the Candidate-Cache and calls uninstall-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command ls called' {
        Mock-Dispatcher-Test
        Mock List-Candidate-Versions -verifiable -parameterFilter { $Candidate -eq 'grails'  }

        gvm ls grails

        It 'checks for new broadcast, inits the Candidate-Cache and calls list-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command list called' {
        Mock-Dispatcher-Test
        Mock List-Candidate-Versions -verifiable -parameterFilter { $Candidate -eq 'grails'  }

        gvm list grails

        It 'checks for new broadcast, inits the Candidate-Cache and calls list-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command u called' {
        Mock-Dispatcher-Test
        Mock Use-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.1' }

        gvm u grails 2.2.1

        It 'checks for new broadcast, inits the Candidate-Cache and calls use-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command use called' {
        Mock-Dispatcher-Test
        Mock Use-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.1' }

        gvm use grails 2.2.1

        It 'checks for new broadcast, inits the Candidate-Cache and calls use-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command d called' {
        Mock-Dispatcher-Test
        Mock Set-Default-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.1' }

        gvm d grails 2.2.1

        It 'checks for new broadcast, inits the Candidate-Cache and calls default-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command default called' {
        Mock-Dispatcher-Test
        Mock Set-Default-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.1' }

        gvm default grails 2.2.1

        It 'checks for new broadcast, inits the Candidate-Cache and calls default-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command c called' {
        Mock-Dispatcher-Test
        Mock Show-Current-Version -verifiable -parameterFilter { $Candidate -eq 'grails'  }

        gvm c grails

        It 'checks for new broadcast, inits the Candidate-Cache and calls current-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command current called' {
        Mock-Dispatcher-Test
        Mock Show-Current-Version -verifiable -parameterFilter { $Candidate -eq 'grails'  }

        gvm current grails

        It 'checks for new broadcast, inits the Candidate-Cache and calls current-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command v called' {
        Mock-Dispatcher-Test
        Mock Show-Posh-Gvm-Version -verifiable

        gvm v

        It 'checks for new broadcast, inits the Candidate-Cache and calls version-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command version called' {
        Mock-Dispatcher-Test
        Mock Show-Posh-Gvm-Version -verifiable

        gvm version

        It 'checks for new broadcast, inits the Candidate-Cache and calls version-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command b called' {
        Mock-Dispatcher-Test
        Mock Show-Broadcast-Message -verifiable

        gvm b

        It 'checks for new broadcast, inits the Candidate-Cache and calls broadcast-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command broadcast called' {
        Mock-Dispatcher-Test
        Mock Show-Broadcast-Message -verifiable

        gvm broadcast

        It 'checks for new broadcast, inits the Candidate-Cache and calls broadcast-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command h called' {
        Mock-Dispatcher-Test
        Mock Show-Help -verifiable

        gvm h

        It 'checks for new broadcast, inits the Candidate-Cache and calls help-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command help called' {
        Mock-Dispatcher-Test
        Mock Show-Help -verifiable

        gvm help

        It 'checks for new broadcast, inits the Candidate-Cache and calls help-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command offline called' {
        Mock-Dispatcher-Test -Offline
        Mock Set-Offline-Mode -verifiable -parameterFilter { $Flag -eq 'enable' }

        gvm offline enable

        It 'checks for new broadcast, inits the Candidate-Cache and calls offline-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command selfupdate called' {
        Mock-Dispatcher-Test
        Mock Invoke-Self-Update -verifiable

        gvm selfupdate

        It 'checks for new broadcast, inits the Candidate-Cache and calls selfupdate-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }

    Context 'posh-gvm online and command flush called' {
        Mock-Dispatcher-Test
        Mock Flush-Cache -verifiable -parameterFilter { $DataType -eq 'version'  }

        gvm flush version

        It 'checks for new broadcast, inits the Candidate-Cache and calls flush-command' {
            Assert-VerifiableMocks
        }

        Reset-Dispatcher-Test
    }
}

Describe 'Install-Candidate-Version' {
    Context 'Remote Version already installed' {
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Check-Candidate-Version-Available { '1.1.1' } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Is-Candidate-Version-Locally-Available { $true } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }

        It 'throw an error' {
            { Install-Candidate-Version grails 1.1.1 } | Should Throw
        }

        It 'process precondition checks' {
            Assert-VerifiableMocks
        }
    }

    Context 'Local Version already installed' {
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Check-Candidate-Version-Available { throw 'error' } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Is-Candidate-Version-Locally-Available { $true } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }

        It 'throw an error' {
            { Install-Candidate-Version grails 1.1.1 \bla } | Should Throw
        }

        It 'process precondition checks' {
            Assert-VerifiableMocks
        }
    }

    Context 'Local path but version is remote available already installed' {
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Check-Candidate-Version-Available { 1.1.1 } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }

        It 'throw an error' {
            { Install-Candidate-Version grails 1.1.1 \bla } | Should Throw
        }

        It 'process precondition checks' {
            Assert-VerifiableMocks
        }
    }

    Context 'Local version installation without defaulting' {
        $backupAutoAnswer = $Global:PGVM_AUTO_ANSWER
        $Global:PGVM_AUTO_ANSWER = $false
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Check-Candidate-Version-Available { throw 'error' } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Is-Candidate-Version-Locally-Available { $false } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Install-Local-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' -and $LocalPath -eq '\bla' }
        Mock Read-Host { 'n' }
        Mock Set-Linked-Candidate-Version

        Install-Candidate-Version grails 1.1.1 \bla

        It 'installs the local version' {
            Assert-VerifiableMocks
        }

        It "does not set default" {
            Assert-MockCalled Set-Linked-Candidate-Version 0
        }

        $Global:PGVM_AUTO_ANSWER = $backupAutoAnswer
    }

    Context 'Local version installation with auto defaulting' {
        $backupAutoAnswer = $Global:PGVM_AUTO_ANSWER
        $Global:PGVM_AUTO_ANSWER = $true
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Check-Candidate-Version-Available { throw 'error' } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Is-Candidate-Version-Locally-Available { $false } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Install-Local-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' -and $LocalPath -eq '\bla' }
        Mock Set-Linked-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Write-Output -verifiable

        Install-Candidate-Version grails 1.1.1 \bla

        It 'installs the local version' {
            Assert-VerifiableMocks
        }

        $Global:PGVM_AUTO_ANSWER = $backupAutoAnswer
    }

    Context 'Remote version installation with prompt defaulting' {
        $backupAutoAnswer = $Global:PGVM_AUTO_ANSWER
        $Global:PGVM_AUTO_ANSWER = $false
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Check-Candidate-Version-Available { '1.1.1' } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Is-Candidate-Version-Locally-Available { $false } -verifiable { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Install-Remote-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Read-Host { 'y' }
        Mock Set-Linked-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Write-Output -verifiable

        Install-Candidate-Version grails 1.1.1

        It 'installs the local version' {
            Assert-VerifiableMocks
        }

        $Global:PGVM_AUTO_ANSWER = $backupAutoAnswer
    }
}

Describe 'Uninstall-Candidate-Version' {
    Context 'No version is provided' {
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        It 'throws an error' {
            { Uninstall-Candidate-Version grails } | Should Throw
        }
    }

    Context 'To be uninstalled version is not installed' {
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Is-Candidate-Version-Locally-Available { $false } -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '24.3' }

        It 'throws an error' {
            { Uninstall-Candidate-Version grails 24.3 } | Should Throw
        }

        It 'checks candidate' {
            Assert-VerifiableMocks
        }
    }

    Context 'To be uninstalled Version is current version' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\24.3" | Out-Null
        Set-Linked-Candidate-Version grails 24.3

        It 'finds current-junction defined' {
            Test-Path "$Global:PGVM_DIR\grails\current" | Should Be $true
        }

        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Is-Candidate-Version-Locally-Available { $true } -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '24.3' }
        Mock Get-Current-Candidate-Version { '24.3' } -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable

        Uninstall-Candidate-Version grails 24.3

        It 'delete the current-junction' {
            Test-Path "$Global:PGVM_DIR\grails\current" | Should Be $false
        }

        It 'delete the version' {
            Test-Path "$Global:PGVM_DIR\grails\24.3" | Should Be $false
        }

        It "checks different preconditions correctly" {
            Assert-VerifiableMocks
        }

        Reset-PGVM-Dir
    }

    Context 'To be uninstalled version is installed' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\24.3" | Out-Null

        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Is-Candidate-Version-Locally-Available { $true } -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '24.3'}
        Mock Get-Current-Candidate-Version { $null } -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable

        Uninstall-Candidate-Version grails 24.3

        It 'delete the version' {
            Test-Path "$Global:PGVM_DIR\grails\24.3" | Should Be $false
        }

        It "checks different preconditions correctly" {
            Assert-VerifiableMocks
        }

        Reset-PGVM-Dir
    }
}

Describe 'List-Candidate-Versions' {
    Context 'if in online mode' {
        Mock-Online
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Version-List -verifiable -parameterFilter { $Candidate -eq 'grails' }

        List-Candidate-Versions grails

        It 'write the version list retrieved from api' {
            Assert-VerifiableMocks
        }
    }

    Context 'If in offline mode' {
        Mock-Offline
        Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Offline-Version-List -verifiable -parameterFilter { $Candidate -eq 'grails' }

        List-Candidate-Versions grails

        It 'write the version list based on local file structure' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Use-Candidate-Version' {
    Context 'If new use version is already used' {
        Mock Check-Candidate-Version-Available { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Get-Env-Candidate-Version { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable
        Mock Check-Candidate-Version-Locally-Available

        Use-Candidate-Version grails 1.1.1

        It 'changes nothing' {
            Assert-VerifiableMocks
        }

        It 'does not test candidate version' {
            Assert-MockCalled Check-Candidate-Version-Locally-Available 0
        }
    }

    Context 'If setting a different version as the current version to use' {
        Mock Check-Candidate-Version-Available { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Get-Env-Candidate-Version { '1.1.0' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable
        Mock Check-Candidate-Version-Locally-Available -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }

        Use-Candidate-Version grails 1.1.1

        It 'perform the changes' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Set-Default-Version' {
    Context 'If new default is already default' {
        Mock Check-Candidate-Version-Available { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Get-Current-Candidate-Version { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable
        Mock Check-Candidate-Version-Locally-Available

        Set-Default-Version grails 1.1.1

        It 'changes nothing' {
            Assert-VerifiableMocks
        }

        It 'does not test candidate version' {
            Assert-MockCalled Check-Candidate-Version-Locally-Available 0
        }
    }

    Context 'If setting a new default' {
        Mock Check-Candidate-Version-Available { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Get-Current-Candidate-Version { '1.1.0' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable
        Mock Check-Candidate-Version-Locally-Available -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
        Mock Set-Linked-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }

        Set-Default-Version grails 1.1.1

        It 'perform the changes' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Show-Current-Version' {
    Context 'If called without candidate' {
        $Script:GVM_CANDIDATES = @('grails','groovy','bla')
        Mock Get-Env-Candidate-Version { '1.1.0' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Get-Env-Candidate-Version { '2.1.0' } -parameterFilter { $Candidate -eq 'groovy' }
        Mock Get-Env-Candidate-Version { '0.1.0' } -parameterFilter { $Candidate -eq 'bla' }
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'Using:' }
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'grails: 1.1.0' }
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'groovy: 2.1.0' }
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'bla: 0.1.0' }

        Show-Current-Version

        It 'write the version for all currently used candidates' {
            Assert-VerifiableMocks
        }
    }

    Context 'If called with specifiv candidate and version available' {
        Mock Check-Candidate-Present -verifiable
        Mock Get-Env-Candidate-Version { '1.1.0' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'Using grails version 1.1.0' }

        Show-Current-Version grails

        It 'write version info' {
            Assert-VerifiableMocks
        }
    }

    Context 'If called with specifiv candidate and no version available' {
        Mock Check-Candidate-Present -verifiable
        Mock Get-Env-Candidate-Version { $null } -parameterFilter { $Candidate -eq 'grails' }
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'Not using any version of grails' }

        Show-Current-Version grails

        It 'write no version is available' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Show-Posh-Gvm-Version' {
    Context 'When called' {
        Mock Get-GVM-API-Version -verifiable
        Mock Get-Posh-Gvm-Version -verifiable
        Mock Write-Output -verifiable

        Show-Posh-Gvm-Version

        It 'write the version message to output' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Show-Broadcast-Message' {
    Context 'When called' {
        $Script:PGVM_BROADCAST_PATH = 'broadcast'
        Mock Get-Content { 'broadcast' } -verifiable -parameterFilter { $Path -eq 'broadcast' }
        Mock Write-Output -verifiable

        Show-Broadcast-Message

        It 'Write broadcast message to output' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Set-Offline-Mode' {
    Context 'If called with invalid flag' {
        It 'throws an error' {
            { Set-Offline-Mode invalid } | Should Throw
        }
    }

    Context 'If called with enable flag' {
        $Script:GVM_FORCE_OFFLINE = $false
        Mock Write-Output -verifiable

        Set-Offline-Mode enable

        It "set offline mode" {
            $Script:GVM_FORCE_OFFLINE | Should Be $true
        }

        It "writes info to output" {
            Assert-VerifiableMocks
        }
    }

    Context 'if called with disable flag' {
        $Script:GVM_ONLINE = $false
        $Script:GVM_FORCE_OFFLINE = $true
        Mock Write-Output -verifiable

        Set-Offline-Mode disable

        It "deactivate offline mode" {
            $Script:GVM_FORCE_OFFLINE | Should Be $false
        }

        It "set gvm to online" {
            $Script:GVM_ONLINE | Should Be $true
        }

        It "writes info to output" {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Flush-Cache' {
    Context 'Try to delete existing candidates cache' {
        $Script:PGVM_CANDIDATES_PATH = 'test'
        Mock Test-Path { $true } -parameterFilter { $Path -eq 'test' }
        Mock Remove-Item -verifiable -parameterFilter { $Path -eq 'test' }
        Mock Write-Output -verifiable

        Flush-Cache candidates

        It 'deletes the file and writes flush message' {
            Assert-VerifiableMocks
        }
    }

    Context 'Try to delete non-existing candidates cache' {
        $Script:PGVM_CANDIDATES_PATH = 'test2'
        Mock Test-Path { $false } -parameterFilter { $Path -eq 'test2' }
        Mock Write-Warning -verifiable

        Flush-Cache candidates

        It 'writes warning about non existing file' {
            Assert-VerifiableMocks
        }
    }

    Context 'Try to delete existing broadcast cache' {
        $Script:PGVM_BROADCAST_PATH = 'test'
        Mock Test-Path { $true } -parameterFilter { $Path -eq 'test' }
        Mock Remove-Item -verifiable -parameterFilter { $Path -eq 'test' }
        Mock Write-Output -verifiable

        Flush-Cache broadcast

        It 'deletes the file and writes flush message' {
            Assert-VerifiableMocks
        }
    }

    Context 'Try to delete non-existing broadcast cache' {
        $Script:PGVM_BROADCAST_PATH = 'test2'
        Mock Test-Path { $false } -parameterFilter { $Path -eq 'test2' }
        Mock Write-Warning -verifiable

        Flush-Cache broadcast

        It 'writes warning about non existing file' {
            Assert-VerifiableMocks
        }
    }

    Context 'Try to delete existing version cache' {
        $Script:GVM_API_VERSION_PATH = 'test'
        Mock Test-Path { $true } -parameterFilter { $Path -eq 'test' }
        Mock Remove-Item -verifiable -parameterFilter { $Path -eq 'test' }
        Mock Write-Output -verifiable

        Flush-Cache version

        It 'deletes the file and writes flush message' {
            Assert-VerifiableMocks
        }
    }

    Context 'Try to delete non-existing version cache' {
        $Script:GVM_API_VERSION_PATH = 'test2'
        Mock Test-Path { $false } -parameterFilter { $Path -eq 'test2' }
        Mock Write-Warning -verifiable

        Flush-Cache version

        It 'writes warning about non existing file' {
            Assert-VerifiableMocks
        }
    }

    Context 'Cleanup archives directory' {
        $Script:PGVM_ARCHIVES_PATH = 'archives'
        Mock Cleanup-Directory -verifiable -parameterFilter { $Path -eq  'archives' }

        Flush-Cache archives

        It 'cleanup archives directory' {
            Assert-VerifiableMocks
        }
    }

    Context 'Cleanup temp directory' {
        $Script:PGVM_TEMP_PATH = 'temp'
        Mock Cleanup-Directory -verifiable -parameterFilter { $Path -eq  'temp' }

        Flush-Cache temp

        It 'cleanup temp directory' {
            Assert-VerifiableMocks
        }
    }

    Context 'Cleanup tmp directory' {
        $Script:PGVM_TEMP_PATH = 'temp'
        Mock Cleanup-Directory -verifiable -parameterFilter { $Path -eq  'temp' }

        Flush-Cache tmp

        It 'cleanup temp directory' {
            Assert-VerifiableMocks
        }
    }

    Context 'flush invalid parameter' {
        It 'throws an error' {
            { Flush-Cache invalid } | Should Throw
        }
    }
}

Describe 'Show-Help' {
    Context 'If Show-Help is called' {
        Mock Write-Output -verifiable

        Show-Help

        It 'write the help to the output' {
            Assert-VerifiableMocks
        }
    }
}


================================================
FILE: Commands.ps1
================================================
function gvm([string]$Command, [string]$Candidate, [string]$Version, [string]$InstallPath, [switch]$Verbose, [switch]$Force) {
    $ErrorActionPreference = 'Stop'
	$ProgressPreference = 'SilentlyContinue'
	if ($Verbose) { $VerbosePreference = 'Continue' }

    if ( !( Test-Path $Global:PGVM_DIR ) ) {
        Write-Warning "$Global:PGVM_DIR does not exists. Reinitialize posh-gvm"
        Init-Posh-Gvm
    }

    $Script:GVM_AVAILABLE = $true
    if ( !($Script:GVM_FORCE_OFFLINE) -and $Command -ne 'offline' ) {
        Check-Available-Broadcast $Command

        if ( $Script:GVM_AVAILABLE ) {
            if ( $Script:FIRST_RUN ) {
                Check-GVM-API-Version
                Check-Posh-Gvm-Version
                $Script:FIRST_RUN = $false
            }
            Write-New-Version-Broadcast
        }
    }

    Init-Candidate-Cache

    Write-Verbose "Command: $Command"

    if ($Command -eq '') {
        $Command = 'help'
    }

    try {
        switch -regex ($Command) {
            '^i(nstall)?$'    { Install-Candidate-Version $Candidate $Version $InstallPath }
            '^(uninstall|rm)$'{ Uninstall-Candidate-Version $Candidate $Version }
            '^(ls|list)$'     { List-Candidate-Versions $Candidate }
            '^u(se)?$'        { Use-Candidate-Version $Candidate $Version }
            '^d(efault)?$'    { Set-Default-Version $Candidate $Version }
            '^c(urrent)?$'    { Show-Current-Version $Candidate }
            '^v(ersion)?$'    { Show-Posh-Gvm-Version }
            '^b(roadcast)?$'  { Show-Broadcast-Message }
            '^h(elp)?$'       { Show-Help }
            '^offline$'       { Set-Offline-Mode $Candidate }
            '^selfupdate$'    { Invoke-Self-Update($Force) }
            '^flush$'         { Flush-Cache $Candidate }
            default           { Write-Warning "Invalid command: $Command. Check gvm help!" }
        }
    } catch {
        if ( $_.CategoryInfo.Category -eq 'OperationStopped') {
            Write-Warning $_.CategoryInfo.TargetName
        } else {
            throw
        }
    }
}

function Install-Candidate-Version($Candidate, $Version, $InstallPath) {
    Write-Verbose 'Perform Install-Candidate-Version'
    Check-Candidate-Present $Candidate

    $localInstallation = $false
    if ($Version -and $InstallPath) {
        #local installation
        try {
            $Version = Check-Candidate-Version-Available $Candidate $Version
        } catch {
            $localInstallation = $true
        }
		if ( !($localInstallation) ) {
			throw 'Stop! Local installation for $Candidate $Version not possible. It exists remote already.'
		}
    } else {
        $Version = Check-Candidate-Version-Available $Candidate $Version
    }

    if ( Is-Candidate-Version-Locally-Available $Candidate $Version ) {
        throw "Stop! $Candidate $Version is already installed."
    }

    if ( $localInstallation ) {
        Install-Local-Version $Candidate $Version $InstallPath
    } else {
        Install-Remote-Version $Candidate $Version
    }

    $default = $false
    if ( !$Global:PGVM_AUTO_ANSWER ) {
        $default = (Read-Host -Prompt "Do you want $Candidate $Version to be set as default? (Y/n)") -match '(y|\A\z)'
    } else {
        $default = $true
    }

    if ( $default ) {
        Write-Output "Setting $Candidate $Version as default."
        Set-Linked-Candidate-Version $Candidate $Version
    }
}

function Uninstall-Candidate-Version($Candidate, $Version) {
    Write-Verbose 'Perform Uninstall-Candidate-Version'
    Check-Candidate-Present $Candidate
    Check-Version-Present $Version

    if ( !(Is-Candidate-Version-Locally-Available $Candidate $Version) ) {
        throw "$Candidate $Version is not installed."
    }

    $current = Get-Current-Candidate-Version $Candidate

    if ( $current -eq $Version ) {
        Write-Output "Unselecting $Candidate $Version..."
        (Get-Item "$Global:PGVM_DIR\$Candidate\current").Delete()
    }

    Write-Output "Uninstalling $Candidate $Version..."
    Remove-Item -Recurse -Force "$Global:PGVM_DIR\$Candidate\$Version"
}

function List-Candidate-Versions($Candidate) {
    Write-Verbose 'Perform List-Candidate-Version'
    Check-Candidate-Present $Candidate
    if ( Get-Online-Mode ) {
        Write-Version-List $Candidate
    } else {
        Write-Offline-Version-List $Candidate
    }
}

function Use-Candidate-Version($Candidate, $Version) {
    Write-Verbose 'Perform Use-Candidate-Version'
    $Version = Check-Candidate-Version-Available $Candidate $Version

    if ( $Version -eq (Get-Env-Candidate-Version $Candidate) ) {
        Write-Output "$Candidate $Version is used. Nothing changed."
    } else {
        Check-Candidate-Version-Locally-Available $Candidate $Version
        Set-Env-Candidate-Version $Candidate $Version
		Write-Output "Using $CANDIDATE version $Version in this shell."
    }
}

function Set-Default-Version($Candidate, $Version) {
    Write-Verbose 'Perform Set-Default-Version'
    $Version = Check-Candidate-Version-Available $Candidate $Version

    if ( $Version -eq (Get-Current-Candidate-Version $Candidate) ) {
        Write-Output "$Candidate $Version is already default. Nothing changed."
    } else {
        Check-Candidate-Version-Locally-Available $Candidate $Version
        Set-Linked-Candidate-Version $Candidate $Version
        Write-Output "Default $Candidate version set to $Version"
    }
}

function Show-Current-Version($Candidate) {
    Write-Verbose 'Perform Set-Current-Version'

    if ( !($Candidate) ) {
        Write-Output 'Using:'
        foreach ( $c in $Script:GVM_CANDIDATES ) {
            $v = Get-Env-Candidate-Version $c
            if ($v) {
                Write-Output "$c`: $v"
            }
        }
        return
    }

    Check-Candidate-Present $Candidate
    $Version = Get-Env-Candidate-Version $Candidate
    if ( $Version ) {
        Write-Output "Using $Candidate version $Version"
    } else {
        Write-Output "Not using any version of $Candidate"
    }
}

function Show-Posh-Gvm-Version() {
    $poshGvmVersion = Get-Posh-Gvm-Version
    $apiVersion = Get-GVM-API-Version
    Write-Output "posh-gvm (POwer SHell Groovy enVironment Manager) $poshGvmVersion base on GVM $GVM_BASE_VERSION and GVM API $apiVersion"
}

function Show-Broadcast-Message() {
    Write-Verbose 'Perform Show-Broadcast-Message'
    Get-Content $Script:PGVM_BROADCAST_PATH | Write-Output
}

function Set-Offline-Mode($Flag) {
    Write-Verbose 'Perform Set-Offline-Mode'
    switch ($Flag) {
        'enable'  { $Script:GVM_FORCE_OFFLINE = $true; Write-Output 'Forced offline mode enabled.' }
        'disable' { $Script:GVM_FORCE_OFFLINE = $false; $Script:GVM_ONLINE = $true; Write-Output 'Online mode re-enabled!' }
        default   { throw "Stop! $Flag is not a valid offline offline mode." }
    }
}

function Flush-Cache($DataType) {
    Write-Verbose 'Perform Flush-Cache'
    switch ($DataType) {
        'candidates' {
                        if ( Test-Path $Script:PGVM_CANDIDATES_PATH ) {
                            Remove-Item $Script:PGVM_CANDIDATES_PATH
                            Write-Output 'Candidates have been flushed.'
                        } else {
                            Write-Warning 'No candidate list found so not flushed.'
                        }
                     }
        'broadcast'  {
                        if ( Test-Path $Script:PGVM_BROADCAST_PATH ) {
                            Remove-Item $Script:PGVM_BROADCAST_PATH
                            Write-Output 'Broadcast have been flushed.'
                        } else {
                            Write-Warning 'No prior broadcast found so not flushed.'
                        }
                     }
        'version'    {
                        if ( Test-Path $Script:GVM_API_VERSION_PATH ) {
                            Remove-Item $Script:GVM_API_VERSION_PATH
                            Write-Output 'Version Token have been flushed.'
                        } else {
                            Write-Warning 'No prior Remote Version found so not flushed.'
                        }
                     }
        'archives'   { Cleanup-Directory $Script:PGVM_ARCHIVES_PATH }
        'temp'       { Cleanup-Directory $Script:PGVM_TEMP_PATH }
        'tmp'        { Cleanup-Directory $Script:PGVM_TEMP_PATH }
        default      { throw 'Stop! Please specify what you want to flush.' }
    }
}

function Show-Help() {
    Write-Output @"
Usage: gvm <command> <candidate> [version]
    gvm offline <enable|disable>

    commands:
        install   or i    <candidate> [version]
        uninstall or rm   <candidate> <version>
        list      or ls   <candidate>
        use       or u    <candidate> [version]
        default   or d    <candidate> [version]
        current   or c    [candidate]
        version   or v
        broadcast or b
        help      or h
        offline           <enable|disable>
        selfupdate        [-Force]
        flush             <candidates|broadcast|archives|temp>
    candidate  :  $($Script:GVM_CANDIDATES -join ', ')

    version    :  where optional, defaults to latest stable if not provided

eg: gvm install groovy
"@
}


================================================
FILE: GetPoshGvm.ps1
================================================
<#
	Paragon for the installation script is PsGet
#>

function Install-Posh-Gvm() {
    $poshGvmZipUrl = 'https://github.com/flofreud/posh-gvm/archive/master.zip'

    $poshGvmPath = Find-Module-Location

    try {
        # create temp dir
        $tempDir = [guid]::NewGuid().ToString()
        $tempDir = Join-Path -Path $env:TEMP -ChildPath $tempDir
        New-Item -ItemType Directory $tempDir | Out-Null

        # download current version
        $poshGvmZip = "$tempDir\posh-gvm-master.zip"
        Write-Output "Downloading posh-gvm from $poshGvmZipUrl"

        $client = (New-Object Net.WebClient)
        $client.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
	[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $client.DownloadFile($poshGvmZipUrl, $poshGvmZip)

        # unzip archive
        $shell = New-Object -com shell.application
        $shell.namespace($tempDir).copyhere($shell.namespace($poshGvmZip).items(), 0x14)

        # check if unzip successfully
        if ( Test-Path "$tempDir\posh-gvm-master" ) {
            if ( !(Test-Path $poshGvmPath) ) {
               New-Item -ItemType Directory $poshGvmPath | Out-Null
            }

            Copy-Item "$tempDir\posh-gvm-master\*" $poshGvmPath -Force -Recurse
            Write-Output "posh-gvm installed!"
            Write-Output "Please see https://github.com/flofreud/posh-gvm#usage for details to get started."
            Write-Warning "Execute 'Import-Module posh-gvm -Force' so changes take effect!"
        } else {
            Write-Warning 'Could not unzip archive containing posh-gvm. Most likely the archive is currupt. Please try to install again.'
        }
    } finally {
        # clear temp dir
        Remove-Item -Recurse -Force $tempDir
    }
}

function Find-Module-Location {
    $moduleDescriptor = Get-Module posh-gvm

    if ( $moduleDescriptor ) {
        return (Get-Item ($moduleDescriptor).Path).Directory.FullName
    } else {
        $modulePaths = @($Env:PSModulePath -split ';')
        # set module path to posh default
        $targetModulePath = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath WindowsPowerShell\Modules
        # if its not use select the first defined
        if ( $modulePaths -inotcontains $targetModulePath  ) {
            $targetModulePath = $modulePaths | Select-Object -Index 0
        }

        return "$targetModulePath\posh-gvm"
    }
}

Install-Posh-Gvm


================================================
FILE: Init.Tests.ps1
================================================
. .\Utils.ps1
. .\Init.ps1
. .\TestUtils.ps1

Describe 'Init-Posh-Gvm' {
    Context 'PGVM-Dir with only a grails folder' {
        Mock-PGVM-Dir
        Mock Check-JAVA-HOME -verifiable
        Mock Update-Candidates-Cache -verifiable
        Mock Init-Candidate-Cache -verifiable
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq 'current' }
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'groovy' -and $Version -eq 'current' }
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'bla' -and $Version -eq 'current' }
        $Script:PGVM_CANDIDATES_PATH = "$Global:PGVM_DIR\.meta\candidates.txt"
        $Script:GVM_CANDIDATES = 'grails','groovy','bla'

        Init-Posh-Gvm

        It "creates .meta" {
            Test-Path "$Global:PGVM_DIR\.meta" | Should Be $true
        }

        It "creates grails" {
            Test-Path "$Global:PGVM_DIR\grails" | Should Be $true
        }

        It "creates groovy" {
            Test-Path "$Global:PGVM_DIR\groovy" | Should Be $true
        }

        It "creates bla" {
            Test-Path "$Global:PGVM_DIR\bla" | Should Be $true
        }

        It "calls methods to test JAVA_HOME, API version, loads candidate cache and setup env variables" {
            Assert-VerifiableMocks
        }

        Reset-PGVM-Dir
    }

    Context 'PGVM-Dir with only a grails folder and a candidates list' {
        Mock-PGVM-Dir
        Mock Check-JAVA-HOME -verifiable
        Mock Update-Candidates-Cache
        Mock Init-Candidate-Cache -verifiable
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq 'current' }
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'groovy' -and $Version -eq 'current' }
        Mock Set-Env-Candidate-Version -verifiable -parameterFilter { $Candidate -eq 'bla' -and $Version -eq 'current' }
        $Script:PGVM_CANDIDATES_PATH = "$Global:PGVM_DIR\.meta\candidates.txt"
        New-Item -ItemType Directory "$Global:PGVM_DIR\.meta" | Out-Null
        New-Item -ItemType File $Script:PGVM_CANDIDATES_PATH | Out-Null
        $Script:GVM_CANDIDATES = 'grails','groovy','bla'

        Init-Posh-Gvm

        It "creates .meta" {
            Test-Path "$Global:PGVM_DIR\.meta" | Should Be $true
        }

        It "creates grails" {
            Test-Path "$Global:PGVM_DIR\grails" | Should Be $true
        }

        It "creates groovy" {
            Test-Path "$Global:PGVM_DIR\groovy" | Should Be $true
        }

        It "creates bla" {
            Test-Path "$Global:PGVM_DIR\bla" | Should Be $true
        }

        It "calls methods to test JAVA_HOME, API version, loads candidate cache and setup env variables" {
            Assert-VerifiableMocks
        }

        It "does not call update-candidates-cache" {
            Assert-MockCalled Update-Candidates-Cache 0
        }

        Reset-PGVM-Dir
    }
}

Describe 'Check-JAVA-HOME' {
    Context 'JAVA_HOME is set' {
        Mock Get-Command
        Mock Test-Path { $true } -parameterFilter { $Path -eq 'env:Java_HOME' }

        Check-JAVA-HOME

        It "changes nothing" {
            Assert-MockCalled Get-Command 0
        }
    }

    Context 'JAVA_HOME is not set but javac is on path' {
        $backupJAVAHOME = [Environment]::GetEnvironmentVariable('JAVA_HOME')
        Mock Test-Path { $false } -parameterFilter { $Path -eq 'env:Java_HOME' }
        Mock Get-Command { New-Object PSObject -Property @{ Path = (Get-Item 'C:\Windows\explorer.exe') } } -parameterFilter { $Name -eq 'javac' }
        $expectedNewJAVAHOME = 'C:\'

        Check-JAVA-HOME

        It "sets JAVA_HOME to javac parent" {
            [Environment]::GetEnvironmentVariable('JAVA_HOME') | Should Be $expectedNewJAVAHOME
        }

        [Environment]::SetEnvironmentVariable('JAVA_HOME', $backupJAVAHOME)
    }

    Context 'JAVA_HOME is not set and javax is not on path' {
        Mock Test-Path { $false } -parameterFilter { $Path -eq 'env:Java_HOME' }
        Mock Get-Command { throw 'error' } -parameterFilter { $Name -eq 'javac' }

        It "throws an error" {
            { Check-JAVA-HOME } | Should Throw
        }
    }
}

================================================
FILE: Init.ps1
================================================
#region Initialization
function Init-Posh-Gvm() {
    Write-Verbose 'Init posh-gvm'

    $ErrorActionPreference = 'Stop'
    $ProgressPreference = 'SilentlyContinue'

    Check-JAVA-HOME

    # Check if $Global:PGVM_DIR is available, if not create it
    if ( !( Test-Path "$Global:PGVM_DIR\.meta" ) ) {
        New-Item -ItemType Directory "$Global:PGVM_DIR\.meta" | Out-Null
    }

    # Load candidates cache
    if ( ! (Test-Path $Script:PGVM_CANDIDATES_PATH) ) {
        Update-Candidates-Cache
    }

    Init-Candidate-Cache

    #Setup default paths
    Foreach ( $candidate in $Script:GVM_CANDIDATES ) {
		if ( !( Test-Path "$Global:PGVM_DIR\$candidate" ) ) {
			New-Item -ItemType Directory "$Global:PGVM_DIR\$candidate" | Out-Null
		}

        Set-Env-Candidate-Version $candidate 'current'
    }

    # Check if we can use unzip (which is much faster)
    Check-Unzip-On-Path
}

function Check-JAVA-HOME() {
	# Check for JAVA_HOME, If not set, try to interfere it
    if ( ! (Test-Path env:JAVA_HOME) ) {
        try {
            [Environment]::SetEnvironmentVariable('JAVA_HOME', (Get-Item (Get-Command 'javac').Path).Directory.Parent.FullName)
        } catch {
            throw "Could not find java, please set JAVA_HOME"
        }
    }
}

function Check-Unzip-On-Path() {
    try {
        Get-Command 'unzip.exe' | Out-Null
        $Script:UNZIP_ON_PATH = $true
    } catch {
        $Script:UNZIP_ON_PATH = $false
    }

    try {
        Get-Command '7z.exe' | Out-Null
        $Script:SEVENZ_ON_PATH = $true
    } catch {
        $Script:SEVENZ_ON_PATH = $false
    }
}
#endregion


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS


================================================
FILE: README.md
================================================
The code inside of this repository is broken. If you need the functionality of SDKMAN on Windows consider using Docker or WSL.


================================================
FILE: TabExpansion.ps1
================================================
# Check if function TabExpansion already exists and backup existing version to
# prevent breaking other TabExpansion implementations.
# Taken from posh-git https://github.com/dahlbyk/posh-git/blob/master/GitTabExpansion.ps1#L297
$tabExpansionBackup = 'PoshGVM_DefaultTabExpansion'
if (Test-Path Function:\TabExpansion) {
    Rename-Item Function:\TabExpansion $tabExpansionBackup -ErrorAction SilentlyContinue
}

function TabExpansion($line, $lastWord) {
    $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()

    switch -regex ($lastBlock) {
        # Execute gvm tab expansion for gvm command
        '^gvm (.*)' { gvmTabExpansion($lastBlock) }
        # Fall back on existing tab expansion
        default { if (Test-Path Function:\$tabExpansionBackup) { & $tabExpansionBackup $line $lastWord } }
    }
}

$Script:PGVM_TAB_COMMANDS = @('install','uninstall','rm','list','use','default','current','version','broadcast','help','offline','selfupdate','flush')
function gvmTabExpansion($lastBlock) {
    if ( !($lastBlock -match '^gvm\s+(?<cmd>\S+)?(?<args> .*)?$') ) {
        return
    }
    $command = $Matches['cmd']
    $arguments = $Matches['args']

    if ( !($arguments) ) {
        # Try to complete the command
        return $Script:PGVM_TAB_COMMANDS | Where-Object { $_.StartsWith($command) }
    }

    $arguments = $arguments.TrimStart()
    # Help add correct parameters
    switch -regex ($command) {
        '^i(nstall)?'    { gvmTabExpandion-Need-Candidate $command $arguments }
        '^(uninstall|rm)'{ gvmTabExpandion-Need-Candidate $command $arguments }
        '^(ls|list)'     { gvmTabExpandion-Need-Candidate $command $arguments }
        '^u(se)?'        { gvmTabExpandion-Need-Candidate $command $arguments }
        '^d(efault)?'    { gvmTabExpandion-Need-Candidate $command $arguments }
        '^c(urrent)?'    { gvmTabExpandion-Need-Candidate $command $arguments }
        '^offline'       { gvmTabExpansion-Offline $arguments }
        '^flush'         { gvmTabExpansion-Flush $arguments }
        default          {}
    }
}

function gvmTabExpandion-Need-Candidate($Command, $LastBlock) {
    if ( !($LastBlock -match "^(?<candidate>\S+)?(?<args> .*)?$") ) {
        return
    }
    $candidate = $Matches['candidate']
    $arguments = $Matches['args']

    Init-Candidate-Cache

    if ( !($arguments) ) {
        # Try to complete the command
        return $Script:GVM_CANDIDATES | Where-Object { $_.StartsWith($candidate) }
    }

    if ( !($Script:GVM_CANDIDATES -contains $candidate) ) {
        return
    }

    $arguments = $arguments.TrimStart()
    # Help add correct parameters
    switch -regex ($command) {
        #'^i(nstall)?'    { gvmTabExpandion-Need-Version $candidate $arguments }
        '^(uninstall|rm)'{ gvmTabExpandion-Need-Version $candidate $arguments }
        '^u(se)?'        { gvmTabExpandion-Need-Version $candidate $arguments }
        '^d(efault)?'    { gvmTabExpandion-Need-Version $candidate $arguments }
        default          {}
    }
}

function gvmTabExpandion-Need-Version($Candidate, $LastBlock) {
    Get-Installed-Candidate-Version-List $Candidate | Where-Object { $_.StartsWith($LastBlock) }
}

function gvmTabExpansion-Offline($Arguments) {
    @('enable','disable') | Where-Object { ([string]$_).StartsWith($Arguments) }
}

function gvmTabExpansion-Flush($Arguments) {
    @('candidates','broadcast','archives','temp') | Where-Object { ([string]$_).StartsWith($Arguments) }
}

Export-ModuleMember TabExpansion
Export-ModuleMember gvmTabExpansion

================================================
FILE: TestUtils.ps1
================================================
. .\Utils.ps1

function Mock-Check-Candidate-Grails {
    Mock Check-Candidate-Present -verifiable -parameterFilter { $Candidate -eq 'grails' }
}

function Mock-Online {
    Mock Get-Online-Mode { return $true }
}

function Mock-Offline {
    Mock Get-Online-Mode { return $false }
}

function Mock-Grails-1.1.1-Locally-Available($Available) {
    if ( $Available ) {
        Mock Is-Candidate-Version-Locally-Available { return $true }  -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
    } else {
        Mock Is-Candidate-Version-Locally-Available { return $false }  -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '1.1.1' }
    }
}

function Mock-Current-Grails-1.2 {
    Mock Get-Current-Candidate-Version { return 1.2 } -parameterFilter { $Candidate -eq 'grails' }
}

function Mock-No-Current-Grails {
    Mock Get-Current-Candidate-Version { return $null } -parameterFilter { $Candidate -eq 'grails' }
}

function Mock-Api-Call-Default-Grails-2.2 {
    Mock Invoke-API-Call { return 2.2 } -parameterFilter { $Path -eq 'candidates/grails/default' }
}

function Mock-Api-Call-Grails-1.1.1-Available($Available) {
    if ( $Available ) {
        Mock Invoke-API-Call { return $true } -parameterFilter { $Path -eq 'candidates/grails/1.1.1' }
    } else {
        Mock Invoke-API-Call { return $false } -parameterFilter { $Path -eq 'candidates/grails/1.1.1' }
    }
}

function Mock-PGVM-Dir {
    $Script:backup_PGVM_DIR = $Global:PGVM_DIR
    New-Item -ItemType Directory "TestDrive:.posh-gvm" | Out-Null
    $Global:PGVM_DIR = (Get-Item "TestDrive:.posh-gvm").FullName
    New-Item -ItemType Directory "$Global:PGVM_DIR\grails" | Out-Null
}

function Reset-PGVM-Dir {
    $link = "$Global:PGVM_DIR\grails\current"
    if ( Test-Path $link ) {
        (Get-Item $link).Delete()
    }

    $Global:PGVM_DIR = $Script:backup_PGVM_DIR
}

function Mock-Grails-Home($Version) {
    $Script:backup_GRAILS_HOME = [System.Environment]::GetEnvironmentVariable('GRAILS_HOME')
    [System.Environment]::SetEnvironmentVariable('GRAILS_HOME', "$Global:PGVM_DIR\grails\$Version")
}

function Reset-Grails-Home {
    [System.Environment]::SetEnvironmentVariable('GRAILS_HOME', $Script:backup_GRAILS_HOME)
}

function Mock-Dispatcher-Test([switch]$Offline) {
    Mock-PGVM-Dir
    $Script:GVM_FORCE_OFFLINE = $false
    $Script:FIRST_RUN = $false
    if ( !($Offline) ) {
        Mock Check-Available-Broadcast -verifiable
        Write-New-Version-Broadcast -verifiable
    }
    Mock Init-Candidate-Cache -verifiable
}

function Reset-Dispatcher-Test {
    Reset-PGVM-Dir
}

================================================
FILE: Utils.Tests.ps1
================================================
. .\Utils.ps1
. .\TestUtils.ps1

Describe 'Check-GVM-API-Version' {
    Context 'API offline' {
        $Script:GVM_AVAILABLE = $true
        $Script:GVM_API_NEW_VERSION = $false
        Mock Get-GVM-API-Version
        Mock Invoke-API-Call { throw 'error' }  -parameterFilter { $Path -eq 'app/Version' }

        Check-GVM-API-Version

        It 'the error handling set the app in offline mode' {
            $Script:GVM_AVAILABLE | Should be $false
        }

        It 'does not informs about new version' {
            $Script:GVM_API_NEW_VERSION | Should Be $false
        }
    }

    Context 'No new version' {
        $backup_Global_PGVM_AUTO_SELFUPDTE = $Global:PGVM_AUTO_SELFUPDATE
        $Global:PGVM_AUTO_SELFUPDATE = $true
        $Script:GVM_API_NEW_VERSION = $false

        Mock Get-GVM-API-Version { 1.2.2 }
        Mock Invoke-API-Call { 1.2.2 } -parameterFilter { $Path -eq 'app/Version' }
        Mock Invoke-Self-Update

        Check-GVM-API-Version

        It 'do nothing' {
            Assert-MockCalled Invoke-Self-Update 0
        }

        It 'does not informs about new version' {
            $Script:GVM_API_NEW_VERSION | Should Be $false
        }

        $Global:PGVM_AUTO_SELFUPDATE = $backup_Global_PGVM_AUTO_SELFUPDTE
    }

    Context 'New version and no auto selfupdate' {
        $backup_Global_PGVM_AUTO_SELFUPDTE = $Global:PGVM_AUTO_SELFUPDATE
        $Global:PGVM_AUTO_SELFUPDATE = $false
        $Script:GVM_API_NEW_VERSION = $false

        Mock Get-GVM-API-Version { '1.2.2' }
        Mock Invoke-API-Call { '1.2.3' } -parameterFilter { $Path -eq 'app/Version' }

        Check-GVM-API-Version

        It 'informs about new version' {
            $Script:GVM_API_NEW_VERSION | Should Be $true
        }

        It 'write a warning about needed update' {
            Assert-VerifiableMocks
        }

        $Global:PGVM_AUTO_SELFUPDATE = $backup_Global_PGVM_AUTO_SELFUPDTE
    }

    Context 'New version and auto selfupdate' {
        $backup_Global_PGVM_AUTO_SELFUPDTE = $Global:PGVM_AUTO_SELFUPDATE
        $Global:PGVM_AUTO_SELFUPDATE = $true
        $Script:GVM_API_NEW_VERSION = $false

        Mock Get-GVM-API-Version { '1.2.2' }
        Mock Invoke-API-Call { '1.2.3' } -parameterFilter { $Path -eq 'app/Version' }
        Mock Invoke-Self-Update -verifiable

        Check-GVM-API-Version

        It 'updates self' {
            Assert-VerifiableMocks
        }

        It 'does not informs about new version' {
            $Script:GVM_API_NEW_VERSION | Should Be $false
        }

        $Global:PGVM_AUTO_SELFUPDATE = $backup_Global_PGVM_AUTO_SELFUPDTE
    }
}

Describe 'Check-Posh-Gvm-Version' {
    Context 'No new Version' {
        $backup_Global_PGVM_AUTO_SELFUPDTE = $Global:PGVM_AUTO_SELFUPDATE
        $Global:PGVM_AUTO_SELFUPDATE = $false
        $Script:PGVM_NEW_VERSION = $false

        Mock Is-New-Posh-GVM-Version-Available { $false }
        Mock Invoke-Self-Update

        Check-Posh-Gvm-Version

        It 'does not update itself' {
            Assert-MockCalled Invoke-Self-Update -Times 0
        }

        It 'does not informs about new version' {
            $Script:PGVM_NEW_VERSION | Should Be $false
        }

        $Global:PGVM_AUTO_SELFUPDATE = $backup_Global_PGVM_AUTO_SELFUPDTE
    }

    Context 'New version and no auto selfupdate' {
        $backup_Global_PGVM_AUTO_SELFUPDTE = $Global:PGVM_AUTO_SELFUPDATE
        $Global:PGVM_AUTO_SELFUPDATE = $false
        $Script:PGVM_NEW_VERSION = $false

        Mock Is-New-Posh-GVM-Version-Available { $true }
        Mock Invoke-Self-Update

        Check-Posh-Gvm-Version

        It 'informs about new version' {
            $Script:PGVM_NEW_VERSION | Should Be $true
        }

        It 'does not update itself' {
            Assert-MockCalled Invoke-Self-Update -Times 0
        }

        $Global:PGVM_AUTO_SELFUPDATE = $backup_Global_PGVM_AUTO_SELFUPDTE
    }

    Context 'New version and auto selfupdate' {
        $backup_Global_PGVM_AUTO_SELFUPDTE = $Global:PGVM_AUTO_SELFUPDATE
        $Global:PGVM_AUTO_SELFUPDATE = $true
        $Script:PGVM_NEW_VERSION = $false

        Mock Is-New-Posh-GVM-Version-Available { $true }
        Mock Invoke-Self-Update -verifiable

        Check-Posh-Gvm-Version

        It 'updates self' {
            Assert-VerifiableMocks
        }

        It 'does not informs about new version' {
            $Script:PGVM_NEW_VERSION | Should Be $false
        }

        $Global:PGVM_AUTO_SELFUPDATE = $backup_Global_PGVM_AUTO_SELFUPDTE
    }
}

Describe 'Is-New-Posh-GVM-Version-Available' {
    Context 'New version available' {
        $Script:PGVM_VERSION_SERVICE = 'blub'
        $Script:PGVM_VERSION_PATH = 'TestDrive:VERSION.txt'
        Set-Content $Script:PGVM_VERSION_PATH '1.1.1'

        Mock Invoke-RestMethod { '1.2.1' } -parameterFilter { $Uri -eq 'blub' }

        $result = Is-New-Posh-GVM-Version-Available

        It 'returns $true' {
            $result | Should Be $true
        }
    }

    Context 'No new version available' {
        $Script:PGVM_VERSION_SERVICE = 'blub'
        $Script:PGVM_VERSION_PATH = 'TestDrive:VERSION.txt'
        Set-Content $Script:PGVM_VERSION_PATH '1.1.1'

        Mock Invoke-RestMethod { '1.1.1' } -parameterFilter { $Uri -eq 'blub' }

        $result = Is-New-Posh-GVM-Version-Available

        It 'returns $false' {
            $result | Should Be $false
        }
    }

    Context 'Version service error' {
        $Script:PGVM_VERSION_SERVICE = 'blub'
        $Script:PGVM_VERSION_PATH = 'TestDrive:VERSION.txt'
        Set-Content $Script:PGVM_VERSION_PATH '1.1.1'

        Mock Invoke-RestMethod { throw 'error' } -parameterFilter { $Uri -eq 'blub' }

        $result = Is-New-Posh-GVM-Version-Available

        It 'returns $false' {
            $result | Should Be $false
        }
    }
}

Describe 'Get-GVM-API-Version' {
    Context 'No cached version' {
        $Script:GVM_API_VERSION_PATH = 'TestDrive:version.txt'

        It 'returns `$null' {
            Get-GVM-API-Version | Should Be $null
        }
    }

    Context 'No cached version' {
        $Script:GVM_API_VERSION_PATH = 'TestDrive:version.txt'
        Set-Content $Script:GVM_API_VERSION_PATH '1.1.1'

        It 'returns $null' {
            Get-GVM-API-Version | Should Be 1.1.1
        }
    }
}

Describe 'Check-Available-Broadcast' {
    Context 'Last execution was online, still online' {
        $Script:GVM_ONLINE = $true
        $Script:GVM_AVAILABLE = $true
        Mock Get-GVM-API-Version { '1.2.3' }
        Mock Invoke-Broadcast-API-Call { 'Broadcast message' }
        Mock Handle-Broadcast -verifiable -parameterFilter { $Command -eq $null -and $Broadcast -eq 'Broadcast message' }
        Mock Write-Offline-Broadcast
        Mock Write-Online-Broadcast

        Check-Available-Broadcast

        It 'does not announce any mode changes' {
            Assert-MockCalled Write-Offline-Broadcast 0
            Assert-MockCalled Write-Online-Broadcast 0
        }

        It 'calls Handle-Broadcast' {
            Assert-VerifiableMocks
        }
    }

    Context 'Last execution was online, now offline' {
        $Script:GVM_ONLINE = $true
        $Script:GVM_AVAILABLE = $false
        Mock Get-GVM-API-Version { '1.2.4' }
        Mock Invoke-Broadcast-API-Call { $null }
        Mock Handle-Broadcast
        Mock Write-Offline-Broadcast
        Mock Write-Online-Broadcast

        Check-Available-Broadcast

        It 'does announce offline mode' {
            Assert-MockCalled Write-Offline-Broadcast 1
            Assert-MockCalled Write-Online-Broadcast 0
        }

        It 'does not call Handle-Broadcast' {
            Assert-MockCalled Handle-Broadcast 0
        }
    }

    Context 'Last execution was offline, still offline' {
        $Script:GVM_ONLINE = $false
        $Script:GVM_AVAILABLE = $false
        Mock Get-GVM-API-Version { '1.2.4' }
        Mock Invoke-Broadcast-API-Call { $null }
        Mock Handle-Broadcast
        Mock Write-Offline-Broadcast
        Mock Write-Online-Broadcast

        Check-Available-Broadcast

        It 'does not announce any mode changes' {
            Assert-MockCalled Write-Offline-Broadcast 0
            Assert-MockCalled Write-Online-Broadcast 0
        }

        It 'does not call Handle-Broadcast' {
            Assert-MockCalled Handle-Broadcast 0
        }
    }

    Context 'Last execution was offline, now online' {
        $Script:GVM_ONLINE = $false
        $Script:GVM_AVAILABLE = $true
        Mock Get-GVM-API-Version { '1.2.5' }
        Mock Invoke-Broadcast-API-Call { 'Broadcast message' }
        Mock Handle-Broadcast -verifiable -parameterFilter { $Command -eq $null -and $Broadcast -eq 'Broadcast message' }
        Mock Write-Offline-Broadcast
        Mock Write-Online-Broadcast

        Check-Available-Broadcast

        It 'does announce online mode' {
            Assert-MockCalled Write-Offline-Broadcast 0
            Assert-MockCalled Write-Online-Broadcast 1
        }

        It 'calls Handle-Broadcast' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Invoke-Self-Update' {
    Context 'Selfupdate will be triggered, no force, no new version' {
        Mock Update-Candidates-Cache -verifiable
        Mock Write-Output -verifiable
        Mock Is-New-Posh-GVM-Version-Available { $false }
        Mock Invoke-Posh-Gvm-Update

        Invoke-Self-Update

        It 'updates the candidate cache' {
            Assert-VerifiableMocks
        }

        It 'does not updates itself' {
            Assert-MockCalled Invoke-Posh-Gvm-Update -Times 0
        }
    }

    Context 'Selfupdate will be triggered, no force, new version' {
        Mock Update-Candidates-Cache -verifiable
        Mock Write-Output -verifiable
        Mock Is-New-Posh-GVM-Version-Available { $true }
        Mock Invoke-Posh-Gvm-Update -verifiable

        Invoke-Self-Update

        It 'updates the candidate cache and version' {
            Assert-VerifiableMocks
        }
    }

    Context 'Selfupdate will be triggered, force, no new version' {
        Mock Update-Candidates-Cache -verifiable
        Mock Write-Output -verifiable
        Mock Is-New-Posh-GVM-Version-Available { $false }
        Mock Invoke-Posh-Gvm-Update -verifiable

        Invoke-Self-Update -Force $true

        It 'updates the candidate cache and version' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Check-Candidate-Present checks if candidate parameter is valid' {
	It 'throws an error if no candidate is provided' {
		{ Check-Candidate-Present } | Should Throw
	}

    $Script:GVM_CANDIDATES = @('grails','groovy')
    It 'throws error if candidate unknown' {
        { Check-Candidate-Present java } | Should Throw
    }

    It 'throws no error if candidate known' {
        { Check-Candidate-Present groovy } | Should Not Throw
    }
}

Describe 'Check-Version-Present checks if version parameter is defined' {
    It 'throws an error if no candidate is provided' {
        { Check-Version-Present } | Should Throw
    }

    It 'throws no error if version provided' {
        { Check-Version-Present 2.1.3 } | Should Not Throw
    }
}

Describe 'Check-Candidate-Version-Available select or vadidates a version for a candidate' {
    Context 'When grails version 1.1.1 is locally available' {
        Mock-Check-Candidate-Grails
        Mock-Grails-1.1.1-Locally-Available $true

        $result = Check-Candidate-Version-Available grails 1.1.1

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }

        It 'returns the 1.1.1' {
            $result | Should Be 1.1.1
        }
    }

    Context 'When gvm is offline and the provided version is not locally available' {
        Mock-Check-Candidate-Grails
        Mock-Offline
        Mock-Grails-1.1.1-Locally-Available $false

        It 'throws an error' {
            { Check-Candidate-Version-Available grails 1.1.1 } | Should Throw
        }

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }
    }

    Context 'When gvm is offline and no version is provided but there is a current version' {
        Mock-Check-Candidate-Grails
        Mock-Offline
        Mock-Current-Grails-1.2

        $result = Check-Candidate-Version-Available grails

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }

        It 'returns the current version' {
            $result | Should Be 1.2
        }
    }

    Context 'When gvm is offline and no version is provided and no current version is defined' {
        Mock-Check-Candidate-Grails
        Mock-Offline
        Mock-No-Current-Grails

        It 'throws an error' {
            { Check-Candidate-Version-Available grails } | Should Throw
        }

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }
    }

    Context 'When gvm is online and no version is provided' {
        Mock-Check-Candidate-Grails
        Mock-Online
        Mock-Api-Call-Default-Grails-2.2

        $result = Check-Candidate-Version-Available grails

        It 'the API default is returned' {
            $result | Should Be 2.2
        }

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }
    }

    Context 'When gvm is online and the provided version is valid' {
        Mock-Check-Candidate-Grails
        Mock-Online
        Mock-Api-Call-Grails-1.1.1-Available $true

        $result = Check-Candidate-Version-Available grails 1.1.1

        It 'returns the version' {
            $result | Should Be 1.1.1
        }

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }
    }

    Context 'When gvm is online and the provided version is invalid' {
        Mock-Check-Candidate-Grails
        Mock-Online
        Mock-Api-Call-Grails-1.1.1-Available $false

        It 'throws an error' {
            { Check-Candidate-Version-Available grails 1.1.1 } | Should Throw
        }

        It 'check candidate parameter' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Get-Current-Candidate-Version reads the currently linked version' {
    Context 'When current is not defined' {
        Mock-PGVM-Dir

        It 'returns $null if current not defined' {
            Get-Current-Candidate-Version grails | Should Be $null
        }

        Reset-PGVM-DIR
    }

    Context 'When current is defined' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\2.2.2" | Out-Null
        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\current" "$Global:PGVM_DIR\grails\2.2.2"

        It 'returns the liked version' {
            Get-Current-Candidate-Version grails | Should Be 2.2.2
        }

        Reset-PGVM-Dir
    }
}

Describe 'Get-Env-Candidate-Version reads the version set in $Candidate-Home' {
    Context 'When GRAILS_HOME is set to a specific version' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\2.2.1" | Out-Null
        Mock-Grails-Home 2.2.1

        It 'returns the set version' {
            Get-Env-Candidate-Version grails | Should Be 2.2.1
        }

        Reset-Grails-Home
        Reset-PGVM-Dir
    }

    Context 'When GRAILS_HOME is set to current' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\2.2.1" | Out-Null
        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\current" "$Global:PGVM_DIR\grails\2.2.1"

        Mock-Grails-Home current

        It 'returns the version linked to current' {
            Get-Env-Candidate-Version grails | Should Be 2.2.1
        }

        Reset-Grails-Home
        Reset-PGVM-Dir
    }
}

Describe 'Check-Candidate-Version-Locally-Available throws error message if not available' {
    Context 'Version not available' {
        Mock-Grails-1.1.1-Locally-Available $false
        It 'throws an error' {
            { Check-Candidate-Version-Locally-Available grails 1.1.1 } | Should Throw
        }
    }

    Context 'Version is available' {
        Mock-Grails-1.1.1-Locally-Available $true

        It 'not throws any error' {
            { Check-Candidate-Version-Locally-Available grails 1.1.1 } | Should Not Throw
        }
    }
}

Describe 'Is-Candidate-Version-Locally-Available check the path exists' {
    Context 'No version provided' {
        it 'returns $false' {
            Is-Candidate-Version-Locally-Available grails | Should Be $false
        }
    }

    Context 'COC path for grails 1.1.1 is missing' {
        Mock-PGVM-Dir

        it 'returns $false' {
            Is-Candidate-Version-Locally-Available grails 1.1.1 | Should Be $false
        }

        Reset-PGVM-Dir
    }

    Context 'COC path for grails 1.1.1 exists' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.1.1" | Out-Null

        it 'returns $true' {
            Is-Candidate-Version-Locally-Available grails 1.1.1 | Should Be $true
        }

        Reset-PGVM-Dir
    }
}

Describe 'Get-Installed-Candidate-Version-List' {
    Context 'Version 1.1, 1.3.7 and 2.2.1 of grails installed' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.1" | Out-Null
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.7" | Out-Null
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\2.2.1" | Out-Null
        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\current" "$Global:PGVM_DIR\grails\2.2.1"

        It 'returns list of installed versions' {
            Get-Installed-Candidate-Version-List grails | Should Be 1.1,1.3.7,2.2.1
        }

        Reset-PGVM-Dir
    }
}

Describe 'Set-Env-Candidate-Version' {
    Context 'Env-Version of grails is current' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.7" | Out-Null
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\2.2.1" | Out-Null
        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\current" "$Global:PGVM_DIR\grails\2.2.1"
        Mock-Grails-Home current
        $backupPATH = $env:Path

        Set-Env-Candidate-Version grails 1.3.7

        It 'sets GRAILS_HOME' {
            $env:GRAILS_HOME -eq "$Global:PGVM_DIR\grails\1.3.7"
        }

        It 'extends the Path' {
            $env:Path -eq "$Global:PGVM_DIR\grails\1.3.7\bin"
        }

        $env:Path = $backupPATH
        Reset-Grails-Home
        Reset-PGVM-Dir
    }
}

Describe 'Set-Linked-Candidate-Version' {
    Context 'In a initialized PGVM-Dir' {
        Mock-PGVM-Dir
        Mock Set-Junction-Via-Mklink -verifiable -parameterFilter { $Candidate -eq 'grails' -and $Version -eq '2.2.1' }

        Set-Linked-Candidate-Version grails 2.2.1

        It 'calls Set-Junction-Via-Mklink with the correct paths' {
            Assert-VerifiableMocks
        }

        Reset-PGVM-Dir
    }
}

Describe 'Set-Junction-Via-Mklink' {
    Context 'No junction for the link-path exists' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.7" | Out-Null

        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\bla" "$Global:PGVM_DIR\grails\1.3.7"

        It 'creates a junction to the target location' {
            (Get-Junction-Target "$Global:PGVM_DIR\grails\bla").FullName -eq "$Global:PGVM_DIR\grails\1.3.7" 
        }

        (Get-Item "$Global:PGVM_DIR\grails\bla").Delete()
        Reset-PGVM-Dir
    }

    Context 'A Junction for the link-path exists' {
        Mock-PGVM-Dir
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.7" | Out-Null
        New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.8" | Out-Null
        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\bla" "$Global:PGVM_DIR\grails\1.3.8"
        Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\bla" "$Global:PGVM_DIR\grails\1.3.7"

        It 'creates a junction to the target location without errors' {
            (Get-Junction-Target "$Global:PGVM_DIR\grails\bla").FullName -eq "$Global:PGVM_DIR\grails\1.3.7"
        }

        (Get-Item "$Global:PGVM_DIR\grails\bla").Delete()
        Reset-PGVM-Dir
    }
}

Describe 'Get-Junction-Target' {
    Context 'Provided path is a junction' {
      Mock-PGVM-Dir
      New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.7" | Out-Null

      Set-Junction-Via-Mklink "$Global:PGVM_DIR\grails\bla" "$Global:PGVM_DIR\grails\1.3.7"

      It 'returns the item of the junction correctly' {
          (Get-Junction-Target "$Global:PGVM_DIR\grails\bla").FullName -eq "$Global:PGVM_DIR\grails\1.3.7"
      }

      (Get-Item "$Global:PGVM_DIR\grails\bla").Delete()
      Reset-PGVM-Dir
    }

    Context 'Provided path is no junction' {
      Mock-PGVM-Dir
      New-Item -ItemType Directory "$Global:PGVM_DIR\grails\1.3.7" | Out-Null

      It 'returns correctly a null object without exception' {
          Get-Junction-Target "$Global:PGVM_DIR\grails\1.3.7" -eq $null
      }

      Reset-PGVM-Dir
    }
}

Describe 'Get-Online-Mode check the state variables for GVM-API availablitiy and for force offline mode' {
    Context 'GVM-Api unavailable but may be connected' {
        $Script:GVM_AVAILABLE = $false
        $Script:GVM_FORCE_OFFLINE = $false

        It 'returns $false' {
            Get-Online-Mode | Should Be $false
        }
    }

    Context 'GVM-Api unavailable and may not be connected' {
        $Script:GVM_AVAILABLE = $false
        $Script:GVM_FORCE_OFFLINE = $true

        It 'returns $false' {
            Get-Online-Mode | Should Be $false
        }
    }

    Context 'GVM-Api is available and may not be connected' {
        $Script:GVM_AVAILABLE = $true
        $Script:GVM_FORCE_OFFLINE = $true

        It 'returns $false' {
            Get-Online-Mode | Should Be $false
        }
    }

    Context 'GVM-Api is available and may be connected' {
        $Script:GVM_AVAILABLE = $true
        $Script:GVM_FORCE_OFFLINE = $false

        It 'returns $true' {
            Get-Online-Mode | Should Be $true
        }
    }
}


Describe 'Check-Online-Mode throws an error when offline' {
    Context 'Offline' {
        Mock-Offline

        It 'throws an error' {
            { Check-Online-Mode } | Should Throw
        }
    }

    Context 'Online' {
        Mock-Online

        It 'throws no error' {
            { Check-Online-Mode } | Should Not Throw
        }
    }
}

Describe 'Invoke-API-Call helps doing calls to the GVM-API' {
    Context 'Successful API call only with API path' {
        $Script:PGVM_SERVICE = 'blub'
        Mock Invoke-RestMethod { 'called' } -parameterFilter { $Uri -eq 'blub/na/rock' }

        It 'returns the result from Invoke-RestMethod' {
            Invoke-API-Call 'na/rock' | Should Be 'called'
        }
    }

    Context 'Failed API call only with API path' {
        $Script:PGVM_SERVICE = 'blub'
        $Script:GVM_AVAILABLE = $true
        Mock Invoke-RestMethod { throw 'error' } -parameterFilter { $Uri -eq 'blub/na/rock' }
        Mock Check-Online-Mode -verifiable

        Invoke-API-Call 'na/rock'

        It 'sets GVM_AVAILABLE to false' {
            $Script:GVM_AVAILABLE | Should Be $false
        }

        It 'calls Check-Online-Mode which throws an error' {
            Assert-VerifiableMocks
        }
    }

    Context 'Failed API call with API path and IgnoreFailure' {
        $Script:PGVM_SERVICE = 'blub'
        $Script:GVM_AVAILABLE = $true
        Mock Invoke-RestMethod { throw 'error' } -parameterFilter { $Uri -eq 'blub/na/rock' }
        Mock Check-Online-Mode

        Invoke-API-Call 'na/rock' -IgnoreFailure

        It 'sets GVM_AVAILABLE to false' {
            $Script:GVM_AVAILABLE | Should Be $false
        }

        It 'do not call Check-Online-Mode' {
            Assert-MockCalled Check-Online-Mode 0
        }
    }

    Context 'Successful API call with API path and FilePath' {
        $Script:PGVM_SERVICE = 'blub'
        Mock Invoke-RestMethod -verifiable -parameterFilter { $Uri -eq 'blub/na/rock' -and $OutFile -eq 'TestDrive:a.txt' }

        Invoke-API-Call 'na/rock' TestDrive:a.txt

        It 'calls Invoke-RestMethod with file path' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Cleanup-Directory' {
    Context 'Directory with subdirectories and files' {
        New-Item -ItemType Directory TestDrive:bla | Out-Null
        New-Item -ItemType Directory TestDrive:bla\a | Out-Null
        New-Item -ItemType Directory TestDrive:bla\b | Out-Null
        New-Item -ItemType File TestDrive:bla\c | Out-Null
        New-Item -ItemType File TestDrive:bla\a\a | Out-Null

        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq '2 archive(s) flushed, freeing 0 MB' }

        Cleanup-Directory TestDrive:bla

        It 'Cleans the Test-Path file' {
            Test-Path TestDrive:bla | Should Be $False
        }

        It 'Write info to host' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Handle-Broadcast' {
    Context 'Cache broadcast message different than new broadcast' {
        Mock-PGVM-Dir
        $Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\broadcast.txt"
        Set-Content $Script:PGVM_BROADCAST_PATH 'Old Broadcast message'
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'New Broadcast message' }

        Handle-Broadcast list 'New Broadcast message'

        It 'outputs the broadcast message' {
            Assert-VerifiableMocks
        }

        It 'sets the new broadcast message in file' {
            Get-Content $Script:PGVM_BROADCAST_PATH | Should Be 'New Broadcast message'
        }


        Reset-PGVM-Dir
    }

    Context 'No cached broadcast message' {
        Mock-PGVM-Dir

        $Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\broadcast.txt"
        Mock Write-Output -verifiable -parameterFilter { $InputObject -eq 'New Broadcast message' }

        Handle-Broadcast list 'New Broadcast message'

        It 'outputs the broadcast message' {
            Assert-VerifiableMocks
        }

        It 'sets the new broadcast message in file' {
            Get-Content $Script:PGVM_BROADCAST_PATH | Should Be 'New Broadcast message'
        }

        Reset-PGVM-Dir
    }

    Context 'b do not print the new broadcast message' {
        Mock-PGVM-Dir

        $Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\broadcast.txt"
        Mock Write-Output -verifiable

        Handle-Broadcast b 'New Broadcast message'

        It 'no Broadcast' {
            Assert-MockCalled Write-Output 0
        }

        It 'sets the new broadcast message in file' {
            Test-Path $Script:PGVM_BROADCAST_PATH | Should Be $false
        }

        Reset-PGVM-Dir
    }

    Context 'Broadcast do nOt print the new broadcast message' {
        Mock-PGVM-Dir

        $Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\broadcast.txt"
        Mock Write-Output -verifiable

        Handle-Broadcast broadcast 'New Broadcast message'

        It 'no Broadcast' {
            Assert-MockCalled Write-Output 0
        }

        It 'sets the new broadcast message in file' {
            Test-Path $Script:PGVM_BROADCAST_PATH | Should Be $false
        }

        Reset-PGVM-Dir
    }

    Context 'selfupdate do not print the new broadcast message' {
        Mock-PGVM-Dir

        $Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\broadcast.txt"
        Mock Write-Output -verifiable

        Handle-Broadcast selfupdate 'New Broadcast message'

        It 'no Broadcast' {
            Assert-MockCalled Write-Output 0
        }

        It 'sets the new broadcast message in file' {
            Test-Path $Script:PGVM_BROADCAST_PATH | Should Be $false
        }

        Reset-PGVM-Dir
    }

    Context 'flush do not print the new broadcast message' {
        Mock-PGVM-Dir

        $Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\broadcast.txt"
        Mock Write-Output -verifiable

        Handle-Broadcast flush 'New Broadcast message'

        It 'no Broadcast' {
            Assert-MockCalled Write-Output 0
        }

        It 'sets the new broadcast message in file' {
            Test-Path $Script:PGVM_BROADCAST_PATH | Should Be $false
        }

        Reset-PGVM-Dir
    }
}

Describe 'Init-Candidate-Cache' {
    Context 'Candidate cache file does not exists' {
        Mock-PGVM-Dir
        $Script:PGVM_CANDIDATES_PATH = "$Global:PGVM_DIR\candidates.txt"

        It 'throws an error' {
            { Init-Candidate-Cache } | Should Throw
        }

        Reset-PGVM-Dir
    }

    Context 'Candidate cache file does exists' {
        Mock-PGVM-Dir
        $Script:PGVM_CANDIDATES_PATH = "$Global:PGVM_DIR\candidates.txt"
        Set-Content $Script:PGVM_CANDIDATES_PATH 'grails,groovy,test'
        $Script:GVM_CANDIDATES = $null

        Init-Candidate-Cache

        It 'sets `$Script:GVM_CANDIDATES' {
            $Script:GVM_CANDIDATEs | Should Be grails,groovy,test
        }

        Reset-PGVM-Dir
    }
}

Describe 'Update-Candidate-Cache' {
    Context 'Checks online mode and than get version and candidates from api' {
        Mock-PGVM-Dir

        $Script:GVM_API_VERSION_PATH = "$Global:PGVM_DIR\version.txt"
        $Script:PGVM_CANDIDATES_PATH = "$Global:PGVM_DIR\candidates.txt"

        Mock Check-Online-Mode -verifiable
        Mock Invoke-API-Call -verifiable -parameterFilter { $Path -eq 'app/version' -and $FileTarget -eq "$Global:PGVM_DIR\version.txt" }
        Mock Invoke-API-Call -verifiable -parameterFilter { $Path -eq 'candidates' -and $FileTarget -eq "$Global:PGVM_DIR\candidates.txt" }

        Update-Candidates-Cache

        It 'calls the Check-Online-Mode and two API paths' {
            Assert-VerifiableMocks
        }

        Reset-PGVM-Dir
    }
}

Describe 'Write-Offline-Version-List' {
    Context 'no versions of grails installed' {
        Mock Write-Output
        Mock Get-Current-Candidate-Version { $null } -parameterFilter { $Candidate -eq 'grails' }
        Mock Get-Installed-Candidate-Version-List { $null } -parameterFilter { $Candidate -eq 'grails' }

        Write-Offline-Version-List grails

        It 'Outputs 11 lines' {
            Assert-MockCalled Write-Output 9
        }
    }

    Context 'Three versions of grails installed' {
        Mock Write-Output
        Mock Get-Current-Candidate-Version { 1.1.1 } -parameterFilter { $Candidate -eq 'grails' }
        Mock Get-Installed-Candidate-Version-List { 1.1.1,2.2.2,2.3.0 } -parameterFilter { $Candidate -eq 'grails' }

        Write-Offline-Version-List grails

        It 'Outputs 11 lines' {
            Assert-MockCalled Write-Output 11
        }
    }
}

Describe 'Write-Version-List' {
    Context 'Three versions of grails installed' {
        Mock Write-Output
        Mock Get-Current-Candidate-Version { '1.1.1' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Get-Installed-Candidate-Version-List { return '1.1.1','2.2.2','2.3.0' } -parameterFilter { $Candidate -eq 'grails' }
        Mock Invoke-API-Call { 'bla' } -parameterFilter { $Path -eq 'candidates/grails/list?platform=posh&current=1.1.1&installed=1.1.1,2.2.2,2.3.0' }

        Write-Version-List grails

        It 'writes to host' {
            Assert-MockCalled Write-Output 1
        }
    }
}

Describe 'Install-Local-Version' {
    Context 'LocalPath is no directory' {
        New-Item -ItemType File TestDrive:a.txt | Out-Null

        It 'throws an error' {
            { Install-Local-Version grails snapshot TestDrive:a.txt } | Should Throw
        }
    }

    Context 'LocalPath is valid' {
        New-Item -ItemType Directory TestDrive:Snapshot | Out-Null
        Mock Write-Output
        Mock Set-Junction-Via-Mklink -verifiable -parameterFilter { $Link -eq "$Global:PGVM_DIR\grails\snapshot" -and $Target -eq 'TestDrive:Snapshot' }

        Install-Local-Version grails snapshot TestDrive:Snapshot

        It 'creates junction for candidate version' {
            Assert-VerifiableMocks
        }
    }
}

Describe 'Install-Remote-Version' {
    Context 'Install of a valid version without local archive' {
        Mock-PGVM-Dir

        Mock Write-Output
        Mock Check-Online-Mode -verifiable
        $Script:PGVM_SERVICE = 'foobar'
        $Script:PGVM_ARCHIVES_PATH = "$Global:PGVM_DIR\archives"
        $Script:PGVM_TEMP_PATH = "$Global:PGVM_DIR\temp"
        $testFilePath = "$PSScriptRoot\test\grails-1.3.9.zip"

        Mock Download-File -verifiable { Copy-Item $testFilePath "$Script:PGVM_ARCHIVES_PATH\grails-1.3.9.zip" } -parameterFilter { $Url -eq 'foobar/download/grails/1.3.9?platform=posh' -and $TargetFile -eq "$Script:PGVM_ARCHIVES_PATH\grails-1.3.9.zip" }

        Install-Remote-Version grails 1.3.9

        It 'downloads the archive' {
            Assert-VerifiableMocks
        }

        It 'install it correctly' {
            Test-Path "$Global:PGVM_DIR\grails\1.3.9\bin\grails" | Should be $true
        }

        Reset-PGVM-DIR
    }

    Context 'Install of a valid version with local archive' {
        Mock-PGVM-Dir

        Mock Write-Output
        Mock Download-File

        $Script:PGVM_ARCHIVES_PATH = "$Global:PGVM_DIR\archives"
        $Script:PGVM_TEMP_PATH = "$Global:PGVM_DIR\temp"
        New-Item -ItemType Directory $Script:PGVM_ARCHIVES_PATH | Out-Null
        Copy-Item "$PSScriptRoot\test\grails-1.3.9.zip" "$Script:PGVM_ARCHIVES_PATH\grails-1.3.9.zip"

        Install-Remote-Version grails 1.3.9

        It 'does not download the archive again' {
            Assert-MockCalled Download-File 0
        }

        It 'install it correctly' {
            Test-Path "$Global:PGVM_DIR\grails\1.3.9\bin\grails" | Should be $true
        }

        Reset-PGVM-DIR
    }

    Context 'Install of a currupt archive' {
        Mock-PGVM-Dir

        Mock Write-Output
        Mock Download-File

        $Script:PGVM_ARCHIVES_PATH = "$Global:PGVM_DIR\archives"
        $Script:PGVM_TEMP_PATH = "$Global:PGVM_DIR\temp"
        New-Item -ItemType Directory $Script:PGVM_ARCHIVES_PATH | Out-Null
        Copy-Item "$PSScriptRoot\test\grails-2.2.2.zip" "$Script:PGVM_ARCHIVES_PATH\grails-2.2.2.zip"

        It 'fails because of no unziped files' {
            {  Install-Remote-Version grails 2.2.2 } | Should Throw
        }

        It 'does not download the archive again' {
            Assert-MockCalled Download-File 0
        }

        Reset-PGVM-DIR
    }
}


================================================
FILE: Utils.ps1
================================================
function Write-Offline-Broadcast() {
    Write-Output @"
==== BROADCAST =================================================================

OFFLINE MODE ENABLED! Some functionality is now disabled.

================================================================================
"@
}

function Write-Online-Broadcast() {
    Write-Output @"
==== BROADCAST =================================================================

ONLINE MODE RE-ENABLED! All functionality now restored.

================================================================================

"@
}

function Write-New-Version-Broadcast() {
    if ( $Script:GVM_API_NEW_VERSION -or $Script:PGVM_NEW_VERSION ) {
Write-Output @"
==== UPDATE AVAILABLE ==========================================================

A new version is available. Please consider to execute:

    gvm selfupdate

================================================================================
"@
    }
}

function Check-GVM-API-Version() {
    Write-Verbose 'Checking GVM-API version'
    try {
        $apiVersion = Get-GVM-API-Version
        $gvmRemoteVersion = Invoke-API-Call "app/version"

        if ( $gvmRemoteVersion -gt $apiVersion) {
            if ( $Global:PGVM_AUTO_SELFUPDATE ) {
                Invoke-Self-Update
            } else {
                $Script:GVM_API_NEW_VERSION = $true
            }
        }
    } catch {
        $Script:GVM_AVAILABLE = $false
    }
}

function Check-Posh-Gvm-Version() {
    Write-Verbose 'Checking posh-gvm version'
    if ( Is-New-Posh-GVM-Version-Available ) {
        if ( $Global:PGVM_AUTO_SELFUPDATE ) {
            Invoke-Self-Update
        } else {
            $Script:PGVM_NEW_VERSION = $true
        }
    }
}

function Get-Posh-Gvm-Version() {
    return Get-Content $Script:PGVM_VERSION_PATH
}

function Is-New-Posh-GVM-Version-Available() {
    try {
        $localVersion = (Get-Posh-Gvm-Version).Trim()
        $currentVersion = (Invoke-RestMethod $Script:PGVM_VERSION_SERVICE).Trim()

        Write-Verbose "posh-gvm version check $currentVersion > $localVersion = $($currentVersion -gt $localVersion)"

        return ( $currentVersion -gt $localVersion )
    } catch {
        return $false
    }
}

function Get-GVM-API-Version() {
	if ( !(Test-Path $Script:GVM_API_VERSION_PATH) ) {
		return $null
	}
    return Get-Content $Script:GVM_API_VERSION_PATH
}

function Check-Available-Broadcast($Command) {
    $version = Get-GVM-API-Version
    if ( !( $version ) ) {
        return
    }

    $liveBroadcast = Invoke-Broadcast-API-Call

	Write-Verbose "Online-Mode: $Script:GVM_AVAILABLE"

	if ( $Script:GVM_ONLINE -and !($Script:GVM_AVAILABLE) ) {
		Write-Offline-Broadcast
	} elseif ( !($Script:GVM_ONLINE) -and $Script:GVM_AVAILABLE ) {
		Write-Online-Broadcast
	}
	$Script:GVM_ONLINE = $Script:GVM_AVAILABLE

	if ( $liveBroadcast ) {
		Handle-Broadcast $Command $liveBroadcast
	}
}

function Invoke-Broadcast-API-Call {
    try {
        $target = "$Script:PGVM_BROADCAST_SERVICE/broadcast/latest"
        Write-Verbose "Broadcast API call to: $target"
        return Invoke-RestMethod $target
    } catch {
        Write-Verbose "Could not reached broadcast API"
        $Script:GVM_AVAILABLE = $false
        return $null
    }
}

function Invoke-Self-Update($Force) {
    Write-Verbose 'Perform Invoke-Self-Update'
    Write-Output 'Update list of available candidates...'
    Update-Candidates-Cache
    $Script:GVM_API_NEW_VERSION = $false
    if ( $Force ) {
        Invoke-Posh-Gvm-Update
    } else {
        if ( Is-New-Posh-GVM-Version-Available ) {
            Invoke-Posh-Gvm-Update
        }
    }
    $Script:PGVM_NEW_VERSION = $false
}

function Invoke-Posh-Gvm-Update {
    Write-Output 'Update posh-gvm...'
    . "$psScriptRoot\GetPoshGvm.ps1"
}

function Check-Candidate-Present($Candidate) {
    if ( !($Candidate) ) {
        throw 'No candidate provided.'
    }

    if ( !($Script:GVM_CANDIDATES -contains $Candidate) ) {
        throw "Stop! $Candidate is no valid candidate!"
    }
}

function Check-Version-Present($Version) {
    if ( !($Version)) {
        throw 'No version provided.'
    }
}

function Check-Candidate-Version-Available($Candidate, $Version) {
    Check-Candidate-Present $Candidate

    $UseDefault = $false
    if ( !($Version) ) {
        Write-Verbose 'No version provided. Fallback to default version!'
        $UseDefault = $true
    }

    # Check locally
    elseif ( Is-Candidate-Version-Locally-Available $Candidate $Version ) {
        return $Version
    }

    # Check if offline
    if ( ! (Get-Online-Mode) ) {
        if ( $UseDefault ) {
            $Version = Get-Current-Candidate-Version $Candidate
            if ( $Version ) {
                return $Version
            } else {
                throw "Stop! No local default version for $Candidate and in offline mode."
            }
        }

        throw "Stop! $Candidate $Version is not available in offline mode."
    }

    if ( $UseDefault ) {
        Write-Verbose 'Try to get default version from remote'
        return Invoke-API-Call "candidates/$Candidate/default"
    }

    $VersionAvailable = Invoke-API-Call "candidates/$Candidate/$Version"

    if ( $VersionAvailable -eq 'valid' ) {
        return $Version
    } else {
        throw "Stop! $Version is not a valid $Candidate version."
    }
}

function Get-Current-Candidate-Version($Candidate) {
    $currentLink = "$Global:PGVM_DIR\$Candidate\current"

    $targetItem = Get-Junction-Target $currentLink

    if ($targetItem) {
        return $targetItem.Name
    }

    return $null
}

function Get-Junction-Target($linkPath) {
    if ( Test-Path $linkPath ) {
        try {
            $linkItem = Get-Item $linkPath

            if (Get-Member -InputObject $linkItem -Name "ReparsePoint") {
                return (Get-Item $linkItem.ReparsePoint.Target)
            }

            if (Get-Member -InputObject $linkItem -Name "Target") {
                return (Get-Item $linkItem.Target)
            }
        } catch {
            return $null
        }
    }

    return $null
}

function Get-Env-Candidate-Version($Candidate) {
    $envLink = [System.Environment]::GetEnvironmentVariable(([string]$Candidate).ToUpper() + "_HOME")

    if ( $envLink -match '(.*)current$' ) {
        Get-Current-Candidate-Version $Candidate
    } else {
        return (Get-Item $envLink).Name
    }
}

function Check-Candidate-Version-Locally-Available($Candidate, $Version) {
    if ( !(Is-Candidate-Version-Locally-Available $Candidate $Version) ) {
        throw "Stop! $Candidate $Version is not installed."
    }
}

function Is-Candidate-Version-Locally-Available($Candidate, $Version) {
    if ( $Version ) {
        return Test-Path "$Global:PGVM_DIR\$Candidate\$Version"
    } else {
        return $false
    }
}

function Get-Installed-Candidate-Version-List($Candidate) {
    return Get-ChildItem "$Global:PGVM_DIR\$Candidate" | ?{ $_.PSIsContainer -and $_.Name -ne 'current' } | Foreach { $_.Name }
}

function Set-Env-Candidate-Version($Candidate, $Version) {
    $candidateEnv = ([string]$candidate).ToUpper() + "_HOME"
    $candidateDir = "$Global:PGVM_DIR\$candidate"
    $candidateHome = "$candidateDir\$Version"
    $candidateBin = "$candidateHome\bin"

    if ( !([Environment]::GetEnvironmentVariable($candidateEnv) -eq $candidateHome) ) {
        [Environment]::SetEnvironmentVariable($candidateEnv, $candidateHome)
    }

    $env:PATH = "$candidateBin;$env:PATH"
}

function Set-Linked-Candidate-Version($Candidate, $Version) {
    $Link = "$Global:PGVM_DIR\$Candidate\current"
    $Target = "$Global:PGVM_DIR\$Candidate\$Version"
    Set-Junction-Via-Mklink $Link $Target
}

function Set-Junction-Via-Mklink($Link, $Target) {
    if ( Test-Path $Link ) {
        (Get-Item $Link).Delete()
    }

    Invoke-Expression -Command "cmd.exe /c mklink /J '$Link' '$Target'" | Out-Null
}

function Get-Online-Mode() {
    return $Script:GVM_AVAILABLE -and ! ($Script:GVM_FORCE_OFFLINE)
}

function Check-Online-Mode() {
    if ( ! (Get-Online-Mode) ) {
        throw 'This command is not available in offline mode.'
    }
}

function Invoke-API-Call([string]$Path, [string]$FileTarget, [switch]$IgnoreFailure) {
    try {
        $target = "$Script:PGVM_SERVICE/$Path"

        if ( $FileTarget ) {
            return Invoke-RestMethod $target -OutFile $FileTarget
        }

        return Invoke-RestMethod $target
    } catch {
        $Script:GVM_AVAILABLE = $false
        if ( ! ($IgnoreFailure) ) {
            Check-Online-Mode
        } else {
			return $null
		}
    }
}

function Cleanup-Directory($Path) {
    $dirStats = Get-ChildItem $Path -Recurse | Measure-Object -property length -sum
    Remove-Item -Force -Recurse $Path
    $count = $dirStats.Count
    $size = $dirStats.Sum/(1024*1024)
    Write-Output "$count archive(s) flushed, freeing $size MB"
}

function Handle-Broadcast($Command, $Broadcast) {
    $oldBroadcast = $null
    if (Test-Path $Script:PGVM_BROADCAST_PATH) {
        $oldBroadcast = (Get-Content $Script:PGVM_BROADCAST_PATH) -join "`n"
        Write-Verbose 'Old broadcast message loaded'
    }

    if ($oldBroadcast -ne $Broadcast -and !($Command -match 'b(roadcast)?') -and $Command -ne 'selfupdate' -and $Command -ne 'flush' ) {
        Write-Verbose 'Showing the new broadcast message'
        Set-Content $Script:PGVM_BROADCAST_PATH $Broadcast
        Write-Output $Broadcast
    }
}

function Init-Candidate-Cache() {
    if ( !(Test-Path $Script:PGVM_CANDIDATES_PATH) ) {
        throw 'Can not retrieve list of candidates'
    }

    $Script:GVM_CANDIDATES = (Get-Content $Script:PGVM_CANDIDATES_PATH).Split(',')
    Write-Verbose "Available candidates: $Script:GVM_CANDIDATES"
}

function Update-Candidates-Cache() {
    Write-Verbose 'Update candidates-cache from GVM-API'
    Check-Online-Mode
    Invoke-Api-Call 'app/version' $Script:GVM_API_VERSION_PATH
    Invoke-API-Call 'candidates' $Script:PGVM_CANDIDATES_PATH
}

function Write-Offline-Version-List($Candidate) {
    Write-Verbose 'Get version list from directory'

    Write-Output '------------------------------------------------------------'
    Write-Output "Offline Mode: only showing installed ${Candidate} versions"
    Write-Output '------------------------------------------------------------'
    Write-Output ''

    $current = Get-Current-Candidate-Version $Candidate
    $versions = Get-Installed-Candidate-Version-List $Candidate

    if ($versions) {
        foreach ($version in $versions) {
            if ($version -eq $current) {
                Write-Output " > $version"
            } else {
                Write-Output " * $version"
            }
        }
    } else {
        Write-Output '    None installed!'
    }

    Write-Output '------------------------------------------------------------'
	Write-Output '* - installed                                               '
	Write-Output '> - currently in use                                        '
	Write-Output '------------------------------------------------------------'
}

function Write-Version-List($Candidate) {
    Write-Verbose 'Get version list from API'

    $current = Get-Current-Candidate-Version $Candidate
    $versions = (Get-Installed-Candidate-Version-List $Candidate) -join ','
    Invoke-API-Call "candidates/$Candidate/list?platform=posh&current=$current&installed=$versions" | Write-Output
}

function Install-Local-Version($Candidate, $Version, $LocalPath) {
    $dir = Get-Item $LocalPath

    if ( !(Test-Path $dir -PathType Container) ) {
        throw "Local installation path $LocalPath is no directory"
    }

    Write-Output "Linking $Candidate $Version to $LocalPath"
    $link = "$Global:PGVM_DIR\$Candidate\$Version"
    Set-Junction-Via-Mklink $link $LocalPath
    Write-Output "Done installing!"
}

function Install-Remote-Version($Candidate, $Version) {

    if ( !(Test-Path $Script:PGVM_ARCHIVES_PATH) ) {
        New-Item -ItemType Directory $Script:PGVM_ARCHIVES_PATH | Out-Null
    }

    $archive = "$Script:PGVM_ARCHIVES_PATH\$Candidate-$Version.zip"
    if ( Test-Path $archive ) {
        Write-Output "Found a previously downloaded $Candidate $Version archive. Not downloading it again..."
    } else {
		Check-Online-Mode
        Write-Output "`nDownloading: $Candidate $Version`n"
        Download-File "$Script:PGVM_SERVICE/download/$Candidate/$Version`?platform=posh" $archive
    }

    Write-Output "Installing: $Candidate $Version"

    # create temp dir if necessary
    if ( !(Test-Path $Script:PGVM_TEMP_PATH) ) {
        New-Item -ItemType Directory $Script:PGVM_TEMP_PATH | Out-Null
    }

    # unzip downloaded archive
    Unzip-Archive $archive $Script:PGVM_TEMP_PATH

	# check if unzip successfully
	if ( !(Test-Path "$Script:PGVM_TEMP_PATH\*-$Version") ) {
		throw "Could not unzip the archive of $Candidate $Version. Please delete archive from $Script:PGVM_ARCHIVES_PATH (or delete all with 'gvm flush archives'"
	}

    # move to target location
    # Move was replaced by copy and remove because of random access denied errors
    # when Unzip was done by via -com shell.application
    # Move-Item "$Script:PGVM_TEMP_PATH\*-$Version" "$Global:PGVM_DIR\$Candidate\$Version"
    Copy-Item "$Script:PGVM_TEMP_PATH\*-$Version" "$Global:PGVM_DIR\$Candidate\$Version" -Recurse
    Remove-Item "$Script:PGVM_TEMP_PATH\*-$Version" -Recurse -Force
    Write-Output "Done installing!"
}

function Unzip-Archive($Archive, $Target) {
    if ( $Script:SEVENZ_On_PATH ) {
        $zipProcess = Start-Process 7z.exe -ArgumentList "x -o`"$Target`" -y `"$Archive`"" -Wait -PassThru -NoNewWindow

        if ($zipProcess.ExitCode -ne 0) {
            Remove-Item $Target -Recurse -Force
        }
    } elseif ( $Script:UNZIP_ON_PATH ) {
        unzip.exe -oq $Archive -d $Target
    } else {
        # use the windows shell as general fallback (no working on Windows Server Core because there is no shell)
        $shell = New-Object -com shell.application
        $shell.namespace($Target).copyhere($shell.namespace($Archive).items(), 0x10)
    }
}

function Download-File($Url, $TargetFile) {
	<#
		Adepted from http://blogs.msdn.com/b/jasonn/archive/2008/06/13/downloading-files-from-the-internet-in-powershell-with-progress.aspx
	#>
    Write-Verbose "Try to download $Url with HttpWebRequest"
	$uri = New-Object "System.Uri" $Url
    $request = [System.Net.HttpWebRequest]::Create($uri)
    $request.set_Timeout(15000)
    $response = $request.GetResponse()
	$totalLength = [System.Math]::Floor($response.get_ContentLength()/1024)
	$responseStream = $response.GetResponseStream()
    $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create
	$buffer = new-object byte[] 10KB
    $count = $responseStream.Read($buffer,0,$buffer.length)
    $downloadedBytes = $count
	while ($count -gt 0)
    {
        if ($totalLength -lt 0) {
            $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024)
        }
        [System.Console]::CursorLeft = 0
        [System.Console]::Write("Downloaded {0}K of {1}K", [System.Math]::Floor($downloadedBytes/1024), $totalLength)
        $targetStream.Write($buffer, 0, $count)
        $count = $responseStream.Read($buffer,0,$buffer.length)
        $downloadedBytes = $downloadedBytes + $count
    }
    $targetStream.Flush()
    $targetStream.Close()
    $targetStream.Dispose()
    $responseStream.Dispose()
    Write-Output ''
}


================================================
FILE: VERSION.txt
================================================
1.3.1


================================================
FILE: posh-gvm.psm1
================================================
<#
posh-gvm / POwerSHell Groovy enVironment Manager

https://github.com/flofreud/posh-gvm

Needed:
- Powershell 3.0 (For Windows 7 install Windows Management Framework 3.0)
#>

#region Config
if ( !(Test-Path Variable:Global:PGVM_DIR) ) {
	$Global:PGVM_DIR = "$env:USERPROFILE\.posh_gvm"
}
if ( !(Test-Path Variable:Global:PGVM_AUTO_ANSWER) ) {
	$Global:PGVM_AUTO_ANSWER = $false
}
if ( !(Test-Path Variable:Global:PGVM_AUTO_SELFUPDATE) ) {
	$Global:PGVM_AUTO_SELFUPDATE = $false
}

$Script:PGVM_INIT = $false
$Script:PGVM_SERVICE = 'https://api.sdkman.io'
$Script:PGVM_BROADCAST_SERVICE = 'https://api.sdkman.io/2'
$Script:GVM_BASE_VERSION = '1.3.13'

$Script:PGVM_CANDIDATES_PATH = "$Global:PGVM_DIR\.meta\candidates.txt"
$Script:PGVM_BROADCAST_PATH = "$Global:PGVM_DIR\.meta\broadcast.txt"
$Script:GVM_API_VERSION_PATH = "$Global:PGVM_DIR\.meta\version.txt"
$Script:PGVM_ARCHIVES_PATH = "$Global:PGVM_DIR\.meta\archives"
$Script:PGVM_TEMP_PATH = "$Global:PGVM_DIR\.meta\tmp"

$Script:GVM_API_NEW_VERSION = $false
$Script:PGVM_NEW_VERSION = $false
$Script:PGVM_VERSION_PATH = "$psScriptRoot\VERSION.txt"
$Script:PGVM_VERSION_SERVICE = "https://raw.githubusercontent.com/flofreud/posh-gvm/master/VERSION.txt"

$Script:GVM_AVAILABLE = $true
$Script:GVM_ONLINE = $true
$Script:GVM_FORCE_OFFLINE = $false
$Script:GVM_CANDIDATES = $null
$Script:FIRST_RUN = $true

$Script:UNZIP_ON_PATH = $false
#endregion

Push-Location $psScriptRoot
. .\Utils.ps1
. .\Commands.ps1
. .\Init.ps1
. .\TabExpansion.ps1
Pop-Location

Init-Posh-Gvm

Export-ModuleMember 'gvm'
Download .txt
gitextract_9qyeor5j/

├── CHANGELOG.md
├── Commands.Tests.ps1
├── Commands.ps1
├── GetPoshGvm.ps1
├── Init.Tests.ps1
├── Init.ps1
├── LICENSE
├── README.md
├── TabExpansion.ps1
├── TestUtils.ps1
├── Utils.Tests.ps1
├── Utils.ps1
├── VERSION.txt
└── posh-gvm.psm1
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (120K chars).
[
  {
    "path": "CHANGELOG.md",
    "chars": 1224,
    "preview": "### Version 1.3.0\n* BUGFIX: update url to API endpoint\n* BUGFIX: support for symlink handling in Win10\n* IMPROVE: use 7z"
  },
  {
    "path": "Commands.Tests.ps1",
    "chars": 28277,
    "preview": ". .\\Commands.ps1\n. .\\Utils.ps1\n. .\\Init.ps1\n. .\\TestUtils.ps1\n\nDescribe 'gvm' {\n    Context 'No posh-gvm dir available'{"
  },
  {
    "path": "Commands.ps1",
    "chars": 9234,
    "preview": "function gvm([string]$Command, [string]$Candidate, [string]$Version, [string]$InstallPath, [switch]$Verbose, [switch]$F"
  },
  {
    "path": "GetPoshGvm.ps1",
    "chars": 2495,
    "preview": "<#\n\tParagon for the installation script is PsGet\n#>\n\nfunction Install-Posh-Gvm() {\n    $poshGvmZipUrl = 'https://github."
  },
  {
    "path": "Init.Tests.ps1",
    "chars": 4300,
    "preview": ". .\\Utils.ps1\n. .\\Init.ps1\n. .\\TestUtils.ps1\n\nDescribe 'Init-Posh-Gvm' {\n    Context 'PGVM-Dir with only a grails folder"
  },
  {
    "path": "Init.ps1",
    "chars": 1604,
    "preview": "#region Initialization\nfunction Init-Posh-Gvm() {\n    Write-Verbose 'Init posh-gvm'\n\n    $ErrorActionPreference = 'Stop'"
  },
  {
    "path": "LICENSE",
    "chars": 10174,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 127,
    "preview": "The code inside of this repository is broken. If you need the functionality of SDKMAN on Windows consider using Docker o"
  },
  {
    "path": "TabExpansion.ps1",
    "chars": 3541,
    "preview": "# Check if function TabExpansion already exists and backup existing version to\n# prevent breaking other TabExpansion im"
  },
  {
    "path": "TestUtils.ps1",
    "chars": 2600,
    "preview": ". .\\Utils.ps1\n\nfunction Mock-Check-Candidate-Grails {\n    Mock Check-Candidate-Present -verifiable -parameterFilter { $"
  },
  {
    "path": "Utils.Tests.ps1",
    "chars": 34407,
    "preview": ". .\\Utils.ps1\n. .\\TestUtils.ps1\n\nDescribe 'Check-GVM-API-Version' {\n    Context 'API offline' {\n        $Script:GVM_AVA"
  },
  {
    "path": "Utils.ps1",
    "chars": 15486,
    "preview": "function Write-Offline-Broadcast() {\n    Write-Output @\"\n==== BROADCAST ==============================================="
  },
  {
    "path": "VERSION.txt",
    "chars": 6,
    "preview": "1.3.1\n"
  },
  {
    "path": "posh-gvm.psm1",
    "chars": 1553,
    "preview": "<#\nposh-gvm / POwerSHell Groovy enVironment Manager\n\nhttps://github.com/flofreud/posh-gvm\n\nNeeded:\n- Powershell 3.0 (Fo"
  }
]

About this extraction

This page contains the full source code of the flofreud/posh-gvm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (112.3 KB), approximately 29.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!