mod support;
use std::fs;
use std::process::Command as StdCommand;
use predicates::prelude::*;
use support::{lx, lx_no_colour};
use tempfile::tempdir;
fn git_fixture() -> tempfile::TempDir {
let dir = tempdir().expect("failed to create tempdir");
let path = dir.path();
StdCommand::new("git")
.args(["init", "-b", "main"])
.current_dir(path)
.output()
.expect("git init failed");
StdCommand::new("git")
.args(["config", "user.email", "test@test.com"])
.current_dir(path)
.output()
.expect("git config failed");
StdCommand::new("git")
.args(["config", "user.name", "Test"])
.current_dir(path)
.output()
.expect("git config failed");
fs::write(path.join("tracked.txt"), "hello").unwrap();
StdCommand::new("git")
.args(["add", "tracked.txt"])
.current_dir(path)
.output()
.expect("git add failed");
StdCommand::new("git")
.args(["commit", "-m", "initial"])
.current_dir(path)
.output()
.expect("git commit failed");
fs::write(path.join("untracked.txt"), "new").unwrap();
fs::write(path.join("tracked.txt"), "modified").unwrap();
dir
}
fn jj_available() -> bool {
StdCommand::new("jj")
.arg("version")
.output()
.is_ok_and(|o| o.status.success())
}
fn jj_feature_enabled() -> bool {
let output = lx_no_colour()
.args(["--vcs=jj", "/nonexistent"])
.output()
.expect("failed to run lx");
let stderr = String::from_utf8_lossy(&output.stderr);
!stderr.contains("disabled")
}
#[test]
fn vcs_invalid_value() {
lx()
.arg("--vcs=svn")
.assert()
.failure()
.stderr(predicate::str::contains("invalid value"));
}
#[test]
fn vcs_none_disables_status() {
let dir = git_fixture();
lx_no_colour()
.args(["--vcs=none", "--vcs-status", "-l"])
.arg(dir.path())
.assert()
.success()
.stdout(predicate::str::contains(" M ").not())
.stdout(predicate::str::contains(" N ").not());
}
#[test]
fn git_vcs_status_shows_column() {
let dir = git_fixture();
lx_no_colour()
.args(["--vcs=git", "--vcs-status", "-l"])
.arg(dir.path())
.assert()
.success()
.stdout(predicate::str::contains("N"))
.stdout(predicate::str::contains("untracked.txt"));
}
#[test]
fn git_modified_file_shows_m() {
let dir = git_fixture();
lx_no_colour()
.args(["--vcs=git", "--vcs-status", "-l"])
.arg(dir.path())
.assert()
.success()
.stdout(predicate::str::contains("M"))
.stdout(predicate::str::contains("tracked.txt"));
}
#[test]
fn git_vcs_status_header() {
let dir = git_fixture();
lx_no_colour()
.args(["--vcs=git", "--vcs-status", "-lh"])
.arg(dir.path())
.assert()
.success()
.stdout(predicate::str::contains("Git"));
}
#[test]
fn git_vcs_ignore_hides_ignored_files() {
let dir = git_fixture();
let path = dir.path();
fs::write(path.join(".gitignore"), "*.log\n").unwrap();
StdCommand::new("git")
.args(["add", ".gitignore"])
.current_dir(path)
.output()
.expect("git add failed");
fs::write(path.join("debug.log"), "log output").unwrap();
lx_no_colour()
.args(["--vcs=git", "--vcs-ignore", "-1"])
.arg(path)
.assert()
.success()
.stdout(predicate::str::contains("debug.log").not())
.stdout(predicate::str::contains("tracked.txt"));
}
#[test]
fn vcs_status_without_long_is_fine() {
lx_no_colour()
.args(["--vcs-status", "."])
.assert()
.success();
}
#[test]
fn jj_vcs_status_in_this_repo() {
if !jj_feature_enabled() || !jj_available() {
eprintln!("skipping: jj feature disabled or jj not available");
return;
}
lx_no_colour()
.args(["--vcs=jj", "--vcs-status", "-l", "Cargo.toml"])
.assert()
.success()
.stdout(predicate::str::contains("Cargo.toml"));
}
#[test]
fn jj_single_column_display() {
if !jj_feature_enabled() || !jj_available() {
eprintln!("skipping: jj feature disabled or jj not available");
return;
}
lx_no_colour()
.args(["--vcs=jj", "--vcs-status", "-l", "."])
.assert()
.success()
.stdout(predicate::str::contains("MM").not())
.stdout(predicate::str::contains("NN").not());
}
#[test]
fn jj_auto_detection() {
if !jj_feature_enabled() || !jj_available() {
eprintln!("skipping: jj feature disabled or jj not available");
return;
}
lx_no_colour()
.args(["--vcs=auto", "--vcs-status", "-l", "."])
.assert()
.success()
.stdout(predicate::str::contains("MM").not());
}
#[test]
fn auto_falls_back_to_git() {
let dir = git_fixture();
lx_no_colour()
.args(["--vcs=auto", "--vcs-status", "-l"])
.arg(dir.path())
.assert()
.success()
.stdout(predicate::str::contains("N"))
.stdout(predicate::str::contains("untracked.txt"));
}