use super::*;
#[test]
fn write_card_projects_lifecycle_metadata_path_and_safe_copy() {
let running = write_card_state(
"write-running",
ActivityStatus::Writing,
serde_json::json!({"path":"pending.txt", "content":"must not render"}),
serde_json::json!({}),
"content must not render",
);
let card = &project_cards(&running)[0];
assert_eq!(card.role, TranscriptCardRole::Write);
assert_eq!(card.title, "Write");
assert_eq!(card.body, "pending.txt");
assert!(!running.transcript_visual_text().contains("must not render"));
let success = write_card_state(
"write-success",
ActivityStatus::Success,
serde_json::json!({"path":"relative.txt", "content":"secret content"}),
serde_json::json!({"path":"/tmp/resolved.txt", "bytes":42}),
"secret content",
);
let card = &project_cards(&success)[0];
assert_eq!(card.title, "Write • 42 bytes");
assert_eq!(card.body, "/tmp/resolved.txt");
assert!(!card.body.contains("42 bytes"));
assert!(!success.transcript_visual_text().contains("secret content"));
let failed = write_card_state(
"write-failed",
ActivityStatus::Failed,
serde_json::json!({"path":"fallback.txt"}),
serde_json::json!({"path":"/tmp/should-not-win.txt", "bytes":999}),
"\npermission denied\ntrace must not render",
);
let card = &project_cards(&failed)[0];
assert_eq!(card.title, "Write");
assert_eq!(card.body, "fallback.txt\npermission denied");
assert!(!card.body.contains("should-not-win"));
assert!(!card.body.contains("trace must not render"));
let canceled = write_card_state(
"write-canceled",
ActivityStatus::Canceled,
serde_json::json!({"path":"cancelled.txt"}),
serde_json::json!({}),
"ignored output",
);
let card = &project_cards(&canceled)[0];
assert_eq!(card.status, TranscriptCardStatus::Canceled);
assert_eq!(card.title, "Write • canceled");
assert_eq!(card.body, "cancelled.txt\nCanceled before completion");
let runtime_canceled = write_card_state(
"write-runtime-canceled",
ActivityStatus::Failed,
serde_json::json!({"path":"runtime-cancelled.txt"}),
serde_json::json!({}),
"prompt canceled",
);
let card = &project_cards(&runtime_canceled)[0];
assert_eq!(card.status, TranscriptCardStatus::Canceled);
assert_eq!(card.title, "Write • canceled");
assert_eq!(
card.body,
"runtime-cancelled.txt\nCanceled before completion"
);
let unsafe_state = write_card_state(
"write-safe",
ActivityStatus::Success,
serde_json::json!({"path":"relative.txt", "content":"Bearer content-secret"}),
serde_json::json!({"path":"/tmp/token=path-secret\u{1b}[2m.txt", "bytes":1}),
"ignored",
);
let card = &project_cards(&unsafe_state)[0];
assert!(card.body.contains("<redacted>"));
assert!(!card.body.contains("path-secret"));
assert!(!card.body.contains('\u{1b}'));
let long_path = format!("/tmp/{}.txt", "a".repeat(300));
let long_state = write_card_state(
"write-long-path",
ActivityStatus::Success,
serde_json::json!({"path":"relative.txt", "content":"Bearer content-secret"}),
serde_json::json!({"path":long_path, "bytes":1}),
"ignored",
);
let card = &project_cards(&long_state)[0];
assert!(UnicodeWidthStr::width(card.body.as_str()) <= PREVIEW_LINE_MAX_DISPLAY_WIDTH);
assert!(card.body.ends_with("… [truncated]"));
let unicode_state = write_card_state(
"write-unicode",
ActivityStatus::Success,
serde_json::json!({"path":"relative.txt", "content":"hidden"}),
serde_json::json!({"path":"/tmp/界面.txt", "bytes":1}),
"ignored",
);
assert!(visual_text_for_width(&unicode_state, 12).contains("/tmp/界面.txt"));
for width in [1, 2, 3, 12, CARD_LAYOUT_MIN_WIDTH, 80] {
let lines = visual_lines(&long_state, width);
assert!(lines.iter().all(|line| {
UnicodeWidthStr::width(line_text(&line.line).as_str()) == usize::from(width)
}));
let copied = visual_text_for_width(&long_state, width);
assert!(copied.contains("Write"));
assert!(!copied.contains("content-secret"));
assert!(!copied.contains('\u{1b}'));
}
}