mod common;
use common::{copy_fixture, run_ok, workdir};
fn fixture() -> tempfile::TempDir {
let repo = copy_fixture("contract-ontology-service");
let dir = workdir(repo.path());
run_ok(&dir, &["index", "--quiet"]);
repo
}
#[test]
fn atlas_renders_per_subclass_contract_groups() {
let repo = fixture();
let dir = workdir(repo.path());
let atlas = run_ok(&dir, &["atlas"]);
assert!(atlas.contains("# CONTRACTS"), "{atlas}");
assert!(atlas.contains("http: GET /users"), "http contract: {atlas}");
assert!(atlas.contains("cli: --port"), "cli contract: {atlas}");
assert!(atlas.contains("cli: --verbose"), "cli contract: {atlas}");
assert!(atlas.contains("event: user.created"), "event contract: {atlas}");
assert!(atlas.contains("config: PORT"), "config contract: {atlas}");
assert!(atlas.contains("config: DEBUG"), "config contract: {atlas}");
assert!(atlas.contains("public-api: NewUser"), "public-api contract (go): {atlas}");
assert!(atlas.contains("public-api: toJson"), "public-api contract (ts): {atlas}");
assert!(atlas.contains("public-api: list_users"), "public-api contract (python): {atlas}");
assert!(atlas.contains("extension: Plugin"), "extension contract (ts): {atlas}");
assert!(atlas.contains("extension: Greeter"), "extension contract (java): {atlas}");
assert!(
atlas.contains("serialization: to_dict/from_dict"),
"serialization contract (python): {atlas}"
);
assert!(
atlas.contains("serialization: toJson/fromJson"),
"serialization contract (ts/java): {atlas}"
);
assert!(
atlas.contains("serialization: Serialize/Deserialize"),
"serialization contract (rust): {atlas}"
);
assert!(
atlas.contains("serialization: MarshalJSON/UnmarshalJSON"),
"serialization contract (go): {atlas}"
);
let atlas2 = run_ok(&dir, &["atlas"]);
assert_eq!(atlas, atlas2, "atlas must be deterministic");
}
#[test]
fn contracts_render_as_grouped_subclass_lines_only() {
let repo = fixture();
let dir = workdir(repo.path());
let atlas = run_ok(&dir, &["atlas"]);
let body = atlas
.split("# CONTRACTS")
.nth(1)
.expect("CONTRACTS header")
.split("\n# ")
.next()
.unwrap_or("");
let lines: Vec<&str> = body
.lines()
.map(|l| l.trim())
.filter(|l| !l.is_empty())
.collect();
assert!(!lines.is_empty(), "CONTRACTS body must render lines: {atlas}");
const SUBCLASS_PREFIXES: [&str; 12] = [
"call", "public-api", "http", "rpc", "cli", "event", "message", "schema", "config",
"plugin", "extension", "serialization",
];
for l in &lines {
let prefix = l.split(':').next().unwrap_or("");
assert!(
SUBCLASS_PREFIXES.contains(&prefix),
"line has no known subclass prefix: {l:?} (full: {atlas})"
);
}
assert!(
!lines.iter().any(|l| l.starts_with("annotation:")),
"annotations must not be contracts: {lines:?}"
);
assert!(
!lines.iter().any(|l| l.starts_with("call: Debug") || l.starts_with("call: app.get")),
"framework noise must not be contracts: {lines:?}"
);
let prefixes: Vec<&str> = lines.iter().map(|l| l.split(':').next().unwrap()).collect();
let mut sorted = prefixes.clone();
sorted.sort_unstable();
assert_eq!(prefixes, sorted, "per-subclass groups must be contiguous: {lines:?}");
let atlas2 = run_ok(&dir, &["atlas"]);
assert_eq!(atlas, atlas2, "atlas must be deterministic");
}