functions/Get-EndjinGist.Tests.ps1
|
# <copyright file="Get-EndjinGist.Tests.ps1" company="Endjin Limited"> # Copyright (c) Endjin Limited. All rights reserved. # </copyright> Describe "Get-EndjinGist" { BeforeAll { # Define stubs for external module functions to avoid dependency and ensure mocking works function ConvertTo-Yaml { param($Data, $OutFile, [switch]$Force) } function ConvertFrom-Yaml { param([switch]$Ordered) } $sut = "$PSScriptRoot\Get-EndjinGist.ps1" . $sut # Mock Data $mockGistMap = @{ 'test-group' = @( @{ name = 'test-gist' source = 'https://github.com/org/repo.git' ref = 'main' includePaths = @('path/to/include') } ) } } Context "Prerequisites" { It "Should throw if 'vendir' is not in PATH" { Mock Get-Command { return $null } -ParameterFilter { $Name -eq 'vendir' } { Get-EndjinGist -Group 'any' -Name 'any' -GistMapPath 'dummy' } | Should -Throw "Please install 'vendir' to your PATH before using this tool." } } Context "Input Validation" { BeforeAll { Mock Get-Command { return $true } -ParameterFilter { $Name -eq 'vendir' } Mock Get-Content { return "yaml content" } Mock ConvertFrom-Yaml { return $mockGistMap } } It "Should throw if Group is unknown" { { Get-EndjinGist -Group 'unknown-group' -Name 'test-gist' -GistMapPath 'dummy' } | Should -Throw "Unknown gist group: unknown-group" } It "Should throw if Name is unknown in Group" { { Get-EndjinGist -Group 'test-group' -Name 'unknown-gist' -GistMapPath 'dummy' } | Should -Throw "Unknown gist 'unknown-gist' in group 'test-group'" } } Context "Execution" { BeforeAll { Mock Get-Command { return $true } -ParameterFilter { $Name -eq 'vendir' } Mock Get-Content { return "yaml content" } Mock ConvertFrom-Yaml { return $mockGistMap } Mock ConvertTo-Yaml { } Mock Remove-Item { } Mock Write-Host { } } It "Should invoke vendir with generated config" { Mock Invoke-Command { $global:LASTEXITCODE = 0 return "Success" } Get-EndjinGist -Group 'test-group' -Name 'test-gist' -GistMapPath 'dummy' Assert-MockCalled ConvertTo-Yaml -Times 1 Assert-MockCalled Invoke-Command -Times 1 } It "Should handle vendir failure" { Mock Invoke-Command { # Simulate failure $global:LASTEXITCODE = 1 return "Error message" } { Get-EndjinGist -Group 'test-group' -Name 'test-gist' -GistMapPath 'dummy' } | Should -Throw "Operation failed with exit code 1.`nError message" } } Context "MovePaths Processing" { BeforeAll { $mockGistMapWithMovePaths = @{ 'test-group' = @( @{ name = 'test-gist' source = 'https://github.com/org/repo.git' ref = 'main' includePaths = @('content/**/*') movePaths = @( @{ from = 'content/**/*' to = '${repoRoot}/target/' } ) } ) } Mock Get-Command { return $true } -ParameterFilter { $Name -eq 'vendir' } Mock Get-Content { return "yaml content" } Mock ConvertTo-Yaml { } Mock Write-Host { } } It "Should expand repoRoot variable in destination path" { Mock ConvertFrom-Yaml { return $mockGistMapWithMovePaths } Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" } Mock Remove-Item { } # Mock git to return a specific repo root Mock git { return '/mock/repo/root' } -ParameterFilter { $args[0] -eq 'rev-parse' } # Mock Get-ChildItem to return no files (avoiding actual file operations) Mock Get-ChildItem { return @() } Get-EndjinGist -Group 'test-group' -Name 'test-gist' -GistMapPath 'dummy' # Verify the function executed without errors (variable expansion happened internally) Should -Invoke Invoke-Command -Times 1 } It "Should not process moves if movePaths is not defined" { $mockGistMapWithoutMovePaths = @{ 'test-group' = @( @{ name = 'test-gist' source = 'https://github.com/org/repo.git' ref = 'main' includePaths = @('content/**/*') } ) } Mock ConvertFrom-Yaml { return $mockGistMapWithoutMovePaths } Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" } Mock Remove-Item { } Mock Move-Item { } Get-EndjinGist -Group 'test-group' -Name 'test-gist' -GistMapPath 'dummy' # Move-Item should never be called when movePaths is not defined Should -Invoke Move-Item -Times 0 } It "Should move files and preserve directory structure" { Mock ConvertFrom-Yaml { return $mockGistMapWithMovePaths } Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" } Mock Remove-Item { } Mock git { return $TestDrive } -ParameterFilter { $args[0] -eq 'rev-parse' } # Setup source files in TestDrive $sourceDir = Join-Path $TestDrive '.endjin/test-group/test-gist/content' $subDir = Join-Path $sourceDir 'subfolder' New-Item -ItemType Directory -Path $subDir -Force | Out-Null Set-Content -Path (Join-Path $sourceDir 'file1.txt') -Value 'content1' Set-Content -Path (Join-Path $subDir 'file2.txt') -Value 'content2' # Run in TestDrive context Push-Location $TestDrive try { Get-EndjinGist -Group 'test-group' -Name 'test-gist' -GistMapPath 'dummy' } finally { Pop-Location } # Verify files were moved to target with preserved structure $targetFile1 = Join-Path $TestDrive 'target/file1.txt' $targetFile2 = Join-Path $TestDrive 'target/subfolder/file2.txt' Test-Path $targetFile1 | Should -Be $true Test-Path $targetFile2 | Should -Be $true # Use [System.IO.File] to bypass the Get-Content mock [System.IO.File]::ReadAllText($targetFile1).Trim() | Should -Be 'content1' [System.IO.File]::ReadAllText($targetFile2).Trim() | Should -Be 'content2' } It "Should clean up empty source directories after move" { Mock ConvertFrom-Yaml { return $mockGistMapWithMovePaths } Mock Invoke-Command { $global:LASTEXITCODE = 0; return "Success" } Mock Remove-Item { } -ParameterFilter { $Path -like '*vendir*' -or $Path -like '*.yml' } Mock git { return $TestDrive } -ParameterFilter { $args[0] -eq 'rev-parse' } # Setup source files in TestDrive $sourceDir = Join-Path $TestDrive '.endjin/test-group/test-gist/content' New-Item -ItemType Directory -Path $sourceDir -Force | Out-Null Set-Content -Path (Join-Path $sourceDir 'file.txt') -Value 'content' Push-Location $TestDrive try { Get-EndjinGist -Group 'test-group' -Name 'test-gist' -GistMapPath 'dummy' } finally { Pop-Location } # Source directory should be cleaned up (empty after move) Test-Path $sourceDir | Should -Be $false } } } |