mod common;
use common::{OutputAssertions, TestRepo};
use serde_json::Value;
#[test]
fn test_downstack_get_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["downstack", "get"]);
output.assert_success();
}
#[test]
fn test_downstack_get_with_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b", "c"]);
let output = repo.run_stax(&["downstack", "get"]);
output.assert_success();
}
#[test]
fn test_upstack_restack_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["upstack", "restack"]);
let _ = output;
}
#[test]
fn test_upstack_restack_with_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
repo.run_stax(&["checkout", "a"]);
let output = repo.run_stax(&["upstack", "restack"]);
output.assert_success();
}
#[test]
fn test_branch_create_from_different_parent() {
let repo = TestRepo::new();
repo.create_stack(&["base"]);
repo.run_stax(&["trunk"]);
let output = repo.run_stax(&["bc", "sibling"]);
output.assert_success();
}
#[test]
fn test_branch_create_deep_nesting() {
let repo = TestRepo::new();
for i in 0..5 {
let name = format!("level-{}", i);
let output = repo.run_stax(&["bc", &name]);
output.assert_success();
}
let output = repo.run_stax(&["status"]);
output.assert_success();
}
#[test]
fn test_log_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["log"]);
output.assert_success();
}
#[test]
fn test_log_alias_ll() {
let repo = TestRepo::new();
repo.create_stack(&["feature"]);
let output = repo.run_stax(&["ll"]);
output.assert_success();
}
#[test]
fn test_log_with_empty_stack() {
let repo = TestRepo::new();
let output = repo.run_stax(&["log"]);
output.assert_success();
}
#[test]
fn test_trunk_alias_t() {
let repo = TestRepo::new();
repo.create_stack(&["feature"]);
let output = repo.run_stax(&["t"]);
output.assert_success();
let current = repo.current_branch();
assert!(current == "main" || current == "master");
}
#[test]
fn test_trunk_when_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["trunk"]);
output.assert_success();
}
#[test]
fn test_modify_with_staged_changes() {
let repo = TestRepo::new();
repo.create_stack(&["feature"]);
repo.create_file("new_file.txt", "content");
repo.git(&["add", "new_file.txt"]);
let output = repo.run_stax(&["modify"]);
output.assert_success();
}
#[test]
fn test_modify_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["modify"]);
let _ = output;
}
#[test]
fn test_doctor_with_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b", "c"]);
let output = repo.run_stax(&["doctor"]);
output.assert_success();
}
#[test]
fn test_doctor_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["doctor"]);
output.assert_success();
}
#[test]
fn test_restack_clean_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
let output = repo.run_stax(&["restack"]);
output.assert_success();
}
#[test]
fn test_restack_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["restack"]);
let _ = output;
}
#[test]
fn test_restack_with_parent_changes() {
let repo = TestRepo::new();
repo.create_stack(&["parent", "child"]);
repo.run_stax(&["checkout", "parent"]);
repo.create_file("parent_file.txt", "content");
repo.commit("Parent change");
repo.run_stax(&["checkout", "child"]);
let output = repo.run_stax(&["restack"]);
output.assert_success();
}
#[test]
fn test_restack_auto_stash_pop_restores_dirty_current_worktree() {
let repo = TestRepo::new();
let branches = repo.create_stack(&["a", "b", "c"]);
repo.run_stax(&["t"]);
repo.create_file("main-update.txt", "main update");
repo.commit("Main update");
repo.run_stax(&["checkout", &branches[2]]);
repo.create_file("dirty.txt", "committed content\n");
repo.commit("Add dirty file");
repo.create_file("dirty.txt", "committed content\nlocal change\n");
let output = repo.run_stax(&["restack", "--auto-stash-pop"]);
output.assert_success();
let status = repo.git(&["status", "--porcelain"]);
assert!(status.status.success());
let stdout = TestRepo::stdout(&status);
assert!(
stdout.contains("dirty.txt"),
"Expected dirty current worktree changes to be restored, got:\n{}",
stdout
);
}
#[test]
fn test_restack_stop_here_excludes_descendants() {
let repo = TestRepo::new();
let branches = repo.create_stack(&["stop-a", "stop-b", "stop-c"]);
repo.run_stax(&["t"]).assert_success();
repo.create_file("root-change.txt", "updated trunk content");
repo.commit("Trunk change");
repo.run_stax(&["checkout", &branches[1]]).assert_success();
let output = repo.run_stax(&["restack", "--stop-here"]);
output.assert_success();
let status = repo.get_status_json();
assert_eq!(
branch_needs_restack(&status, &branches[0]),
Some(false),
"expected ancestor '{}' to be restacked",
branches[0]
);
assert_eq!(
branch_needs_restack(&status, &branches[1]),
Some(false),
"expected current branch '{}' to be restacked",
branches[1]
);
assert_eq!(
branch_needs_restack(&status, &branches[2]),
Some(true),
"expected descendant '{}' to remain needing restack",
branches[2]
);
}
#[test]
fn test_status_on_untracked_branch() {
let repo = TestRepo::new();
repo.git(&["checkout", "-b", "untracked"]);
let output = repo.run_stax(&["status"]);
let _ = output;
}
#[test]
fn test_status_long() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
let output = repo.run_stax(&["ll"]);
output.assert_success();
}
fn branch_needs_restack(status: &Value, branch: &str) -> Option<bool> {
status["branches"].as_array().and_then(|branches| {
branches
.iter()
.find(|b| b["name"].as_str() == Some(branch))
.and_then(|b| b["needs_restack"].as_bool())
})
}
#[test]
fn test_branch_untrack() {
let repo = TestRepo::new();
repo.create_stack(&["tracked"]);
let branch = repo.current_branch();
let metadata_ref = format!("refs/branch-metadata/{}", branch);
let before = repo.git(&["show", &metadata_ref]);
assert!(
before.status.success(),
"Expected metadata ref to exist before untrack"
);
let output = repo.run_stax(&["branch", "untrack", &branch]);
output.assert_success();
assert!(repo.list_branches().contains(&branch));
let after = repo.git(&["show", &metadata_ref]);
assert!(
!after.status.success(),
"Expected metadata ref to be removed after untrack"
);
}
#[test]
fn test_checkout_nonexistent_branch() {
let repo = TestRepo::new();
let output = repo.run_stax(&["checkout", "nonexistent"]);
output.assert_failure();
}
#[test]
fn test_checkout_with_stack() {
let repo = TestRepo::new();
let branches = repo.create_stack(&["a", "b", "c"]);
let output = repo.run_stax(&["checkout", &branches[1]]);
output.assert_success();
assert_eq!(repo.current_branch(), branches[1]);
}
#[test]
fn test_diff_with_changes() {
let repo = TestRepo::new();
repo.create_stack(&["feature"]);
repo.create_file("new_file.txt", "content");
repo.commit("Added file");
let output = repo.run_stax(&["diff"]);
output.assert_success();
}
#[test]
fn test_diff_empty_branch() {
let repo = TestRepo::new();
repo.create_stack(&["empty"]);
let output = repo.run_stax(&["diff"]);
output.assert_success();
}
#[test]
fn test_config_shows_values() {
let repo = TestRepo::new();
let output = repo.run_stax(&["config"]);
output.assert_success();
}
#[test]
fn test_multiple_independent_stacks() {
let repo = TestRepo::new();
repo.run_stax(&["bc", "stack1-a"]);
repo.create_file("s1.txt", "content");
repo.commit("Stack 1 commit");
repo.run_stax(&["trunk"]);
repo.run_stax(&["bc", "stack2-a"]);
repo.create_file("s2.txt", "content");
repo.commit("Stack 2 commit");
let output = repo.run_stax(&["status"]);
output.assert_success();
}
#[test]
fn test_up_from_top() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
let output = repo.run_stax(&["up"]);
output.assert_success();
}
#[test]
fn test_down_from_bottom() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
repo.run_stax(&["bottom"]);
let output = repo.run_stax(&["down"]);
let _ = output;
}
#[test]
fn test_up_with_count_exceeding_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
repo.run_stax(&["bottom"]);
let output = repo.run_stax(&["up", "10"]);
output.assert_success();
}
#[test]
fn test_branch_squash_single_commit() {
let repo = TestRepo::new();
repo.create_stack(&["feature"]);
let output = repo.run_stax(&["branch", "squash"]);
let _ = output;
}
#[test]
fn test_rename_to_existing_name() {
let repo = TestRepo::new();
repo.create_stack(&["existing"]);
repo.run_stax(&["trunk"]);
repo.create_stack(&["to-rename"]);
let output = repo.run_stax(&["rename", "existing"]);
output.assert_failure();
}
#[test]
fn test_rename_on_trunk() {
let repo = TestRepo::new();
let output = repo.run_stax(&["rename", "new-name"]);
output.assert_failure();
}
#[test]
fn test_auth_status() {
let repo = TestRepo::new();
let output = repo.run_stax(&["auth", "status"]);
let _ = output;
}
#[test]
fn test_auth_help() {
let repo = TestRepo::new();
let output = repo.run_stax(&["auth", "--help"]);
output.assert_success();
}
#[test]
fn test_continue_no_rebase() {
let repo = TestRepo::new();
let output = repo.run_stax(&["continue"]);
output.assert_success();
output.assert_stdout_contains("No rebase");
}
#[test]
fn test_pr_help() {
let repo = TestRepo::new();
let output = repo.run_stax(&["pr", "--help"]);
output.assert_success();
}
#[test]
fn test_submit_help() {
let repo = TestRepo::new();
let output = repo.run_stax(&["submit", "--help"]);
output.assert_success();
}
#[test]
fn test_undo_no_operations() {
let repo = TestRepo::new();
let output = repo.run_stax(&["undo"]);
output.assert_failure();
}
#[test]
fn test_redo_no_operations() {
let repo = TestRepo::new();
let output = repo.run_stax(&["redo"]);
output.assert_failure();
}
#[test]
fn test_merge_help() {
let repo = TestRepo::new();
let output = repo.run_stax(&["merge", "--help"]);
output.assert_success();
}
#[test]
fn test_range_diff_help() {
let repo = TestRepo::new();
let output = repo.run_stax(&["range-diff", "--help"]);
output.assert_success();
}
#[test]
fn test_branch_fold_in_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b"]);
let output = repo.run_stax(&["branch", "fold", "--yes"]);
output.assert_success();
}
#[test]
fn test_reparent_in_stack() {
let repo = TestRepo::new();
repo.create_stack(&["a", "b", "c"]);
let output = repo.run_stax(&["branch", "reparent", "a"]);
let _ = output;
}
#[test]
fn test_sync_help() {
let repo = TestRepo::new();
let output = repo.run_stax(&["sync", "--help"]);
output.assert_success();
}