Files
distribution/tests/manifest_parse.sx
agra 6c19f1073f lang migration: rename signed integer types sN -> iN
Mechanical sweep of all .sx sources and plan docs (PLAN.md, current/,
.agents/) for the sx language rename (s8/s16/s32/s64 -> i8/i16/i32/i64).
Verified: make build + make test, 14/14.
2026-06-12 09:39:49 +03:00

92 lines
4.2 KiB
Plaintext

// Acceptance for P3.2 — the v0 publish manifest model + parse + validate.
//
// 1. Parses `examples/dist.json` into a typed `Manifest` and asserts the
// fields (app/version/channel, the artifact count, and each artifact's
// platform + path).
// 2. Asserts each failure class surfaces a DISTINCT machine-readable error
// (never a silent default):
// - a missing required field (a manifest lacking `version`) -> MissingField
// - an unknown platform ("psvita") -> UnknownPlatform
// - a non-existent artifact path -> MissingArtifact
//
// Prints a PASS/FAIL line per case and exits non-zero if any case behaves
// unexpectedly, so the test runner counts it as a failure.
#import "modules/std.sx";
#import "../src/domain/platform.sx";
#import "../src/manifest/manifest.sx";
// ── happy path: examples/dist.json -> typed Manifest ────────────────────
check_parse_valid :: (alloc: Allocator) -> bool {
m, e := load_manifest("examples/dist.json", alloc);
if e { return false; }
if m.app != "acme-app" { return false; }
if m.version != "1.2.3" { return false; }
if m.channel != "stable" { return false; }
if m.artifacts.len != 2 { return false; }
a0 := m.artifacts.items[0];
if a0.platform != .android_apk { return false; }
if a0.path != "fixtures/acme-1.2.3-android.apk" { return false; }
if a0.filename != "acme.apk" { return false; }
if a0.content_type != "application/vnd.android.package-archive" { return false; }
a1 := m.artifacts.items[1];
if a1.platform != .ios { return false; }
if a1.path != "fixtures/acme-1.2.3-ios.ipa" { return false; }
if a1.filename != "" { return false; } // optional override, absent -> ""
return true;
}
// ── failure: a required field (version) is absent -> MissingField ───────
check_missing_version :: (alloc: Allocator) -> bool {
src := "{\"app\":\"acme-app\",\"channel\":\"stable\",\"artifacts\":[{\"platform\":\"ios\",\"path\":\"fixtures/acme-1.2.3-ios.ipa\"}]}";
_, e := parse_manifest(src, alloc);
return e == error.MissingField;
}
// ── failure: an artifact platform id is unknown -> UnknownPlatform ──────
check_unknown_platform :: (alloc: Allocator) -> bool {
src := "{\"app\":\"acme-app\",\"version\":\"1.2.3\",\"channel\":\"stable\",\"artifacts\":[{\"platform\":\"psvita\",\"path\":\"fixtures/acme-1.2.3-ios.ipa\"}]}";
_, e := parse_manifest(src, alloc);
return e == error.UnknownPlatform;
}
// ── failure: an artifact path does not exist on disk -> MissingArtifact ─
// Parse SUCCEEDS (parse is filesystem-free); the missing file surfaces only
// at validate time, against the manifest's base directory.
check_missing_artifact_path :: (alloc: Allocator) -> bool {
src := "{\"app\":\"acme-app\",\"version\":\"1.2.3\",\"channel\":\"stable\",\"artifacts\":[{\"platform\":\"ios\",\"path\":\"fixtures/does-not-exist.ipa\"}]}";
m, pe := parse_manifest(src, alloc);
if pe { return false; } // parse must not fail here
raised := false;
matched := false;
validate_manifest(m, "examples") catch (err) { raised = true; matched = (err == error.MissingArtifact); };
return raised and matched;
}
run_case :: (label: string, ok: bool) -> i32 {
if ok { print(" PASS {}\n", label); return 0; }
print(" FAIL {}\n", label);
return 1;
}
main :: () -> i32 {
gpa := GPA.init();
arena := Arena.init(xx gpa, 65536);
defer arena.deinit();
failures : i32 = 0;
failures += run_case("parse valid dist.json -> fields", check_parse_valid(xx arena));
failures += run_case("missing version -> MissingField", check_missing_version(xx arena));
failures += run_case("unknown platform 'psvita' -> UnknownPlatform", check_unknown_platform(xx arena));
failures += run_case("nonexistent path -> MissingArtifact", check_missing_artifact_path(xx arena));
print("------------------------------------------------\n");
if failures == 0 {
print("manifest_parse: ALL CASES PASS\n");
return 0;
}
print("manifest_parse: {} CASE(S) FAILED\n", failures);
return 1;
}