Skip to content

Commit ba966ba

Browse files
chtnnhcursoragent
andcommitted
Fix Windows CI and restore ≥95% coverage.
Gate the unix git-wrapper probe test behind cfg(unix), and add probe/gitfile/label coverage so the line gate clears again. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 449af04 commit ba966ba

2 files changed

Lines changed: 117 additions & 1 deletion

File tree

tests/commands_extra.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,36 @@ fn doctor_detached_and_json() {
114114
.stdout(predicates::str::contains("detached").or(predicates::str::contains("warn")));
115115
}
116116

117+
#[test]
118+
fn doctor_reports_gitfile_worktree() {
119+
let f = Fixture::with_repos(&["mainrepo"]);
120+
let linked = f.root.path().join("linked");
121+
fs::create_dir_all(&linked).unwrap();
122+
let real_git = f.repos[0].join(".git");
123+
fs::write(
124+
linked.join(".git"),
125+
format!("gitdir: {}\n", real_git.display()),
126+
)
127+
.unwrap();
128+
129+
f.gg()
130+
.args([
131+
"--root",
132+
f.root.path().to_str().unwrap(),
133+
"--in",
134+
linked.to_str().unwrap(),
135+
"--include-submodules",
136+
"doctor",
137+
])
138+
.assert()
139+
.success()
140+
.stdout(
141+
predicates::str::contains("gitfile")
142+
.or(predicates::str::contains("worktree"))
143+
.or(predicates::str::contains("submodule")),
144+
);
145+
}
146+
117147
#[test]
118148
fn only_detached_filter() {
119149
let f = Fixture::with_repos(&["onbranch", "detachme"]);

tests/unit_repo_filters.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use git_gist::filters;
66
use git_gist::repo::{self, ProbeOpts, Repo, RepoStatus};
77
use serial_test::serial;
88
use std::fs;
9-
use std::os::unix::fs::PermissionsExt;
109
use std::process::Command;
1110
use tempfile::tempdir;
1211

@@ -188,7 +187,10 @@ fn probe_opts_for_cli_filters_skips_unused_work() {
188187

189188
#[test]
190189
#[serial]
190+
#[cfg(unix)]
191191
fn probe_with_filter_tree_uses_few_git_invocations() {
192+
use std::os::unix::fs::PermissionsExt;
193+
192194
let (_dir, repo) = setup_repo(true);
193195
let wrapper_dir = tempdir().unwrap();
194196
let log = wrapper_dir.path().join("git.log");
@@ -280,3 +282,87 @@ fn resolve_git_dir_for_normal_repo() {
280282
assert!(git_dir.ends_with(".git"));
281283
assert!(git_dir.is_dir());
282284
}
285+
286+
#[test]
287+
fn resolve_git_dir_from_gitfile() {
288+
let dir = tempdir().unwrap();
289+
let work = dir.path().join("work");
290+
let real = dir.path().join("real.git");
291+
fs::create_dir_all(&work).unwrap();
292+
fs::create_dir_all(&real).unwrap();
293+
294+
fs::write(work.join(".git"), format!("gitdir: {}\n", real.display())).unwrap();
295+
assert_eq!(repo::resolve_git_dir(&work), real);
296+
297+
let work2 = dir.path().join("work2");
298+
fs::create_dir_all(&work2).unwrap();
299+
fs::write(work2.join(".git"), "gitdir: ../real.git\n").unwrap();
300+
assert_eq!(repo::resolve_git_dir(&work2), work2.join("../real.git"));
301+
}
302+
303+
#[test]
304+
fn apply_porcelain_v2_unknown_when_no_head() {
305+
let mut status = RepoStatus::default();
306+
repo::apply_porcelain_v2(&mut status, "# branch.oid abcdef0\n");
307+
assert_eq!(status.branch, "(unknown)");
308+
}
309+
310+
#[test]
311+
fn apply_porcelain_v2_detached_without_oid_uses_fallback() {
312+
let mut status = RepoStatus::default();
313+
repo::apply_porcelain_v2(&mut status, "# branch.head (detached from deadbeef)\n");
314+
assert!(status.detached);
315+
assert_eq!(status.branch, "detached");
316+
}
317+
318+
#[test]
319+
fn probe_stale_and_doctor_opts() {
320+
let (_dir, repo) = setup_repo(true);
321+
let stale = repo::probe_with(&repo.path, ProbeOpts::STALE).unwrap();
322+
assert!(stale.last_commit_age_secs.is_some());
323+
assert_eq!(stale.last_commit_subject.as_deref(), Some("c"));
324+
assert!(stale.branch.is_empty());
325+
326+
fs::write(repo.path.join(".git").join("MERGE_HEAD"), "deadbeef\n").unwrap();
327+
let doctor = repo::probe_with(&repo.path, ProbeOpts::DOCTOR).unwrap();
328+
assert_eq!(doctor.in_progress.as_deref(), Some("merge"));
329+
assert_eq!(doctor.branch, "main");
330+
}
331+
332+
#[test]
333+
fn probe_filter_stash_counts_entries() {
334+
let (_dir, repo) = setup_repo(true);
335+
fs::write(repo.path.join("extra"), "y").unwrap();
336+
let stash = Command::new("git")
337+
.args(["stash", "push", "-u", "-m", "wip"])
338+
.current_dir(&repo.path)
339+
.env("GIT_AUTHOR_NAME", "T")
340+
.env("GIT_AUTHOR_EMAIL", "t@e.com")
341+
.env("GIT_COMMITTER_NAME", "T")
342+
.env("GIT_COMMITTER_EMAIL", "t@e.com")
343+
.stdout(std::process::Stdio::null())
344+
.stderr(std::process::Stdio::null())
345+
.status()
346+
.unwrap();
347+
assert!(stash.success());
348+
let status = repo::probe_with(&repo.path, ProbeOpts::FILTER_STASH).unwrap();
349+
assert!(status.stashed >= 1);
350+
assert!(status.branch.is_empty());
351+
}
352+
353+
#[test]
354+
fn output_repo_label_respects_show_path() {
355+
use git_gist::cli::OutputFormat;
356+
use git_gist::output::OutputCtx;
357+
358+
let root = tempdir().unwrap();
359+
let nested = root.path().join("oss").join("demo");
360+
fs::create_dir_all(&nested).unwrap();
361+
let repo = Repo::new(nested);
362+
let mut out = OutputCtx::new(false, OutputFormat::Human, false, 0);
363+
assert_eq!(out.repo_label(&repo), "demo");
364+
out = out.with_show_path(true, Some(root.path().to_path_buf()));
365+
let label = out.repo_label(&repo);
366+
assert!(label.starts_with("demo ("));
367+
assert!(label.contains("oss"));
368+
}

0 commit comments

Comments
 (0)