use super::*;
use crate::git::status::StashEntry;
#[test]
fn refresh_decision_runs_without_previous_refresh() {
let now = Instant::now();
assert_eq!(
refresh_decision(None, now, Duration::from_millis(1000)),
RefreshDecision::Now
);
}
#[test]
fn refresh_decision_delays_inside_cooldown() {
let last = Instant::now();
let now = last + Duration::from_millis(250);
assert_eq!(
refresh_decision(Some(last), now, Duration::from_millis(1000)),
RefreshDecision::Later(Duration::from_millis(750))
);
}
#[test]
fn refresh_decision_runs_after_cooldown() {
let last = Instant::now();
let now = last + Duration::from_millis(1000);
assert_eq!(
refresh_decision(Some(last), now, Duration::from_millis(1000)),
RefreshDecision::Now
);
}
#[test]
fn graph_status_changed_ignores_file_only_changes() {
let previous = test_status("main", Some("aaa"));
let next = test_status("main", Some("aaa"));
assert!(!graph_status_changed(
Some(&previous),
&next,
BranchFilter::All
));
}
#[test]
fn graph_status_changed_detects_head_changes() {
let previous = test_status("main", Some("aaa"));
let next = test_status("main", Some("bbb"));
assert!(graph_status_changed(
Some(&previous),
&next,
BranchFilter::All
));
}
#[test]
fn graph_status_changed_detects_stash_changes() {
let previous = test_status("main", Some("aaa"));
let mut next = test_status("main", Some("aaa"));
next.stashes.push(StashEntry {
index: 0,
message: "WIP on main".to_string(),
oid: "stash-oid".to_string(),
});
assert!(graph_status_changed(
Some(&previous),
&next,
BranchFilter::All
));
}
#[test]
fn graph_status_changed_detects_commit_on_other_branch() {
let previous = test_status("main", Some("aaa"));
let mut next = test_status("main", Some("aaa"));
next.refs.local = previous.refs.local ^ 0x9e37_79b9;
assert!(graph_status_changed(
Some(&previous),
&next,
BranchFilter::All
));
assert!(graph_status_changed(
Some(&previous),
&next,
BranchFilter::Local
));
}
#[test]
fn graph_status_changed_local_filter_ignores_remote_only_moves() {
let previous = test_status("main", Some("aaa"));
let mut next = test_status("main", Some("aaa"));
next.refs.remote = previous.refs.remote ^ 0x1234_5678;
assert!(!graph_status_changed(
Some(&previous),
&next,
BranchFilter::Local
));
assert!(graph_status_changed(
Some(&previous),
&next,
BranchFilter::All
));
}
fn test_status(branch: &str, head_oid: Option<&str>) -> RepoStatus {
RepoStatus {
branch: branch.to_string(),
head_oid: head_oid.map(str::to_string),
files: Vec::new(),
ahead: 0,
behind: 0,
is_dirty: false,
worktree_info: Vec::new(),
has_submodules: false,
submodules: Vec::new(),
has_dirty_submodules: false,
has_unpushed_submodules: false,
fetch_failed: false,
stashes: Vec::new(),
refs: crate::git::status::RefsFingerprint::default(),
}
}
fn make_repo(root: &std::path::Path, rel: &str) -> std::path::PathBuf {
let repo = root.join(rel);
let dot_git = repo.join(".git");
std::fs::create_dir_all(&dot_git).unwrap();
std::fs::write(dot_git.join("HEAD"), "ref: refs/heads/main\n").unwrap();
repo
}
fn displays(app: &App) -> Vec<String> {
app.repo_list
.repos
.iter()
.map(|r| r.display.clone())
.collect()
}
#[test]
fn app_opens_with_the_repo_list_already_sorted() {
let tmp = tempfile::TempDir::new().unwrap();
make_repo(tmp.path(), "alpha/zulu");
make_repo(tmp.path(), "zeta/bravo");
let config = Config {
root_dirs: vec![tmp.path().to_path_buf()],
scan_depth: 3,
..Config::default()
};
let mut app = App::new(config);
let at_startup = displays(&app);
assert_eq!(at_startup, ["alpha/zulu", "zeta/bravo"]);
app.sort_repos();
assert_eq!(
displays(&app),
at_startup,
"first rescan reshuffled the list"
);
}
#[test]
fn sort_repos_keeps_pinned_repos_on_top() {
let tmp = tempfile::TempDir::new().unwrap();
make_repo(tmp.path(), "aaa");
let pinned = make_repo(tmp.path(), "zzz");
let config = Config {
root_dirs: vec![tmp.path().to_path_buf()],
pinned_repos: vec![pinned],
scan_depth: 2,
..Config::default()
};
let mut app = App::new(config);
assert_eq!(displays(&app), ["zzz", "aaa"]);
app.sort_repos();
assert_eq!(displays(&app), ["zzz", "aaa"], "the pin was sorted away");
}