microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
fix/1232-recursive-plugin

Branches

Tags

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

Clone

HTTPS

Download ZIP

.github/skills/shared/pr-reference/tests/read-diff.Tests.ps1

451lines · modecode

1#Requires -Modules Pester
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5BeforeAll {
6 . (Join-Path -Path $PSScriptRoot -ChildPath '../scripts/read-diff.ps1')
7
8 # Fixture XML with multiple file diffs for comprehensive testing
9 $script:FixtureXml = @'
10<commit_history>
11 <current_branch>feature/test</current_branch>
12 <base_branch>origin/main</base_branch>
13 <commits>
14 <commit hash="abc1234" date="2026-01-15">
15 <message>
16 <subject><![CDATA[test commit]]></subject>
17 <body><![CDATA[]]></body>
18 </message>
19 </commit>
20 </commits>
21 <full_diff>
22diff --git a/src/alpha.ts b/src/alpha.ts
23new file mode 100644
24index 0000000..a1b2c3d
25--- /dev/null
26+++ b/src/alpha.ts
27@@ -0,0 +1,5 @@
28+export function alpha() {
29+ return 1;
30+}
31+
32+export default alpha;
33
34diff --git a/src/beta.ts b/src/beta.ts
35index a1b2c3d..d4e5f6a 100644
36--- a/src/beta.ts
37+++ b/src/beta.ts
38@@ -1,4 +1,6 @@
39 export function beta() {
40- return false;
41+ return true;
42+ // added line one
43+ // added line two
44 }
45
46diff --git a/src/gamma.ts b/src/gamma.ts
47deleted file mode 100644
48index a1b2c3d..0000000
49--- a/src/gamma.ts
50+++ /dev/null
51@@ -1,3 +0,0 @@
52-export function gamma() {
53- return null;
54-}
55 </full_diff>
56</commit_history>
57'@
58 $script:TempDir = Join-Path ([System.IO.Path]::GetTempPath()) "rd-tests-$([System.Guid]::NewGuid())"
59 New-Item -ItemType Directory -Path $script:TempDir -Force | Out-Null
60 $script:FixturePath = Join-Path $script:TempDir 'pr-reference.xml'
61 Set-Content -Path $script:FixturePath -Value $script:FixtureXml -NoNewline
62}
63
64AfterAll {
65 Remove-Item -Path $script:TempDir -Recurse -Force -ErrorAction SilentlyContinue
66}
67
68Describe 'Get-ChunkInfo' {
69 It 'Calculates total chunks when lines divide evenly' {
70 $result = Get-ChunkInfo -TotalLines 1000 -ChunkSize 500
71 $result.TotalChunks | Should -Be 2
72 $result.TotalLines | Should -Be 1000
73 $result.ChunkSize | Should -Be 500
74 }
75
76 It 'Rounds up when lines do not divide evenly' {
77 $result = Get-ChunkInfo -TotalLines 1001 -ChunkSize 500
78 $result.TotalChunks | Should -Be 3
79 }
80
81 It 'Returns 1 chunk when total lines equal chunk size' {
82 $result = Get-ChunkInfo -TotalLines 500 -ChunkSize 500
83 $result.TotalChunks | Should -Be 1
84 }
85
86 It 'Returns 1 chunk when total lines are less than chunk size' {
87 $result = Get-ChunkInfo -TotalLines 100 -ChunkSize 500
88 $result.TotalChunks | Should -Be 1
89 }
90
91 It 'Returns 0 chunks when total lines is 0' {
92 $result = Get-ChunkInfo -TotalLines 0 -ChunkSize 500
93 $result.TotalChunks | Should -Be 0
94 }
95}
96
97Describe 'Get-ChunkRange' {
98 It 'Returns correct range for the first chunk' {
99 $result = Get-ChunkRange -ChunkNumber 1 -ChunkSize 10 -TotalLines 25
100 $result.Start | Should -Be 1
101 $result.End | Should -Be 10
102 }
103
104 It 'Returns correct range for a middle chunk' {
105 $result = Get-ChunkRange -ChunkNumber 2 -ChunkSize 10 -TotalLines 25
106 $result.Start | Should -Be 11
107 $result.End | Should -Be 20
108 }
109
110 It 'Caps end at TotalLines for the last partial chunk' {
111 $result = Get-ChunkRange -ChunkNumber 3 -ChunkSize 10 -TotalLines 25
112 $result.Start | Should -Be 21
113 $result.End | Should -Be 25
114 }
115
116 It 'Handles single-line file' {
117 $result = Get-ChunkRange -ChunkNumber 1 -ChunkSize 500 -TotalLines 1
118 $result.Start | Should -Be 1
119 $result.End | Should -Be 1
120 }
121}
122
123Describe 'Get-FileDiff' {
124 BeforeAll {
125 $script:fileDiffContent = @(Get-Content -LiteralPath $script:FixturePath)
126 }
127
128 It 'Extracts diff block for an existing file' {
129 $result = Get-FileDiff -Content $script:fileDiffContent -FilePath 'src/beta.ts'
130 $result | Should -Not -BeNullOrEmpty
131 $result | Should -Match 'diff --git a/src/beta.ts'
132 $result | Should -Match 'return true'
133 }
134
135 It 'Stops extraction at the next diff header' {
136 $result = Get-FileDiff -Content $script:fileDiffContent -FilePath 'src/alpha.ts'
137 $result | Should -Match 'diff --git a/src/alpha.ts'
138 $result | Should -Not -Match 'diff --git a/src/beta.ts'
139 }
140
141 It 'Returns empty string when file is not in the diff' {
142 $result = Get-FileDiff -Content $script:fileDiffContent -FilePath 'src/nonexistent.ts'
143 $result | Should -BeNullOrEmpty
144 }
145
146 It 'Extracts the last file in the diff without a trailing diff header' {
147 $result = Get-FileDiff -Content $script:fileDiffContent -FilePath 'src/gamma.ts'
148 $result | Should -Match 'diff --git a/src/gamma.ts'
149 $result | Should -Match 'deleted file mode'
150 }
151
152 It 'Handles file paths containing regex special characters' {
153 $specialContent = @(
154 'diff --git a/src/[utils].ts b/src/[utils].ts'
155 'index abc..def 100644'
156 '--- a/src/[utils].ts'
157 '+++ b/src/[utils].ts'
158 '@@ -1 +1 @@'
159 '-old'
160 '+new'
161 )
162 $result = Get-FileDiff -Content $specialContent -FilePath 'src/[utils].ts'
163 $result | Should -Match '\[utils\]'
164 }
165}
166
167Describe 'Get-DiffSummary' {
168 BeforeAll {
169 $script:summaryContent = @(Get-Content -LiteralPath $script:FixturePath)
170 }
171
172 It 'Counts additions and deletions per file' {
173 $result = Get-DiffSummary -Content $script:summaryContent
174 # src/alpha.ts: 4 additions (bare + line excluded by regex), 0 deletions
175 $result | Should -Match 'src/alpha.ts \(\+4/-0\)'
176 }
177
178 It 'Reports correct counts for modified files' {
179 $result = Get-DiffSummary -Content $script:summaryContent
180 # src/beta.ts: 3 additions (+return true, +added line one, +added line two), 1 deletion (-return false)
181 $result | Should -Match 'src/beta.ts \(\+3/-1\)'
182 }
183
184 It 'Reports correct counts for deleted files' {
185 $result = Get-DiffSummary -Content $script:summaryContent
186 # src/gamma.ts: 0 additions, 3 deletions
187 $result | Should -Match 'src/gamma.ts \(\+0/-3\)'
188 }
189
190 It 'Starts output with Changed files header' {
191 $result = Get-DiffSummary -Content $script:summaryContent
192 $result | Should -Match '^Changed files:'
193 }
194
195 It 'Sorts files alphabetically' {
196 $result = Get-DiffSummary -Content $script:summaryContent
197 $lines = ($result -split [Environment]::NewLine) | Where-Object { $_ -match '^\s+\S' }
198 $filePaths = $lines | ForEach-Object { ($_ -replace '^\s+(\S+)\s.*', '$1') }
199 $sorted = $filePaths | Sort-Object
200 @($filePaths) | Should -Be @($sorted)
201 }
202
203 It 'Returns only header when content has no diff blocks' {
204 $result = Get-DiffSummary -Content @('no diff content here')
205 $result | Should -Be 'Changed files:'
206 }
207
208 It 'Does not count lines starting with ++ or -- as changes' {
209 $content = @(
210 'diff --git a/file.ts b/file.ts'
211 '--- a/file.ts'
212 '+++ b/file.ts'
213 '@@ -1,2 +1,2 @@'
214 '-old line'
215 '+new line'
216 )
217 $result = Get-DiffSummary -Content $content
218 # Only 1 addition and 1 deletion; --- and +++ are excluded
219 $result | Should -Match 'file.ts \(\+1/-1\)'
220 }
221}
222
223Describe 'Invoke-ReadDiff' {
224 Context 'Info mode' {
225 It 'Outputs file path and chunk breakdown' {
226 $result = Invoke-ReadDiff -InputPath $script:FixturePath -Info
227 $joined = $result -join "`n"
228 $joined | Should -Match 'Total lines:'
229 $joined | Should -Match 'Total chunks:'
230 $joined | Should -Match 'Chunk breakdown:'
231 }
232
233 It 'Respects custom ChunkSize' {
234 $result = Invoke-ReadDiff -InputPath $script:FixturePath -Info -ChunkSize 10
235 $joined = $result -join "`n"
236 $joined | Should -Match 'Chunk size: 10'
237 }
238 }
239
240 Context 'Summary mode' {
241 It 'Outputs changed files with counts' {
242 $result = Invoke-ReadDiff -InputPath $script:FixturePath -Summary
243 $joined = $result -join "`n"
244 $joined | Should -Match 'Changed files:'
245 $joined | Should -Match 'src/alpha.ts'
246 }
247 }
248
249 Context 'File extraction mode' {
250 It 'Extracts diff for a specific file' {
251 $result = Invoke-ReadDiff -InputPath $script:FixturePath -File 'src/beta.ts'
252 $joined = $result -join "`n"
253 $joined | Should -Match 'diff --git a/src/beta.ts'
254 }
255
256 It 'Warns when file is not in the diff' {
257 $result = Invoke-ReadDiff -InputPath $script:FixturePath -File 'src/missing.ts' 3>&1
258 $result | Should -Match 'No diff found'
259 }
260 }
261
262 Context 'Chunk mode' {
263 It 'Reads chunk with header comment' {
264 $result = Invoke-ReadDiff -InputPath $script:FixturePath -Chunk 1 -ChunkSize 10
265 $joined = $result -join "`n"
266 $joined | Should -Match '# Chunk 1/'
267 }
268
269 It 'Throws when chunk number exceeds total' {
270 { Invoke-ReadDiff -InputPath $script:FixturePath -Chunk 9999 -ChunkSize 10 } | Should -Throw '*exceeds file*'
271 }
272 }
273
274 Context 'Lines mode' {
275 It 'Reads a line range with header' {
276 $result = Invoke-ReadDiff -InputPath $script:FixturePath -Lines '1,5'
277 $joined = $result -join "`n"
278 $joined | Should -Match '# Lines 1-5'
279 }
280
281 It 'Throws on invalid line range format' {
282 { Invoke-ReadDiff -InputPath $script:FixturePath -Lines 'invalid' } | Should -Throw '*Invalid line range*'
283 }
284
285 It 'Throws when start line exceeds file length' {
286 { Invoke-ReadDiff -InputPath $script:FixturePath -Lines '99999,100000' } | Should -Throw '*exceeds file length*'
287 }
288
289 It 'Caps end line at file length' {
290 $result = Invoke-ReadDiff -InputPath $script:FixturePath -Lines '1,999999'
291 $joined = $result -join "`n"
292 $joined | Should -Match '# Lines 1-'
293 }
294 }
295
296 Context 'Default mode' {
297 It 'Displays usage guidance when no mode requested' {
298 $result = Invoke-ReadDiff -InputPath $script:FixturePath
299 $joined = $result -join "`n"
300 $joined | Should -Match 'Total lines:'
301 $joined | Should -Match 'Use -Chunk N'
302 }
303 }
304
305 Context 'Error handling' {
306 It 'Throws when file does not exist' {
307 { Invoke-ReadDiff -InputPath '/nonexistent/file.xml' } | Should -Throw '*PR reference file not found*'
308 }
309
310 It 'Uses default path when InputPath is empty' {
311 Mock Get-RepositoryRoot { return $script:TempDir }
312 { Invoke-ReadDiff } | Should -Throw '*PR reference file not found*'
313 }
314 }
315}
316
317Describe 'Entry-point: file not found' -Tag 'Integration' {
318 BeforeAll {
319 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
320 }
321
322 It 'Exits 1 when PR reference file does not exist' {
323 $null = & pwsh -File $script:ScriptPath -InputPath '/nonexistent/file.xml' 2>&1
324 $LASTEXITCODE | Should -Be 1
325 }
326}
327
328Describe 'Entry-point: Info mode' -Tag 'Integration' {
329 BeforeAll {
330 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
331 }
332
333 It 'Displays file path and chunk breakdown' {
334 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Info 2>&1
335 $LASTEXITCODE | Should -Be 0
336 $joined = $output -join "`n"
337 $joined | Should -Match 'Total lines:'
338 $joined | Should -Match 'Total chunks:'
339 $joined | Should -Match 'Chunk breakdown:'
340 }
341
342 It 'Respects custom ChunkSize in info output' {
343 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Info -ChunkSize 10 2>&1
344 $LASTEXITCODE | Should -Be 0
345 $joined = $output -join "`n"
346 $joined | Should -Match 'Chunk size: 10'
347 }
348}
349
350Describe 'Entry-point: Summary mode' -Tag 'Integration' {
351 BeforeAll {
352 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
353 }
354
355 It 'Outputs changed files with add/remove counts' {
356 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Summary 2>&1
357 $LASTEXITCODE | Should -Be 0
358 $joined = $output -join "`n"
359 $joined | Should -Match 'Changed files:'
360 $joined | Should -Match 'src/alpha.ts'
361 }
362}
363
364Describe 'Entry-point: File mode' -Tag 'Integration' {
365 BeforeAll {
366 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
367 }
368
369 It 'Extracts diff for a specific file' {
370 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -File 'src/beta.ts' 2>&1
371 $LASTEXITCODE | Should -Be 0
372 $joined = $output -join "`n"
373 $joined | Should -Match 'diff --git a/src/beta.ts'
374 }
375
376 It 'Warns when file is not found in the diff' {
377 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -File 'src/missing.ts' 2>&1
378 $LASTEXITCODE | Should -Be 0
379 $joined = $output -join "`n"
380 $joined | Should -Match 'No diff found for file'
381 }
382}
383
384Describe 'Entry-point: Chunk mode' -Tag 'Integration' {
385 BeforeAll {
386 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
387 }
388
389 It 'Reads the first chunk with header comment' {
390 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Chunk 1 -ChunkSize 10 2>&1
391 $LASTEXITCODE | Should -Be 0
392 $joined = $output -join "`n"
393 $joined | Should -Match '# Chunk 1/'
394 }
395
396 It 'Exits 1 when chunk number exceeds total chunks' {
397 $null = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Chunk 9999 -ChunkSize 10 2>&1
398 $LASTEXITCODE | Should -Be 1
399 }
400}
401
402Describe 'Entry-point: Lines mode' -Tag 'Integration' {
403 BeforeAll {
404 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
405 }
406
407 It 'Reads a line range using comma separator' {
408 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Lines '1,5' 2>&1
409 $LASTEXITCODE | Should -Be 0
410 $joined = $output -join "`n"
411 $joined | Should -Match '# Lines 1-5'
412 }
413
414 It 'Reads a line range using dash separator' {
415 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Lines '2-4' 2>&1
416 $LASTEXITCODE | Should -Be 0
417 $joined = $output -join "`n"
418 $joined | Should -Match '# Lines 2-4'
419 }
420
421 It 'Exits 1 when start line exceeds file length' {
422 $null = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Lines '99999,100000' 2>&1
423 $LASTEXITCODE | Should -Be 1
424 }
425
426 It 'Exits 1 with invalid line range format' {
427 $null = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Lines 'invalid' 2>&1
428 $LASTEXITCODE | Should -Be 1
429 }
430
431 It 'Caps end line at file length when range exceeds total' {
432 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath -Lines '1,999999' 2>&1
433 $LASTEXITCODE | Should -Be 0
434 $joined = $output -join "`n"
435 $joined | Should -Match '# Lines 1-'
436 }
437}
438
439Describe 'Entry-point: Default mode' -Tag 'Integration' {
440 BeforeAll {
441 $script:ScriptPath = Join-Path $PSScriptRoot '../scripts/read-diff.ps1'
442 }
443
444 It 'Displays usage guidance when no mode arguments are supplied' {
445 $output = & pwsh -File $script:ScriptPath -InputPath $script:FixturePath 2>&1
446 $LASTEXITCODE | Should -Be 0
447 $joined = $output -join "`n"
448 $joined | Should -Match 'Total lines:'
449 $joined | Should -Match 'Use -Chunk N'
450 }
451}
452