// Acceptance for P2.1 — the domain boundary validator. Constructs valid // App/Release/Artifact/Channel and asserts they are accepted, then mutates // each into one invalid form and asserts it is rejected with the SPECIFIC // typed ValidationErr (not merely "some failure"). Prints a pass/fail line // per case and exits non-zero if any case behaves unexpectedly. #import "modules/std.sx"; #import "../src/domain/platform.sx"; #import "../src/domain/app.sx"; #import "../src/domain/release.sx"; #import "../src/domain/artifact.sx"; #import "../src/domain/channel.sx"; #import "../src/domain/validate.sx"; // ── Valid fixtures ────────────────────────────────────────────────────── valid_app :: () -> App { a : App = .{ id = "app_01", slug = "acme-app", display_name = "Acme App", owner = "user_01", visibility = .public, created_at = 1700000000, updated_at = 1700000000, }; a.bundle_ids.append(BundleId.{ platform = .ios, value = "co.acme.app" }); return a; } valid_release :: () -> Release { return Release.{ id = "rel_01", app_id = "app_01", version = "1.2.3-beta.1", build = 42, channel = "stable", notes = "first cut", created_by = "user_01", created_at = 1700000000, published_at = 1700000200, }; } valid_artifact :: () -> Artifact { return Artifact.{ id = "art_01", app_id = "app_01", release_id = "rel_01", platform = .android_apk, filename = "acme.apk", content_type = "application/vnd.android.package-archive", size_bytes = 10485760, sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", storage_key = "apps/app_01/rel_01/acme.apk", metadata = "{\"min_os\":\"14\"}", validation_status = .valid, }; } valid_channel :: () -> Channel { return Channel.{ app_id = "app_01", name = "stable", current_release_id = "rel_01", policy = .percentage, rollout_percent = 25, }; } // ── Cases ─────────────────────────────────────────────────────────────── check_accepts_app :: () -> bool { a := valid_app(); ok := true; validate_app(a) catch { ok = false; }; return ok; } check_accepts_release :: () -> bool { r := valid_release(); ok := true; validate_release(r) catch { ok = false; }; return ok; } check_accepts_artifact :: () -> bool { a := valid_artifact(); ok := true; validate_artifact(a) catch { ok = false; }; return ok; } check_accepts_channel :: () -> bool { c := valid_channel(); ok := true; validate_channel(c) catch { ok = false; }; return ok; } check_accepts_platform :: () -> bool { p, e := parse_platform("android_apk"); ok := false; if !e { ok = (p == .android_apk); } return ok; } check_rejects_bad_slug :: () -> bool { a := valid_app(); a.slug = "Bad_Slug"; // uppercase + underscore matched := false; validate_app(a) catch e { matched = (e == error.BadSlug); }; return matched; } check_rejects_empty_version :: () -> bool { r := valid_release(); r.version = ""; matched := false; validate_release(r) catch e { matched = (e == error.EmptyVersion); }; return matched; } check_rejects_bad_version :: () -> bool { r := valid_release(); r.version = "1.2"; // missing PATCH component matched := false; validate_release(r) catch e { matched = (e == error.BadVersion); }; return matched; } check_rejects_unknown_platform :: () -> bool { _, e := parse_platform("plan9"); return e == error.UnknownPlatform; } check_rejects_bad_channel :: () -> bool { c := valid_channel(); c.name = "Bad Channel"; // space + uppercase matched := false; validate_channel(c) catch e { matched = (e == error.BadChannelName); }; return matched; } check_rejects_empty_content_type :: () -> bool { a := valid_artifact(); a.content_type = ""; // required string cleared matched := false; validate_artifact(a) catch e { matched = (e == error.MissingField); }; return matched; } check_rejects_bad_size :: () -> bool { a := valid_artifact(); a.size_bytes = -1; // a content-addressed artifact has positive bytes matched := false; validate_artifact(a) catch e { matched = (e == error.BadSize); }; return matched; } check_rejects_bad_digest :: () -> bool { a := valid_artifact(); a.sha256 = "not-a-sha"; // not 64 lowercase-hex chars matched := false; validate_artifact(a) catch e { matched = (e == error.BadDigest); }; return matched; } // Contract pins: read back the renamed Release.published_at and the new // Artifact.metadata. These references fail to compile against the pre-change // structs (Release.updated_at / no Artifact.metadata). check_release_published_at :: () -> bool { r := valid_release(); return r.published_at == 1700000200; } check_artifact_metadata :: () -> bool { a := valid_artifact(); return a.metadata == "{\"min_os\":\"14\"}"; } run_case :: (label: string, ok: bool) -> s32 { if ok { print(" PASS {}\n", label); return 0; } print(" FAIL {}\n", label); return 1; } main :: () -> s32 { failures : s32 = 0; failures += run_case("accept: valid app", check_accepts_app()); failures += run_case("accept: valid release", check_accepts_release()); failures += run_case("accept: valid artifact", check_accepts_artifact()); failures += run_case("accept: valid channel", check_accepts_channel()); failures += run_case("accept: platform 'android_apk'", check_accepts_platform()); failures += run_case("reject: bad slug -> BadSlug", check_rejects_bad_slug()); failures += run_case("reject: empty version -> EmptyVersion", check_rejects_empty_version()); failures += run_case("reject: bad version -> BadVersion", check_rejects_bad_version()); failures += run_case("reject: unknown platform -> UnknownPlatform", check_rejects_unknown_platform()); failures += run_case("reject: bad channel -> BadChannelName", check_rejects_bad_channel()); failures += run_case("reject: empty content_type -> MissingField", check_rejects_empty_content_type()); failures += run_case("reject: non-positive size_bytes -> BadSize", check_rejects_bad_size()); failures += run_case("reject: malformed sha256 -> BadDigest", check_rejects_bad_digest()); failures += run_case("contract: Release.published_at readback", check_release_published_at()); failures += run_case("contract: Artifact.metadata readback", check_artifact_metadata()); print("------------------------------------------------\n"); if failures == 0 { print("domain_validate: ALL CASES PASS\n"); return 0; } print("domain_validate: {} CASE(S) FAILED\n", failures); return 1; }