use std::path::Path;
use super::claude_code_gh_env::{gh_env_source_prefix, write_gh_env_file};
use super::{resume_command, spawn_command};
const TEST_CWD: &str = "/tmp/ws";
const TEST_SESSION_ID: &str = "11111111-2222-3333-4444-555555555555";
#[test]
fn write_gh_env_file_empty_is_none() {
assert!(write_gh_env_file(&[]).is_none());
}
#[test]
fn write_gh_env_file_writes_export_lines_in_order() {
let gh_env = vec![
("GH_TOKEN".to_string(), "ghp_fake_token".to_string()),
("GH_USER".to_string(), "bobmatnyc".to_string()),
];
let file = write_gh_env_file(&gh_env).expect("file written");
let content = std::fs::read_to_string(&file).expect("read gh-env file");
let _ = std::fs::remove_file(&file);
let token_pos = content
.find("export GH_TOKEN='ghp_fake_token'")
.expect("token line");
let user_pos = content
.find("export GH_USER='bobmatnyc'")
.expect("user line");
assert!(
token_pos < user_pos,
"GH_TOKEN export must precede GH_USER export: {content}"
);
}
#[cfg(unix)]
#[test]
fn write_gh_env_file_is_mode_0600() {
use std::os::unix::fs::PermissionsExt;
let gh_env = vec![("GH_TOKEN".to_string(), "ghp_fake_token".to_string())];
let file = write_gh_env_file(&gh_env).expect("file written");
let mode = std::fs::metadata(&file)
.expect("metadata")
.permissions()
.mode()
& 0o777;
let _ = std::fs::remove_file(&file);
assert_eq!(mode, 0o600, "gh-env file must be mode 0600, got {mode:o}");
}
#[test]
fn gh_env_source_prefix_none_is_empty() {
assert_eq!(gh_env_source_prefix(None), "");
}
#[test]
fn gh_env_source_prefix_sources_and_deletes() {
let prefix = gh_env_source_prefix(Some(Path::new("/tmp/tm-gh-env-test.sh")));
assert_eq!(
prefix,
". '/tmp/tm-gh-env-test.sh'; rm -f '/tmp/tm-gh-env-test.sh'; "
);
}
#[test]
fn spawn_command_sources_gh_env_file_before_env_invocation() {
let cmd = spawn_command(
Path::new(TEST_CWD),
"claude",
None,
TEST_SESSION_ID,
None,
None,
Some(Path::new("/tmp/tm-gh-env-test.sh")),
);
assert!(
cmd.contains(
". '/tmp/tm-gh-env-test.sh'; rm -f '/tmp/tm-gh-env-test.sh'; env -u ANTHROPIC_API_KEY"
),
"gh-env source-and-delete must immediately precede the env invocation: {cmd}"
);
assert!(!cmd.contains("GH_TOKEN="), "cmd: {cmd}");
assert!(!cmd.contains("GH_USER="), "cmd: {cmd}");
}
#[test]
fn spawn_command_without_gh_env_is_byte_identical_to_pre_3025() {
let with_none = spawn_command(
Path::new(TEST_CWD),
"claude",
None,
TEST_SESSION_ID,
None,
None,
None,
);
assert!(!with_none.contains("gh-env"), "cmd: {with_none}");
assert!(!with_none.contains(". '"), "cmd: {with_none}");
}
#[test]
fn resume_command_sources_gh_env_file_before_env_invocation() {
let cmd = resume_command(
Path::new(TEST_CWD),
"claude",
None,
None,
false,
TEST_SESSION_ID,
None,
None,
Some(Path::new("/tmp/tm-gh-env-test.sh")),
);
assert!(
cmd.contains(
". '/tmp/tm-gh-env-test.sh'; rm -f '/tmp/tm-gh-env-test.sh'; env -u ANTHROPIC_API_KEY"
),
"gh-env source-and-delete must immediately precede the env invocation: {cmd}"
);
}