v / .github / workflows / windows_ci_msvc.yml
677 lines · 605 sloc · 33.48 KB · ddb021b9866c3b4523b746fa2f4c16a594f8bd89
Raw
1name: CI Windows MSVC
2
3on:
4 push:
5 branches:
6 - master
7 paths-ignore:
8 - '**.md'
9 - '**.yml'
10 - '!**.bat'
11 - '!**/windows_ci_msvc.yml'
12 - 'cmd/tools/**'
13 - '!cmd/tools/builders/**.v'
14 pull_request:
15 paths-ignore:
16 - '**.md'
17 - '**.yml'
18 - '!**.bat'
19 - '!**/windows_ci_msvc.yml'
20 - '!**/windows-install-sqlite.bat'
21 - 'cmd/tools/**'
22 - '!cmd/tools/builders/**.v'
23
24concurrency:
25 group: windows-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
26 cancel-in-progress: true
27
28jobs:
29 msvc-windows:
30 runs-on: windows-2022
31 timeout-minutes: 70
32 env:
33 VFLAGS: -cc msvc
34 VTEST_SHOW_LONGEST_BY_RUNTIME: 3
35 VTEST_SHOW_LONGEST_BY_COMPTIME: 3
36 VTEST_SHOW_LONGEST_BY_TOTALTIME: 3
37 steps:
38 - uses: actions/checkout@v6
39 - uses: ilammy/msvc-dev-cmd@v1
40 with:
41 arch: x64
42 - name: Verify MSVC tools
43 run: |
44 where.exe cl.exe
45 where.exe link.exe
46 where.exe dumpbin.exe
47 - name: Build
48 run: |
49 echo %VFLAGS%
50 echo $VFLAGS
51 .\makev.bat -msvc
52 .\v.exe symlink
53 - name: backend x64 regressions
54 run: |
55 function Assert-LastExit([string] $label) {
56 if ($LASTEXITCODE -ne 0) {
57 throw "$label failed with exit code $LASTEXITCODE"
58 }
59 }
60
61 $env:VJOBS = '1'
62 .\v.exe test `
63 vlib/v2/abi `
64 vlib/v2/gen/x64/x64_abi_test.v `
65 vlib/v2/gen/x64/x64_backend_diagnostics_test.v `
66 vlib/v2/gen/x64/x64_object_format_test.v `
67 vlib/v2/gen/x64/x64_pe_linker_test.v `
68 vlib/v2/ssa/tree_sumtype_lowering_test.v
69 Assert-LastExit 'stable V2 x64 unit tests'
70 .\v.exe test -run-only test_module_qualified_alias_array_field_index_has_alias_element_type,test_module_storage_legacy_direct_import_nested_module_selector_uses_declared_leaf_module,test_module_storage_flat_direct_import_nested_module_selector_uses_declared_leaf_module vlib/v2/ssa/module_storage_test.v
71 Assert-LastExit 'targeted vlib/v2/ssa/module_storage_test.v regressions'
72 .\v.exe test -run-only test_x64_macos_windows_math_log_20_stdout_exact_bytes,test_x64_macos_windows_generic_sumtype_repeated_base_specialization_stdout_exact_bytes,test_x64_macos_windows_formatted_int_interpolation_stdout_exact_bytes,test_x64_macos_windows_formatted_int_width_100_interpolation_stdout_exact_bytes,test_x64_macos_windows_formatted_f64_interpolation_stdout_exact_bytes,test_x64_macos_windows_formatted_string_return_lifetime_stdout_exact_bytes,test_x64_macos_windows_spectral_reduced_formatted_stdout_exact_bytes,test_x64_macos_windows_bits_len32_stdout_exact_bytes,test_x64_macos_windows_rand_u32n_interface_result_stdout_exact_bytes,test_x64_macos_windows_rand_intn_range_interface_result_stdout_exact_bytes,test_x64_macos_windows_textscanner_embedded_parser_stdout_exact_bytes,test_x64_macos_windows_struct_positional_side_effect_stdout_exact_bytes,test_x64_macos_windows_struct_named_side_effect_stdout_exact_bytes,test_x64_macos_windows_unrelated_same_shape_struct_stdout_exact_bytes,test_x64_macos_windows_named_init_embedded_value_stdout_exact_bytes,test_x64_macos_windows_get_raw_line_example_stdin_stdout_exact_bytes,test_x64_macos_windows_mini_calculator_example_stdin_stdout_exact_bytes,test_x64_macos_windows_mini_calculator_recursive_descent_example_stdin_stdout_exact_bytes vlib/v2/gen/x64/x64_runtime_smoke_test.v
73 Assert-LastExit 'reduced V2 x64 runtime smoke tests'
74 Remove-Item Env:\VJOBS -ErrorAction SilentlyContinue
75 .\v.exe test vlib/v2/builder/native_test.v vlib/v2/builder/target_os_test.v
76 Assert-LastExit 'vlib/v2/builder/native_test.v vlib/v2/builder/target_os_test.v'
77 .\v.exe test vlib/v2/ssa/optimize
78 Assert-LastExit 'vlib/v2/ssa/optimize'
79 $env:V2_VERIFY_STRICT = '1'
80 .\v.exe test vlib/v2/ssa/optimize
81 Assert-LastExit 'strict vlib/v2/ssa/optimize'
82 Remove-Item Env:\V2_VERIFY_STRICT -ErrorAction SilentlyContinue
83 - name: backend x64 examples
84 run: |
85 function Assert-LastExit([string] $label) {
86 if ($LASTEXITCODE -ne 0) {
87 throw "$label failed with exit code $LASTEXITCODE"
88 }
89 }
90
91 function Assert-ByteArrayEqual([byte[]] $actual, [byte[]] $expected, [string] $label) {
92 if ($actual.Length -ne $expected.Length) {
93 $actual_text = [System.Text.Encoding]::UTF8.GetString($actual)
94 $expected_text = [System.Text.Encoding]::UTF8.GetString($expected)
95 throw "$label mismatch. Expected length $($expected.Length), got $($actual.Length).`nExpected:`n$expected_text`nActual:`n$actual_text"
96 }
97 for ($i = 0; $i -lt $actual.Length; $i++) {
98 if ($actual[$i] -ne $expected[$i]) {
99 $actual_text = [System.Text.Encoding]::UTF8.GetString($actual)
100 $expected_text = [System.Text.Encoding]::UTF8.GetString($expected)
101 throw "$label mismatch at byte $i.`nExpected:`n$expected_text`nActual:`n$actual_text"
102 }
103 }
104 }
105
106 function Get-PeImportedDlls([string] $exe) {
107 $output = & dumpbin.exe /imports $exe 2>&1
108 if ($LASTEXITCODE -ne 0) {
109 $text = ($output | Out-String).Trim()
110 throw "dumpbin import inspection failed for $exe with exit code $LASTEXITCODE`n$text"
111 }
112
113 $dlls = [System.Collections.Generic.List[string]]::new()
114 foreach ($lineObject in $output) {
115 $line = [string] $lineObject
116 if ($line -match '^\s*([A-Za-z0-9_.-]+\.dll)\s*$') {
117 $dlls.Add($matches[1].ToLowerInvariant())
118 }
119 }
120 return $dlls | Sort-Object -Unique
121 }
122
123 function Assert-TinyPeImports([string] $name, [string] $exe, [string] $pe_import_mode) {
124 if ($pe_import_mode -eq '') {
125 return
126 }
127 if ($pe_import_mode -eq 'tiny-used') {
128 [string[]] $allowed_dlls = @('kernel32.dll')
129 } elseif ($pe_import_mode -eq 'tiny-shell32-argv') {
130 [string[]] $allowed_dlls = @('kernel32.dll', 'shell32.dll')
131 } else {
132 throw "$name has unknown PE import validation mode: $pe_import_mode"
133 }
134
135 [string[]] $dlls = @(Get-PeImportedDlls $exe)
136 if ($dlls.Count -eq 0) {
137 throw "$name PE import validation found no imported DLLs with dumpbin.exe"
138 }
139
140 $crt_dlls = $dlls | Where-Object {
141 $_ -match '^(msvcrt|ucrtbase|vcruntime)[0-9]*\.dll$' -or $_ -match '^api-ms-win-crt-.*\.dll$'
142 }
143 if ($crt_dlls.Count -gt 0) {
144 throw "$name tiny PE unexpectedly imports CRT DLL(s): $($crt_dlls -join ', ')"
145 }
146
147 $unexpected_dlls = $dlls | Where-Object { $_ -notin $allowed_dlls }
148 if ($unexpected_dlls.Count -gt 0) {
149 throw "$name PE imports unexpected DLL(s): $($unexpected_dlls -join ', ')"
150 }
151
152 $missing_dlls = $allowed_dlls | Where-Object { $_ -notin $dlls }
153 if ($missing_dlls.Count -gt 0) {
154 throw "$name PE import validation missed expected DLL(s): $($missing_dlls -join ', ')"
155 }
156 }
157
158 function Invoke-NativeX64Example([string] $source, [string] $name, [byte[]] $expected_stdout, [string] $pe_import_mode = '', [string[]] $program_args = @()) {
159 $exe = Join-Path $tmp "$name.exe"
160 $stdout_path = Join-Path $tmp "$name.out"
161 $stderr_path = Join-Path $tmp "$name.err"
162
163 $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1
164 $compile_exit = $LASTEXITCODE
165 foreach ($line in $compile_output) {
166 Write-Host $line
167 }
168 if ($compile_exit -ne 0) {
169 throw "compile $source failed with exit code $compile_exit"
170 }
171 Assert-TinyPeImports $name $exe $pe_import_mode
172
173 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
174 if ($program_args.Count -gt 0) {
175 $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
176 } else {
177 $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
178 }
179 if ($process.ExitCode -ne 0) {
180 if (Test-Path -LiteralPath $stderr_path) {
181 Get-Content -LiteralPath $stderr_path
182 }
183 throw "$source exited with code $($process.ExitCode)"
184 }
185
186 [byte[]] $stdout = if (Test-Path -LiteralPath $stdout_path) { [System.IO.File]::ReadAllBytes($stdout_path) } else { New-Object byte[] 0 }
187 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
188 $empty = New-Object byte[] 0
189 Assert-ByteArrayEqual $stdout $expected_stdout "$source stdout"
190 Assert-ByteArrayEqual $stderr $empty "$source stderr"
191 }
192
193 function Invoke-NativeX64ExampleWithStdin([string] $source, [string] $name, [byte[]] $expected_stdout, [string] $stdin_path, [string] $pe_import_mode = '', [string[]] $program_args = @()) {
194 $exe = Join-Path $tmp "$name.exe"
195 $stdout_path = Join-Path $tmp "$name.out"
196 $stderr_path = Join-Path $tmp "$name.err"
197
198 $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1
199 $compile_exit = $LASTEXITCODE
200 foreach ($line in $compile_output) {
201 Write-Host $line
202 }
203 if ($compile_exit -ne 0) {
204 throw "compile $source failed with exit code $compile_exit"
205 }
206 Assert-TinyPeImports $name $exe $pe_import_mode
207
208 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
209 if ($program_args.Count -gt 0) {
210 $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
211 } else {
212 $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
213 }
214 if ($process.ExitCode -ne 0) {
215 if (Test-Path -LiteralPath $stderr_path) {
216 Get-Content -LiteralPath $stderr_path
217 }
218 throw "$source exited with code $($process.ExitCode)"
219 }
220
221 [byte[]] $stdout = if (Test-Path -LiteralPath $stdout_path) { [System.IO.File]::ReadAllBytes($stdout_path) } else { New-Object byte[] 0 }
222 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
223 $empty = New-Object byte[] 0
224 Assert-ByteArrayEqual $stdout $expected_stdout "$source stdout"
225 Assert-ByteArrayEqual $stderr $empty "$source stderr"
226 }
227
228 function Invoke-NativeX64ExampleCapture([string] $source, [string] $name, [string[]] $program_args = @()) {
229 $exe = Join-Path $tmp "$name.exe"
230 $stdout_path = Join-Path $tmp "$name.out"
231 $stderr_path = Join-Path $tmp "$name.err"
232
233 $compile_output = & .\v.exe -v2 -no-parallel -b x64 $source -o $exe 2>&1
234 $compile_exit = $LASTEXITCODE
235 foreach ($line in $compile_output) {
236 Write-Host $line
237 }
238 if ($compile_exit -ne 0) {
239 throw "compile $source failed with exit code $compile_exit"
240 }
241
242 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
243 if ($program_args.Count -gt 0) {
244 $process = Start-Process -FilePath $exe -ArgumentList $program_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
245 } else {
246 $process = Start-Process -FilePath $exe -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
247 }
248 if ($process.ExitCode -ne 0) {
249 if (Test-Path -LiteralPath $stderr_path) {
250 Get-Content -LiteralPath $stderr_path
251 }
252 throw "$source exited with code $($process.ExitCode)"
253 }
254
255 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
256 $empty = New-Object byte[] 0
257 Assert-ByteArrayEqual $stderr $empty "$source stderr"
258 return $stdout_path
259 }
260
261 function Assert-RandomIpsStdout([string] $path) {
262 [string[]] $lines = [System.IO.File]::ReadAllLines($path)
263 if ($lines.Count -ne 10) {
264 throw "random_ips expected 10 lines, got $($lines.Count)"
265 }
266 $rows = [System.Collections.Generic.List[string]]::new()
267 $all_second_zero = $true
268 $all_fourth_zero = $true
269 foreach ($line in $lines) {
270 [string[]] $parts = $line.Split('.')
271 if ($parts.Count -ne 4) {
272 throw "random_ips invalid IPv4 shape: $line"
273 }
274 [int[]] $octets = @()
275 foreach ($part in $parts) {
276 if ($part -notmatch '^[0-9]+$') {
277 throw "random_ips non-numeric octet: $line"
278 }
279 $value = [int] $part
280 if ($value -lt 0 -or $value -gt 254) {
281 throw "random_ips octet out of range: $line"
282 }
283 $octets += $value
284 }
285 if ($octets[1] -ne 0) {
286 $all_second_zero = $false
287 }
288 if ($octets[3] -ne 0) {
289 $all_fourth_zero = $false
290 }
291 $rows.Add(($octets -join '.'))
292 }
293 if (($rows | Sort-Object -Unique).Count -lt 3) {
294 throw 'random_ips output has too little row diversity'
295 }
296 if ($all_second_zero -and $all_fourth_zero) {
297 throw 'random_ips suspicious old x.0.x.0 pattern'
298 }
299 }
300
301 function Assert-Rule110Stdout([string] $path, [int] $width) {
302 [string[]] $lines = [System.IO.File]::ReadAllLines($path)
303 $title = 'Rule 110 V Implementation'
304 $idx = -1
305 for ($i = 0; $i -lt $lines.Count; $i++) {
306 if ($lines[$i].Contains($title)) {
307 $idx = $i
308 break
309 }
310 }
311 if ($idx -lt 0) {
312 throw 'rule110 missing title'
313 }
314 [string[]] $generations = @()
315 if ($idx + 1 -lt $lines.Count) {
316 $generations = @($lines[($idx + 1)..($lines.Count - 1)])
317 }
318 if ($generations.Count -gt 0 -and $generations[0] -eq '') {
319 if ($generations.Count -eq 1) {
320 $generations = @()
321 } else {
322 $generations = @($generations[1..($generations.Count - 1)])
323 }
324 }
325 if ($generations.Count -ne $width) {
326 throw "rule110 expected $width generation lines, got $($generations.Count)"
327 }
328 $has_live_cell = $false
329 foreach ($line in $generations) {
330 if ($line.Length -ne $width) {
331 throw "rule110 generation line has width $($line.Length), expected $width`: '$line'"
332 }
333 if ($line -match '[^ *]') {
334 throw "rule110 invalid generation chars: '$line'"
335 }
336 if ($line.Contains('*')) {
337 $has_live_cell = $true
338 }
339 }
340 if (-not $has_live_cell) {
341 throw 'rule110 expected at least one live cell'
342 }
343 if (($generations | Sort-Object -Unique).Count -lt 3) {
344 throw 'rule110 expected at least 3 distinct generation lines'
345 }
346 }
347
348 $tmp = Join-Path $env:RUNNER_TEMP 'v2_x64_native'
349 New-Item -ItemType Directory -Force -Path $tmp | Out-Null
350
351 function Get-VRunExpectedBytes([string] $source, [string] $name, [string[]] $program_args = @()) {
352 $stdout_path = Join-Path $tmp "$name.vrun.out"
353 $stderr_path = Join-Path $tmp "$name.vrun.err"
354 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
355
356 $v_args = @('run', $source) + $program_args
357 $process = Start-Process -FilePath '.\v.exe' -ArgumentList $v_args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
358 if ($process.ExitCode -ne 0) {
359 if (Test-Path -LiteralPath $stderr_path) {
360 Get-Content -LiteralPath $stderr_path
361 }
362 throw "v run $source $($program_args -join ' ') failed with code $($process.ExitCode)"
363 }
364
365 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
366 $empty = New-Object byte[] 0
367 Assert-ByteArrayEqual $stderr $empty "v run $source stderr"
368 return [System.IO.File]::ReadAllBytes($stdout_path)
369 }
370
371 function Get-VRunExpectedBytesWithStdin([string] $source, [string] $name, [string] $stdin_path, [string[]] $program_args = @()) {
372 $stdout_path = Join-Path $tmp "$name.vrun.out"
373 $stderr_path = Join-Path $tmp "$name.vrun.err"
374 Remove-Item -LiteralPath $stdout_path, $stderr_path -Force -ErrorAction SilentlyContinue
375
376 $v_args = @('run', $source) + $program_args
377 $process = Start-Process -FilePath '.\v.exe' -ArgumentList $v_args -NoNewWindow -Wait -PassThru -RedirectStandardInput $stdin_path -RedirectStandardOutput $stdout_path -RedirectStandardError $stderr_path
378 if ($process.ExitCode -ne 0) {
379 if (Test-Path -LiteralPath $stderr_path) {
380 Get-Content -LiteralPath $stderr_path
381 }
382 throw "v run $source $($program_args -join ' ') failed with code $($process.ExitCode)"
383 }
384
385 [byte[]] $stderr = if (Test-Path -LiteralPath $stderr_path) { [System.IO.File]::ReadAllBytes($stderr_path) } else { New-Object byte[] 0 }
386 $empty = New-Object byte[] 0
387 Assert-ByteArrayEqual $stderr $empty "v run $source stderr"
388 return [System.IO.File]::ReadAllBytes($stdout_path)
389 }
390
391 $hello_expected = [System.Text.Encoding]::UTF8.GetBytes("Hello, World!`n")
392 Invoke-NativeX64Example 'examples/hello_world.v' 'hello_world' $hello_expected 'tiny-used'
393
394 $fizz_lines = 1..100 | ForEach-Object {
395 if ($_ % 15 -eq 0) {
396 'FizzBuzz'
397 } elseif ($_ % 3 -eq 0) {
398 'Fizz'
399 } elseif ($_ % 5 -eq 0) {
400 'Buzz'
401 } else {
402 [string] $_
403 }
404 }
405 $fizz_expected = [System.Text.Encoding]::UTF8.GetBytes(($fizz_lines -join "`n") + "`n")
406 Invoke-NativeX64Example 'examples/fizz_buzz.v' 'fizz_buzz' $fizz_expected 'tiny-used'
407
408 $fibonacci_expected = [System.Text.Encoding]::UTF8.GetBytes("1`n1`n2`n3`n5`n8`n13`n21`n34`n55`n89`n")
409 Invoke-NativeX64Example 'examples/fibonacci.v' 'fibonacci' $fibonacci_expected 'tiny-shell32-argv' @('10')
410
411 $dump_factorial_expected = [System.Text.Encoding]::UTF8.GetBytes("120`n")
412 Invoke-NativeX64Example 'examples/dump_factorial.v' 'dump_factorial' $dump_factorial_expected 'tiny-used'
413
414 function Get-HanoiExpectedLines([int] $n, [string] $a, [string] $b, [string] $c) {
415 if ($n -eq 1) {
416 "Disc 1 from $a to $c..."
417 return
418 }
419 Get-HanoiExpectedLines ($n - 1) $a $c $b
420 "Disc $n from $a to $c..."
421 Get-HanoiExpectedLines ($n - 1) $b $a $c
422 }
423
424 $hanoi_lines = @(Get-HanoiExpectedLines 7 'A' 'B' 'C')
425 $hanoi_expected = [System.Text.Encoding]::UTF8.GetBytes(($hanoi_lines -join "`n") + "`n")
426 Invoke-NativeX64Example 'examples/hanoi.v' 'hanoi' $hanoi_expected 'tiny-used'
427
428 function Get-SudokuExpectedLines {
429 $puzzle = @(
430 ,@(0, 3, 0, 0, 7, 0, 0, 0, 0)
431 ,@(0, 0, 0, 1, 3, 5, 0, 0, 0)
432 ,@(0, 0, 1, 0, 0, 0, 0, 5, 0)
433 ,@(1, 0, 0, 0, 6, 0, 0, 0, 3)
434 ,@(4, 0, 0, 8, 0, 3, 0, 0, 1)
435 ,@(7, 0, 0, 0, 2, 0, 0, 0, 6)
436 ,@(0, 0, 0, 0, 0, 0, 2, 1, 0)
437 ,@(0, 0, 0, 4, 1, 2, 0, 0, 5)
438 ,@(0, 0, 0, 0, 0, 0, 0, 7, 4)
439 )
440 $solution = @(
441 ,@(2, 3, 5, 6, 7, 8, 1, 4, 9)
442 ,@(9, 4, 7, 1, 3, 5, 8, 6, 2)
443 ,@(6, 8, 1, 2, 4, 9, 3, 5, 7)
444 ,@(1, 2, 8, 7, 6, 4, 5, 9, 3)
445 ,@(4, 5, 6, 8, 9, 3, 7, 2, 1)
446 ,@(7, 9, 3, 5, 2, 1, 4, 8, 6)
447 ,@(3, 6, 4, 9, 5, 7, 2, 1, 8)
448 ,@(8, 7, 9, 4, 1, 2, 6, 3, 5)
449 ,@(5, 1, 2, 3, 8, 6, 9, 7, 4)
450 )
451 $lines = [System.Collections.Generic.List[string]]::new()
452
453 function Add-SudokuGrid([string] $label, [object[]] $grid) {
454 $lines.Add($label)
455 for ($i = 0; $i -lt $grid.Count; $i++) {
456 if ($i % 3 -eq 0 -and $i -ne 0) {
457 $lines.Add('- - - - - - - - - - - -')
458 }
459 $line = ''
460 for ($j = 0; $j -lt $grid[$i].Count; $j++) {
461 if ($j % 3 -eq 0 -and $j -ne 0) {
462 $line += ' | '
463 }
464 $line += "$($grid[$i][$j]) "
465 }
466 $lines.Add($line)
467 }
468 }
469
470 Add-SudokuGrid 'Sudoku Puzzle:' $puzzle
471 $lines.Add('Solving...')
472 Add-SudokuGrid 'Solution:' $solution
473 return $lines.ToArray()
474 }
475
476 $sudoku_lines = @(Get-SudokuExpectedLines)
477 $sudoku_expected = [System.Text.Encoding]::UTF8.GetBytes(($sudoku_lines -join "`n") + "`n")
478 if ($sudoku_expected.Length -ne 582) {
479 throw "sudoku stdout oracle shape changed: $($sudoku_expected.Length) bytes"
480 }
481 Invoke-NativeX64Example 'examples/sudoku.v' 'sudoku' $sudoku_expected
482
483 $function_types_expected = [System.Text.Encoding]::UTF8.GetBytes("HELLO WORLD`nHELLO WORLD`nHELLO WORLD`n")
484 Invoke-NativeX64Example 'examples/function_types.v' 'function_types' $function_types_expected
485
486 $submodule_expected = [System.Text.Encoding]::UTF8.GetBytes("5`n3`n")
487 Invoke-NativeX64Example 'examples/submodule/main.v' 'submodule' $submodule_expected 'tiny-used'
488
489 function Get-TreeOfNodesExpectedLines {
490 @(
491 'tree structure:'
492 ' Node{'
493 ' value: 10'
494 ' left: Tree(Node{'
495 ' value: 30'
496 ' left: Tree(Empty{})'
497 ' right: Tree(Empty{})'
498 ' })'
499 ' right: Tree(Node{'
500 ' value: 20'
501 ' left: Tree(Empty{})'
502 ' right: Tree(Empty{})'
503 ' })'
504 '}'
505 'tree size: 3'
506 )
507 }
508
509 $tree_of_nodes_lines = @(Get-TreeOfNodesExpectedLines)
510 $tree_of_nodes_expected = [System.Text.Encoding]::UTF8.GetBytes(($tree_of_nodes_lines -join "`n") + "`n")
511 if ($tree_of_nodes_expected.Length -ne 259) {
512 throw "tree_of_nodes stdout oracle shape changed: $($tree_of_nodes_expected.Length) bytes"
513 }
514 Invoke-NativeX64Example 'examples/tree_of_nodes.v' 'tree_of_nodes' $tree_of_nodes_expected
515
516 $js_hello_world_expected = [System.Text.Encoding]::UTF8.GetBytes("Hello from V.js (0)`nHello from V.js (1)`nHello from V.js (2)`n")
517 Invoke-NativeX64Example 'examples/js_hello_world.v' 'js_hello_world' $js_hello_world_expected 'tiny-used'
518
519 function Get-VSingleQuotedLiteralBytes([string] $literal) {
520 $bytes = [System.Collections.Generic.List[byte]]::new()
521 for ($i = 0; $i -lt $literal.Length; $i++) {
522 $ch = $literal[$i]
523 if ($ch -eq '\') {
524 $i++
525 if ($i -ge $literal.Length) {
526 throw 'unterminated escape in V single-quoted literal'
527 }
528 $escaped = $literal[$i]
529 switch ([int][char] $escaped) {
530 110 { [void] $bytes.Add(10) }
531 116 { [void] $bytes.Add(9) }
532 114 { [void] $bytes.Add(13) }
533 92 { [void] $bytes.Add(92) }
534 39 { [void] $bytes.Add(39) }
535 34 { [void] $bytes.Add(34) }
536 default {
537 foreach ($byte in [System.Text.Encoding]::UTF8.GetBytes([string] $escaped)) {
538 [void] $bytes.Add($byte)
539 }
540 }
541 }
542 } else {
543 foreach ($byte in [System.Text.Encoding]::UTF8.GetBytes([string] $ch)) {
544 [void] $bytes.Add($byte)
545 }
546 }
547 }
548 return $bytes.ToArray()
549 }
550
551 function Get-VasciiExpectedBytes() {
552 $source = [System.IO.File]::ReadAllText((Join-Path (Get-Location) 'examples/vascii.v'), [System.Text.Encoding]::UTF8)
553 $start_marker = "println('"
554 $end_marker = "')"
555 $first = $source.IndexOf($start_marker, [System.StringComparison]::Ordinal)
556 if ($first -lt 0) {
557 throw 'missing vascii println literal start'
558 }
559 $second = $source.IndexOf($start_marker, $first + $start_marker.Length, [System.StringComparison]::Ordinal)
560 if ($second -ne -1) {
561 throw 'vascii stdout oracle expects one single-quoted println literal'
562 }
563 $start = $first + $start_marker.Length
564 $end = $source.LastIndexOf($end_marker, [System.StringComparison]::Ordinal)
565 if ($end -lt $start) {
566 throw 'missing vascii println literal end'
567 }
568 if ($source.Substring($end + $end_marker.Length).Trim() -ne '}') {
569 throw 'vascii stdout oracle expects the println literal to be the final main statement'
570 }
571 [byte[]] $bytes = Get-VSingleQuotedLiteralBytes ($source.Substring($start, $end - $start))
572 return $bytes + [byte] 10
573 }
574
575 [byte[]] $vascii_expected = Get-VasciiExpectedBytes
576 Invoke-NativeX64Example 'examples/vascii.v' 'vascii' $vascii_expected 'tiny-used'
577
578 [byte[]] $rune_expected = 0xF0, 0x9F, 0x98, 0x80, 0x0A, 0x40, 0x0A
579 Invoke-NativeX64Example 'examples/rune.v' 'rune' $rune_expected 'tiny-used'
580
581 [byte[]] $bfs_expected = Get-VRunExpectedBytes 'examples/graphs/bfs.v' 'bfs'
582 Invoke-NativeX64Example 'examples/graphs/bfs.v' 'bfs' $bfs_expected
583
584 [byte[]] $bfs3_expected = Get-VRunExpectedBytes 'examples/graphs/bfs3.v' 'bfs3'
585 Invoke-NativeX64Example 'examples/graphs/bfs3.v' 'bfs3' $bfs3_expected
586
587 [byte[]] $primes_expected = Get-VRunExpectedBytes 'examples/primes.v' 'primes' @('20')
588 Invoke-NativeX64Example 'examples/primes.v' 'primes' $primes_expected '' @('20')
589
590 [byte[]] $dfs_expected = Get-VRunExpectedBytes 'examples/graphs/dfs.v' 'dfs'
591 Invoke-NativeX64Example 'examples/graphs/dfs.v' 'dfs' $dfs_expected
592
593 [byte[]] $dijkstra_expected = Get-VRunExpectedBytes 'examples/graphs/dijkstra.v' 'dijkstra'
594 Invoke-NativeX64Example 'examples/graphs/dijkstra.v' 'dijkstra' $dijkstra_expected
595
596 [byte[]] $topological_sorting_greedy_expected = Get-VRunExpectedBytes 'examples/graphs/topological_sorting_greedy.v' 'topological_sorting_greedy'
597 Invoke-NativeX64Example 'examples/graphs/topological_sorting_greedy.v' 'topological_sorting_greedy' $topological_sorting_greedy_expected
598
599 [byte[]] $topological_sorting_dfs_expected = Get-VRunExpectedBytes 'examples/graphs/topological_sorting_dfs.v' 'topological_sorting_dfs'
600 Invoke-NativeX64Example 'examples/graphs/topological_sorting_dfs.v' 'topological_sorting_dfs' $topological_sorting_dfs_expected
601
602 [byte[]] $dfs2_expected = Get-VRunExpectedBytes 'examples/graphs/dfs2.v' 'dfs2'
603 Invoke-NativeX64Example 'examples/graphs/dfs2.v' 'dfs2' $dfs2_expected
604
605 [byte[]] $minimal_spann_tree_prim_expected = Get-VRunExpectedBytes 'examples/graphs/minimal_spann_tree_prim.v' 'minimal_spann_tree_prim'
606 Invoke-NativeX64Example 'examples/graphs/minimal_spann_tree_prim.v' 'minimal_spann_tree_prim' $minimal_spann_tree_prim_expected
607
608 [byte[]] $bellman_ford_expected = Get-VRunExpectedBytes 'examples/graphs/bellman-ford.v' 'bellman_ford'
609 Invoke-NativeX64Example 'examples/graphs/bellman-ford.v' 'bellman_ford' $bellman_ford_expected
610
611 [byte[]] $binary_search_tree_expected = Get-VRunExpectedBytes 'examples/binary_search_tree.v' 'binary_search_tree'
612 Invoke-NativeX64Example 'examples/binary_search_tree.v' 'binary_search_tree' $binary_search_tree_expected
613
614 # normal-required: IError/custom errors
615 [byte[]] $errors_expected = [System.Text.Encoding]::UTF8.GetBytes("wrong format`nempty input`n")
616 Invoke-NativeX64Example 'examples/errors.v' 'errors' $errors_expected
617
618 [byte[]] $custom_error_expected = Get-VRunExpectedBytes 'examples/custom_error.v' 'custom_error'
619 Invoke-NativeX64Example 'examples/custom_error.v' 'custom_error' $custom_error_expected
620
621 # normal-required: spectral norm/math.sqrt/formatted f64 interpolation
622 [byte[]] $spectral_expected = Get-VRunExpectedBytes 'examples/spectral.v' 'spectral' @('10')
623 Invoke-NativeX64Example 'examples/spectral.v' 'spectral' $spectral_expected '' @('10')
624
625 [byte[]] $quick_sort_expected = [System.Text.Encoding]::UTF8.GetBytes("length of random array is 1000`nbefore quick sort whether array is sorted: false`nafter quick sort whether array is sorted: true`n")
626 Invoke-NativeX64Example 'examples/quick_sort.v' 'quick_sort' $quick_sort_expected
627
628 $get_raw_line_input = Join-Path $tmp 'get_raw_line.in'
629 [System.IO.File]::WriteAllText($get_raw_line_input, "hello`nworld`n", [System.Text.UTF8Encoding]::new($false))
630 [byte[]] $get_raw_line_expected = Get-VRunExpectedBytesWithStdin 'examples/get_raw_line.v' 'get_raw_line' $get_raw_line_input
631 Invoke-NativeX64ExampleWithStdin 'examples/get_raw_line.v' 'get_raw_line' $get_raw_line_expected $get_raw_line_input
632
633 $mini_calculator_input = Join-Path $tmp 'mini_calculator.in'
634 [System.IO.File]::WriteAllText($mini_calculator_input, "3+4*2`nexit`n", [System.Text.UTF8Encoding]::new($false))
635 [byte[]] $mini_calculator_expected = Get-VRunExpectedBytesWithStdin 'examples/mini_calculator.v' 'mini_calculator' $mini_calculator_input
636 Invoke-NativeX64ExampleWithStdin 'examples/mini_calculator.v' 'mini_calculator' $mini_calculator_expected $mini_calculator_input
637
638 $mini_calculator_recursive_descent_input = Join-Path $tmp 'mini_calculator_recursive_descent.in'
639 [System.IO.File]::WriteAllText($mini_calculator_recursive_descent_input, "3+4*2`nexit`n", [System.Text.UTF8Encoding]::new($false))
640 [byte[]] $mini_calculator_recursive_descent_expected = Get-VRunExpectedBytesWithStdin 'examples/mini_calculator_recursive_descent.v' 'mini_calculator_recursive_descent' $mini_calculator_recursive_descent_input
641 Invoke-NativeX64ExampleWithStdin 'examples/mini_calculator_recursive_descent.v' 'mini_calculator_recursive_descent' $mini_calculator_recursive_descent_expected $mini_calculator_recursive_descent_input
642
643 $random_ips_stdout = Invoke-NativeX64ExampleCapture 'examples/random_ips.v' 'random_ips'
644 Assert-RandomIpsStdout $random_ips_stdout
645
646 $rule110_stdout = Invoke-NativeX64ExampleCapture 'examples/rule110.v' 'rule110' @('31')
647 Assert-Rule110Stdout $rule110_stdout 31
648 - name: Build V with WX
649 run: v -cflags /WX self
650 - name: All code is formatted
651 run: v -silent test-cleancode
652 - name: Test -cc msvc works
653 run: v -no-retry-compilation run examples/hello_world.v
654 - name: Install dependencies
655 run: |
656 v retry -- v setup-freetype
657 .\.github\workflows\windows-install-sqlite.bat
658 - name: v doctor
659 run: |
660 v doctor
661 - name: Verify `v test` works
662 run: |
663 echo $VFLAGS
664 v cmd/tools/test_if_v_test_system_works.v
665 ./cmd/tools/test_if_v_test_system_works
666 - name: Test pure V math module
667 run: v -silent -exclude @vlib/math/*.c.v test vlib/math/
668 - name: Self tests
669 run: v -silent test-self vlib
670 - name: Test v->js
671 run: v -o hi.js examples/js_hello_world.v && node hi.js
672 - name: Test v binaries
673 run: v build-vbinaries
674 - name: Build examples
675 run: v build-examples
676 - name: v2 self compilation
677 run: v -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
678