feat: full feature parity for all 42 SDKs + comprehensive tests

All SDKs now implement 58+ functions matching C reference (un.h):
- Execution (8): execute, execute_async, wait_job, get_job, cancel_job, list_jobs, get_languages, detect_language
- Sessions (9): list, get, create, destroy, freeze, unfreeze, boost, unboost, execute
- Services (17): list, get, create, destroy, freeze, unfreeze, lock, unlock, set_unfreeze_on_demand, redeploy, logs, execute, env_get/set/delete/export, resize
- Snapshots (9): list, get, session, service, restore, delete, lock, unlock, clone
- Images (13): list, get, publish, delete, lock, unlock, set_visibility, grant/revoke_access, list_trusted, transfer, spawn, clone
- PaaS Logs (2): fetch, stream
- Utilities (5): validate_keys, hmac_sign, health_check, version, last_error

Test suites created for all SDKs with unit, integration, and functional tests.

Languages: AWK, Bash, C++, C#, Clojure, COBOL, Crystal, D, Dart, .NET, Elixir, Erlang, F#, Forth, Fortran, Go, Groovy, Haskell, Java, JavaScript, Julia, Kotlin, Lisp, Lua, Nim, Objective-C, OCaml, Perl, PHP, PowerShell, Prolog, Python, R, Raku, Ruby, Rust, Scheme, Swift, Tcl, TypeScript, V, Zig
This commit is contained in:
russell@unturf.com 2026-02-05 16:45:02 -05:00
parent a5155aed4f
commit 6e746ace44
90 changed files with 28955 additions and 3028 deletions

View file

@ -0,0 +1,213 @@
// Tests for the Zig unsandbox SDK
// Run with: zig test tests/test_un.zig
const std = @import("std");
const un = @import("../src/un.zig");
const testing = std.testing;
const mem = std.mem;
// ============================================================================
// Unit Tests - Test exported library functions
// ============================================================================
test "detectLanguage" {
try testing.expectEqualStrings("python", un.detectLanguage("script.py") orelse "");
try testing.expectEqualStrings("javascript", un.detectLanguage("script.js") orelse "");
try testing.expectEqualStrings("typescript", un.detectLanguage("script.ts") orelse "");
try testing.expectEqualStrings("go", un.detectLanguage("script.go") orelse "");
try testing.expectEqualStrings("rust", un.detectLanguage("script.rs") orelse "");
try testing.expectEqualStrings("c", un.detectLanguage("script.c") orelse "");
try testing.expectEqualStrings("cpp", un.detectLanguage("script.cpp") orelse "");
try testing.expectEqualStrings("d", un.detectLanguage("script.d") orelse "");
try testing.expectEqualStrings("zig", un.detectLanguage("script.zig") orelse "");
try testing.expectEqualStrings("bash", un.detectLanguage("script.sh") orelse "");
try testing.expectEqualStrings("ruby", un.detectLanguage("script.rb") orelse "");
try testing.expectEqualStrings("php", un.detectLanguage("script.php") orelse "");
try testing.expect(un.detectLanguage("script.unknown") == null);
try testing.expect(un.detectLanguage("script") == null);
}
test "version" {
const v = un.version();
try testing.expect(v.len > 0);
// Should be in semver format (at least "0.0.0")
try testing.expect(v.len >= 5);
}
test "lastError" {
// Set an error
un.setLastError("test error message");
// Retrieve it
const err = un.lastError();
try testing.expectEqualStrings("test error message", err);
// Clear it
un.setLastError("");
const err2 = un.lastError();
try testing.expectEqualStrings("", err2);
}
test "SDK_VERSION constant" {
try testing.expect(un.SDK_VERSION.len > 0);
try testing.expect(un.SDK_VERSION.len >= 5);
}
// ============================================================================
// Integration Tests - Test SDK internal consistency
// ============================================================================
test "hmacSign" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const secret_key = "test-secret";
const message = "test-message";
const result = try un.hmacSign(allocator, secret_key, message);
defer allocator.free(result);
// Should return a 64-character hex string
try testing.expectEqual(@as(usize, 64), result.len);
// Should be deterministic
const result2 = try un.hmacSign(allocator, secret_key, message);
defer allocator.free(result2);
try testing.expectEqualStrings(result, result2);
// Different inputs should produce different outputs
const result3 = try un.hmacSign(allocator, secret_key, "different-message");
defer allocator.free(result3);
try testing.expect(!mem.eql(u8, result, result3));
}
// ============================================================================
// Functional Tests - Test against real API (requires credentials)
// These tests are marked as skipped by default since they require credentials
// ============================================================================
fn hasCredentials() bool {
const pk = std.posix.getenv("UNSANDBOX_PUBLIC_KEY") orelse return false;
const sk = std.posix.getenv("UNSANDBOX_SECRET_KEY") orelse return false;
return pk.len > 0 and sk.len > 0;
}
fn getCredentials() ?struct { pk: []const u8, sk: []const u8 } {
const pk = std.posix.getenv("UNSANDBOX_PUBLIC_KEY") orelse return null;
const sk = std.posix.getenv("UNSANDBOX_SECRET_KEY") orelse return null;
if (pk.len == 0 or sk.len == 0) return null;
return .{ .pk = pk, .sk = sk };
}
test "healthCheck functional" {
if (!hasCredentials()) {
std.debug.print("SKIP (no credentials)\n", .{});
return;
}
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const healthy = try un.healthCheck(allocator);
std.debug.print("Health check result: {}\n", .{healthy});
}
test "getLanguages functional" {
const creds = getCredentials() orelse {
std.debug.print("SKIP (no credentials)\n", .{});
return;
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try un.getLanguages(allocator, creds.pk, creds.sk);
defer allocator.free(result);
try testing.expect(result.len > 0);
// Should contain python
try testing.expect(mem.indexOf(u8, result, "python") != null);
}
test "validateKeys functional" {
const creds = getCredentials() orelse {
std.debug.print("SKIP (no credentials)\n", .{});
return;
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try un.validateKeys(allocator, creds.pk, creds.sk);
defer allocator.free(result);
try testing.expect(result.len > 0);
}
test "sessionList functional" {
const creds = getCredentials() orelse {
std.debug.print("SKIP (no credentials)\n", .{});
return;
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try un.sessionList(allocator, creds.pk, creds.sk);
defer allocator.free(result);
try testing.expect(result.len > 0);
}
test "serviceList functional" {
const creds = getCredentials() orelse {
std.debug.print("SKIP (no credentials)\n", .{});
return;
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try un.serviceList(allocator, creds.pk, creds.sk);
defer allocator.free(result);
try testing.expect(result.len > 0);
}
test "snapshotList functional" {
const creds = getCredentials() orelse {
std.debug.print("SKIP (no credentials)\n", .{});
return;
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try un.snapshotList(allocator, creds.pk, creds.sk);
defer allocator.free(result);
try testing.expect(result.len > 0);
}
test "imageList functional" {
const creds = getCredentials() orelse {
std.debug.print("SKIP (no credentials)\n", .{});
return;
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const result = try un.imageList(allocator, null, creds.pk, creds.sk);
defer allocator.free(result);
try testing.expect(result.len > 0);
}