Skip to content

Commit a670fb8

Browse files
committed
added windows cli test powershell script and modified ci/cd structure a bit
1 parent c8521e1 commit a670fb8

2 files changed

Lines changed: 225 additions & 6 deletions

File tree

.github/workflows/cross-platform-build.yml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
- '.github/workflows/cross-platform-build.yml'
1010
- 'CMakeLists.txt'
1111
- 'auxiliary/test_cli.sh'
12+
- 'auxiliary/test_cli.ps1'
1213
pull_request:
1314
branches: ["main"]
1415
paths:
@@ -17,6 +18,7 @@ on:
1718
- '.github/workflows/cross-platform-build.yml'
1819
- 'CMakeLists.txt'
1920
- 'auxiliary/test_cli.sh'
21+
- 'auxiliary/test_cli.ps1'
2022
workflow_dispatch:
2123

2224
env:
@@ -280,7 +282,7 @@ jobs:
280282
steps:
281283
- run: echo "Windows builds completed"
282284

283-
cli-test:
285+
cli-test-linux:
284286
needs: [linux]
285287
runs-on: ubuntu-latest
286288

@@ -330,19 +332,25 @@ jobs:
330332
path: build
331333

332334
- name: Run CLI test suite
333-
shell: bash
335+
shell: pwsh
334336
run: |
335-
BIN=$(find build -name "*.exe" | head -1)
336-
bash auxiliary/test_cli.sh "$BIN"
337+
$bin = Get-ChildItem build -Filter "*.exe" | Select-Object -First 1 -ExpandProperty FullName
338+
pwsh auxiliary/test_cli.ps1 -BIN $bin
337339
338340
platform-builds:
339-
needs: [cli-test, cli-test-macos, cli-test-windows]
341+
needs: [linux, macos, windows]
340342
runs-on: ubuntu-latest
341343
steps:
342344
- run: echo "All platform builds completed"
343345

346+
cli-tests:
347+
needs: [cli-test-linux, cli-test-macos, cli-test-windows]
348+
runs-on: ubuntu-latest
349+
steps:
350+
- run: echo "All CLI tests completed"
351+
344352
completed:
345-
needs: [platform-builds]
353+
needs: [platform-builds, cli-tests]
346354
runs-on: ubuntu-latest
347355
steps:
348356
- run: echo "All checks passed"

