microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/update-workflow-file-and-script

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/skills/shared/pr-reference/tests/generate.Tests.ps1

373lines · modecode

1#Requires -Modules Pester
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5BeforeAll {
6 . (Join-Path -Path $PSScriptRoot -ChildPath '../scripts/generate.ps1')
7}
8
9Describe 'Test-GitAvailability' {
10 It 'Does not throw when git is available' {
11 # This test assumes git is installed in the test environment
12 { Test-GitAvailability } | Should -Not -Throw
13 }
14
15 It 'Should throw when git is not available' {
16 Mock Get-Command { $null } -ParameterFilter { $Name -eq 'git' }
17 { Test-GitAvailability } | Should -Throw '*Git is required*'
18 }
19}
20
21Describe 'New-PrDirectory' {
22 BeforeAll {
23 $script:tempRepo = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString())
24 New-Item -ItemType Directory -Path $script:tempRepo -Force | Out-Null
25 }
26
27 AfterAll {
28 Remove-Item -Path $script:tempRepo -Recurse -Force -ErrorAction SilentlyContinue
29 }
30
31 It 'Creates parent directory for the output file' {
32 $outputFile = Join-Path $script:tempRepo '.copilot-tracking/pr/pr-reference.xml'
33 $result = New-PrDirectory -OutputFilePath $outputFile
34 $result | Should -Not -BeNullOrEmpty
35 Test-Path -Path $result -PathType Container | Should -BeTrue
36 $result | Should -Match '\.copilot-tracking[\\/]pr$'
37 }
38
39 It 'Returns existing directory without error' {
40 $outputFile = Join-Path $script:tempRepo '.copilot-tracking/pr/pr-reference.xml'
41 $firstCall = New-PrDirectory -OutputFilePath $outputFile
42 $secondCall = New-PrDirectory -OutputFilePath $outputFile
43 $secondCall | Should -Be $firstCall
44 }
45}
46
47Describe 'Resolve-ComparisonReference' {
48 It 'Returns PSCustomObject with Ref and Label properties' {
49 $result = Resolve-ComparisonReference -BaseBranch 'main'
50 $result | Should -BeOfType [PSCustomObject]
51 $result.PSObject.Properties.Name | Should -Contain 'Ref'
52 $result.PSObject.Properties.Name | Should -Contain 'Label'
53 }
54
55 It 'Uses merge-base when remote branch exists' {
56 # This test assumes main branch exists
57 $result = Resolve-ComparisonReference -BaseBranch 'main'
58 $result.Ref | Should -Not -BeNullOrEmpty
59 }
60
61 It 'Should throw when base branch does not exist' {
62 Mock git { $global:LASTEXITCODE = 1; return $null }
63 { Resolve-ComparisonReference -BaseBranch 'nonexistent-branch-xyz' } | Should -Throw '*does not exist*'
64 }
65}
66
67Describe 'Get-ShortCommitHash' {
68 It 'Returns 7-character hash for HEAD' {
69 $result = Get-ShortCommitHash -Ref 'HEAD'
70 $result | Should -Match '^[a-f0-9]{7,}$'
71 }
72
73 It 'Returns consistent result for same ref' {
74 $first = Get-ShortCommitHash -Ref 'HEAD'
75 $second = Get-ShortCommitHash -Ref 'HEAD'
76 $first | Should -Be $second
77 }
78
79 It 'Should throw when ref resolution fails' {
80 Mock git { $global:LASTEXITCODE = 128; return '' }
81 { Get-ShortCommitHash -Ref 'invalid-ref-xyz' } | Should -Throw "*Failed to resolve ref*"
82 }
83}
84
85Describe 'Get-CommitEntry' {
86 It 'Returns array of formatted commit entries' {
87 $result = Get-CommitEntry -ComparisonRef 'HEAD~1'
88 $result | Should -BeOfType [string]
89 }
90
91 It 'Returns empty array when no commits in range' {
92 $result = Get-CommitEntry -ComparisonRef 'HEAD'
93 $result | Should -BeNullOrEmpty
94 }
95
96 It 'Should throw when commit history retrieval fails' {
97 Mock git { $global:LASTEXITCODE = 128; return $null }
98 { Get-CommitEntry -ComparisonRef 'main' } | Should -Throw '*Failed to retrieve commit history*'
99 }
100}
101
102Describe 'Get-CommitCount' {
103 It 'Returns integer count' {
104 $result = Get-CommitCount -ComparisonRef 'HEAD~5'
105 $result | Should -BeOfType [int]
106 # Merge commits can inflate the count, so just verify it returns a positive integer
107 $result | Should -BeGreaterOrEqual 1
108 }
109
110 It 'Returns 0 when no commits in range' {
111 $result = Get-CommitCount -ComparisonRef 'HEAD'
112 $result | Should -Be 0
113 }
114
115 It 'Should throw when commit count fails' {
116 Mock git { $global:LASTEXITCODE = 128; return '' }
117 { Get-CommitCount -ComparisonRef 'main' } | Should -Throw '*Failed to count commits*'
118 }
119
120 It 'Should return 0 when commit count text is empty' {
121 Mock git { $global:LASTEXITCODE = 0; return '' }
122 $result = Get-CommitCount -ComparisonRef 'main'
123 $result | Should -Be 0
124 }
125}
126
127Describe 'Get-DiffOutput' {
128 It 'Returns array of diff lines' {
129 $result = Get-DiffOutput -ComparisonRef 'HEAD~1'
130 $result | Should -Not -BeNullOrEmpty
131 }
132
133 It 'Excludes markdown when specified' {
134 # Verify the function executes without error when excluding markdown
135 # The result may be empty if only markdown files were changed
136 { Get-DiffOutput -ComparisonRef 'HEAD~1' -ExcludeMarkdownDiff } | Should -Not -Throw
137 }
138
139 It 'Should throw when diff output fails' {
140 Mock git { $global:LASTEXITCODE = 128; return $null }
141 { Get-DiffOutput -ComparisonRef 'main' } | Should -Throw '*Failed to retrieve diff output*'
142 }
143}
144
145Describe 'Get-DiffSummary' {
146 It 'Returns shortstat summary string' {
147 $result = Get-DiffSummary -ComparisonRef 'HEAD~1'
148 $result | Should -BeOfType [string]
149 }
150
151 It 'Should throw when diff summary fails' {
152 Mock git { $global:LASTEXITCODE = 128; return $null }
153 { Get-DiffSummary -ComparisonRef 'main' } | Should -Throw '*Failed to summarize diff output*'
154 }
155
156 It 'Should return "0 files changed" when diff summary is empty' {
157 Mock git { $global:LASTEXITCODE = 0; return '' }
158 $result = Get-DiffSummary -ComparisonRef 'main'
159 $result | Should -Be '0 files changed'
160 }
161}
162
163Describe 'Get-PrXmlContent' {
164 It 'Returns valid XML string' {
165 $result = Get-PrXmlContent -CurrentBranch 'feature/test' -BaseBranch 'main' -CommitEntries @('commit 1', 'commit 2') -DiffOutput @('diff line 1', 'diff line 2')
166 $result | Should -Not -BeNullOrEmpty
167 $result | Should -Match '<commit_history>'
168 $result | Should -Match '</commit_history>'
169 }
170
171 It 'Includes branch information' {
172 $result = Get-PrXmlContent -CurrentBranch 'feature/my-branch' -BaseBranch 'main' -CommitEntries @() -DiffOutput @()
173 $result | Should -Match 'feature/my-branch'
174 $result | Should -Match 'main'
175 }
176
177 It 'Includes commit entries' {
178 $result = Get-PrXmlContent -CurrentBranch 'feature/test' -BaseBranch 'main' -CommitEntries @('abc123 Test commit') -DiffOutput @()
179 $result | Should -Match 'abc123 Test commit'
180 }
181
182 It 'Handles empty inputs' {
183 $result = Get-PrXmlContent -CurrentBranch 'branch' -BaseBranch 'main' -CommitEntries @() -DiffOutput @()
184 $result | Should -Not -BeNullOrEmpty
185 }
186}
187
188Describe 'Get-LineImpact' {
189 It 'Parses insertions and deletions from shortstat' {
190 $result = Get-LineImpact -DiffSummary '5 files changed, 100 insertions(+), 50 deletions(-)'
191 $result | Should -Be 150
192 }
193
194 It 'Handles insertions only' {
195 $result = Get-LineImpact -DiffSummary '2 files changed, 25 insertions(+)'
196 $result | Should -Be 25
197 }
198
199 It 'Handles deletions only' {
200 $result = Get-LineImpact -DiffSummary '1 file changed, 10 deletions(-)'
201 $result | Should -Be 10
202 }
203
204 It 'Returns 0 for summary without insertions or deletions' {
205 $result = Get-LineImpact -DiffSummary 'no changes'
206 $result | Should -Be 0
207 }
208
209 It 'Returns 0 for no changes' {
210 $result = Get-LineImpact -DiffSummary '0 files changed'
211 $result | Should -Be 0
212 }
213}
214
215Describe 'Get-CurrentBranchOrRef' {
216 BeforeAll {
217 . (Join-Path -Path $PSScriptRoot -ChildPath '../scripts/generate.ps1')
218 }
219
220 It 'Returns branch name when on a branch' {
221 # This test runs in a real git repo, so it should return something
222 $result = Get-CurrentBranchOrRef
223 $result | Should -Not -BeNullOrEmpty
224 $result | Should -BeOfType [string]
225 }
226
227 It 'Returns string starting with detached@ or branch name' {
228 $result = Get-CurrentBranchOrRef
229 # Either a branch name or detached@<sha>
230 ($result -match '^detached@' -or $result -notmatch '^detached@') | Should -BeTrue
231 }
232
233 It 'Should return detached@sha when in detached HEAD state' {
234 # Use call sequence to distinguish git commands (cross-platform safe)
235 $script:gitCallCount = 0
236 Mock git {
237 $script:gitCallCount++
238 if ($script:gitCallCount -eq 1) {
239 # First call: git branch --show-current returns empty (detached)
240 $global:LASTEXITCODE = 0
241 return ''
242 }
243 # Second call: git rev-parse --short HEAD returns SHA
244 $global:LASTEXITCODE = 0
245 return 'abc1234'
246 }
247 $result = Get-CurrentBranchOrRef
248 $result | Should -Be 'detached@abc1234'
249 }
250
251 It 'Should return unknown when both branch and rev-parse fail' {
252 Mock git {
253 $global:LASTEXITCODE = 128
254 return $null
255 }
256 $result = Get-CurrentBranchOrRef
257 $result | Should -Be 'unknown'
258 }
259}
260
261Describe 'Invoke-PrReferenceGeneration' {
262 It 'Uses custom OutputPath when specified' {
263 $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString())
264 $customPath = Join-Path $tempDir 'custom-output/pr-ref.xml'
265
266 try {
267 $result = Invoke-PrReferenceGeneration -BaseBranch 'HEAD~1' -OutputPath $customPath
268 $result | Should -BeOfType [System.IO.FileInfo]
269 $result.FullName | Should -Be (Resolve-Path $customPath).Path
270 Test-Path $customPath | Should -BeTrue
271 }
272 finally {
273 Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
274 }
275 }
276
277 It 'Returns FileInfo object' {
278 # Skip if not in a git repo or no commits to compare
279 $commitCount = Get-CommitCount -ComparisonRef 'HEAD~1'
280 if ($commitCount -eq 0) {
281 Set-ItResult -Skipped -Because 'No commits available for comparison'
282 return
283 }
284
285 # Determine available base branch - prefer origin/main, fall back to main, then HEAD~1
286 $baseBranch = $null
287 foreach ($candidate in @('origin/main', 'main', 'HEAD~1')) {
288 & git rev-parse --verify $candidate 2>$null | Out-Null
289 if ($LASTEXITCODE -eq 0) {
290 $baseBranch = $candidate
291 break
292 }
293 }
294
295 if (-not $baseBranch) {
296 Set-ItResult -Skipped -Because 'No suitable base branch available for comparison'
297 return
298 }
299
300 $result = Invoke-PrReferenceGeneration -BaseBranch $baseBranch
301 $result | Should -BeOfType [System.IO.FileInfo]
302 $result.Extension | Should -Be '.xml'
303 }
304
305 It 'Should include markdown exclusion note when ExcludeMarkdownDiff is specified' {
306 # Skip if not in a git repo or no commits
307 $commitCount = Get-CommitCount -ComparisonRef 'HEAD~1'
308 if ($commitCount -eq 0) {
309 Set-ItResult -Skipped -Because 'No commits available for comparison'
310 return
311 }
312
313 $baseBranch = $null
314 foreach ($candidate in @('origin/main', 'main', 'HEAD~1')) {
315 & git rev-parse --verify $candidate 2>$null | Out-Null
316 if ($LASTEXITCODE -eq 0) {
317 $baseBranch = $candidate
318 break
319 }
320 }
321
322 if (-not $baseBranch) {
323 Set-ItResult -Skipped -Because 'No suitable base branch available for comparison'
324 return
325 }
326
327 Mock Write-Host {}
328
329 $result = Invoke-PrReferenceGeneration -BaseBranch $baseBranch -ExcludeMarkdownDiff
330 $result | Should -BeOfType [System.IO.FileInfo]
331
332 # Verify the markdown exclusion note was output
333 Should -Invoke Write-Host -ParameterFilter { $Object -eq 'Note: Markdown files were excluded from diff output' }
334 }
335}
336
337Describe 'Large diff warning' {
338 It 'Should output large diff message when line impact exceeds 1000' {
339 Mock Test-GitAvailability {}
340 Mock Get-RepositoryRoot { return (& git rev-parse --show-toplevel).Trim() }
341 Mock Get-CurrentBranchOrRef { return 'feature/test' }
342 Mock Resolve-ComparisonReference { return [PSCustomObject]@{ Ref = 'HEAD~1'; Label = 'main' } }
343 Mock Get-ShortCommitHash { return 'abc1234' }
344 Mock Get-CommitEntry { return @('<commit hash="abc1234" date="2026-01-01"><message><subject><![CDATA[test]]></subject><body><![CDATA[]]></body></message></commit>') }
345 Mock Get-CommitCount { return 1 }
346 Mock Get-DiffOutput { return @('diff --git a/file.txt b/file.txt') }
347 Mock Get-DiffSummary { return '10 files changed, 800 insertions(+), 500 deletions(-)' }
348 Mock Set-Content {}
349 Mock Get-Content { return @('line1', 'line2') }
350 Mock Get-Item { return [System.IO.FileInfo]::new('/tmp/pr-reference.xml') }
351 Mock Write-Host {}
352
353 $null = Invoke-PrReferenceGeneration -BaseBranch 'main'
354
355 Should -Invoke Write-Host -ParameterFilter {
356 $Object -like '*Large diff detected*'
357 }
358 }
359}
360
361Describe 'Entry-point execution' -Tag 'Integration' {
362 It 'Should exit 0 when executed successfully as a script' {
363 $scriptPath = Join-Path $PSScriptRoot '../scripts/generate.ps1'
364 $null = & pwsh -File $scriptPath -BaseBranch 'HEAD~1' 2>&1
365 $LASTEXITCODE | Should -Be 0
366 }
367
368 It 'Should exit 1 with error message when generation fails' {
369 $scriptPath = Join-Path $PSScriptRoot '../scripts/generate.ps1'
370 $null = & pwsh -File $scriptPath -BaseBranch 'nonexistent-branch-xyz-999' 2>&1
371 $LASTEXITCODE | Should -Be 1
372 }
373}
374