use super::*;
use crate::test_support::{fixture, remove};
const COMMIT: &str = "0123456789abcdef0123456789abcdef01234567";
const OTHER_COMMIT: &str = "89abcdef0123456789abcdef0123456789abcdef";
const BRANCH: &str = "refs/heads/main";
fn region(words: &[&str]) -> Vec<OsString> {
return words.iter().map(OsString::from).collect();
}
#[test]
fn the_text_names_the_branch_the_commit_the_reason_and_the_remedy() {
let said: &str = "! [rejected] main -> main (non-fast-forward)";
let text: String = push_failure_text(BRANCH, COMMIT, said);
assert!(text.contains("branch main"), "{text}");
assert!(text.contains(&COMMIT[..SHORT_COMMIT]), "{text}");
assert!(text.contains(said), "{text}");
assert!(text.contains("saved in this repository"), "{text}");
assert!(text.contains("`git push`"), "{text}");
assert!(text.contains("`git pull`"), "{text}");
assert!(text.ends_with(PUSH_FAILED_NOTE), "{text}");
}
#[test]
fn an_empty_reason_is_said_plainly() {
let text: String = push_failure_text(BRANCH, COMMIT, " \n");
assert!(text.contains(NO_REASON), "{text}");
assert!(!text.contains("Git said:"), "{text}");
}
#[test]
fn credentials_and_the_lfs_endpoint_setting_are_masked() {
let said: &str = "fatal: unable to access 'https://user:s3cret@example.invalid/repo.git/': 403\n\
error: lfs.url=https://tok3n@lfs.example.invalid/x is not allowed\n\
remote: denied";
let text: String = push_failure_text(BRANCH, COMMIT, said);
for secret in ["s3cret", "tok3n", "lfs.url", "user:"] {
assert!(!text.contains(secret), "{secret} leaked: {text}");
}
assert!(text.contains(mask_userinfo_text("https://user:s3cret@example.invalid/").as_str()), "{text}");
assert!(text.contains(LEFT_OUT_LINE), "{text}");
assert!(text.contains("remote: denied"), "{text}");
}
#[test]
fn control_characters_are_dropped_and_long_output_is_cut() {
let cleaned: String = clean_reason("remote: \u{1b}[31mred\u{1b}[0m\u{7}\n\tindented");
assert_eq!(cleaned, "remote: [31mred[0m\n\tindented");
let long: String = "x".repeat(LONGEST_REASON * 2);
let cut: String = clean_reason(long.as_str());
assert!(cut.len() < LONGEST_REASON + 100, "{}", cut.len());
assert!(cut.ends_with("(Git's output is cut here.)"));
}
#[test]
fn record_names_separate_branches_and_stay_valid_file_names() {
let short: String = record_name("refs/heads/a", COMMIT);
let longer: String = record_name("refs/heads/a-b", COMMIT);
assert!(!longer.starts_with(branch_prefix("refs/heads/a").as_str()), "{short} / {longer}");
let huge: String = format!("refs/heads/{}", "feature/".repeat(60));
assert!(record_name(huge.as_str(), COMMIT).len() < 255);
assert_ne!(record_name(huge.as_str(), COMMIT), record_name(format!("{huge}x").as_str(), COMMIT));
}
#[test]
fn a_record_is_taken_once_and_a_repeat_leaves_one() {
let root: PathBuf = fixture("push-failure-once");
record_push_failure(root.as_path(), BRANCH, COMMIT, "first").expect("record");
record_push_failure(root.as_path(), BRANCH, COMMIT, "again").expect("record");
let shown: Vec<String> = take_push_failures(root.as_path());
assert_eq!(shown, vec![push_failure_text(BRANCH, COMMIT, "again")]);
assert!(take_push_failures(root.as_path()).is_empty(), "a record is shown once");
remove(root.as_path());
}
#[test]
fn nothing_failed_means_nothing_to_read_and_nothing_created() {
let root: PathBuf = fixture("push-failure-none");
assert!(take_push_failures(root.as_path()).is_empty());
clear_push_failures(root.as_path(), BRANCH);
assert!(!notice_directory(root.as_path()).exists());
remove(root.as_path());
}
#[test]
fn clearing_a_branch_keeps_the_records_of_other_branches() {
let root: PathBuf = fixture("push-failure-clear");
record_push_failure(root.as_path(), BRANCH, COMMIT, "main failed").expect("record");
record_push_failure(root.as_path(), "refs/heads/main-two", OTHER_COMMIT, "two failed").expect("record");
clear_push_failures(root.as_path(), BRANCH);
let shown: Vec<String> = take_push_failures(root.as_path());
assert_eq!(shown, vec![push_failure_text("refs/heads/main-two", OTHER_COMMIT, "two failed")]);
remove(root.as_path());
}
#[test]
fn machine_read_commands_are_told_from_human_ones() {
for command in ["rev-parse", "cat-file", "for-each-ref", "ls-files", "config", "upload-pack", "update-ref", "diff-index"] {
assert!(is_machine_read(command.as_bytes(), &[]), "{command}");
}
for words in [&["--porcelain"][..], &["--porcelain=v2", "-b"], &["-z"], &["--null"], &["--format=%H"], &["--pretty=format:%h"], &["-s", "-z"]] {
assert!(is_machine_read(b"status", ®ion(words)), "{words:?}");
}
for (command, words) in [("status", &[][..]), ("log", &["--oneline"]), ("diff", &["--stat"]), ("branch", &[]), ("pull", &[])] {
assert!(!is_machine_read(command.as_bytes(), ®ion(words)), "{command} {words:?}");
}
assert!(!is_machine_read(b"log", ®ion(&["--", "-z"])));
}