use assert_cmd::prelude::*;
use serde_json::Value;
use std::process::Command;
use tempfile::TempDir;
fn bin() -> Command {
Command::cargo_bin("grex").expect("grex binary built")
}
fn key_offset(body: &str, key: &str) -> Option<usize> {
let needle = format!("\"{key}\"");
body.find(&needle)
}
#[test]
fn ls_envelope_contains_both_workspace_and_pack() {
let tmp = TempDir::new().expect("tempdir");
std::fs::create_dir_all(tmp.path().join(".grex")).unwrap();
std::fs::write(
tmp.path().join(".grex/pack.yaml"),
"schema_version: \"1\"\nname: tmp\ntype: meta\n",
)
.unwrap();
let out = bin()
.current_dir(tmp.path())
.args(["--json", "ls"])
.assert()
.success()
.get_output()
.clone();
let stdout = String::from_utf8(out.stdout).expect("stdout utf-8");
let v: Value = serde_json::from_str(&stdout)
.unwrap_or_else(|e| panic!("ls --json must produce valid JSON: {e}\n---\n{stdout}\n---"));
let workspace = v
.get("workspace")
.and_then(Value::as_str)
.unwrap_or_else(|| panic!("ls envelope MUST contain `workspace` key; got:\n{stdout}"));
let pack = v.get("pack").and_then(Value::as_str).unwrap_or_else(|| {
panic!("ls envelope MUST contain `pack` key (v1.3.0 dual-emit); got:\n{stdout}")
});
assert_eq!(
workspace, pack,
"v1.3.0 contract: `workspace` and `pack` MUST carry identical values; got workspace={workspace:?}, pack={pack:?}"
);
let ws_offset = key_offset(&stdout, "workspace").expect("workspace key in raw output");
let pack_offset = key_offset(&stdout, "pack").expect("pack key in raw output");
assert!(
ws_offset < pack_offset,
"v1.3.0 contract: `workspace` MUST appear before `pack` in JSON output (diff-friendly stability); ws={ws_offset}, pack={pack_offset}\n{stdout}"
);
}
#[test]
fn doctor_envelope_contains_both_workspace_and_pack() {
let tmp = TempDir::new().expect("tempdir");
let out = bin()
.current_dir(tmp.path())
.args(["doctor", "--json"])
.output()
.expect("spawn grex doctor --json");
let stdout = String::from_utf8(out.stdout).expect("stdout utf-8");
let v: Value = serde_json::from_str(&stdout).unwrap_or_else(|e| {
panic!("doctor --json must produce valid JSON: {e}\n---\n{stdout}\n---")
});
let workspace = v.get("workspace").and_then(Value::as_str).unwrap_or_else(|| {
panic!("doctor envelope MUST contain `workspace` key (v1.3.0 dual-emit); got:\n{stdout}")
});
let pack = v.get("pack").and_then(Value::as_str).unwrap_or_else(|| {
panic!("doctor envelope MUST contain `pack` key (v1.3.0 dual-emit); got:\n{stdout}")
});
assert_eq!(
workspace, pack,
"v1.3.0 contract: doctor `workspace` and `pack` MUST carry identical values; got workspace={workspace:?}, pack={pack:?}"
);
let ws_offset = key_offset(&stdout, "workspace").expect("workspace key in raw output");
let pack_offset = key_offset(&stdout, "pack").expect("pack key in raw output");
assert!(
ws_offset < pack_offset,
"v1.3.0 contract: doctor `workspace` MUST appear before `pack` in JSON output; ws={ws_offset}, pack={pack_offset}\n{stdout}"
);
}