microsoft/hve-core
Publicmirrored fromhttps://github.com/microsoft/hve-coreAvailable
scripts/tests/linting/Markdown-Link-Check.Tests.ps1
202lines · modecode
| 1 | #Requires -Modules Pester |
| 2 | <# |
| 3 | .SYNOPSIS |
| 4 | Pester tests for Markdown-Link-Check.ps1 script |
| 5 | .DESCRIPTION |
| 6 | Tests for markdown link checking wrapper functions: |
| 7 | - Get-MarkdownTarget |
| 8 | - Get-RelativePrefix |
| 9 | #> |
| 10 | |
| 11 | BeforeAll { |
| 12 | # Extract functions from script using AST |
| 13 | $scriptPath = Join-Path $PSScriptRoot '../../linting/Markdown-Link-Check.ps1' |
| 14 | $scriptContent = Get-Content -Path $scriptPath -Raw |
| 15 | $ast = [System.Management.Automation.Language.Parser]::ParseInput($scriptContent, [ref]$null, [ref]$null) |
| 16 | $functions = $ast.FindAll({ param($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true) |
| 17 | |
| 18 | foreach ($func in $functions) { |
| 19 | . ([scriptblock]::Create($func.Extent.Text)) |
| 20 | } |
| 21 | |
| 22 | # Import LintingHelpers for mocking |
| 23 | Import-Module (Join-Path $PSScriptRoot '../../linting/Modules/LintingHelpers.psm1') -Force |
| 24 | |
| 25 | $script:FixtureDir = Join-Path $PSScriptRoot '../Fixtures/Linting' |
| 26 | } |
| 27 | |
| 28 | AfterAll { |
| 29 | Remove-Module LintingHelpers -Force -ErrorAction SilentlyContinue |
| 30 | } |
| 31 | |
| 32 | #region Get-MarkdownTarget Tests |
| 33 | |
| 34 | Describe 'Get-MarkdownTarget' -Tag 'Unit' { |
| 35 | BeforeAll { |
| 36 | # Create a temp directory to use as test input |
| 37 | $script:TempDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString()) |
| 38 | New-Item -ItemType Directory -Path $script:TempDir -Force | Out-Null |
| 39 | } |
| 40 | |
| 41 | AfterAll { |
| 42 | Remove-Item -Path $script:TempDir -Recurse -Force -ErrorAction SilentlyContinue |
| 43 | } |
| 44 | |
| 45 | Context 'Git-tracked files in repository' { |
| 46 | BeforeEach { |
| 47 | # Create test markdown files |
| 48 | $script:TestFile1 = Join-Path $script:TempDir 'test1.md' |
| 49 | $script:TestFile2 = Join-Path $script:TempDir 'test2.md' |
| 50 | Set-Content -Path $script:TestFile1 -Value '# Test 1' |
| 51 | Set-Content -Path $script:TestFile2 -Value '# Test 2' |
| 52 | |
| 53 | # Mock git to indicate we're in a repo and return tracked files |
| 54 | Mock git { |
| 55 | if ($args -contains 'rev-parse') { |
| 56 | $global:LASTEXITCODE = 0 |
| 57 | return $script:TempDir |
| 58 | } |
| 59 | elseif ($args -contains 'ls-files') { |
| 60 | $global:LASTEXITCODE = 0 |
| 61 | return @('test1.md', 'test2.md') |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | It 'Returns markdown files when given a directory' { |
| 67 | $result = Get-MarkdownTarget -InputPath $script:TempDir |
| 68 | $result | Should -Not -BeNullOrEmpty |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | Context 'Non-git fallback mode' { |
| 73 | BeforeEach { |
| 74 | # Create test files |
| 75 | $script:TestFile = Join-Path $script:TempDir 'readme.md' |
| 76 | Set-Content -Path $script:TestFile -Value '# Readme' |
| 77 | |
| 78 | # Mock git to simulate not being in a repo |
| 79 | Mock git { |
| 80 | $global:LASTEXITCODE = 128 |
| 81 | return 'fatal: not a git repository' |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | It 'Falls back to filesystem when not in git repo' { |
| 86 | $result = Get-MarkdownTarget -InputPath $script:TempDir |
| 87 | $result | Should -Not -BeNullOrEmpty |
| 88 | } |
| 89 | |
| 90 | It 'Returns absolute paths' { |
| 91 | $result = Get-MarkdownTarget -InputPath $script:TempDir |
| 92 | if ($result) { |
| 93 | [System.IO.Path]::IsPathRooted($result[0]) | Should -BeTrue |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | Context 'Empty input handling' { |
| 99 | It 'Returns empty array for null input' { |
| 100 | $result = Get-MarkdownTarget -InputPath $null |
| 101 | $result | Should -BeNullOrEmpty |
| 102 | } |
| 103 | |
| 104 | It 'Returns empty array for empty string input' { |
| 105 | $result = Get-MarkdownTarget -InputPath '' |
| 106 | $result | Should -BeNullOrEmpty |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | #endregion |
| 112 | |
| 113 | #region Get-RelativePrefix Tests |
| 114 | |
| 115 | Describe 'Get-RelativePrefix' -Tag 'Unit' { |
| 116 | BeforeAll { |
| 117 | # Create a temp directory structure for testing relative paths |
| 118 | $script:TempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString()) |
| 119 | New-Item -ItemType Directory -Path $script:TempRoot -Force | Out-Null |
| 120 | New-Item -ItemType Directory -Path (Join-Path $script:TempRoot 'docs') -Force | Out-Null |
| 121 | New-Item -ItemType Directory -Path (Join-Path $script:TempRoot 'docs/guide') -Force | Out-Null |
| 122 | New-Item -ItemType Directory -Path (Join-Path $script:TempRoot 'src') -Force | Out-Null |
| 123 | } |
| 124 | |
| 125 | AfterAll { |
| 126 | Remove-Item -Path $script:TempRoot -Recurse -Force -ErrorAction SilentlyContinue |
| 127 | } |
| 128 | |
| 129 | Context 'Nested directory traversal' { |
| 130 | It 'Returns relative prefix from subdirectory to root' { |
| 131 | $fromPath = Join-Path $script:TempRoot 'docs/guide' |
| 132 | $result = Get-RelativePrefix -FromPath $fromPath -ToPath $script:TempRoot |
| 133 | $result | Should -Be '../../' |
| 134 | } |
| 135 | |
| 136 | It 'Returns relative prefix from single-level directory to root' { |
| 137 | $fromPath = Join-Path $script:TempRoot 'docs' |
| 138 | $result = Get-RelativePrefix -FromPath $fromPath -ToPath $script:TempRoot |
| 139 | $result | Should -Be '../' |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | Context 'Same directory' { |
| 144 | It 'Returns empty string for same directory' { |
| 145 | $result = Get-RelativePrefix -FromPath $script:TempRoot -ToPath $script:TempRoot |
| 146 | $result | Should -Be '' |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | Context 'Sibling directories' { |
| 151 | It 'Returns correct prefix between sibling directories' { |
| 152 | $fromPath = Join-Path $script:TempRoot 'docs' |
| 153 | $toPath = Join-Path $script:TempRoot 'src' |
| 154 | $result = Get-RelativePrefix -FromPath $fromPath -ToPath $toPath |
| 155 | $result | Should -Be '../src/' |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | Context 'Forward slash normalization' { |
| 160 | It 'Returns forward slashes on Windows' { |
| 161 | $fromPath = Join-Path $script:TempRoot 'docs/guide' |
| 162 | $result = Get-RelativePrefix -FromPath $fromPath -ToPath $script:TempRoot |
| 163 | $result | Should -Not -Match '\\' |
| 164 | } |
| 165 | |
| 166 | It 'Always has trailing slash when not empty' { |
| 167 | $fromPath = Join-Path $script:TempRoot 'docs' |
| 168 | $result = Get-RelativePrefix -FromPath $fromPath -ToPath $script:TempRoot |
| 169 | if ($result -ne '') { |
| 170 | $result | Should -Match '/$' |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | #endregion |
| 177 | |
| 178 | #region Script Integration Tests |
| 179 | |
| 180 | Describe 'Markdown-Link-Check Integration' -Tag 'Integration' { |
| 181 | Context 'Config file loading' { |
| 182 | BeforeAll { |
| 183 | $script:ConfigPath = Join-Path $PSScriptRoot '../Fixtures/Linting/link-check-config.json' |
| 184 | } |
| 185 | |
| 186 | It 'Config fixture file exists' { |
| 187 | Test-Path $script:ConfigPath | Should -BeTrue |
| 188 | } |
| 189 | |
| 190 | It 'Config fixture is valid JSON' { |
| 191 | { Get-Content $script:ConfigPath | ConvertFrom-Json } | Should -Not -Throw |
| 192 | } |
| 193 | |
| 194 | It 'Config contains expected properties' { |
| 195 | $config = Get-Content $script:ConfigPath | ConvertFrom-Json |
| 196 | $config.PSObject.Properties.Name | Should -Contain 'ignorePatterns' |
| 197 | $config.PSObject.Properties.Name | Should -Contain 'replacementPatterns' |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | #endregion |
| 203 | |