use serial_test::serial;
use std::process::{Command, Stdio};
use tempfile::TempDir;
const MX: &str = env!("CARGO_BIN_EXE_mx");
fn mx(dir: &TempDir, args: &[&str]) -> std::process::Output {
let mut cmd = Command::new(MX);
cmd.args(args)
.env("MX_CURRENT_AGENT", "agent-a")
.env("MX_SURREAL_MODE", "embedded")
.env("MX_SURREAL_ROOT", dir.path().join("surreal"))
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = cmd.spawn().expect("failed to spawn mx");
drop(child.stdin.take());
child.wait_with_output().expect("failed to wait on mx")
}
fn stdout_of(out: &std::process::Output) -> String {
String::from_utf8_lossy(&out.stdout).into_owned()
}
fn stderr_of(out: &std::process::Output) -> String {
String::from_utf8_lossy(&out.stderr).into_owned()
}
const HINT_MARK: &str = "private entry of yours";
const HINT_FLAG: &str = "--include-private";
#[test]
#[serial]
fn hint_reaches_stderr_only_and_never_stdout() {
let dir = TempDir::new().unwrap();
let add = mx(
&dir,
&[
"memory",
"add",
"--category",
"insight",
"--title",
"unique searchable widget",
"--content",
"unique searchable widget body",
"--private",
],
);
assert!(
add.status.success(),
"private add must succeed; stderr: {}",
stderr_of(&add)
);
let out = mx(&dir, &["memory", "list"]);
assert!(
out.status.success(),
"list must succeed; stderr: {}",
stderr_of(&out)
);
let (so, se) = (stdout_of(&out), stderr_of(&out));
assert!(
se.contains(HINT_MARK) && se.contains(HINT_FLAG),
"list hint must appear on STDERR; stderr was: {se:?}"
);
assert!(
!so.contains(HINT_MARK) && !so.contains(HINT_FLAG),
"list hint must NEVER touch STDOUT; stdout was: {so:?}"
);
let out = mx(&dir, &["memory", "search", "widget"]);
assert!(
out.status.success(),
"search must succeed; stderr: {}",
stderr_of(&out)
);
let (so, se) = (stdout_of(&out), stderr_of(&out));
assert!(
se.contains(HINT_MARK) && se.contains(HINT_FLAG),
"search hint must appear on STDERR; stderr was: {se:?}"
);
assert!(
!so.contains(HINT_MARK) && !so.contains(HINT_FLAG),
"search hint must NEVER touch STDOUT; stdout was: {so:?}"
);
let out = mx(&dir, &["memory", "list", "--json"]);
assert!(
out.status.success(),
"list --json must succeed; stderr: {}",
stderr_of(&out)
);
let so = stdout_of(&out);
assert!(
!so.contains(HINT_MARK) && !so.contains(HINT_FLAG),
"the hint must not appear in --json stdout; stdout was: {so:?}"
);
serde_json::from_str::<serde_json::Value>(so.trim())
.expect("list --json stdout must be valid JSON even when the hint fires on stderr");
let out = mx(&dir, &["memory", "list", "--include-private"]);
assert!(out.status.success(), "list --include-private must succeed");
let (so, se) = (stdout_of(&out), stderr_of(&out));
assert!(
so.contains("unique searchable widget"),
"the private entry must be visible with --include-private; stdout: {so:?}"
);
assert!(
!se.contains(HINT_MARK) && !so.contains(HINT_MARK),
"no hint when --include-private already reveals the entry; stdout: {so:?} stderr: {se:?}"
);
}