auxiliary/test_cli.ps1

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#!/usr/bin/env pwsh
2+
# CLI argument test suite for VMAware (Windows / PowerShell)
3+
4+
param([string]$BIN = "build\vmaware.exe")
5+
6+
if (-not (Test-Path $BIN)) {
7+
Write-Error "Binary not found: $BIN"
8+
exit 1
9+
}
10+
11+
$script:pass = 0
12+
$script:fail = 0
13+
14+
function ok([string]$desc) { Write-Host " PASS $desc"; $script:pass++ }
15+
function Fail-Test([string]$desc) { Write-Host " FAIL $desc"; $script:fail++ }
16+
17+
# Runs $BIN with the given args, expects exit 0
18+
function check([string]$desc, [string[]]$binArgs) {
19+
$null = & $BIN @binArgs 2>&1
20+
if ($LASTEXITCODE -eq 0) { ok $desc } else { Fail-Test $desc }
21+
}
22+
23+
# Runs $BIN with the given args, expects a non-zero exit code
24+
function check_fails([string]$desc, [string[]]$binArgs) {
25+
$null = & $BIN @binArgs 2>&1
26+
if ($LASTEXITCODE -ne 0) { ok $desc } else { Fail-Test $desc }
27+
}
28+
29+
# Captures stdout+stderr, expects output to match $pattern (regex)
30+
function match_out([string]$desc, [string]$pattern, [string[]]$binArgs) {
31+
$out = (& $BIN @binArgs 2>&1) -join "`n"
32+
if ($out -match $pattern) { ok $desc }
33+
else { Fail-Test "$desc (got: $(($out -split "`n")[0]))" }
34+
}
35+
36+
# Captures stdout, expects an integer in [$lo, $hi]
37+
function range_out([string]$desc, [int]$lo, [int]$hi, [string[]]$binArgs) {
38+
$out = (& $BIN @binArgs 2>$null) -join ""
39+
if ($LASTEXITCODE -ne 0) { Fail-Test "$desc (non-zero exit)"; return }
40+
if ($out -match '^\d+$' -and [int]$out -ge $lo -and [int]$out -le $hi) {
41+
ok $desc
42+
} else {
43+
Fail-Test "$desc (got: $out, expected $lo-$hi)"
44+
}
45+
}
46+
47+
Write-Host "=== vmaware CLI tests ==="
48+
Write-Host ""
49+
50+
# exit codes
51+
Write-Host "exit codes"
52+
check "--help exits 0" @("--help")
53+
check "--version exits 0" @("--version")
54+
check "--brand-list exits 0" @("--brand-list")
55+
check "--detect exits 0" @("--detect")
56+
check "--percent exits 0" @("--percent")
57+
check "--brand exits 0" @("--brand")
58+
check "--type exits 0" @("--type")
59+
check "--conclusion exits 0" @("--conclusion")
60+
check "--number exits 0" @("--number")
61+
62+
# --stdout
63+
$null = & $BIN "--stdout" 2>&1
64+
if ($LASTEXITCODE -le 1) { ok "--stdout exits 0 or 1" } else { Fail-Test "--stdout exits 0 or 1" }
65+
66+
check_fails "unknown arg exits non-zero" @("--this-arg-does-not-exist")
67+
68+
# short-flag aliases
69+
Write-Host ""
70+
Write-Host "short flag aliases"
71+
check "-h exits 0" @("-h")
72+
check "-v exits 0" @("-v")
73+
check "-a exits 0" @("-a", "--detect")
74+
check "-d exits 0" @("-d")
75+
check "-b exits 0" @("-b")
76+
check "-p exits 0" @("-p")
77+
check "-c exits 0" @("-c")
78+
check "-n exits 0" @("-n")
79+
check "-t exits 0" @("-t")
80+
check "-l exits 0" @("-l")
81+
82+
# output format
83+
Write-Host ""
84+
Write-Host "output format"
85+
match_out "--detect outputs 0 or 1" '^[01]$' @("--detect")
86+
range_out "--percent outputs 0-100" 0 100 @("--percent")
87+
match_out "--number outputs a positive int" '^[1-9][0-9]*$' @("--number")
88+
match_out "--brand outputs a non-empty line" '.' @("--brand")
89+
match_out "--type outputs a non-empty line" '.' @("--type")
90+
match_out "--conclusion outputs a sentence" '.' @("--conclusion")
91+
92+
# no-ansi strips escape codes
93+
Write-Host ""
94+
Write-Host "no-ansi"
95+
$ansiOut = (& $BIN "--no-ansi" 2>&1) -join "`n"
96+
if ($ansiOut -match '\x1B\[') {
97+
Fail-Test "--no-ansi still contains ANSI escape codes"
98+
} else {
99+
ok "--no-ansi output contains no ANSI escape codes"
100+
}
101+
102+
# technique count
103+
Write-Host ""
104+
Write-Host "technique count"
105+
$n = (& $BIN "--number" 2>$null) -join ""
106+
if ($n -match '^\d+$' -and [int]$n -gt 10) {
107+
ok "--number returns plausible technique count ($n)"
108+
} else {
109+
Fail-Test "--number returned unexpected value: $n"
110+
}
111+
112+
# mutual exclusion
113+
Write-Host ""
114+
Write-Host "mutual exclusion"
115+
check_fails "--detect + --brand rejected" @("--detect", "--brand")
116+
check_fails "--percent + --brand rejected" @("--percent", "--brand")
117+
check_fails "--stdout + --detect rejected" @("--stdout", "--detect")
118+
119+
# --disable: valid names
120+
Write-Host ""
121+
Write-Host "--disable (valid names)"
122+
check "--disable single name works" @("--disable", "HYPERVISOR_BIT", "--detect")
123+
check "--disable multiple space-sep names works" @("--disable", "HYPERVISOR_BIT", "NVRAM", "QEMU_USB", "--detect")
124+
check "--disable comma-separated names works" @("--disable", "HYPERVISOR_BIT,NVRAM", "--detect")
125+
check "--disable mixed comma+space works" @("--disable", "HYPERVISOR_BIT,", "NVRAM,", "QEMU_USB", "--detect")
126+
check "--disable WINE (was WINE_FUNC) works" @("--disable", "WINE", "--detect")
127+
check "--disable SYSTEM_REGISTERS works" @("--disable", "SYSTEM_REGISTERS", "--detect")
128+
check "--disable UD works" @("--disable", "UD", "--detect")
129+
check "--disable HYPERVISOR_HOOK works" @("--disable", "HYPERVISOR_HOOK", "--detect")
130+
check "--disable SINGLE_STEP works" @("--disable", "SINGLE_STEP", "--detect")
131+
check "--disable DBVM works" @("--disable", "DBVM", "--detect")
132+
133+
# --disable: invalid names
134+
Write-Host ""
135+
Write-Host "--disable (invalid names)"
136+
check_fails "--disable bogus name fails" @("--disable", "NOT_A_REAL_TECHNIQUE", "--detect")
137+
check_fails "--disable MULTIPLE (setting) fails" @("--disable", "MULTIPLE", "--detect")
138+
139+
# --disable reflected in general output
140+
Write-Host ""
141+
Write-Host "--disable reflected in general output"
142+
$disOut = (& $BIN "--no-ansi", "--disable", "HYPERVISOR_BIT" 2>&1) -join "`n"
143+
if ($disOut -match "Skipped CPUID hypervisor bit") {
144+
ok "--disable HYPERVISOR_BIT shows as skipped in general output"
145+
} else {
146+
Fail-Test "--disable HYPERVISOR_BIT not reflected in general output"
147+
}
148+
149+
# --high-threshold
150+
Write-Host ""
151+
Write-Host "--high-threshold"
152+
$pNormal = [string]((& $BIN "--percent" 2>$null) -join "")
153+
$pHigh = [string]((& $BIN "--percent", "--high-threshold" 2>$null) -join "")
154+
$pNormal = if ($pNormal -match '^\d+$') { [int]$pNormal } else { 0 }
155+
$pHigh = if ($pHigh -match '^\d+$') { [int]$pHigh } else { 0 }
156+
if ($pNormal -ge $pHigh) {
157+
ok "--high-threshold produces equal or lower percentage ($pNormal -> $pHigh)"
158+
} else {
159+
Fail-Test "--high-threshold produced higher percentage ($pNormal -> $pHigh)"
160+
}
161+
162+
# --all
163+
Write-Host ""
164+
Write-Host "--all"
165+
check "--all --detect exits 0" @("--all", "--detect")
166+
check "--all --percent exits 0" @("--all", "--percent")
167+
168+
# --dynamic
169+
Write-Host ""
170+
Write-Host "--dynamic"
171+
check "--dynamic --conclusion exits 0" @("--dynamic", "--conclusion")
172+
173+
# --json
174+
Write-Host ""
175+
Write-Host "--json"
176+
$tmpJson = [System.IO.Path]::GetTempFileName() + ".json"
177+
try {
178+
$null = & $BIN "--json", "--output", $tmpJson 2>$null
179+
if ((Test-Path $tmpJson) -and (Get-Item $tmpJson).Length -gt 0) {
180+
ok "--json creates a non-empty output file"
181+
} else {
182+
Fail-Test "--json did not create an output file"
183+
}
184+
$jsonContent = if (Test-Path $tmpJson) { Get-Content $tmpJson -Raw } else { "" }
185+
if ($jsonContent -match '"is_detected"') {
186+
ok "--json output contains expected keys"
187+
} else {
188+
Fail-Test "--json output missing expected keys"
189+
}
190+
} finally {
191+
if (Test-Path $tmpJson) { Remove-Item $tmpJson -Force }
192+
}
193+
194+
# --brand-list
195+
Write-Host ""
196+
Write-Host "--brand-list"
197+
$brandLines = (& $BIN "--brand-list" 2>$null) | Where-Object { $_ -ne "" }
198+
$count = $brandLines.Count
199+
if ($count -gt 5) {
200+
ok "--brand-list returns multiple entries ($count lines)"
201+
} else {
202+
Fail-Test "--brand-list returned too few entries ($count lines)"
203+
}
204+
205+
# summary
206+
Write-Host ""
207+
Write-Host "==========================="
208+
Write-Host " Passed: $($script:pass)"
209+
Write-Host " Failed: $($script:fail)"
210+
Write-Host "==========================="
211+
if ($script:fail -ne 0) { exit 1 }

0 commit comments

Comments
 (0)