use std::path::PathBuf;
use std::process::Command;
use tempfile::TempDir;
#[tokio::test]
async fn test_complete_stack_workflow() {
let (_temp_dir, repo_path) = create_test_git_repo().await;
let build_output = Command::new("cargo")
.args(["build", "--release"])
.output()
.expect("Failed to build binary");
if !build_output.status.success() {
panic!(
"Failed to build binary: {}",
String::from_utf8_lossy(&build_output.stderr)
);
}
let binary_path = super::test_helpers::get_binary_path();
let output = Command::new(&binary_path)
.args(["stacks", "create", "test-feature"])
.current_dir(&repo_path)
.env("RUST_LOG", "info")
.output()
.expect("Failed to create stack");
if !output.status.success() {
eprintln!(
"Command failed. Stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
eprintln!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
}
assert!(output.status.success());
create_test_commits(&repo_path, 3).await;
let output = Command::new(&binary_path)
.args(["push", "--yes"])
.current_dir(&repo_path)
.env("RUST_LOG", "info")
.output()
.expect("Failed to push stack");
if !output.status.success() {
eprintln!(
"Push failed. Stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
eprintln!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
}
let output = Command::new(&binary_path)
.args(["stacks", "list"])
.current_dir(&repo_path)
.env("RUST_LOG", "info")
.output()
.expect("Failed to list stacks");
if !output.status.success() {
eprintln!(
"List failed. Stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
eprintln!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
} else {
println!("List output: {}", String::from_utf8_lossy(&output.stdout));
}
assert!(output.status.success());
assert!(String::from_utf8_lossy(&output.stdout).contains("test-feature"));
}
#[tokio::test]
async fn test_rebase_conflict_scenarios() {
let (_temp_dir, repo_path) = create_test_git_repo().await;
create_conflicting_base_changes(&repo_path).await;
create_conflicting_stack(&repo_path).await;
let binary_path = super::test_helpers::get_binary_path();
let output = Command::new(&binary_path)
.args(["rebase"])
.current_dir(&repo_path)
.env("RUST_LOG", "info")
.output()
.expect("Failed to rebase with conflicts");
if !output.status.success() {
eprintln!(
"Rebase failed. Stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
eprintln!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("Rebase failed as expected (conflict scenarios are complex)");
return; }
}
#[tokio::test]
async fn test_error_recovery_scenarios() {
let (_temp_dir, repo_path) = create_test_git_repo().await;
let binary_path = super::test_helpers::get_binary_path();
let output = Command::new(&binary_path)
.args(["stacks", "create", ""])
.current_dir(&repo_path)
.env("RUST_LOG", "info")
.output()
.expect("Command should run but fail gracefully");
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
if !output.status.success() {
assert!(
stderr.contains("error")
|| stderr.contains("invalid")
|| stdout.contains("error")
|| stdout.contains("invalid")
|| stderr.contains("name")
|| stdout.contains("name"),
"Should contain error about invalid input. Stderr: {stderr}, Stdout: {stdout}"
);
} else {
println!("CLI handled empty stack name gracefully");
}
}
async fn create_test_git_repo() -> (TempDir, PathBuf) {
let temp_dir = TempDir::new().unwrap();
let repo_path = temp_dir.path().to_path_buf();
Command::new("git")
.args(["init"])
.current_dir(&repo_path)
.output()
.unwrap();
Command::new("git")
.args(["config", "user.name", "Test"])
.current_dir(&repo_path)
.output()
.unwrap();
Command::new("git")
.args(["config", "user.email", "test@test.com"])
.current_dir(&repo_path)
.output()
.unwrap();
std::fs::write(repo_path.join("README.md"), "# Test").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(&repo_path)
.output()
.unwrap();
Command::new("git")
.args(["commit", "-m", "Initial"])
.current_dir(&repo_path)
.output()
.unwrap();
cascade_cli::config::initialize_repo(
&repo_path,
Some("https://test.bitbucket.com".to_string()),
)
.unwrap();
(temp_dir, repo_path)
}
async fn create_test_commits(repo_path: &PathBuf, count: u32) {
for i in 1..=count {
std::fs::write(
repo_path.join(format!("file{i}.txt")),
format!("Content {i}"),
)
.unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(repo_path)
.output()
.unwrap();
Command::new("git")
.args(["commit", "-m", &format!("Add file {i}")])
.current_dir(repo_path)
.output()
.unwrap();
}
}
async fn create_conflicting_base_changes(repo_path: &PathBuf) {
std::fs::write(repo_path.join("shared.txt"), "Base content").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(repo_path)
.output()
.unwrap();
Command::new("git")
.args(["commit", "-m", "Add shared file"])
.current_dir(repo_path)
.output()
.unwrap();
}
async fn create_conflicting_stack(repo_path: &PathBuf) {
let binary_path = super::test_helpers::get_binary_path();
Command::new(&binary_path)
.args(["stacks", "create", "conflict-test"])
.current_dir(repo_path)
.output()
.unwrap();
std::fs::write(repo_path.join("shared.txt"), "Stack content").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(repo_path)
.output()
.unwrap();
Command::new("git")
.args(["commit", "-m", "Modify shared file"])
.current_dir(repo_path)
.output()
.unwrap();
}