Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ jobs:
- name: Verify Zig installation
run: zig version

- name: Generate Code using OpenAPI v3.0 Petstore example
run: |
zig build run-generate
zig run generated/main.zig
- name: Run smoke tests
shell: pwsh
timeout-minutes: 15
run: ./test/smoke-tests.ps1
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,16 @@ zig build-exe generated/main.zig -fno-emit-bin
zig build test-package
```

### Smoke tests

The pull request workflow runs `test/smoke-tests.ps1` to generate and compile Zig clients from each supported JSON OpenAPI example under `openapi/`. The script prints the current specification before each operation, making it easy to identify which input file caused a failure. Expect the full suite to take several minutes because it builds the CLI and compiles generated code for every supported example.

```powershell
pwsh ./test/smoke-tests.ps1
```

YAML examples are skipped by default because YAML input is not implemented yet. Use `-IncludeYaml` when YAML generation support is added.

## Using as a Library

openapi2zig can also be used as a Zig library for parsing OpenAPI/Swagger specifications and generating code programmatically.
Expand Down
178 changes: 178 additions & 0 deletions test/smoke-tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
param (
[Parameter(Mandatory=$false)]
[switch]
$UseInstalled = $false,

[Parameter(Mandatory=$false)]
[switch]
$IncludeYaml = $false,

[Parameter(Mandatory=$false)]
[string]
$OutputRoot = "./.zig-cache/smoke-tests"
)

$ErrorActionPreference = "Stop"

function Invoke-NativeCommand {
param (
[Parameter(Mandatory=$true)]
[string]
$FilePath,

[Parameter(Mandatory=$false)]
[string[]]
$Arguments = @(),

[Parameter(Mandatory=$false)]
[string]
$FailureMessage = "Native command failed"
)

if (-not (Get-Command $FilePath -ErrorAction SilentlyContinue)) {
throw "$FailureMessage. Command not found: $FilePath"
}

Write-Host "> $FilePath $($Arguments -join ' ')"
& $FilePath @Arguments
if ($LASTEXITCODE -ne 0) {
throw "$FailureMessage (exit code: $LASTEXITCODE)"
}
}

function Test-IsOpenApiExampleSpec {
param (
[Parameter(Mandatory=$true)]
[System.IO.FileInfo]
$File,

[Parameter(Mandatory=$true)]
[string[]]
$Extensions
)

# The json-schema folder contains reference schemas, not API examples that openapi2zig can generate clients from.
$normalizedPath = $File.FullName.Replace('\', '/')
return $Extensions -contains $File.Extension.ToLowerInvariant() -and
$normalizedPath -notlike "*/json-schema/*"
}

function Get-OpenApiSpecs {
param (
[Parameter(Mandatory=$true)]
[string]
$OpenApiRoot,

[Parameter(Mandatory=$true)]
[bool]
$IncludeYamlSpecs
)

$extensions = @(".json")
if ($IncludeYamlSpecs) {
$extensions += @(".yaml", ".yml")
}

Get-ChildItem -Path $OpenApiRoot -Recurse -File |
Where-Object { Test-IsOpenApiExampleSpec -File $_ -Extensions $extensions } |
Sort-Object FullName
}

function Get-SafeName {
param (
[Parameter(Mandatory=$true)]
[string]
$Value
)

return ($Value -replace '[^A-Za-z0-9_]', '_')
}

$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$openApiRoot = Join-Path $repoRoot "openapi"
$outputRootPath = Join-Path $repoRoot $OutputRoot

if (-not (Test-Path -Path $openApiRoot -PathType Container)) {
throw "OpenAPI examples directory not found: $openApiRoot"
}

Push-Location $repoRoot
try {
Invoke-NativeCommand -FilePath "zig" -Arguments @("version") -FailureMessage "Zig is required to run smoke tests"

$openapi2zig = "openapi2zig"
if (-not $UseInstalled) {
Write-Host "`n=== Building openapi2zig ===`n"
Write-Host "Initial Zig builds can take 2-5 minutes, and generated code compilation across all specs can take several more minutes; do not cancel these steps."
Invoke-NativeCommand -FilePath "zig" -Arguments @("build", "-Doptimize=Debug") -FailureMessage "Failed to build openapi2zig"

$isWindowsPlatform = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT
$binaryName = if ($isWindowsPlatform) { "openapi2zig.exe" } else { "openapi2zig" }
$openapi2zig = Join-Path $repoRoot (Join-Path "zig-out/bin" $binaryName)
if (-not (Test-Path -Path $openapi2zig -PathType Leaf)) {
throw "Built openapi2zig binary not found: $openapi2zig"
}
}

if (Test-Path -Path $outputRootPath) {
Remove-Item -Path $outputRootPath -Recurse -Force
}
New-Item -Path $outputRootPath -ItemType Directory -Force | Out-Null

$allSpecs = @(Get-OpenApiSpecs -OpenApiRoot $openApiRoot -IncludeYamlSpecs $true)
$specs = if ($IncludeYaml) {
$allSpecs
} else {
@($allSpecs | Where-Object { $_.Extension.ToLowerInvariant() -eq ".json" })
}
if ($specs.Count -eq 0) {
throw "No OpenAPI specification examples found under $openApiRoot"
}

if (-not $IncludeYaml) {
$yamlCount = @($allSpecs | Where-Object { $_.Extension.ToLowerInvariant() -in @(".yaml", ".yml") }).Count
if ($yamlCount -gt 0) {
Write-Host "Skipping $yamlCount YAML specs because YAML input has not been implemented by openapi2zig yet. Use -IncludeYaml to verify YAML support when it is available."
}
}

Write-Host "`n=== Smoke testing $($specs.Count) OpenAPI specification examples ===`n"
Write-Host "Generated code compilation runs once per specification and can take several minutes across the full suite; CI allows up to 15 minutes for this job."

for ($i = 0; $i -lt $specs.Count; $i++) {
$spec = $specs[$i]
$relativeSpec = [System.IO.Path]::GetRelativePath($repoRoot, $spec.FullName)
$safeName = Get-SafeName -Value ([System.IO.Path]::ChangeExtension($relativeSpec, $null))
$caseOutputRoot = Join-Path $outputRootPath $safeName
$generatedFile = Join-Path $caseOutputRoot "client.zig"
$compileFile = Join-Path $caseOutputRoot "compile.zig"

New-Item -Path $caseOutputRoot -ItemType Directory -Force | Out-Null

Write-Host "`n[$($i + 1)/$($specs.Count)] Generating $relativeSpec"
Invoke-NativeCommand `
-FilePath $openapi2zig `
-Arguments @("generate", "-i", $spec.FullName, "-o", $generatedFile) `
-FailureMessage "Generation failed for $relativeSpec"

@'
const std = @import("std");
const generated = @import("client.zig");

test "generated client compiles" {
std.testing.refAllDecls(generated);
}
'@ | Set-Content -Path $compileFile -Encoding utf8NoBOM

Write-Host "[$($i + 1)/$($specs.Count)] Compiling generated Zig for $relativeSpec"
Invoke-NativeCommand `
-FilePath "zig" `
-Arguments @("test", $compileFile) `
-FailureMessage "Generated Zig failed to compile for $relativeSpec"
}

Write-Host "`nSmoke tests passed for $($specs.Count) OpenAPI specification examples."
}
finally {
Pop-Location
}
Loading